@@ -56,6 +56,8 @@ public class TextBufferIssueTrackerTests
5656    private  IIssueConsumerFactory  issueConsumerFactory ; 
5757    private  IIssueConsumerStorage  issueConsumerStorage ; 
5858    private  IIssueConsumer  issueConsumer ; 
59+     private  ITaskExecutorWithDebounceFactory  taskExecutorWithDebounceFactory ; 
60+     private  ITaskExecutorWithDebounce  taskExecutorWithDebounce ; 
5961
6062    [ TestInitialize ] 
6163    public  void  SetUp ( ) 
@@ -71,6 +73,9 @@ public void SetUp()
7173        mockDocumentTextBuffer  =  CreateTextBufferMock ( mockTextSnapshot ) ; 
7274        mockedJavascriptDocumentFooJs  =  CreateDocumentMock ( "foo.js" ,  mockDocumentTextBuffer ) ; 
7375        javascriptLanguage  =  [ AnalysisLanguage . Javascript ] ; 
76+         taskExecutorWithDebounceFactory  =  Substitute . For < ITaskExecutorWithDebounceFactory > ( ) ; 
77+         taskExecutorWithDebounce  =  Substitute . For < ITaskExecutorWithDebounce > ( ) ; 
78+         taskExecutorWithDebounceFactory . Create ( Arg . Any < TimeSpan > ( ) ) . Returns ( taskExecutorWithDebounce ) ; 
7479        MockIssueConsumerFactory ( mockedJavascriptDocumentFooJs ,  issueConsumer ) ; 
7580
7681        testSubject  =  CreateTestSubject ( mockedJavascriptDocumentFooJs ) ; 
@@ -98,6 +103,7 @@ public void Ctor_RegistersEventsTrackerAndFactory()
98103        taggerProvider . ActiveTrackersForTesting . Should ( ) . BeEquivalentTo ( testSubject ) ; 
99104
100105        mockedJavascriptDocumentFooJs . Received ( 1 ) . FileActionOccurred  +=  Arg . Any < EventHandler < TextDocumentFileActionEventArgs > > ( ) ; 
106+         ( ( ITextBuffer2 ) mockDocumentTextBuffer ) . Received ( 1 ) . ChangedOnBackground  +=  Arg . Any < EventHandler < TextContentChangedEventArgs > > ( ) ; 
101107
102108        // Note: the test subject isn't responsible for adding the entry to the buffer.Properties 
103109        // - that's done by the TaggerProvider. 
@@ -150,6 +156,7 @@ public void Dispose_CleansUpEventsAndRegistrations()
150156        taggerProvider . ActiveTrackersForTesting . Should ( ) . BeEmpty ( ) ; 
151157
152158        mockedJavascriptDocumentFooJs . Received ( 1 ) . FileActionOccurred  -=  Arg . Any < EventHandler < TextDocumentFileActionEventArgs > > ( ) ; 
159+         ( ( ITextBuffer2 ) mockDocumentTextBuffer ) . Received ( 1 ) . ChangedOnBackground  -=  Arg . Any < EventHandler < TextContentChangedEventArgs > > ( ) ; 
153160    } 
154161
155162    [ TestMethod ] 
@@ -196,7 +203,6 @@ public void WhenFileIsLoaded_EventsAreNotRaised()
196203        var  renamedEventHandler  =  Substitute . For < EventHandler < DocumentRenamedEventArgs > > ( ) ; 
197204        var  savedEventHandler  =  Substitute . For < EventHandler < DocumentEventArgs > > ( ) ; 
198205        taggerProvider . OpenDocumentRenamed  +=  renamedEventHandler ; 
199-         taggerProvider . DocumentSaved  +=  savedEventHandler ; 
200206
201207        RaiseFileLoadedEvent ( mockedJavascriptDocumentFooJs ) ; 
202208
@@ -326,6 +332,21 @@ public void UpdateAnalysisState_CriticalException_IsNotSuppressed()
326332            . WithMessage ( "this is a test" ) ; 
327333    } 
328334
335+     [ TestMethod ] 
336+     public  void  OnTextBufferChangedOnBackground_UpdatesAnalysisState ( ) 
337+     { 
338+         var  eventHandler  =  SubscribeToDocumentSaved ( ) ; 
339+         var  newContent  =  "new content" ; 
340+         var  newSnapshot  =  CreateTextSnapshotMock ( newContent ) ; 
341+         var  newAnalysisSnapshot  =  new  AnalysisSnapshot ( mockedJavascriptDocumentFooJs . FilePath ,  newSnapshot ) ; 
342+         MockTaskExecutorWithDebounce ( ) ; 
343+         CreateTestSubject ( mockedJavascriptDocumentFooJs ) ; 
344+ 
345+         RaiseTextBufferChangedOnBackground ( currentTextBuffer :  mockDocumentTextBuffer ,  newSnapshot ) ; 
346+ 
347+         VerifyAnalysisStateUpdated ( mockedJavascriptDocumentFooJs ,  newAnalysisSnapshot ,  eventHandler ,  newContent ) ; 
348+     } 
349+ 
329350    private  void  SetUpIssueConsumerStorageThrows ( Exception  exception )  =>  issueConsumerStorage . When ( x =>  x . Remove ( Arg . Any < string > ( ) ) ) . Do ( x =>  throw  exception ) ; 
330351
331352    private  static void  VerifySingletonManagerDoesNotExist ( ITextBuffer  buffer )  =>  FindSingletonManagerInPropertyCollection ( buffer ) . Should ( ) . BeNull ( ) ; 
@@ -372,21 +393,21 @@ private TaggerProvider CreateTaggerProvider()
372393        var  analysisRequester  =  mockAnalysisRequester ; 
373394        var  provider  =  new  TaggerProvider ( sonarErrorListDataSource ,  textDocumentFactoryService , 
374395            serviceProvider ,  languageRecognizer ,  analysisRequester ,  vsProjectInfoProvider ,  issueConsumerFactory ,  issueConsumerStorage ,  Mock . Of < ITaggableBufferIndicator > ( ) , 
375-             mockFileTracker ,  analyzer ,  logger ,  new  InitializationProcessorFactory ( Substitute . For < IAsyncLockFactory > ( ) ,  new  NoOpThreadHandler ( ) ,  new  TestLogger ( ) ) ) ; 
396+             mockFileTracker ,  analyzer ,  logger ,  new  InitializationProcessorFactory ( Substitute . For < IAsyncLockFactory > ( ) ,  new  NoOpThreadHandler ( ) ,  new  TestLogger ( ) ) ,   taskExecutorWithDebounceFactory ) ; 
376397        return  provider ; 
377398    } 
378399
379-     private  static ITextSnapshot  CreateTextSnapshotMock ( ) 
400+     private  static ITextSnapshot  CreateTextSnapshotMock ( string   content   =   TextContent ) 
380401    { 
381402        var  textSnapshot  =  Substitute . For < ITextSnapshot > ( ) ; 
382-         textSnapshot . GetText ( ) . Returns ( TextContent ) ; 
403+         textSnapshot . GetText ( ) . Returns ( content ) ; 
383404        return  textSnapshot ; 
384405    } 
385406
386407    private  static ITextBuffer  CreateTextBufferMock ( ITextSnapshot  textSnapshot ) 
387408    { 
388409        // Text buffer with a properties collection and current snapshot 
389-         var  mockTextBuffer  =  Substitute . For < ITextBuffer > ( ) ; 
410+         var  mockTextBuffer  =  Substitute . For < ITextBuffer2 > ( ) ; 
390411
391412        var  dummyProperties  =  new  PropertyCollection ( ) ; 
392413        mockTextBuffer . Properties . Returns ( dummyProperties ) ; 
@@ -446,12 +467,51 @@ private TextBufferIssueTracker CreateTestSubject(ITextDocument textDocument)
446467    private  TextBufferIssueTracker  CreateTestSubject ( ITextDocument  textDocument ,  ILogger  logger )  => 
447468        new ( taggerProvider , 
448469            textDocument ,  javascriptLanguage , 
449-             mockSonarErrorDataSource ,  vsProjectInfoProvider ,  issueConsumerFactory ,  issueConsumerStorage ,  logger ) ; 
470+             mockSonarErrorDataSource ,  vsProjectInfoProvider ,  issueConsumerFactory ,  issueConsumerStorage ,  taskExecutorWithDebounce ,   logger ) ; 
450471
451472    private  void  ClearIssueConsumerCalls ( ) 
452473    { 
453474        issueConsumerStorage . ClearReceivedCalls ( ) ; 
454475        issueConsumerFactory . ClearReceivedCalls ( ) ; 
455476        vsProjectInfoProvider . ClearReceivedCalls ( ) ; 
456477    } 
478+ 
479+     private  static void  RaiseTextBufferChangedOnBackground ( ITextBuffer  currentTextBuffer ,  ITextSnapshot  newTextSnapshot ) 
480+     { 
481+         var  args  =  new  TextContentChangedEventArgs ( Substitute . For < ITextSnapshot > ( ) ,  newTextSnapshot ,  EditOptions . DefaultMinimalChange ,  null ) ; 
482+         ( ( ITextBuffer2 ) currentTextBuffer ) . ChangedOnBackground  +=  Raise . EventWith ( null ,  args ) ; 
483+     } 
484+ 
485+     private  EventHandler < DocumentEventArgs >  SubscribeToDocumentSaved ( ) 
486+     { 
487+         var  eventHandler  =  Substitute . For < EventHandler < DocumentEventArgs > > ( ) ; 
488+         taggerProvider . DocumentUpdated  +=  eventHandler ; 
489+         return  eventHandler ; 
490+     } 
491+ 
492+     private  void  MockTaskExecutorWithDebounce ( )  => 
493+         taskExecutorWithDebounce . When ( x =>  x . DebounceAsync ( Arg . Any < Action > ( ) ) ) . Do ( callInfo => 
494+         { 
495+             var  action  =  callInfo . Arg < Action > ( ) ; 
496+             action ( ) ; 
497+         } ) ; 
498+ 
499+     private  void  VerifyAnalysisStateUpdated ( 
500+         ITextDocument  textDocument , 
501+         AnalysisSnapshot  newAnalysisSnapshot , 
502+         EventHandler < DocumentEventArgs >  eventHandler , 
503+         string  newContent ) 
504+     { 
505+         issueConsumerStorage . Received ( ) . Remove ( textDocument . FilePath ) ; 
506+         vsProjectInfoProvider . Received ( ) . GetDocumentProjectInfo ( newAnalysisSnapshot . FilePath ) ; 
507+         issueConsumerFactory . Received ( ) . Create ( textDocument ,  newAnalysisSnapshot . FilePath ,  newAnalysisSnapshot . TextSnapshot ,  Arg . Any < string > ( ) ,  Arg . Any < Guid > ( ) , 
508+             Arg . Any < SnapshotChangedHandler > ( ) ) ; 
509+         issueConsumerStorage . Received ( ) . Set ( textDocument . FilePath ,  Arg . Any < IIssueConsumer > ( ) ) ; 
510+         issueConsumer . Received ( ) . SetIssues ( textDocument . FilePath ,  [ ] ) ; 
511+         issueConsumer . Received ( ) . SetHotspots ( textDocument . FilePath ,  [ ] ) ; 
512+         eventHandler . Received ( ) . Invoke ( taggerProvider , 
513+             Arg . Is < DocumentEventArgs > ( x =>  x . Document . FullPath  ==  textDocument . FilePath 
514+                                            &&  x . Document . DetectedLanguages  ==  javascriptLanguage 
515+                                            &&  x . Content  ==  newContent ) ) ; 
516+     } 
457517} 
0 commit comments