diff --git a/src/EditorFeatures/Test/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/Test/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 7484e23fa86b880be55432655bdf84a6ad911a85..c662426e7f418bcafd1ea3e1e76235ca5a825b14 100644 --- a/src/EditorFeatures/Test/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/Test/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -72,53 +72,59 @@ protected void ApplyOptionsToWorkspace(Workspace workspace, IDictionary options = null, - string fixAllActionEquivalenceKey = null) + string fixAllActionEquivalenceKey = null, + object fixProviderData = null) { - await TestMissingAsync(initialMarkup, parseOptions: null, options: options, fixAllActionEquivalenceKey: fixAllActionEquivalenceKey); - await TestMissingAsync(initialMarkup, parseOptions: GetScriptOptions(), options: options, fixAllActionEquivalenceKey: fixAllActionEquivalenceKey); + await TestMissingAsync(initialMarkup, parseOptions: null, options: options, fixAllActionEquivalenceKey: fixAllActionEquivalenceKey, fixProviderData: fixProviderData); + await TestMissingAsync(initialMarkup, parseOptions: GetScriptOptions(), options: options, fixAllActionEquivalenceKey: fixAllActionEquivalenceKey, fixProviderData: fixProviderData); } protected Task TestMissingAsync( string initialMarkup, ParseOptions parseOptions, IDictionary options = null, - string fixAllActionEquivalenceKey = null) + string fixAllActionEquivalenceKey = null, + object fixProviderData = null) { - return TestMissingAsync(initialMarkup, parseOptions, compilationOptions: null, options: options, fixAllActionEquivalenceKey: fixAllActionEquivalenceKey); + return TestMissingAsync(initialMarkup, parseOptions, compilationOptions: null, options: options, fixAllActionEquivalenceKey: fixAllActionEquivalenceKey, fixProviderData: fixProviderData); } protected async Task TestMissingAsync( string initialMarkup, ParseOptions parseOptions, CompilationOptions compilationOptions, IDictionary options = null, - string fixAllActionEquivalenceKey = null) + string fixAllActionEquivalenceKey = null, + object fixProviderData = null) { using (var workspace = await CreateWorkspaceFromFileAsync(initialMarkup, parseOptions, compilationOptions)) { ApplyOptionsToWorkspace(workspace, options); - var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey); + var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey, fixProviderData); Assert.True(actions == null || actions.Count == 0); } } - protected async Task> GetCodeActionsAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey) + protected async Task> GetCodeActionsAsync( + TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData = null) { - return MassageActions(await GetCodeActionsWorkerAsync(workspace, fixAllActionEquivalenceKey)); + return MassageActions(await GetCodeActionsWorkerAsync(workspace, fixAllActionEquivalenceKey, fixProviderData)); } - protected abstract Task> GetCodeActionsWorkerAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey); + protected abstract Task> GetCodeActionsWorkerAsync( + TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData = null); protected async Task TestSmartTagTextAsync( string initialMarkup, string displayText, int index = 0, ParseOptions parseOptions = null, - CompilationOptions compilationOptions = null) + CompilationOptions compilationOptions = null, + object fixProviderData = null) { using (var workspace = await CreateWorkspaceFromFileAsync(initialMarkup, parseOptions, compilationOptions)) { - var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey: null); + var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey: null, fixProviderData: fixProviderData); Assert.Equal(displayText, actions.ElementAt(index).Title); } } @@ -157,10 +163,11 @@ protected async Task> GetCodeActionsAsync(TestWorkspace worksp string initialMarkup, string expectedMarkup, int index = 0, bool compareTokens = true, IDictionary options = null, - string fixAllActionEquivalenceKey = null) + string fixAllActionEquivalenceKey = null, + object fixProviderData = null) { - await TestAsync(initialMarkup, expectedMarkup, null, index, compareTokens, options, fixAllActionEquivalenceKey); - await TestAsync(initialMarkup, expectedMarkup, GetScriptOptions(), index, compareTokens, options, fixAllActionEquivalenceKey); + await TestAsync(initialMarkup, expectedMarkup, null, index, compareTokens, options, fixAllActionEquivalenceKey, fixProviderData); + await TestAsync(initialMarkup, expectedMarkup, GetScriptOptions(), index, compareTokens, options, fixAllActionEquivalenceKey, fixProviderData); } protected Task TestAsync( @@ -168,9 +175,10 @@ protected async Task> GetCodeActionsAsync(TestWorkspace worksp ParseOptions parseOptions, int index = 0, bool compareTokens = true, IDictionary options = null, - string fixAllActionEquivalenceKey = null) + string fixAllActionEquivalenceKey = null, + object fixProviderData = null) { - return TestAsync(initialMarkup, expectedMarkup, parseOptions, null, index, compareTokens, options, fixAllActionEquivalenceKey); + return TestAsync(initialMarkup, expectedMarkup, parseOptions, null, index, compareTokens, options, fixAllActionEquivalenceKey, fixProviderData); } protected async Task TestAsync( @@ -178,7 +186,8 @@ protected async Task> GetCodeActionsAsync(TestWorkspace worksp ParseOptions parseOptions, CompilationOptions compilationOptions, int index = 0, bool compareTokens = true, IDictionary options = null, - string fixAllActionEquivalenceKey = null) + string fixAllActionEquivalenceKey = null, + object fixProviderData = null) { string expected; IDictionary> spanMap; @@ -194,7 +203,7 @@ protected async Task> GetCodeActionsAsync(TestWorkspace worksp { ApplyOptionsToWorkspace(workspace, options); - var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey); + var actions = await GetCodeActionsAsync(workspace, fixAllActionEquivalenceKey, fixProviderData); await TestActionsAsync( workspace, expected, index, actions, @@ -323,11 +332,27 @@ protected static async Task> VerifyInputsAndGet TestWorkspace workspace, IEnumerable operations) { - var applyChangesOperation = operations.OfType().First(); - var oldSolution = workspace.CurrentSolution; - var newSolution = applyChangesOperation.ChangedSolution; + Tuple result = null; + foreach (var operation in operations) + { + if (operation is ApplyChangesOperation && result == null) + { + var oldSolution = workspace.CurrentSolution; + var newSolution = ((ApplyChangesOperation)operation).ChangedSolution; + result = Tuple.Create(oldSolution, newSolution); + } + else if (operation.ApplyDuringTests) + { + operation.Apply(workspace, CancellationToken.None); + } + } - return Tuple.Create(oldSolution, newSolution); + if (result == null) + { + throw new InvalidOperationException("No ApplyChangesOperation found"); + } + + return result; } protected virtual IList MassageActions(IList actions) diff --git a/src/EditorFeatures/Test/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/Test/CodeActions/AbstractCodeActionTest.cs index b01b7c5aca1d3bc2673958f1cd744c07d52b22e6..0eed5e80631d6ca3c881986ae3f5e3917bcf620d 100644 --- a/src/EditorFeatures/Test/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/Test/CodeActions/AbstractCodeActionTest.cs @@ -25,7 +25,8 @@ public abstract class AbstractCodeActionTest : AbstractCodeActionOrUserDiagnosti { protected abstract object CreateCodeRefactoringProvider(Workspace workspace); - protected override async Task> GetCodeActionsWorkerAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey) + protected override async Task> GetCodeActionsWorkerAsync( + TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData) { return (await GetCodeRefactoringAsync(workspace))?.Actions?.ToList(); } diff --git a/src/EditorFeatures/Test/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs b/src/EditorFeatures/Test/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs index c94a8b69862b6bd08aeeac933b4276d9b62f9f99..942db3412aa19308af0e622b0cf4e5755fb55dad 100644 --- a/src/EditorFeatures/Test/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs +++ b/src/EditorFeatures/Test/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs @@ -25,14 +25,24 @@ public abstract class AbstractDiagnosticProviderBasedUserDiagnosticTest : Abstra internal abstract Tuple CreateDiagnosticProviderAndFixer(Workspace workspace); - private Tuple GetOrCreateDiagnosticProviderAndFixer(Workspace workspace) + internal virtual Tuple CreateDiagnosticProviderAndFixer( + Workspace workspace, object fixProviderData) { - return _analyzerAndFixerMap.GetOrAdd(workspace, CreateDiagnosticProviderAndFixer); + return CreateDiagnosticProviderAndFixer(workspace); } - internal async override Task> GetDiagnosticsAsync(TestWorkspace workspace) + private Tuple GetOrCreateDiagnosticProviderAndFixer( + Workspace workspace, object fixProviderData) { - var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace); + return fixProviderData == null + ? _analyzerAndFixerMap.GetOrAdd(workspace, CreateDiagnosticProviderAndFixer) + : CreateDiagnosticProviderAndFixer(workspace, fixProviderData); + } + + internal async override Task> GetDiagnosticsAsync( + TestWorkspace workspace, object fixProviderData = null) + { + var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace, fixProviderData); var provider = providerAndFixer.Item1; TextSpan span; @@ -42,9 +52,10 @@ internal async override Task> GetDiagnosticsAsync(TestWo return allDiagnostics; } - internal override async Task>> GetDiagnosticAndFixesAsync(TestWorkspace workspace, string fixAllActionId) + internal override async Task>> GetDiagnosticAndFixesAsync( + TestWorkspace workspace, string fixAllActionId, object fixProviderData) { - var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace); + var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace, fixProviderData); var provider = providerAndFixer.Item1; Document document; diff --git a/src/EditorFeatures/Test/Diagnostics/AbstractSuppressionDiagnosticTest.cs b/src/EditorFeatures/Test/Diagnostics/AbstractSuppressionDiagnosticTest.cs index 95ee7f3de34d6aad809c3a786919f56b1f131a5a..a7437f8b964fa06a7b8bbde3768350b8b3c6d634 100644 --- a/src/EditorFeatures/Test/Diagnostics/AbstractSuppressionDiagnosticTest.cs +++ b/src/EditorFeatures/Test/Diagnostics/AbstractSuppressionDiagnosticTest.cs @@ -53,7 +53,8 @@ private ImmutableArray FilterDiagnostics(IEnumerable dia return diagnostics.ToImmutableArray(); } - internal override async Task> GetDiagnosticsAsync(TestWorkspace workspace) + internal override async Task> GetDiagnosticsAsync( + TestWorkspace workspace, object fixProviderData) { var providerAndFixer = CreateDiagnosticProviderAndFixer(workspace); @@ -64,7 +65,8 @@ internal override async Task> GetDiagnosticsAsync(TestWo return FilterDiagnostics(diagnostics); } - internal override async Task>> GetDiagnosticAndFixesAsync(TestWorkspace workspace, string fixAllActionId) + internal override async Task>> GetDiagnosticAndFixesAsync( + TestWorkspace workspace, string fixAllActionId, object fixProviderData) { var providerAndFixer = CreateDiagnosticProviderAndFixer(workspace); diff --git a/src/EditorFeatures/Test/Diagnostics/AbstractUserDiagnosticTest.cs b/src/EditorFeatures/Test/Diagnostics/AbstractUserDiagnosticTest.cs index 372438a1b50524bc99b81cc94377c8edd6f927dc..90bf6959a94b239012886f2f93fbbcab34fe8c12 100644 --- a/src/EditorFeatures/Test/Diagnostics/AbstractUserDiagnosticTest.cs +++ b/src/EditorFeatures/Test/Diagnostics/AbstractUserDiagnosticTest.cs @@ -27,18 +27,21 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics { public abstract class AbstractUserDiagnosticTest : AbstractCodeActionOrUserDiagnosticTest { - internal abstract Task>> GetDiagnosticAndFixesAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey); - internal abstract Task> GetDiagnosticsAsync(TestWorkspace workspace); + internal abstract Task>> GetDiagnosticAndFixesAsync( + TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData); + internal abstract Task> GetDiagnosticsAsync(TestWorkspace workspace, object fixProviderData); - protected override async Task> GetCodeActionsWorkerAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey) + protected override async Task> GetCodeActionsWorkerAsync( + TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData) { - var diagnostics = await GetDiagnosticAndFixAsync(workspace, fixAllActionEquivalenceKey); + var diagnostics = await GetDiagnosticAndFixAsync(workspace, fixAllActionEquivalenceKey, fixProviderData); return diagnostics?.Item2?.Fixes.Select(f => f.Action).ToList(); } - internal async Task> GetDiagnosticAndFixAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey = null) + internal async Task> GetDiagnosticAndFixAsync( + TestWorkspace workspace, string fixAllActionEquivalenceKey = null, object fixProviderData = null) { - return (await GetDiagnosticAndFixesAsync(workspace, fixAllActionEquivalenceKey)).FirstOrDefault(); + return (await GetDiagnosticAndFixesAsync(workspace, fixAllActionEquivalenceKey, fixProviderData)).FirstOrDefault(); } protected Document GetDocumentAndSelectSpan(TestWorkspace workspace, out TextSpan span) @@ -224,11 +227,13 @@ protected async Task TestEquivalenceKeyAsync(string initialMarkup, string equiva protected async Task TestActionCountInAllFixesAsync( string initialMarkup, int count, - ParseOptions parseOptions = null, CompilationOptions compilationOptions = null) + ParseOptions parseOptions = null, + CompilationOptions compilationOptions = null, + object fixProviderData = null) { using (var workspace = await CreateWorkspaceFromFileAsync(initialMarkup, parseOptions, compilationOptions)) { - var diagnosticAndFix = await GetDiagnosticAndFixesAsync(workspace, null); + var diagnosticAndFix = await GetDiagnosticAndFixesAsync(workspace, fixAllActionEquivalenceKey: null, fixProviderData: fixProviderData); var diagnosticCount = diagnosticAndFix.Select(x => x.Item2.Fixes.Count()).Sum(); Assert.Equal(count, diagnosticCount); @@ -238,8 +243,11 @@ protected async Task TestEquivalenceKeyAsync(string initialMarkup, string equiva protected async Task TestSpansAsync( string initialMarkup, string expectedMarkup, int index = 0, - ParseOptions parseOptions = null, CompilationOptions compilationOptions = null, - string diagnosticId = null, string fixAllActionEquivalenceId = null) + ParseOptions parseOptions = null, + CompilationOptions compilationOptions = null, + string diagnosticId = null, + string fixAllActionEquivalenceId = null, + object fixProviderData = null) { IList spansList; string unused; @@ -251,13 +259,13 @@ protected async Task TestEquivalenceKeyAsync(string initialMarkup, string equiva ISet actualTextSpans; if (diagnosticId == null) { - var diagnosticsAndFixes = await GetDiagnosticAndFixesAsync(workspace, fixAllActionEquivalenceId); + var diagnosticsAndFixes = await GetDiagnosticAndFixesAsync(workspace, fixAllActionEquivalenceId, fixProviderData); var diagnostics = diagnosticsAndFixes.Select(t => t.Item1); actualTextSpans = diagnostics.Select(d => d.Location.SourceSpan).ToSet(); } else { - var diagnostics = await GetDiagnosticsAsync(workspace); + var diagnostics = await GetDiagnosticsAsync(workspace, fixProviderData); actualTextSpans = diagnostics.Where(d => d.Id == diagnosticId).Select(d => d.Location.SourceSpan).ToSet(); } @@ -437,7 +445,7 @@ protected async Task TestEquivalenceKeyAsync(string initialMarkup, string equiva testState.TestProjectManagementService.SetDefaultNamespace( defaultNamespace: defaultNamespace); - var diagnosticsAndFixes = await GetDiagnosticAndFixesAsync(testState.Workspace, null); + var diagnosticsAndFixes = await GetDiagnosticAndFixesAsync(testState.Workspace, fixAllActionEquivalenceKey: null, fixProviderData: null); var generateTypeDiagFixes = diagnosticsAndFixes.SingleOrDefault(df => GenerateTypeTestState.FixIds.Contains(df.Item1.Id)); if (isMissing) diff --git a/src/Workspaces/Core/Portable/CodeActions/Operations/CodeActionOperation.cs b/src/Workspaces/Core/Portable/CodeActions/Operations/CodeActionOperation.cs index 7788d5d4f5e0e9d9156eef2f66df5aed62ac904c..b70cf06d9d1340f2947ed7751efb63d997170799 100644 --- a/src/Workspaces/Core/Portable/CodeActions/Operations/CodeActionOperation.cs +++ b/src/Workspaces/Core/Portable/CodeActions/Operations/CodeActionOperation.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Threading; +using System.Threading.Tasks; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeActions { @@ -24,5 +26,12 @@ public virtual string Title public virtual void Apply(Workspace workspace, CancellationToken cancellationToken) { } + + /// + /// Operations may make all sorts of changes that may not be appropriate during testing + /// (like popping up UI). So, by default, we don't apply them unless the operation asks + /// for that to happen. + /// + internal virtual bool ApplyDuringTests => false; } }