@@ -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 < ITextSnapshot > 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 < ITextSnapshot > > ( ) ;
78+ taskExecutorWithDebounceFactory . Create < ITextSnapshot > ( Arg . Any < double > ( ) ) . 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.
@@ -196,7 +202,6 @@ public void WhenFileIsLoaded_EventsAreNotRaised()
196202 var renamedEventHandler = Substitute . For < EventHandler < DocumentRenamedEventArgs > > ( ) ;
197203 var savedEventHandler = Substitute . For < EventHandler < DocumentEventArgs > > ( ) ;
198204 taggerProvider . OpenDocumentRenamed += renamedEventHandler ;
199- taggerProvider . DocumentSaved += savedEventHandler ;
200205
201206 RaiseFileLoadedEvent ( mockedJavascriptDocumentFooJs ) ;
202207
@@ -326,6 +331,21 @@ public void UpdateAnalysisState_CriticalException_IsNotSuppressed()
326331 . WithMessage ( "this is a test" ) ;
327332 }
328333
334+ [ TestMethod ]
335+ public void OnTextBufferChangedOnBackground_UpdatesAnalysisState ( )
336+ {
337+ var eventHandler = SubscribeToDocumentSaved ( ) ;
338+ var newContent = "new content" ;
339+ var newSnapshot = CreateTextSnapshotMock ( newContent ) ;
340+ var newAnalysisSnapshot = new AnalysisSnapshot ( mockedJavascriptDocumentFooJs . FilePath , newSnapshot ) ;
341+ MockTaskExecutorWithDebounce ( newSnapshot ) ;
342+ CreateTestSubject ( mockedJavascriptDocumentFooJs ) ;
343+
344+ RaiseTextBufferChangedOnBackground ( currentTextBuffer : mockDocumentTextBuffer , newSnapshot ) ;
345+
346+ VerifyAnalysisStateUpdated ( mockedJavascriptDocumentFooJs , newAnalysisSnapshot , eventHandler , newContent ) ;
347+ }
348+
329349 private void SetUpIssueConsumerStorageThrows ( Exception exception ) => issueConsumerStorage . When ( x => x . Remove ( Arg . Any < string > ( ) ) ) . Do ( x => throw exception ) ;
330350
331351 private static void VerifySingletonManagerDoesNotExist ( ITextBuffer buffer ) => FindSingletonManagerInPropertyCollection ( buffer ) . Should ( ) . BeNull ( ) ;
@@ -372,21 +392,21 @@ private TaggerProvider CreateTaggerProvider()
372392 var analysisRequester = mockAnalysisRequester ;
373393 var provider = new TaggerProvider ( sonarErrorListDataSource , textDocumentFactoryService ,
374394 serviceProvider , languageRecognizer , analysisRequester , vsProjectInfoProvider , issueConsumerFactory , issueConsumerStorage , Mock . Of < ITaggableBufferIndicator > ( ) ,
375- mockFileTracker , analyzer , logger , new InitializationProcessorFactory ( Substitute . For < IAsyncLockFactory > ( ) , new NoOpThreadHandler ( ) , new TestLogger ( ) ) ) ;
395+ mockFileTracker , analyzer , logger , new InitializationProcessorFactory ( Substitute . For < IAsyncLockFactory > ( ) , new NoOpThreadHandler ( ) , new TestLogger ( ) ) , taskExecutorWithDebounceFactory ) ;
376396 return provider ;
377397 }
378398
379- private static ITextSnapshot CreateTextSnapshotMock ( )
399+ private static ITextSnapshot CreateTextSnapshotMock ( string content = TextContent )
380400 {
381401 var textSnapshot = Substitute . For < ITextSnapshot > ( ) ;
382- textSnapshot . GetText ( ) . Returns ( TextContent ) ;
402+ textSnapshot . GetText ( ) . Returns ( content ) ;
383403 return textSnapshot ;
384404 }
385405
386406 private static ITextBuffer CreateTextBufferMock ( ITextSnapshot textSnapshot )
387407 {
388408 // Text buffer with a properties collection and current snapshot
389- var mockTextBuffer = Substitute . For < ITextBuffer > ( ) ;
409+ var mockTextBuffer = Substitute . For < ITextBuffer2 > ( ) ;
390410
391411 var dummyProperties = new PropertyCollection ( ) ;
392412 mockTextBuffer . Properties . Returns ( dummyProperties ) ;
@@ -446,12 +466,51 @@ private TextBufferIssueTracker CreateTestSubject(ITextDocument textDocument)
446466 private TextBufferIssueTracker CreateTestSubject ( ITextDocument textDocument , ILogger logger ) =>
447467 new ( taggerProvider ,
448468 textDocument , javascriptLanguage ,
449- mockSonarErrorDataSource , vsProjectInfoProvider , issueConsumerFactory , issueConsumerStorage , logger ) ;
469+ mockSonarErrorDataSource , vsProjectInfoProvider , issueConsumerFactory , issueConsumerStorage , taskExecutorWithDebounce , logger ) ;
450470
451471 private void ClearIssueConsumerCalls ( )
452472 {
453473 issueConsumerStorage . ClearReceivedCalls ( ) ;
454474 issueConsumerFactory . ClearReceivedCalls ( ) ;
455475 vsProjectInfoProvider . ClearReceivedCalls ( ) ;
456476 }
477+
478+ private static void RaiseTextBufferChangedOnBackground ( ITextBuffer currentTextBuffer , ITextSnapshot newTextSnapshot )
479+ {
480+ var args = new TextContentChangedEventArgs ( Substitute . For < ITextSnapshot > ( ) , newTextSnapshot , EditOptions . DefaultMinimalChange , null ) ;
481+ ( ( ITextBuffer2 ) currentTextBuffer ) . ChangedOnBackground += Raise . EventWith ( null , args ) ;
482+ }
483+
484+ private EventHandler < DocumentEventArgs > SubscribeToDocumentSaved ( )
485+ {
486+ var eventHandler = Substitute . For < EventHandler < DocumentEventArgs > > ( ) ;
487+ taggerProvider . DocumentUpdated += eventHandler ;
488+ return eventHandler ;
489+ }
490+
491+ private void MockTaskExecutorWithDebounce ( ITextSnapshot newSnapshot ) =>
492+ taskExecutorWithDebounce . When ( x => x . DebounceAsync ( Arg . Is < ITextSnapshot > ( x => x == newSnapshot ) , Arg . Any < Action < ITextSnapshot > > ( ) ) ) . Do ( callInfo =>
493+ {
494+ var action = callInfo . Arg < Action < ITextSnapshot > > ( ) ;
495+ action ( newSnapshot ) ;
496+ } ) ;
497+
498+ private void VerifyAnalysisStateUpdated (
499+ ITextDocument textDocument ,
500+ AnalysisSnapshot newAnalysisSnapshot ,
501+ EventHandler < DocumentEventArgs > eventHandler ,
502+ string newContent )
503+ {
504+ issueConsumerStorage . Received ( ) . Remove ( textDocument . FilePath ) ;
505+ vsProjectInfoProvider . Received ( ) . GetDocumentProjectInfo ( newAnalysisSnapshot . FilePath ) ;
506+ issueConsumerFactory . Received ( ) . Create ( textDocument , newAnalysisSnapshot . FilePath , newAnalysisSnapshot . TextSnapshot , Arg . Any < string > ( ) , Arg . Any < Guid > ( ) ,
507+ Arg . Any < SnapshotChangedHandler > ( ) ) ;
508+ issueConsumerStorage . Received ( ) . Set ( textDocument . FilePath , Arg . Any < IIssueConsumer > ( ) ) ;
509+ issueConsumer . Received ( ) . SetIssues ( textDocument . FilePath , [ ] ) ;
510+ issueConsumer . Received ( ) . SetHotspots ( textDocument . FilePath , [ ] ) ;
511+ eventHandler . Received ( ) . Invoke ( taggerProvider ,
512+ Arg . Is < DocumentEventArgs > ( x => x . Document . FullPath == textDocument . FilePath
513+ && x . Document . DetectedLanguages == javascriptLanguage
514+ && x . Content == newContent ) ) ;
515+ }
457516}
0 commit comments