internal static IList<ITagSpan<IErrorTag>> GetErrorsFromUpdateSource(TestWorkspace workspace, TestHostDocument document, DiagnosticsUpdatedArgs updateArgs) { var source = new TestDiagnosticUpdateSource(); var diagnosticWaiter = new DiagnosticServiceWaiter(); var diagnosticListeners = SpecializedCollections.SingletonEnumerable(new Lazy<IAsynchronousOperationListener, FeatureMetadata>( () => diagnosticWaiter, new FeatureMetadata(new Dictionary<string, object>() { { "FeatureName", FeatureAttribute.DiagnosticService } }))); var optionsService = workspace.Services.GetService<IOptionService>(); var diagnosticService = new DiagnosticService(SpecializedCollections.SingletonEnumerable<IDiagnosticUpdateSource>(source), diagnosticListeners); var squiggleWaiter = new ErrorSquiggleWaiter(); var foregroundService = new TestForegroundNotificationService(); var buffer = document.GetTextBuffer(); var taggerSource = new DiagnosticsSquiggleTaggerProvider.TagSource(buffer, foregroundService, diagnosticService, optionsService, squiggleWaiter); source.RaiseDiagnosticsUpdated(updateArgs); diagnosticWaiter.CreateWaitTask().PumpingWait(); squiggleWaiter.CreateWaitTask().PumpingWait(); var snapshot = buffer.CurrentSnapshot; var intervalTree = taggerSource.GetTagIntervalTreeForBuffer(buffer); var spans = intervalTree.GetIntersectingSpans(new SnapshotSpan(snapshot, 0, snapshot.Length)); taggerSource.TestOnly_Dispose(); return spans; }
public TestWorkspace GetWorkspace( string markup, ExportProvider exportProvider = null, string workspaceKind = null ) { // If it looks like XML, we'll treat it as XML; any parse error would be rejected and will throw. // We'll do a case insensitive search here so if somebody has a lowercase W it'll be tried (and // rejected by the XML parser) rather than treated as regular text. if (markup.TrimStart().StartsWith("<Workspace>", StringComparison.OrdinalIgnoreCase)) { CloseTextView(); _workspace?.Dispose(); _workspace = TestWorkspace.CreateWorkspace( XElement.Parse(markup), exportProvider: exportProvider, workspaceKind: workspaceKind ); _currentDocument = _workspace.Documents.First(d => d.CursorPosition.HasValue); Position = _currentDocument.CursorPosition.Value; Code = _currentDocument.GetTextBuffer().CurrentSnapshot.GetText(); return(_workspace); } else { MarkupTestFile.GetPosition(markup.NormalizeLineEndings(), out Code, out Position); var workspace = GetWorkspace(exportProvider); _currentDocument = workspace.Documents.Single(); return(workspace); } }
public override Task <TextAndVersion> LoadTextAndVersionAsync(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken) { // Create a simple SourceText so that way we're not backing "closed" files by editors to best reflect // what closed files look like in reality. var text = SourceText.From(_hostDocument.GetTextBuffer().CurrentSnapshot.GetText()); return(Task.FromResult(TextAndVersion.Create(text, VersionStamp.Create(), _hostDocument.FilePath))); }
public RenameTrackingTestState( string markup, string languageName, bool onBeforeGlobalSymbolRenamedReturnValue = true, bool onAfterGlobalSymbolRenamedReturnValue = true) { this.Workspace = CreateTestWorkspace(markup, languageName, TestExportProvider.CreateExportProviderWithCSharpAndVisualBasic()); _hostDocument = Workspace.Documents.First(); _view = _hostDocument.GetTextView(); _view.Caret.MoveTo(new SnapshotPoint(_view.TextSnapshot, _hostDocument.CursorPosition.Value)); _editorOperations = Workspace.GetService<IEditorOperationsFactoryService>().GetEditorOperations(_view); _historyRegistry = Workspace.ExportProvider.GetExport<ITextUndoHistoryRegistry>().Value; _mockRefactorNotifyService = new MockRefactorNotifyService { OnBeforeSymbolRenamedReturnValue = onBeforeGlobalSymbolRenamedReturnValue, OnAfterSymbolRenamedReturnValue = onAfterGlobalSymbolRenamedReturnValue }; var optionService = this.Workspace.Services.GetService<IOptionService>(); // Mock the action taken by the workspace INotificationService var notificationService = Workspace.Services.GetService<INotificationService>() as INotificationServiceCallback; var callback = new Action<string, string, NotificationSeverity>((message, title, severity) => _notificationMessage = message); notificationService.NotificationCallback = callback; var tracker = new RenameTrackingTaggerProvider( _historyRegistry, Workspace.ExportProvider.GetExport<Host.IWaitIndicator>().Value, Workspace.ExportProvider.GetExport<IInlineRenameService>().Value, Workspace.ExportProvider.GetExport<IDiagnosticAnalyzerService>().Value, SpecializedCollections.SingletonEnumerable(_mockRefactorNotifyService), Workspace.ExportProvider.GetExports<IAsynchronousOperationListener, FeatureMetadata>()); _tagger = tracker.CreateTagger<RenameTrackingTag>(_hostDocument.GetTextBuffer()); if (languageName == LanguageNames.CSharp) { _codeFixProvider = new CSharpRenameTrackingCodeFixProvider( Workspace.ExportProvider.GetExport<Host.IWaitIndicator>().Value, _historyRegistry, SpecializedCollections.SingletonEnumerable(_mockRefactorNotifyService)); } else if (languageName == LanguageNames.VisualBasic) { _codeFixProvider = new VisualBasicRenameTrackingCodeFixProvider( Workspace.ExportProvider.GetExport<Host.IWaitIndicator>().Value, _historyRegistry, SpecializedCollections.SingletonEnumerable(_mockRefactorNotifyService)); } else { throw new ArgumentException("Invalid langauge name: " + languageName, "languageName"); } }
public TestWorkspace GetWorkspace(string markup, ExportProvider exportProvider = null, string workspaceKind = null) { if (TryParseXElement(markup, out var workspaceElement) && workspaceElement.Name == "Workspace") { _workspace = TestWorkspace.CreateWorkspace(workspaceElement, exportProvider: exportProvider, workspaceKind: workspaceKind); _currentDocument = _workspace.Documents.First(d => d.CursorPosition.HasValue); Position = _currentDocument.CursorPosition.Value; Code = _currentDocument.GetTextBuffer().CurrentSnapshot.GetText(); return(_workspace); } else { MarkupTestFile.GetPosition(markup.NormalizeLineEndings(), out Code, out Position); var workspace = GetWorkspace(exportProvider); _currentDocument = workspace.Documents.Single(); return(workspace); } }
public void TestAdditionalFile_OpenClose() { using (var workspace = CreateWorkspace()) { var startText = @"<setting value = ""foo"""; var document = new TestHostDocument("public class C { }"); var additionalDoc = new TestHostDocument(startText); var project1 = new TestHostProject(workspace, name: "project1", documents: new[] { document }, additionalDocuments: new[] { additionalDoc }); workspace.AddTestProject(project1); var buffer = additionalDoc.GetTextBuffer(); var doc = workspace.CurrentSolution.GetAdditionalDocument(additionalDoc.Id); var text = doc.GetTextAsync(CancellationToken.None).PumpingWaitResult(); var version = doc.GetTextVersionAsync(CancellationToken.None).PumpingWaitResult(); workspace.OnAdditionalDocumentOpened(additionalDoc.Id, additionalDoc.GetOpenTextContainer()); // We don't have a GetOpenAdditionalDocumentIds since we don't need it. But make sure additional documents // don't creep into OpenDocumentIds (Bug: 1087470) Assert.Empty(workspace.GetOpenDocumentIds()); workspace.OnAdditionalDocumentClosed(additionalDoc.Id, TextLoader.From(TextAndVersion.Create(text, version))); // Reopen and close to make sure we are not leaking anything. workspace.OnAdditionalDocumentOpened(additionalDoc.Id, additionalDoc.GetOpenTextContainer()); workspace.OnAdditionalDocumentClosed(additionalDoc.Id, TextLoader.From(TextAndVersion.Create(text, version))); Assert.Empty(workspace.GetOpenDocumentIds()); } }
public void TestAdditionalFile_DocumentChanged() { using (var workspace = CreateWorkspace()) { var startText = @"<setting value = ""foo"""; var newText = @"<setting value = ""foo1"""; var document = new TestHostDocument("public class C { }"); var additionalDoc = new TestHostDocument(startText); var project1 = new TestHostProject(workspace, name: "project1", documents: new[] { document }, additionalDocuments: new[] { additionalDoc }); workspace.AddTestProject(project1); var buffer = additionalDoc.GetTextBuffer(); workspace.OnAdditionalDocumentOpened(additionalDoc.Id, additionalDoc.GetOpenTextContainer()); var project = workspace.CurrentSolution.Projects.Single(); var oldVersion = project.GetSemanticVersionAsync().PumpingWaitResult(); // fork the solution to introduce a change. var oldSolution = workspace.CurrentSolution; var newSolution = oldSolution.WithAdditionalDocumentText(additionalDoc.Id, SourceText.From(newText)); workspace.TryApplyChanges(newSolution); var doc = workspace.CurrentSolution.GetAdditionalDocument(additionalDoc.Id); // new text should have been pushed into buffer Assert.Equal(newText, buffer.CurrentSnapshot.GetText()); // Text changes are considered top level changes and they change the project's semantic version. Assert.Equal(doc.GetTextVersionAsync().PumpingWaitResult(), doc.GetTopLevelChangeTextVersionAsync().PumpingWaitResult()); Assert.NotEqual(oldVersion, doc.Project.GetSemanticVersionAsync().PumpingWaitResult()); } }
public void TestApplyChangesWithDocumentTextUpdated() { using (var workspace = CreateWorkspace()) { var startText = "public class C { }"; var newText = "public class D { }"; var document = new TestHostDocument(startText); var project1 = new TestHostProject(workspace, document, name: "project1"); workspace.AddTestProject(project1); var buffer = document.GetTextBuffer(); workspace.OnDocumentOpened(document.Id, document.GetOpenTextContainer()); // prove the document has the correct text Assert.Equal(startText, workspace.CurrentSolution.GetDocument(document.Id).GetTextAsync().PumpingWaitResult().ToString()); // fork the solution to introduce a change. var oldSolution = workspace.CurrentSolution; var newSolution = oldSolution.WithDocumentText(document.Id, SourceText.From(newText)); // prove that current document text is unchanged Assert.Equal(startText, workspace.CurrentSolution.GetDocument(document.Id).GetTextAsync().PumpingWaitResult().ToString()); // prove buffer is unchanged too Assert.Equal(startText, buffer.CurrentSnapshot.GetText()); workspace.TryApplyChanges(newSolution); // new text should have been pushed into buffer Assert.Equal(newText, buffer.CurrentSnapshot.GetText()); } }
public void TestOpenAndChangeDocument() { using (var workspace = CreateWorkspace()) { var solution = workspace.CurrentSolution; var document = new TestHostDocument(string.Empty); var project1 = new TestHostProject(workspace, document, name: "project1"); workspace.AddTestProject(project1); var buffer = document.GetTextBuffer(); workspace.OnDocumentOpened(document.Id, document.GetOpenTextContainer()); buffer.Insert(0, "class C {}"); solution = workspace.CurrentSolution; var doc = solution.Projects.Single().Documents.First(); var syntaxTree = doc.GetSyntaxTreeAsync(CancellationToken.None).Result; Assert.True(syntaxTree.GetRoot().Width() > 0, "syntaxTree.GetRoot().Width should be > 0"); workspace.OnDocumentClosed(document.Id); workspace.OnProjectRemoved(project1.Id); } }
public void TestGetCompilationOnCrossLanguageDependentProjectChangedInProgress() { using (var workspace = CreateWorkspace(disablePartialSolutions: false)) { var solutionX = workspace.CurrentSolution; var document1 = new TestHostDocument(@"public class C { }"); var project1 = new TestHostProject(workspace, document1, name: "project1"); var document2 = new TestHostDocument("Public Class D \r\n Inherits C\r\nEnd Class"); var project2 = new TestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: new[] { project1 }); workspace.AddTestProject(project1); workspace.AddTestProject(project2); var solutionY = workspace.CurrentSolution; var id1 = solutionY.Projects.First(p => p.Name == project1.Name).Id; var id2 = solutionY.Projects.First(p => p.Name == project2.Name).Id; var compilation2y = solutionY.GetProject(id2).GetCompilationAsync().Result; var errors = compilation2y.GetDiagnostics(); var classDy = compilation2y.SourceModule.GlobalNamespace.GetTypeMembers("D").Single(); var classCy = classDy.BaseType; Assert.NotEqual(TypeKind.Error, classCy.TypeKind); // open both documents so background compiler works on their compilations workspace.OnDocumentOpened(document1.Id, document1.GetOpenTextContainer()); workspace.OnDocumentOpened(document2.Id, document2.GetOpenTextContainer()); // change C to X var buffer1 = document1.GetTextBuffer(); buffer1.Replace(new Span(13, 1), "X"); var foundTheError = false; for (int iter = 0; iter < 10; iter++) { WaitHelper.WaitForDispatchedOperationsToComplete(System.Windows.Threading.DispatcherPriority.ApplicationIdle); Thread.Sleep(1000); // the current solution should eventually have the change var cs = workspace.CurrentSolution; var doc1Z = cs.GetDocument(document1.Id); var hasX = doc1Z.GetTextAsync().Result.ToString().Contains("X"); if (hasX) { var doc2Z = cs.GetDocument(document2.Id); var partialDoc2Z = doc2Z.WithFrozenPartialSemanticsAsync(CancellationToken.None).Result; var compilation2Z = partialDoc2Z.Project.GetCompilationAsync().Result; var classDz = compilation2Z.SourceModule.GlobalNamespace.GetTypeMembers("D").Single(); var classCz = classDz.BaseType; if (classCz.TypeKind == TypeKind.Error) { foundTheError = true; break; } } } Assert.True(foundTheError, "Did not find error"); } }
public void TestGetCompilationOnCrossLanguageDependentProjectChanged() { using (var workspace = CreateWorkspace()) { var solutionX = workspace.CurrentSolution; var document1 = new TestHostDocument(@"public class C { }"); var project1 = new TestHostProject(workspace, document1, name: "project1"); var document2 = new TestHostDocument("Public Class D \r\n Inherits C\r\nEnd Class"); var project2 = new TestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: new[] { project1 }); workspace.AddTestProject(project1); workspace.AddTestProject(project2); var solutionY = workspace.CurrentSolution; var id1 = solutionY.Projects.First(p => p.Name == project1.Name).Id; var id2 = solutionY.Projects.First(p => p.Name == project2.Name).Id; var compilation2 = solutionY.GetProject(id2).GetCompilationAsync().Result; var errors = compilation2.GetDiagnostics(); var classD = compilation2.SourceModule.GlobalNamespace.GetTypeMembers("D").Single(); var classC = classD.BaseType; Assert.NotEqual(TypeKind.Error, classC.TypeKind); // change the class name in document1 workspace.OnDocumentOpened(document1.Id, document1.GetOpenTextContainer()); var buffer1 = document1.GetTextBuffer(); // change C to X buffer1.Replace(new Span(13, 1), "X"); // this solution should have the change var solutionZ = workspace.CurrentSolution; var docZ = solutionZ.GetDocument(document1.Id); var docZText = docZ.GetTextAsync().PumpingWaitResult(); var compilation2Z = solutionZ.GetProject(id2).GetCompilationAsync().Result; var classDz = compilation2Z.SourceModule.GlobalNamespace.GetTypeMembers("D").Single(); var classCz = classDz.BaseType; Assert.Equal(TypeKind.Error, classCz.TypeKind); } }
public async Task TestDependentSemanticVersionChangesWhenNotOriginallyAccessed() { using (var workspace = CreateWorkspace(disablePartialSolutions: false)) { var solutionX = workspace.CurrentSolution; var document1 = new TestHostDocument(@"public class C { }"); var project1 = new TestHostProject(workspace, document1, name: "project1"); var document2 = new TestHostDocument("Public Class D \r\n Inherits C\r\nEnd Class"); var project2 = new TestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: new[] { project1 }); workspace.AddTestProject(project1); workspace.AddTestProject(project2); var solutionY = workspace.CurrentSolution; var id1 = solutionY.Projects.First(p => p.Name == project1.Name).Id; var id2 = solutionY.Projects.First(p => p.Name == project2.Name).Id; var compilation2y = await solutionY.GetProject(id2).GetCompilationAsync(); var errors = compilation2y.GetDiagnostics(); var classDy = compilation2y.SourceModule.GlobalNamespace.GetTypeMembers("D").Single(); var classCy = classDy.BaseType; Assert.NotEqual(TypeKind.Error, classCy.TypeKind); // open both documents so background compiler works on their compilations workspace.OnDocumentOpened(document1.Id, document1.GetOpenTextContainer()); workspace.OnDocumentOpened(document2.Id, document2.GetOpenTextContainer()); // change C to X var buffer1 = document1.GetTextBuffer(); buffer1.Replace(new Span(13, 1), "X"); for (int iter = 0; iter < 10; iter++) { WaitHelper.WaitForDispatchedOperationsToComplete(System.Windows.Threading.DispatcherPriority.ApplicationIdle); Thread.Sleep(1000); // the current solution should eventually have the change var cs = workspace.CurrentSolution; var doc1Z = cs.GetDocument(document1.Id); var hasX = (await doc1Z.GetTextAsync()).ToString().Contains("X"); if (hasX) { var newVersion = await cs.GetProject(project1.Id).GetDependentSemanticVersionAsync(); var newVersionX = await doc1Z.Project.GetDependentSemanticVersionAsync(); Assert.NotEqual(VersionStamp.Default, newVersion); Assert.Equal(newVersion, newVersionX); break; } } } }
internal static IList<ITagSpan<IErrorTag>> GetErrorsFromUpdateSource(TestWorkspace workspace, TestHostDocument document, DiagnosticsUpdatedArgs updateArgs) { var source = new TestDiagnosticUpdateSource(); var listener = new AsynchronousOperationListener(); var listeners = AsynchronousOperationListener.CreateListeners( ValueTuple.Create(FeatureAttribute.DiagnosticService, listener), ValueTuple.Create(FeatureAttribute.ErrorSquiggles, listener)); var optionsService = workspace.Services.GetService<IOptionService>(); var diagnosticService = new DiagnosticService(SpecializedCollections.SingletonEnumerable<IDiagnosticUpdateSource>(source), listeners); var foregroundService = workspace.GetService<IForegroundNotificationService>(); //new TestForegroundNotificationService(); var buffer = document.GetTextBuffer(); var provider = new DiagnosticsSquiggleTaggerProvider(optionsService, diagnosticService, foregroundService, listeners); var tagger = provider.CreateTagger<IErrorTag>(buffer); source.RaiseDiagnosticsUpdated(updateArgs); listener.CreateWaitTask().PumpingWait(); var snapshot = buffer.CurrentSnapshot; var spans = tagger.GetTags(new NormalizedSnapshotSpanCollection(new SnapshotSpan(snapshot, 0, snapshot.Length))).ToImmutableArray(); ((IDisposable)tagger).Dispose(); return spans; }