提交 b732d61e 编写于 作者: C CyrusNajmabadi

Provide a way for 'code action' tests to pass data to their CodeFixProvider constructor.

This is useful for testing purposes so we can pass mocks to the
specific CodeFixProvider constructor.  For example 'add nuget reference'
will pass mocks for the nuget search and install services in its tests.

Also provide a way for code action operations to state if they should
be invoked during tests.  Lots of tests just want to examine the
state returned by certain operations (like SolutionChangedOperation).
However, for mutating operations, some tests need the operation to
actually apply so that they can check the results of the operation.
上级 8b8d7ec5
......@@ -72,53 +72,59 @@ protected void ApplyOptionsToWorkspace(Workspace workspace, IDictionary<OptionKe
protected async Task TestMissingAsync(
string initialMarkup,
IDictionary<OptionKey, object> 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<OptionKey, object> 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<OptionKey, object> 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<IList<CodeAction>> GetCodeActionsAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey)
protected async Task<IList<CodeAction>> GetCodeActionsAsync(
TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData = null)
{
return MassageActions(await GetCodeActionsWorkerAsync(workspace, fixAllActionEquivalenceKey));
return MassageActions(await GetCodeActionsWorkerAsync(workspace, fixAllActionEquivalenceKey, fixProviderData));
}
protected abstract Task<IList<CodeAction>> GetCodeActionsWorkerAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey);
protected abstract Task<IList<CodeAction>> 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<IList<CodeAction>> GetCodeActionsAsync(TestWorkspace worksp
string initialMarkup, string expectedMarkup,
int index = 0, bool compareTokens = true,
IDictionary<OptionKey, object> 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<IList<CodeAction>> GetCodeActionsAsync(TestWorkspace worksp
ParseOptions parseOptions,
int index = 0, bool compareTokens = true,
IDictionary<OptionKey, object> 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<IList<CodeAction>> GetCodeActionsAsync(TestWorkspace worksp
ParseOptions parseOptions, CompilationOptions compilationOptions,
int index = 0, bool compareTokens = true,
IDictionary<OptionKey, object> options = null,
string fixAllActionEquivalenceKey = null)
string fixAllActionEquivalenceKey = null,
object fixProviderData = null)
{
string expected;
IDictionary<string, IList<TextSpan>> spanMap;
......@@ -194,7 +203,7 @@ protected async Task<IList<CodeAction>> 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<IEnumerable<CodeActionOperation>> VerifyInputsAndGet
TestWorkspace workspace,
IEnumerable<CodeActionOperation> operations)
{
var applyChangesOperation = operations.OfType<ApplyChangesOperation>().First();
var oldSolution = workspace.CurrentSolution;
var newSolution = applyChangesOperation.ChangedSolution;
Tuple<Solution, Solution> 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<CodeAction> MassageActions(IList<CodeAction> actions)
......
......@@ -25,7 +25,8 @@ public abstract class AbstractCodeActionTest : AbstractCodeActionOrUserDiagnosti
{
protected abstract object CreateCodeRefactoringProvider(Workspace workspace);
protected override async Task<IList<CodeAction>> GetCodeActionsWorkerAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey)
protected override async Task<IList<CodeAction>> GetCodeActionsWorkerAsync(
TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData)
{
return (await GetCodeRefactoringAsync(workspace))?.Actions?.ToList();
}
......
......@@ -25,14 +25,24 @@ public abstract class AbstractDiagnosticProviderBasedUserDiagnosticTest : Abstra
internal abstract Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace);
private Tuple<DiagnosticAnalyzer, CodeFixProvider> GetOrCreateDiagnosticProviderAndFixer(Workspace workspace)
internal virtual Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(
Workspace workspace, object fixProviderData)
{
return _analyzerAndFixerMap.GetOrAdd(workspace, CreateDiagnosticProviderAndFixer);
return CreateDiagnosticProviderAndFixer(workspace);
}
internal async override Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(TestWorkspace workspace)
private Tuple<DiagnosticAnalyzer, CodeFixProvider> GetOrCreateDiagnosticProviderAndFixer(
Workspace workspace, object fixProviderData)
{
var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace);
return fixProviderData == null
? _analyzerAndFixerMap.GetOrAdd(workspace, CreateDiagnosticProviderAndFixer)
: CreateDiagnosticProviderAndFixer(workspace, fixProviderData);
}
internal async override Task<IEnumerable<Diagnostic>> 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<IEnumerable<Diagnostic>> GetDiagnosticsAsync(TestWo
return allDiagnostics;
}
internal override async Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(TestWorkspace workspace, string fixAllActionId)
internal override async Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(
TestWorkspace workspace, string fixAllActionId, object fixProviderData)
{
var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace);
var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace, fixProviderData);
var provider = providerAndFixer.Item1;
Document document;
......
......@@ -53,7 +53,8 @@ private ImmutableArray<Diagnostic> FilterDiagnostics(IEnumerable<Diagnostic> dia
return diagnostics.ToImmutableArray();
}
internal override async Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(TestWorkspace workspace)
internal override async Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(
TestWorkspace workspace, object fixProviderData)
{
var providerAndFixer = CreateDiagnosticProviderAndFixer(workspace);
......@@ -64,7 +65,8 @@ internal override async Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(TestWo
return FilterDiagnostics(diagnostics);
}
internal override async Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(TestWorkspace workspace, string fixAllActionId)
internal override async Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(
TestWorkspace workspace, string fixAllActionId, object fixProviderData)
{
var providerAndFixer = CreateDiagnosticProviderAndFixer(workspace);
......
......@@ -27,18 +27,21 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
{
public abstract class AbstractUserDiagnosticTest : AbstractCodeActionOrUserDiagnosticTest
{
internal abstract Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey);
internal abstract Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(TestWorkspace workspace);
internal abstract Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(
TestWorkspace workspace, string fixAllActionEquivalenceKey, object fixProviderData);
internal abstract Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(TestWorkspace workspace, object fixProviderData);
protected override async Task<IList<CodeAction>> GetCodeActionsWorkerAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey)
protected override async Task<IList<CodeAction>> 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<Tuple<Diagnostic, CodeFixCollection>> GetDiagnosticAndFixAsync(TestWorkspace workspace, string fixAllActionEquivalenceKey = null)
internal async Task<Tuple<Diagnostic, CodeFixCollection>> 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<TextSpan> spansList;
string unused;
......@@ -251,13 +259,13 @@ protected async Task TestEquivalenceKeyAsync(string initialMarkup, string equiva
ISet<TextSpan> 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)
......
// 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)
{
}
/// <summary>
/// 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.
/// </summary>
internal virtual bool ApplyDuringTests => false;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册