public void Document_Reanalyze() { using (var workspace = new TestWorkspace(TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic(), SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); WaitWaiter(workspace.ExportProvider); var info = solution.Projects[0].Documents[0]; var worker = new Analyzer(); var lazyWorker = new Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(worker), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // don't rely on background parser to have tree. explicitly do it here. TouchEverything(workspace.CurrentSolution); service.Reanalyze(workspace, worker, projectIds: null, documentIds: SpecializedCollections.SingletonEnumerable <DocumentId>(info.Id)); TouchEverything(workspace.CurrentSolution); Wait(service, workspace); service.Unregister(workspace); Assert.Equal(1, worker.SyntaxDocumentIds.Count); Assert.Equal(1, worker.DocumentIds.Count); } }
public async Task Document_Cancellation() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); await WaitWaiterAsync(workspace.ExportProvider); var id = workspace.CurrentSolution.Projects.First().DocumentIds[0]; var analyzer = new Analyzer(waitForCancellation: true); var lazyWorker = new Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); workspace.ChangeDocument(id, SourceText.From("//")); analyzer.RunningEvent.Wait(); workspace.ChangeDocument(id, SourceText.From("// ")); await WaitAsync(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(5, analyzer.DocumentIds.Count); } }
public async Task DynamicallyAddAnalyzer() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { // create solution and wait for it to settle var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); await WaitWaiterAsync(workspace.ExportProvider); // create solution crawler and add new analyzer provider dynamically var service = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable<Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>>(), GetListeners(workspace.ExportProvider)); service.Register(workspace); var provider = new AnalyzerProvider(new Analyzer()); service.AddAnalyzerProvider(provider, Metadata.Crawler); // wait for everything to settle await WaitAsync(service, workspace); service.Unregister(workspace); // check whether everything ran as expected Assert.Equal(10, provider.Analyzer.SyntaxDocumentIds.Count); Assert.Equal(10, provider.Analyzer.DocumentIds.Count); } }
public void Document_Cancellation_MultipleTimes() { using (var workspace = new TestWorkspace(TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic(), SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); WaitWaiter(workspace.ExportProvider); var id = workspace.CurrentSolution.Projects.First().DocumentIds[0]; var analyzer = new Analyzer(waitForCancellation: true); var lazyWorker = new Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); workspace.ChangeDocument(id, SourceText.From("//")); analyzer.RunningEvent.Wait(); analyzer.RunningEvent.Reset(); workspace.ChangeDocument(id, SourceText.From("// ")); analyzer.RunningEvent.Wait(); workspace.ChangeDocument(id, SourceText.From("// ")); Wait(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(5, analyzer.DocumentIds.Count); } }
public async Task DynamicallyAddAnalyzer() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { // create solution and wait for it to settle var solution = GetInitialSolutionInfo_2Projects_10Documents(workspace); workspace.OnSolutionAdded(solution); await WaitWaiterAsync(workspace.ExportProvider); // create solution crawler and add new analyzer provider dynamically var service = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable <Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata> >(), GetListenerProvider(workspace.ExportProvider)); service.Register(workspace); var provider = new AnalyzerProvider(new Analyzer()); service.AddAnalyzerProvider(provider, Metadata.Crawler); // wait for everything to settle await WaitAsync(service, workspace); service.Unregister(workspace); // check whether everything ran as expected Assert.Equal(10, provider.Analyzer.SyntaxDocumentIds.Count); Assert.Equal(10, provider.Analyzer.DocumentIds.Count); } }
private void InsertText(string code, string text, bool expectDocumentAnalysis, string language = LanguageNames.CSharp) { using (var workspace = TestWorkspaceFactory.CreateWorkspaceFromLines( SolutionCrawler, language, compilationOptions: null, parseOptions: null, content: new string[] { code })) { var analyzer = new Analyzer(); var lazyWorker = new Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); var testDocument = workspace.Documents.First(); var insertPosition = testDocument.CursorPosition; var textBuffer = testDocument.GetTextBuffer(); using (var edit = textBuffer.CreateEdit()) { edit.Insert(insertPosition.Value, text); edit.Apply(); } Wait(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(expectDocumentAnalysis ? 1 : 0, analyzer.DocumentIds.Count); } }
public async Task Document_Reanalyze() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); await WaitWaiterAsync(workspace.ExportProvider); var info = solution.Projects[0].Documents[0]; var worker = new Analyzer(); var lazyWorker = new Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(worker), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // don't rely on background parser to have tree. explicitly do it here. await TouchEverything(workspace.CurrentSolution); service.Reanalyze(workspace, worker, projectIds: null, documentIds: SpecializedCollections.SingletonEnumerable <DocumentId>(info.Id), highPriority: false); await TouchEverything(workspace.CurrentSolution); await WaitAsync(service, workspace); service.Unregister(workspace); Assert.Equal(1, worker.SyntaxDocumentIds.Count); Assert.Equal(1, worker.DocumentIds.Count); } }
public DiagnosticTaggerWrapper( TestWorkspace workspace, IReadOnlyDictionary <string, ImmutableArray <DiagnosticAnalyzer> >?analyzerMap = null, IDiagnosticUpdateSource?updateSource = null, bool createTaggerProvider = true ) { _threadingContext = workspace.GetService <IThreadingContext>(); _listenerProvider = workspace.GetService <IAsynchronousOperationListenerProvider>(); var analyzerReference = new TestAnalyzerReferenceByLanguage( analyzerMap ?? DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap() ); workspace.TryApplyChanges( workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference }) ); _workspace = workspace; _registrationService = (SolutionCrawlerRegistrationService)workspace.Services.GetRequiredService <ISolutionCrawlerRegistrationService>(); _registrationService.Register(workspace); if ( !_registrationService .GetTestAccessor() .TryGetWorkCoordinator(workspace, out var coordinator) ) { throw new InvalidOperationException(); } AnalyzerService = (DiagnosticAnalyzerService?)_registrationService .GetTestAccessor() .AnalyzerProviders.SelectMany(pair => pair.Value) .SingleOrDefault( lazyProvider => lazyProvider.Metadata.Name == WellKnownSolutionCrawlerAnalyzers.Diagnostic && lazyProvider.Metadata.HighPriorityForActiveFile ) ?.Value; DiagnosticService = (DiagnosticService)workspace.ExportProvider.GetExportedValue <IDiagnosticService>(); if (updateSource is object) { DiagnosticService.Register(updateSource); } if (createTaggerProvider) { _ = TaggerProvider; } }
public void RegisterService() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var registrationService = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable <Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata> >(), AggregateAsynchronousOperationListener.EmptyListeners); // register and unregister workspace to the service registrationService.Register(workspace); registrationService.Unregister(workspace); } }
public void RegisterService() { using (var workspace = new TestWorkspace(TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic(), SolutionCrawler)) { var registrationService = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable<Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>>(), AggregateAsynchronousOperationListener.EmptyListeners); // register and unregister workspace to the service registrationService.Register(workspace); registrationService.Unregister(workspace); } }
public void RegisterService() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var registrationService = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable<Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>>(), AggregateAsynchronousOperationListener.EmptyListeners); // register and unregister workspace to the service registrationService.Register(workspace); registrationService.Unregister(workspace); } }
public void RegisterService() { using (var workspace = new TestWorkspace(TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic(), SolutionCrawler)) { var registrationService = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable <Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata> >(), AggregateAsynchronousOperationListener.EmptyListeners); // register and unregister workspace to the service registrationService.Register(workspace); registrationService.Unregister(workspace); } }
public DiagnosticTaggerWrapper( TestWorkspace workspace, IReadOnlyDictionary <string, ImmutableArray <DiagnosticAnalyzer> >?analyzerMap = null, IDiagnosticUpdateSource?updateSource = null, bool createTaggerProvider = true) { _threadingContext = workspace.GetService <IThreadingContext>(); _listenerProvider = workspace.GetService <IAsynchronousOperationListenerProvider>(); var analyzerReference = new TestAnalyzerReferenceByLanguage(analyzerMap ?? DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); // Change the background analysis scope to OpenFiles instead of ActiveFile (default), // so that every diagnostic tagger test does not need to mark test files as "active" file. var csKey = new OptionKey2(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.CSharp); var vbKey = new OptionKey2(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic); workspace.SetOptions(workspace.Options .WithChangedOption(csKey, BackgroundAnalysisScope.OpenFiles) .WithChangedOption(vbKey, BackgroundAnalysisScope.OpenFiles)); _workspace = workspace; _registrationService = (SolutionCrawlerRegistrationService)workspace.Services.GetRequiredService <ISolutionCrawlerRegistrationService>(); _registrationService.Register(workspace); if (!_registrationService.GetTestAccessor().TryGetWorkCoordinator(workspace, out var coordinator)) { throw new InvalidOperationException(); } AnalyzerService = (DiagnosticAnalyzerService?)_registrationService.GetTestAccessor().AnalyzerProviders.SelectMany(pair => pair.Value).SingleOrDefault(lazyProvider => lazyProvider.Metadata.Name == WellKnownSolutionCrawlerAnalyzers.Diagnostic && lazyProvider.Metadata.HighPriorityForActiveFile)?.Value; DiagnosticService = (DiagnosticService)workspace.ExportProvider.GetExportedValue <IDiagnosticService>(); if (updateSource is object) { DiagnosticService.Register(updateSource); } if (createTaggerProvider) { _ = TaggerProvider; } }
public async Task RegisterService() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var registrationService = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable <Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata> >(), AsynchronousOperationListenerProvider.NullProvider); // register and unregister workspace to the service registrationService.Register(workspace); registrationService.Unregister(workspace); // make sure we wait for all waiter. the test wrongly assumed there won't be // any pending async event which is implementation detail when creating workspace // and changing options. await WaitWaiterAsync(workspace.ExportProvider); } }
public async Task RegisterService() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var registrationService = new SolutionCrawlerRegistrationService( SpecializedCollections.EmptyEnumerable<Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>>(), AggregateAsynchronousOperationListener.EmptyListeners); // register and unregister workspace to the service registrationService.Register(workspace); registrationService.Unregister(workspace); // make sure we wait for all waiter. the test wrongly assumed there won't be // any pending async event which is implementation detail when creating workspace // and changing options. await WaitWaiterAsync(workspace.ExportProvider); } }
private Analyzer ExecuteOperation(TestWorkspace workspace, Action <TestWorkspace> operation) { var worker = new Analyzer(); var lazyWorker = new Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(worker), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // don't rely on background parser to have tree. explicitly do it here. TouchEverything(workspace.CurrentSolution); operation(workspace); TouchEverything(workspace.CurrentSolution); Wait(service, workspace); service.Unregister(workspace); return(worker); }
public void Document_InvocationReasons() { using (var workspace = new TestWorkspace(TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic(), SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); WaitWaiter(workspace.ExportProvider); var id = workspace.CurrentSolution.Projects.First().DocumentIds[0]; var analyzer = new Analyzer(blockedRun: true); var lazyWorker = new Lazy <IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // first invocation will block worker workspace.ChangeDocument(id, SourceText.From("//")); analyzer.RunningEvent.Wait(); var openReady = new ManualResetEventSlim(initialState: false); var closeReady = new ManualResetEventSlim(initialState: false); workspace.DocumentOpened += (o, e) => openReady.Set(); workspace.DocumentClosed += (o, e) => closeReady.Set(); // cause several different request to queue up workspace.ChangeDocument(id, SourceText.From("// ")); workspace.OpenDocument(id); workspace.CloseDocument(id); openReady.Set(); closeReady.Set(); analyzer.BlockEvent.Set(); Wait(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(5, analyzer.DocumentIds.Count); } }
public void Document_Reanalyze() { using (var workspace = new TestWorkspace(TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic(), SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); WaitWaiter(workspace.ExportProvider); var info = solution.Projects[0].Documents[0]; var worker = new Analyzer(); var lazyWorker = new Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(worker), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // don't rely on background parser to have tree. explicitly do it here. TouchEverything(workspace.CurrentSolution); service.Reanalyze(workspace, worker, projectIds: null, documentIds: SpecializedCollections.SingletonEnumerable<DocumentId>(info.Id)); TouchEverything(workspace.CurrentSolution); Wait(service, workspace); service.Unregister(workspace); Assert.Equal(1, worker.SyntaxDocumentIds.Count); Assert.Equal(1, worker.DocumentIds.Count); } }
private async Task<Analyzer> ExecuteOperation(TestWorkspace workspace, Action<TestWorkspace> operation) { var worker = new Analyzer(); var lazyWorker = new Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(worker), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // don't rely on background parser to have tree. explicitly do it here. await TouchEverything(workspace.CurrentSolution); operation(workspace); await TouchEverything(workspace.CurrentSolution); await WaitAsync(service, workspace); service.Unregister(workspace); return worker; }
private async Task InsertText(string code, string text, bool expectDocumentAnalysis, string language = LanguageNames.CSharp) { using (var workspace = await TestWorkspace.CreateAsync( SolutionCrawler, language, compilationOptions: null, parseOptions: null, content: code)) { SetOptions(workspace); var analyzer = new Analyzer(); var lazyWorker = new Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); var testDocument = workspace.Documents.First(); var insertPosition = testDocument.CursorPosition; var textBuffer = testDocument.GetTextBuffer(); using (var edit = textBuffer.CreateEdit()) { edit.Insert(insertPosition.Value, text); edit.Apply(); } await WaitAsync(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(expectDocumentAnalysis ? 1 : 0, analyzer.DocumentIds.Count); } }
public async Task Document_InvocationReasons() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); await WaitWaiterAsync(workspace.ExportProvider); var id = workspace.CurrentSolution.Projects.First().DocumentIds[0]; var analyzer = new Analyzer(blockedRun: true); var lazyWorker = new Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // first invocation will block worker workspace.ChangeDocument(id, SourceText.From("//")); analyzer.RunningEvent.Wait(); var openReady = new ManualResetEventSlim(initialState: false); var closeReady = new ManualResetEventSlim(initialState: false); workspace.DocumentOpened += (o, e) => openReady.Set(); workspace.DocumentClosed += (o, e) => closeReady.Set(); // cause several different request to queue up workspace.ChangeDocument(id, SourceText.From("// ")); workspace.OpenDocument(id); workspace.CloseDocument(id); openReady.Set(); closeReady.Set(); analyzer.BlockEvent.Set(); await WaitAsync(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(5, analyzer.DocumentIds.Count); } }
public async Task Document_Cancellation_MultipleTimes() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); await WaitWaiterAsync(workspace.ExportProvider); var id = workspace.CurrentSolution.Projects.First().DocumentIds[0]; var analyzer = new Analyzer(waitForCancellation: true); var lazyWorker = new Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); workspace.ChangeDocument(id, SourceText.From("//")); analyzer.RunningEvent.Wait(); analyzer.RunningEvent.Reset(); workspace.ChangeDocument(id, SourceText.From("// ")); analyzer.RunningEvent.Wait(); workspace.ChangeDocument(id, SourceText.From("// ")); await WaitAsync(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(5, analyzer.DocumentIds.Count); } }
public async Task Document_Reanalyze() { using (var workspace = new WorkCoordinatorWorkspace(SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); await WaitWaiterAsync(workspace.ExportProvider); var info = solution.Projects[0].Documents[0]; var worker = new Analyzer(); var lazyWorker = new Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(worker), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); // don't rely on background parser to have tree. explicitly do it here. await TouchEverything(workspace.CurrentSolution); service.Reanalyze(workspace, worker, projectIds: null, documentIds: SpecializedCollections.SingletonEnumerable<DocumentId>(info.Id), highPriority: false); await TouchEverything(workspace.CurrentSolution); await WaitAsync(service, workspace); service.Unregister(workspace); Assert.Equal(1, worker.SyntaxDocumentIds.Count); Assert.Equal(1, worker.DocumentIds.Count); } }
public void Document_Cancellation() { using (var workspace = new TestWorkspace(TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic(), SolutionCrawler)) { var solution = GetInitialSolutionInfo(workspace); workspace.OnSolutionAdded(solution); WaitWaiter(workspace.ExportProvider); var id = workspace.CurrentSolution.Projects.First().DocumentIds[0]; var analyzer = new Analyzer(waitForCancellation: true); var lazyWorker = new Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>(() => new AnalyzerProvider(analyzer), Metadata.Crawler); var service = new SolutionCrawlerRegistrationService(new[] { lazyWorker }, GetListeners(workspace.ExportProvider)); service.Register(workspace); workspace.ChangeDocument(id, SourceText.From("//")); analyzer.RunningEvent.Wait(); workspace.ChangeDocument(id, SourceText.From("// ")); Wait(service, workspace); service.Unregister(workspace); Assert.Equal(1, analyzer.SyntaxDocumentIds.Count); Assert.Equal(5, analyzer.DocumentIds.Count); } }