@@ -4,7 +4,7 @@ import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge
44import { TextData } from 'realtime-server/lib/esm/scriptureforge/models/text-data' ;
55import { Chapter , TextInfo } from 'realtime-server/lib/esm/scriptureforge/models/text-info' ;
66import { BehaviorSubject , of } from 'rxjs' ;
7- import { anything , deepEqual , instance , mock , when } from 'ts-mockito' ;
7+ import { anything , instance , mock , when } from 'ts-mockito' ;
88import { ActivatedProjectService } from 'xforge-common/activated-project.service' ;
99import { NoticeService } from 'xforge-common/notice.service' ;
1010import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module' ;
@@ -82,28 +82,12 @@ describe('progress service', () => {
8282 it ( 'updates total progress when chapter content changes' , fakeAsync ( async ( ) => {
8383 const env = new TestEnvironment ( ) ;
8484 const changeEvent = new BehaviorSubject ( { } ) ;
85- when ( mockSFProjectService . getText ( deepEqual ( new TextDocId ( 'project01' , 1 , 2 , 'target' ) ) ) ) . thenCall ( ( ) => {
86- return {
87- getSegmentCount : ( ) => {
88- return { translated : 12 , blank : 2 } ;
89- } ,
90- getNonEmptyVerses : ( ) => env . createVerses ( 12 ) ,
91- changes$ : changeEvent
92- } ;
93- } ) ;
85+ env . setTextData ( 'project01' , 1 , 2 , 'target' , 12 , 2 , changeEvent ) ;
9486
9587 tick ( ) ;
9688
9789 // mock a change
98- when ( mockSFProjectService . getText ( deepEqual ( new TextDocId ( 'project01' , 1 , 2 , 'target' ) ) ) ) . thenCall ( ( ) => {
99- return {
100- getSegmentCount : ( ) => {
101- return { translated : 13 , blank : 1 } ;
102- } ,
103- getNonEmptyVerses : ( ) => env . createVerses ( 13 ) ,
104- changes$ : changeEvent
105- } ;
106- } ) ;
90+ env . setTextData ( 'project01' , 1 , 2 , 'target' , 13 , 1 , changeEvent ) ;
10791
10892 const originalProgress = env . service . overallProgress . translated ;
10993 tick ( 1000 ) ; // wait for the throttle time
@@ -155,9 +139,9 @@ describe('progress service', () => {
155139
156140 it ( 'cannot train suggestions if no source permission' , fakeAsync ( async ( ) => {
157141 const env = new TestEnvironment ( ) ;
158- when (
159- mockPermissionService . canAccessText ( deepEqual ( new TextDocId ( 'sourceId' , anything ( ) , anything ( ) , 'target' ) ) )
160- ) . thenResolve ( false ) ;
142+ when ( mockPermissionService . canAccessText ( anything ( ) ) ) . thenCall ( ( textDocId : TextDocId ) => {
143+ return Promise . resolve ( textDocId . projectId !== 'sourceId' ) ;
144+ } ) ;
161145 tick ( ) ;
162146
163147 expect ( env . service . canTrainSuggestions ) . toBeFalsy ( ) ;
@@ -188,6 +172,9 @@ class TestEnvironment {
188172 readonly mockProject = mock ( SFProjectProfileDoc ) ;
189173 readonly project$ = new BehaviorSubject ( instance ( this . mockProject ) ) ;
190174
175+ // Store all text data in a single map to avoid repeated deepEqual calls
176+ private readonly allTextData = new Map < string , { translated : number ; blank : number } > ( ) ;
177+
191178 constructor (
192179 private readonly translatedSegments : number = 1000 ,
193180 private readonly blankSegments : number = 500
@@ -218,37 +205,75 @@ class TestEnvironment {
218205 id : 'project02' ,
219206 remoteChanges$ : new BehaviorSubject ( [ ] )
220207 } as unknown as SFProjectProfileDoc ) ;
221- this . setUpGetText ( 'project02' , 0 , 1000 ) ;
208+ this . populateTextData ( 'project02' , 0 , 1000 ) ;
209+
210+ this . populateTextData ( 'sourceId' , this . translatedSegments , this . blankSegments ) ;
211+ this . populateTextData ( 'project01' , this . translatedSegments , this . blankSegments ) ;
212+
213+ // Set up a single mock for getText that handles all TextDocId instances
214+ when ( mockSFProjectService . getText ( anything ( ) ) ) . thenCall ( ( textDocId : TextDocId ) => {
215+ const key = `${ textDocId . projectId } :${ textDocId . bookNum } :${ textDocId . chapterNum } :${ textDocId . textType } ` ;
216+ const data = this . allTextData . get ( key ) ;
217+ const changeKey = `${ key } :changes` ;
218+ const customChanges = ( this . allTextData as any ) . get ( changeKey ) ;
219+
220+ if ( data != null ) {
221+ return {
222+ getSegmentCount : ( ) => {
223+ return { translated : data . translated , blank : data . blank } ;
224+ } ,
225+ getNonEmptyVerses : ( ) => this . createVerses ( data . translated ) ,
226+ changes$ : customChanges ?? of ( { } as TextData )
227+ } ;
228+ }
222229
223- this . setUpGetText ( 'sourceId' , this . translatedSegments , this . blankSegments ) ;
224- this . setUpGetText ( 'project01' , this . translatedSegments , this . blankSegments ) ;
230+ // Return a default value if not found
231+ return {
232+ getSegmentCount : ( ) => {
233+ return { translated : 0 , blank : 0 } ;
234+ } ,
235+ getNonEmptyVerses : ( ) => [ ] ,
236+ changes$ : of ( { } as TextData )
237+ } ;
238+ } ) ;
225239
226240 this . service = TestBed . inject ( ProgressService ) ;
227241 }
228242
229- setUpGetText ( projectId : string , translatedSegments : number , blankSegments : number ) : void {
243+ private populateTextData ( projectId : string , translatedSegments : number , blankSegments : number ) : void {
230244 for ( let book = 1 ; book <= this . numBooks ; book ++ ) {
231245 for ( let chapter = 0 ; chapter < this . numChapters ; chapter ++ ) {
232246 const translated = translatedSegments >= 9 ? 9 : translatedSegments ;
233247 translatedSegments -= translated ;
234248 const blank = blankSegments >= 5 ? 5 : blankSegments ;
235249 blankSegments -= blank ;
236250
237- when ( mockSFProjectService . getText ( deepEqual ( new TextDocId ( projectId , book , chapter , 'target' ) ) ) ) . thenCall (
238- ( ) => {
239- return {
240- getSegmentCount : ( ) => {
241- return { translated, blank } ;
242- } ,
243- getNonEmptyVerses : ( ) => this . createVerses ( translated ) ,
244- changes$ : of ( { } as TextData )
245- } ;
246- }
247- ) ;
251+ const key = `${ projectId } :${ book } :${ chapter } :target` ;
252+ this . allTextData . set ( key , { translated, blank } ) ;
248253 }
249254 }
250255 }
251256
257+ setTextData (
258+ projectId : string ,
259+ book : number ,
260+ chapter : number ,
261+ textType : string ,
262+ translated : number ,
263+ blank : number ,
264+ changes$ ?: BehaviorSubject < any >
265+ ) : void {
266+ const key = `${ projectId } :${ book } :${ chapter } :${ textType } ` ;
267+ this . allTextData . set ( key , { translated, blank } ) ;
268+
269+ // If a custom changes$ observable is provided, we need to store it
270+ // so the mock can return it
271+ if ( changes$ != null ) {
272+ const changeKey = `${ key } :changes` ;
273+ ( this . allTextData as any ) . set ( changeKey , changes$ ) ;
274+ }
275+ }
276+
252277 createVerses ( num : number ) : string [ ] {
253278 let count = 0 ;
254279 return Array . from ( { length : num } , ( ) => 'verse' + ++ count ) ;
0 commit comments