@@ -50,6 +50,21 @@ class TestReviewCommentController extends ReviewCommentController {
5050 public workspaceFileChangeCommentThreads ( ) {
5151 return this . _workspaceFileChangeCommentThreads ;
5252 }
53+ public obsoleteFileChangeCommentThreads ( ) {
54+ return this . _obsoleteFileChangeCommentThreads ;
55+ }
56+ public reviewSchemeFileChangeCommentThreads ( ) {
57+ return this . _reviewSchemeFileChangeCommentThreads ;
58+ }
59+ public seedWorkspaceThreads ( path : string , threads : GHPRCommentThread [ ] ) {
60+ this . _workspaceFileChangeCommentThreads [ path ] = threads ;
61+ }
62+ public seedObsoleteThreads ( path : string , threads : GHPRCommentThread [ ] ) {
63+ this . _obsoleteFileChangeCommentThreads [ path ] = threads ;
64+ }
65+ public callFindMatchingThread ( thread : import ( '../../common/comment' ) . IReviewThread ) {
66+ return ( this as any ) . _findMatchingThread ( thread ) ;
67+ }
5368}
5469
5570describe ( 'ReviewCommentController' , function ( ) {
@@ -340,4 +355,61 @@ describe('ReviewCommentController', function () {
340355 assert . strictEqual ( workspaceFileChangeCommentThreads [ fileName ] . length , 1 ) ;
341356 } ) ;
342357 } ) ;
358+
359+ describe ( '_findMatchingThread' , function ( ) {
360+ it ( 'returns the moved thread when an existing workspace thread becomes outdated' , function ( ) {
361+ const fileName = 'data/products.json' ;
362+ const uri = vscode . Uri . parse ( `${ repository . rootUri . toString ( ) } /${ fileName } ` ) ;
363+ const reviewModel = new ReviewModel ( ) ;
364+ const reviewCommentController = new TestReviewCommentController (
365+ reviewManager ,
366+ manager ,
367+ repository ,
368+ reviewModel ,
369+ gitApiImpl ,
370+ telemetry ,
371+ ) ;
372+
373+ const threadA = createGHPRCommentThread ( 'thread-A' , uri ) ;
374+ const threadB = createGHPRCommentThread ( 'thread-B' , uri ) ;
375+ const existingObsolete = createGHPRCommentThread ( 'thread-C' , uri ) ;
376+
377+ reviewCommentController . seedWorkspaceThreads ( fileName , [ threadA , threadB ] ) ;
378+ reviewCommentController . seedObsoleteThreads ( fileName , [ existingObsolete ] ) ;
379+
380+ const reviewThread : import ( '../../common/comment' ) . IReviewThread = {
381+ id : 'thread-B' ,
382+ isResolved : false ,
383+ viewerCanResolve : false ,
384+ viewerCanUnresolve : false ,
385+ path : fileName ,
386+ diffSide : DiffSide . RIGHT ,
387+ startLine : 1 ,
388+ endLine : 1 ,
389+ originalStartLine : 1 ,
390+ originalEndLine : 1 ,
391+ isOutdated : true ,
392+ comments : [ ] ,
393+ subjectType : SubjectType . LINE ,
394+ } ;
395+
396+ const result = reviewCommentController . callFindMatchingThread ( reviewThread ) ;
397+
398+ // The matching thread should be the moved thread, not `undefined` or the wrong one.
399+ assert . strictEqual ( result . threadMap , reviewCommentController . obsoleteFileChangeCommentThreads ( ) ) ;
400+ assert . ok ( result . index > - 1 , 'index should point to the moved thread' ) ;
401+ assert . strictEqual ( result . threadMap [ fileName ] [ result . index ] , threadB ) ;
402+
403+ // Workspace map no longer contains the moved thread.
404+ const workspace = reviewCommentController . workspaceFileChangeCommentThreads ( ) ;
405+ assert . strictEqual ( workspace [ fileName ] . length , 1 ) ;
406+ assert . strictEqual ( workspace [ fileName ] [ 0 ] , threadA ) ;
407+
408+ // Obsolete map now contains the moved thread appended after the pre-existing one.
409+ const obsolete = reviewCommentController . obsoleteFileChangeCommentThreads ( ) ;
410+ assert . strictEqual ( obsolete [ fileName ] . length , 2 ) ;
411+ assert . strictEqual ( obsolete [ fileName ] [ 0 ] , existingObsolete ) ;
412+ assert . strictEqual ( obsolete [ fileName ] [ 1 ] , threadB ) ;
413+ } ) ;
414+ } ) ;
343415} ) ;
0 commit comments