public void ApplyEditorConfigAndFixAllOccurrences() { var markup = @" class C { public int X1 { get { $$return 3; } } public int Y1 => 5; public int X2 { get { return 3; } } public int Y2 => 5; }"; var expectedText = @" class C { public int X1 => 3; public int Y1 => 5; public int X2 => 3; public int Y2 => 5; }"; VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "Class1.cs"); /* * The first portion of this test adds a .editorconfig file to configure the analyzer behavior, and verifies * that diagnostics appear automatically in response to the newly-created file. A fix all operation is * applied, and the result is verified against the expected outcome for the .editorconfig style. */ MarkupTestFile.GetSpans(markup, out _, out ImmutableArray <TextSpan> _); SetUpEditor(markup); VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.Verify.CodeActionsNotShowing(); var editorConfig = @"root = true [*.cs] csharp_style_expression_bodied_properties = true:warning "; VisualStudio.SolutionExplorer.AddFile(new ProjectUtils.Project(ProjectName), ".editorconfig", editorConfig, open: false); VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.InvokeCodeActionList(); VisualStudio.Editor.Verify.CodeAction( "Use expression body for properties", applyFix: true, fixAllScope: FixAllScope.Project); Assert.Equal(expectedText, VisualStudio.Editor.GetText()); /* * The second portion of this test modifier the existing .editorconfig file to configure the analyzer to the * opposite style of the initial configuration, and verifies that diagnostics update automatically in * response to the changes. A fix all operation is applied, and the result is verified against the expected * outcome for the modified .editorconfig style. */ VisualStudio.SolutionExplorer.SetFileContents(new ProjectUtils.Project(ProjectName), ".editorconfig", editorConfig.Replace("true:warning", "false:warning")); VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.InvokeCodeActionList(); VisualStudio.Editor.Verify.CodeAction( "Use block body for properties", applyFix: true, fixAllScope: FixAllScope.Project); expectedText = @" class C { public int X1 { get { return 3; } } public int Y1 { get { return 5; } } public int X2 { get { return 3; } } public int Y2 { get { return 5; } } }"; Assert.Equal(expectedText, VisualStudio.Editor.GetText()); }
public void VerifyLocalVariableRenameWithCommentsUpdated() { // "variable" is intentionally misspelled as "varixable" and "this" is misspelled as // "thix" below to ensure we don't change instances of "x" in comments that are part of // larger words var markup = @" using System; using System.Collections.Generic; using System.Linq; class Program { /// <summary> /// creates a varixable named [|x|] xx /// </summary> /// <param name=""args""></param> static void Main(string[] args) { // thix varixable is named [|x|] xx int [|x|]$$ = 0; [|x|] = 5; TestMethod([|x|]); } static void TestMethod(int y) { /* * [|x|] * xx */ } }"; SetUpEditor(markup); InlineRenameDialog.Invoke(); InlineRenameDialog.ToggleIncludeComments(); MarkupTestFile.GetSpans(markup, out var _, out ImmutableArray <TextSpan> renameSpans); var tags = VisualStudio.Editor.GetTagSpans(InlineRenameDialog.ValidRenameTag); AssertEx.SetEqual(renameSpans, tags); VisualStudio.Editor.SendKeys(VirtualKey.Y, VirtualKey.Enter); VisualStudio.Editor.Verify.TextContains(@" using System; using System.Collections.Generic; using System.Linq; class Program { /// <summary> /// creates a varixable named y xx /// </summary> /// <param name=""args""></param> static void Main(string[] args) { // thix varixable is named y xx int y = 0; y = 5; TestMethod(y); } static void TestMethod(int y) { /* * y * xx */ } }"); }
public void ApplyEditorConfigAndFormatDocument() { var markup = @" class C { public int X1 { get { $$return 3; } } }"; var expectedTextTwoSpaceIndent = @" class C { public int X1 { get { return 3; } } }"; // CodingConventions only sends notifications if a file is open for all directories in the project VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), @"Properties\AssemblyInfo.cs"); // Switch back to the main document we'll be editing VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "Class1.cs"); MarkupTestFile.GetSpans(markup, out var expectedTextFourSpaceIndent, out ImmutableArray <TextSpan> spans); SetUpEditor(markup); VisualStudio.WaitForApplicationIdle(CancellationToken.None); /* * The first portion of this test verifies that Format Document uses the default indentation settings when * no .editorconfig is available. */ VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.FormatDocumentViaCommand(); Assert.Equal(expectedTextFourSpaceIndent, VisualStudio.Editor.GetText()); /* * The second portion of this test adds a .editorconfig file to configure the indentation behavior, and * verifies that the next Format Document operation adheres to the formatting. */ var editorConfig = @"root = true [*.cs] indent_size = 2 "; VisualStudio.SolutionExplorer.BeginWatchForCodingConventionsChange(new ProjectUtils.Project(ProjectName), "Class1.cs"); try { VisualStudio.SolutionExplorer.AddFile(new ProjectUtils.Project(ProjectName), ".editorconfig", editorConfig, open: false); } finally { VisualStudio.SolutionExplorer.EndWaitForCodingConventionsChange(Helper.HangMitigatingTimeout); } // Wait for CodingConventions library events to propagate to the workspace VisualStudio.WaitForApplicationIdle(CancellationToken.None); VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.FormatDocumentViaCommand(); Assert.Equal(expectedTextTwoSpaceIndent, VisualStudio.Editor.GetText()); /* * The third portion of this test modifies the existing .editorconfig file with a new indentation behavior, * and verifies that the next Format Document operation adheres to the updated formatting. */ VisualStudio.SolutionExplorer.BeginWatchForCodingConventionsChange(new ProjectUtils.Project(ProjectName), "Class1.cs"); try { VisualStudio.SolutionExplorer.SetFileContents(new ProjectUtils.Project(ProjectName), ".editorconfig", editorConfig.Replace("2", "4")); } finally { VisualStudio.SolutionExplorer.EndWaitForCodingConventionsChange(Helper.HangMitigatingTimeout); } // Wait for CodingConventions library events to propagate to the workspace VisualStudio.WaitForApplicationIdle(CancellationToken.None); VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.FormatDocumentViaCommand(); Assert.Equal(expectedTextFourSpaceIndent, VisualStudio.Editor.GetText()); }
private static void TestWorker( string inputMarkup, string expectedOutputMarkup, Action callback, bool verifyUndo = true, IndentStyle indentStyle = IndentStyle.Smart, bool useTabs = false) { using var workspace = TestWorkspace.CreateCSharp(inputMarkup); // TODO: set SmartIndent to textView.Options (https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1412138) workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle))); if (useTabs && expectedOutputMarkup != null) { Assert.Contains("\t", expectedOutputMarkup); } var document = workspace.Documents.Single(); var view = document.GetTextView(); view.Options.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); view.Options.SetOptionValue(DefaultOptions.TabSizeOptionId, 4); var originalSnapshot = view.TextBuffer.CurrentSnapshot; var originalSelections = document.SelectedSpans; var snapshotSpans = new List <SnapshotSpan>(); foreach (var selection in originalSelections) { snapshotSpans.Add(selection.ToSnapshotSpan(originalSnapshot)); } view.SetMultiSelection(snapshotSpans); var undoHistoryRegistry = workspace.GetService <ITextUndoHistoryRegistry>(); var commandHandler = workspace.ExportProvider.GetCommandHandler <SplitStringLiteralCommandHandler>(nameof(SplitStringLiteralCommandHandler)); if (!commandHandler.ExecuteCommand(new ReturnKeyCommandArgs(view, view.TextBuffer), TestCommandExecutionContext.Create())) { callback(); } if (expectedOutputMarkup != null) { MarkupTestFile.GetSpans(expectedOutputMarkup, out var expectedOutput, out ImmutableArray <TextSpan> expectedSpans); Assert.Equal(expectedOutput, view.TextBuffer.CurrentSnapshot.AsText().ToString()); Assert.Equal(expectedSpans.First().Start, view.Caret.Position.BufferPosition.Position); if (verifyUndo) { // Ensure that after undo we go back to where we were to begin with. var history = undoHistoryRegistry.GetHistory(document.GetTextBuffer()); history.Undo(count: originalSelections.Count); var currentSnapshot = document.GetTextBuffer().CurrentSnapshot; Assert.Equal(originalSnapshot.GetText(), currentSnapshot.GetText()); Assert.Equal(originalSelections.First().Start, view.Caret.Position.BufferPosition.Position); } } }
/// <summary> /// verifyUndo is needed because of https://github.com/dotnet/roslyn/issues/28033 /// Most tests will continue to verifyUndo, but select tests will skip it due to /// this known test infrastructure issure. This bug does not represent a product /// failure. /// </summary> private void TestWorker( string inputMarkup, string expectedOutputMarkup, Action callback, bool verifyUndo = true, IndentStyle indentStyle = IndentStyle.Smart, bool useTabs = false) { using var workspace = TestWorkspace.CreateCSharp(inputMarkup); workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options .WithChangedOption(SmartIndent, LanguageNames.CSharp, indentStyle) .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); if (useTabs && expectedOutputMarkup != null) { Assert.Contains("\t", expectedOutputMarkup); } var document = workspace.Documents.Single(); var view = document.GetTextView(); var originalSnapshot = view.TextBuffer.CurrentSnapshot; var originalSelections = document.SelectedSpans; var snapshotSpans = new List <SnapshotSpan>(); foreach (var selection in originalSelections) { snapshotSpans.Add(selection.ToSnapshotSpan(originalSnapshot)); } view.SetMultiSelection(snapshotSpans); var undoHistoryRegistry = workspace.GetService <ITextUndoHistoryRegistry>(); var commandHandler = new SplitStringLiteralCommandHandler( undoHistoryRegistry, workspace.GetService <IEditorOperationsFactoryService>()); if (!commandHandler.ExecuteCommand(new ReturnKeyCommandArgs(view, view.TextBuffer), TestCommandExecutionContext.Create())) { callback(); } if (expectedOutputMarkup != null) { MarkupTestFile.GetSpans(expectedOutputMarkup, out var expectedOutput, out ImmutableArray <TextSpan> expectedSpans); Assert.Equal(expectedOutput, view.TextBuffer.CurrentSnapshot.AsText().ToString()); Assert.Equal(expectedSpans.First().Start, view.Caret.Position.BufferPosition.Position); if (verifyUndo) { // Ensure that after undo we go back to where we were to begin with. var history = undoHistoryRegistry.GetHistory(document.GetTextBuffer()); history.Undo(count: originalSelections.Count); var currentSnapshot = document.GetTextBuffer().CurrentSnapshot; Assert.Equal(originalSnapshot.GetText(), currentSnapshot.GetText()); Assert.Equal(originalSelections.First().Start, view.Caret.Position.BufferPosition.Position); } } }
public void ApplyEditorConfigAndFormatDocument() { var markup = @" class C { public int X1 { get { $$return 3; } } }"; var expectedTextTwoSpaceIndent = @" class C { public int X1 { get { return 3; } } }"; VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "Class1.cs"); MarkupTestFile.GetSpans(markup, out var expectedTextFourSpaceIndent, out ImmutableArray <TextSpan> _); SetUpEditor(markup); /* * The first portion of this test verifies that Format Document uses the default indentation settings when * no .editorconfig is available. */ VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.FormatDocumentViaCommand(); Assert.Equal(expectedTextFourSpaceIndent, VisualStudio.Editor.GetText()); /* * The second portion of this test adds a .editorconfig file to configure the indentation behavior, and * verifies that the next Format Document operation adheres to the formatting. */ var editorConfig = @"root = true [*.cs] indent_size = 2 "; VisualStudio.SolutionExplorer.AddFile(new ProjectUtils.Project(ProjectName), ".editorconfig", editorConfig, open: false); VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.FormatDocumentViaCommand(); Assert.Equal(expectedTextTwoSpaceIndent, VisualStudio.Editor.GetText()); /* * The third portion of this test modifies the existing .editorconfig file with a new indentation behavior, * and verifies that the next Format Document operation adheres to the updated formatting. */ VisualStudio.SolutionExplorer.SetFileContents(new ProjectUtils.Project(ProjectName), ".editorconfig", editorConfig.Replace("2", "4")); VisualStudio.Workspace.WaitForAllAsyncOperations( Helper.HangMitigatingTimeout, FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawler, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles); VisualStudio.Editor.FormatDocumentViaCommand(); Assert.Equal(expectedTextFourSpaceIndent, VisualStudio.Editor.GetText()); }
/// <summary> /// verifyUndo is needed because of https://github.com/dotnet/roslyn/issues/28033 /// Most tests will continue to verifyUndo, but select tests will skip it due to /// this known test infrastructure issue. This bug does not represent a product /// failure. /// </summary> private void TestWorker( string inputMarkup, string?expectedOutputMarkup, Action callback, bool enabled, bool useTabs) { if (useTabs) { // Make sure the tests seem well formed (i.e. no one accidentally replaced the tabs in them with spaces. Assert.True(inputMarkup.Contains("\t")); if (expectedOutputMarkup != null) { Assert.True(expectedOutputMarkup.Contains("\t")); } } using var workspace = this.CreateWorkspace(inputMarkup); var language = workspace.Projects.Single().Language; workspace.SetOptions( workspace.Options.WithChangedOption(FormattingOptions.UseTabs, language, useTabs) .WithChangedOption(SplitCommentOptions.Enabled, language, enabled)); var document = workspace.Documents.Single(); var view = document.GetTextView(); var originalSnapshot = view.TextBuffer.CurrentSnapshot; var originalSelections = document.SelectedSpans; var snapshotSpans = new List <SnapshotSpan>(); foreach (var selection in originalSelections) { snapshotSpans.Add(new SnapshotSpan(originalSnapshot, new Span(selection.Start, selection.Length))); } view.SetMultiSelection(snapshotSpans); var undoHistoryRegistry = workspace.GetService <ITextUndoHistoryRegistry>(); var commandHandler = workspace.ExportProvider.GetCommandHandler <SplitCommentCommandHandler>(nameof(SplitCommentCommandHandler)); if (!commandHandler.ExecuteCommand(new ReturnKeyCommandArgs(view, view.TextBuffer), TestCommandExecutionContext.Create())) { callback(); } if (expectedOutputMarkup != null) { MarkupTestFile.GetSpans(expectedOutputMarkup, out var expectedOutput, out ImmutableArray <TextSpan> expectedSpans); Assert.Equal(expectedOutput, view.TextBuffer.CurrentSnapshot.AsText().ToString()); // Ensure that after undo we go back to where we were to begin with. var history = undoHistoryRegistry.GetHistory(document.GetTextBuffer()); history.Undo(count: originalSelections.Count); var currentSnapshot = document.GetTextBuffer().CurrentSnapshot; Assert.Equal(originalSnapshot.GetText(), currentSnapshot.GetText()); } }
private async Task TestAsync( string initialMarkup, string expectedMarkup, TestParameters parameters ) { MarkupTestFile.GetSpans( initialMarkup.NormalizeLineEndings(), out var initialMarkupWithoutSpans, out IDictionary <string, ImmutableArray <TextSpan> > initialSpanMap ); const string UnnecessaryMarkupKey = "Unnecessary"; var unnecessarySpans = initialSpanMap.GetOrAdd( UnnecessaryMarkupKey, _ => ImmutableArray <TextSpan> .Empty ); MarkupTestFile.GetSpans( expectedMarkup.NormalizeLineEndings(), out var expected, out IDictionary <string, ImmutableArray <TextSpan> > expectedSpanMap ); var conflictSpans = expectedSpanMap.GetOrAdd( "Conflict", _ => ImmutableArray <TextSpan> .Empty ); var renameSpans = expectedSpanMap.GetOrAdd( "Rename", _ => ImmutableArray <TextSpan> .Empty ); var warningSpans = expectedSpanMap.GetOrAdd( "Warning", _ => ImmutableArray <TextSpan> .Empty ); var navigationSpans = expectedSpanMap.GetOrAdd( "Navigation", _ => ImmutableArray <TextSpan> .Empty ); using (var workspace = CreateWorkspaceFromOptions(initialMarkup, parameters)) { // Ideally this check would always run, but there are several hundred tests that would need to be // updated with {|Unnecessary:|} spans. if (unnecessarySpans.Any()) { var allDiagnostics = await GetDiagnosticsWorkerAsync( workspace, parameters .WithRetainNonFixableDiagnostics(true) .WithIncludeDiagnosticsOutsideSelection(true) ); TestUnnecessarySpans( allDiagnostics, unnecessarySpans, UnnecessaryMarkupKey, initialMarkupWithoutSpans ); } var(_, action) = await GetCodeActionsAsync(workspace, parameters); await TestActionAsync( workspace, expected, action, conflictSpans, renameSpans, warningSpans, navigationSpans, parameters ); } }
private static void TestWorker( string inputMarkup, string expectedOutputMarkup, Action callback, bool verifyUndo = true, IndentStyle indentStyle = IndentStyle.Smart, bool useTabs = false) { using var workspace = TestWorkspace.CreateCSharp(inputMarkup); if (useTabs && expectedOutputMarkup != null) { Assert.Contains("\t", expectedOutputMarkup); } var editorOptionsFactory = workspace.GetService <IEditorOptionsFactoryService>(); var document = workspace.Documents.Single(); var view = document.GetTextView(); var textBuffer = view.TextBuffer; var options = editorOptionsFactory.GetOptions(textBuffer); options.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, !useTabs); options.SetOptionValue(DefaultOptions.TabSizeOptionId, 4); options.SetOptionValue(DefaultOptions.IndentStyleId, indentStyle.ToEditorIndentStyle()); // Remove once https://github.com/dotnet/roslyn/issues/62204 is fixed: workspace.GlobalOptions.SetGlobalOption(new OptionKey(IndentationOptionsStorage.SmartIndent, document.Project.Language), indentStyle); var originalSnapshot = textBuffer.CurrentSnapshot; var originalSelections = document.SelectedSpans; var snapshotSpans = new List <SnapshotSpan>(); foreach (var selection in originalSelections) { snapshotSpans.Add(selection.ToSnapshotSpan(originalSnapshot)); } view.SetMultiSelection(snapshotSpans); var undoHistoryRegistry = workspace.GetService <ITextUndoHistoryRegistry>(); var commandHandler = workspace.ExportProvider.GetCommandHandler <SplitStringLiteralCommandHandler>(nameof(SplitStringLiteralCommandHandler)); if (!commandHandler.ExecuteCommand(new ReturnKeyCommandArgs(view, textBuffer), TestCommandExecutionContext.Create())) { callback(); } if (expectedOutputMarkup != null) { MarkupTestFile.GetSpans(expectedOutputMarkup, out var expectedOutput, out ImmutableArray <TextSpan> expectedSpans); Assert.Equal(expectedOutput, textBuffer.CurrentSnapshot.AsText().ToString()); Assert.Equal(expectedSpans.First().Start, view.Caret.Position.BufferPosition.Position); if (verifyUndo) { // Ensure that after undo we go back to where we were to begin with. var history = undoHistoryRegistry.GetHistory(document.GetTextBuffer()); history.Undo(count: originalSelections.Count); var currentSnapshot = document.GetTextBuffer().CurrentSnapshot; Assert.Equal(originalSnapshot.GetText(), currentSnapshot.GetText()); Assert.Equal(originalSelections.First().Start, view.Caret.Position.BufferPosition.Position); } } }
public void VerifyLocalVariableRename() { var markup = @" using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { int [|x|]$$ = 0; [|x|] = 5; TestMethod([|x|]); } static void TestMethod(int y) { } }"; using (var telemetry = VisualStudio.EnableTestTelemetryChannel()) { SetUpEditor(markup); InlineRenameDialog.Invoke(); MarkupTestFile.GetSpans( markup, out var _, out ImmutableArray <TextSpan> renameSpans ); var tags = VisualStudio.Editor.GetTagSpans(InlineRenameDialog.ValidRenameTag); AssertEx.SetEqual(renameSpans, tags); VisualStudio.Editor.SendKeys(VirtualKey.Y, VirtualKey.Enter); VisualStudio.Editor.Verify.TextContains( @" using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { int y = 0; y = 5; TestMethod(y); } static void TestMethod(int y) { } }" ); telemetry.VerifyFired( "vs/ide/vbcs/rename/inlinesession/session", "vs/ide/vbcs/rename/commitcore" ); } }