Skip to content

Commit

Permalink
Consolidate shared verifier state
Browse files Browse the repository at this point in the history
  • Loading branch information
sharwell committed Jun 23, 2021
1 parent 1494249 commit ac79a16
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<Compile Include="..\..\..\EditorFeatures\DiagnosticsTestUtilities\CodeActions\CSharpCodeRefactoringVerifier`1+Test.cs" Link="CSharpCodeRefactoringVerifier`1+Test.cs" />
<Compile Include="..\..\..\EditorFeatures\DiagnosticsTestUtilities\CodeActions\CSharpCodeRefactoringVerifier`1.cs" Link="CSharpCodeRefactoringVerifier`1.cs" />
<Compile Include="..\..\..\EditorFeatures\DiagnosticsTestUtilities\CodeActions\CSharpVerifierHelper.cs" Link="CSharpVerifierHelper.cs" />
<Compile Include="..\..\..\EditorFeatures\DiagnosticsTestUtilities\CodeActions\SharedVerifierState.cs" Link="SharedVerifierState.cs" />
<Compile Include="..\..\..\EditorFeatures\DiagnosticsTestUtilities\CodeActions\VisualBasicCodeFixVerifier`2+Test.cs" Link="VisualBasicCodeFixVerifier`2+Test.cs" />
<Compile Include="..\..\..\EditorFeatures\DiagnosticsTestUtilities\CodeActions\VisualBasicCodeFixVerifier`2.cs" Link="VisualBasicCodeFixVerifier`2.cs" />
<Compile Include="..\..\..\EditorFeatures\DiagnosticsTestUtilities\CodeActions\VisualBasicCodeRefactoringVerifier`1+Test.cs" Link="VisualBasicCodeRefactoringVerifier`1+Test.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,7 @@ public static partial class CSharpCodeFixVerifier<TAnalyzer, TCodeFix>
{
public class Test : CSharpCodeFixTest<TAnalyzer, TCodeFix, XUnitVerifier>
{
/// <summary>
/// The index in <see cref="Testing.ProjectState.AnalyzerConfigFiles"/> of the generated
/// <strong>.editorconfig</strong> file for <see cref="Options"/>, or <see langword="null"/> if no such
/// file has been generated yet.
/// </summary>
private int? _analyzerConfigIndex;
private readonly SharedVerifierState _sharedState;

static Test()
{
Expand All @@ -49,6 +44,8 @@ static Test()

public Test()
{
_sharedState = new SharedVerifierState(this, DefaultFileExt);

MarkupOptions = Testing.MarkupOptions.UseFirstDescriptor;

SolutionTransforms.Add((solution, projectId) =>
Expand All @@ -60,17 +57,6 @@ public Test()
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
#if !CODE_STYLE
var options = solution.Options;
var (_, remainingOptions) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(DefaultFileExt, EditorConfig, Options);
foreach (var (key, value) in remainingOptions)
{
options = options.WithChangedOption(key, value);
}
solution = solution.WithOptions(options);
#endif
return solution;
});
}
Expand All @@ -81,13 +67,15 @@ public Test()
/// </summary>
public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.CSharp8;

/// <summary>
/// Gets a collection of options to apply to <see cref="Solution.Options"/> for testing. Values may be added
/// using a collection initializer.
/// </summary>
internal OptionsCollection Options { get; } = new OptionsCollection(LanguageNames.CSharp);
/// <inheritdoc cref="SharedVerifierState.Options"/>
internal OptionsCollection Options => _sharedState.Options;

public string? EditorConfig { get; set; }
/// <inheritdoc cref="SharedVerifierState.EditorConfig"/>
public string? EditorConfig
{
get => _sharedState.EditorConfig;
set => _sharedState.EditorConfig = value;
}

public Func<ImmutableArray<Diagnostic>, Diagnostic?>? DiagnosticSelector { get; set; }

Expand All @@ -98,25 +86,7 @@ protected override async Task RunImplAsync(CancellationToken cancellationToken =
Assert.True(CodeFixTestBehaviors.HasFlag(Testing.CodeFixTestBehaviors.FixOne), $"'{nameof(DiagnosticSelector)}' can only be used with '{nameof(Testing.CodeFixTestBehaviors)}.{nameof(Testing.CodeFixTestBehaviors.FixOne)}'");
}

var (analyzerConfigSource, _) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(DefaultFileExt, EditorConfig, Options);
if (analyzerConfigSource is object)
{
if (_analyzerConfigIndex is null)
{
_analyzerConfigIndex = TestState.AnalyzerConfigFiles.Count;
TestState.AnalyzerConfigFiles.Add(("/.editorconfig", analyzerConfigSource));
}
else
{
TestState.AnalyzerConfigFiles[_analyzerConfigIndex.Value] = ("/.editorconfig", analyzerConfigSource);
}
}
else if (_analyzerConfigIndex is { } index)
{
_analyzerConfigIndex = null;
TestState.AnalyzerConfigFiles.RemoveAt(index);
}

_sharedState.Apply();
await base.RunImplAsync(cancellationToken);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@ public static partial class CSharpCodeRefactoringVerifier<TCodeRefactoring>
{
public class Test : CSharpCodeRefactoringTest<TCodeRefactoring, XUnitVerifier>
{
/// <summary>
/// The index in <see cref="Testing.ProjectState.AnalyzerConfigFiles"/> of the generated
/// <strong>.editorconfig</strong> file for <see cref="Options"/>, or <see langword="null"/> if no such
/// file has been generated yet.
/// </summary>
private int? _analyzerConfigIndex;
private readonly SharedVerifierState _sharedState;

static Test()
{
Expand All @@ -50,6 +45,8 @@ static Test()

public Test()
{
_sharedState = new SharedVerifierState(this, DefaultFileExt);

SolutionTransforms.Add((solution, projectId) =>
{
var parseOptions = (CSharpParseOptions)solution.GetProject(projectId)!.ParseOptions!;
Expand All @@ -59,17 +56,6 @@ public Test()
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
#if !CODE_STYLE
var options = solution.Options;
var (_, remainingOptions) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(DefaultFileExt, EditorConfig, Options);
foreach (var (key, value) in remainingOptions)
{
options = options.WithChangedOption(key, value);
}
solution = solution.WithOptions(options);
#endif
return solution;
});
}
Expand All @@ -80,13 +66,15 @@ public Test()
/// </summary>
public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.CSharp8;

/// <summary>
/// Gets a collection of options to apply to <see cref="Solution.Options"/> for testing. Values may be added
/// using a collection initializer.
/// </summary>
internal OptionsCollection Options { get; } = new OptionsCollection(LanguageNames.CSharp);
/// <inheritdoc cref="SharedVerifierState.Options"/>
internal OptionsCollection Options => _sharedState.Options;

public string? EditorConfig { get; set; }
/// <inheritdoc cref="SharedVerifierState.EditorConfig"/>
public string? EditorConfig
{
get => _sharedState.EditorConfig;
set => _sharedState.EditorConfig = value;
}

/// <summary>
/// The set of code action <see cref="CodeAction.Title"/>s offered the user in this exact order.
Expand All @@ -96,25 +84,7 @@ public Test()

protected override async Task RunImplAsync(CancellationToken cancellationToken)
{
var (analyzerConfigSource, _) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(DefaultFileExt, EditorConfig, Options);
if (analyzerConfigSource is object)
{
if (_analyzerConfigIndex is null)
{
_analyzerConfigIndex = TestState.AnalyzerConfigFiles.Count;
TestState.AnalyzerConfigFiles.Add(("/.editorconfig", analyzerConfigSource));
}
else
{
TestState.AnalyzerConfigFiles[_analyzerConfigIndex.Value] = ("/.editorconfig", analyzerConfigSource);
}
}
else if (_analyzerConfigIndex is { } index)
{
_analyzerConfigIndex = null;
TestState.AnalyzerConfigFiles.RemoveAt(index);
}

_sharedState.Apply();
await base.RunImplAsync(cancellationToken);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Testing.Verifiers;

#if !CODE_STYLE
using Roslyn.Utilities;
#endif

namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions
{
internal sealed class SharedVerifierState
{
private readonly AnalyzerTest<XUnitVerifier> _test;
private readonly string _defaultFileExt;

/// <summary>
/// The index in <see cref="Testing.ProjectState.AnalyzerConfigFiles"/> of the generated
/// <strong>.editorconfig</strong> file for <see cref="Options"/>, or <see langword="null"/> if no such
/// file has been generated yet.
/// </summary>
private int? _analyzerConfigIndex;

/// <summary>
/// The index in <see cref="AnalyzerTest{TVerifier}.SolutionTransforms"/> of the options transformation for
/// remaining <see cref="Options"/>, or <see langword="null"/> if no such transfor has been generated yet.
/// </summary>
private Func<Solution, ProjectId, Solution>? _remainingOptionsSolutionTransform;

public SharedVerifierState(AnalyzerTest<XUnitVerifier> test, string defaultFileExt)
{
_test = test;
_defaultFileExt = defaultFileExt;
Options = new OptionsCollection(test.Language);
}

public string? EditorConfig { get; set; }

/// <summary>
/// Gets a collection of options to apply to <see cref="Solution.Options"/> for testing. Values may be added
/// using a collection initializer.
/// </summary>
internal OptionsCollection Options { get; }

internal void Apply()
{
var (analyzerConfigSource, remainingOptions) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(_defaultFileExt, EditorConfig, Options);
if (analyzerConfigSource is not null)
{
if (_analyzerConfigIndex is null)
{
_analyzerConfigIndex = _test.TestState.AnalyzerConfigFiles.Count;
_test.TestState.AnalyzerConfigFiles.Add(("/.editorconfig", analyzerConfigSource));
}
else
{
_test.TestState.AnalyzerConfigFiles[_analyzerConfigIndex.Value] = ("/.editorconfig", analyzerConfigSource);
}
}
else if (_analyzerConfigIndex is { } index)
{
_analyzerConfigIndex = null;
_test.TestState.AnalyzerConfigFiles.RemoveAt(index);
}

var solutionTransformIndex = _remainingOptionsSolutionTransform is not null ? _test.SolutionTransforms.IndexOf(_remainingOptionsSolutionTransform) : -1;
if (remainingOptions is not null)
{
// Generate a new solution transform
_remainingOptionsSolutionTransform = (solution, projectId) =>
{
#if !CODE_STYLE
var options = solution.Options;
foreach (var (key, value) in remainingOptions)
{
options = options.WithChangedOption(key, value);
}
solution = solution.WithOptions(options);
#endif
return solution;
};

if (solutionTransformIndex < 0)
{
_test.SolutionTransforms.Add(_remainingOptionsSolutionTransform);
}
else
{
_test.SolutionTransforms[solutionTransformIndex] = _remainingOptionsSolutionTransform;
}
}
else if (_remainingOptionsSolutionTransform is not null)
{
_test.SolutionTransforms.Remove(_remainingOptionsSolutionTransform);
_remainingOptionsSolutionTransform = null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,7 @@ public static partial class VisualBasicCodeFixVerifier<TAnalyzer, TCodeFix>
{
public class Test : VisualBasicCodeFixTest<TAnalyzer, TCodeFix, XUnitVerifier>
{
/// <summary>
/// The index in <see cref="Testing.ProjectState.AnalyzerConfigFiles"/> of the generated
/// <strong>.editorconfig</strong> file for <see cref="Options"/>, or <see langword="null"/> if no such
/// file has been generated yet.
/// </summary>
private int? _analyzerConfigIndex;
private readonly SharedVerifierState _sharedState;

static Test()
{
Expand All @@ -49,24 +44,15 @@ static Test()

public Test()
{
_sharedState = new SharedVerifierState(this, DefaultFileExt);

MarkupOptions = Testing.MarkupOptions.UseFirstDescriptor;

SolutionTransforms.Add((solution, projectId) =>
{
var parseOptions = (VisualBasicParseOptions)solution.GetProject(projectId)!.ParseOptions!;
solution = solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(LanguageVersion));
#if !CODE_STYLE
var options = solution.Options;
var (_, remainingOptions) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(DefaultFileExt, EditorConfig, Options);
foreach (var (key, value) in remainingOptions)
{
options = options.WithChangedOption(key, value);
}
solution = solution.WithOptions(options);
#endif
return solution;
});
}
Expand All @@ -77,13 +63,15 @@ public Test()
/// </summary>
public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.VisualBasic16;

/// <summary>
/// Gets a collection of options to apply to <see cref="Solution.Options"/> for testing. Values may be added
/// using a collection initializer.
/// </summary>
internal OptionsCollection Options { get; } = new OptionsCollection(LanguageNames.VisualBasic);
/// <inheritdoc cref="SharedVerifierState.Options"/>
internal OptionsCollection Options => _sharedState.Options;

public string? EditorConfig { get; set; }
/// <inheritdoc cref="SharedVerifierState.EditorConfig"/>
public string? EditorConfig
{
get => _sharedState.EditorConfig;
set => _sharedState.EditorConfig = value;
}

public Func<ImmutableArray<Diagnostic>, Diagnostic?>? DiagnosticSelector { get; set; }

Expand All @@ -94,25 +82,7 @@ protected override async Task RunImplAsync(CancellationToken cancellationToken =
Assert.True(CodeFixTestBehaviors.HasFlag(Testing.CodeFixTestBehaviors.FixOne), $"'{nameof(DiagnosticSelector)}' can only be used with '{nameof(Testing.CodeFixTestBehaviors)}.{nameof(Testing.CodeFixTestBehaviors.FixOne)}'");
}

var (analyzerConfigSource, _) = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(DefaultFileExt, EditorConfig, Options);
if (analyzerConfigSource is object)
{
if (_analyzerConfigIndex is null)
{
_analyzerConfigIndex = TestState.AnalyzerConfigFiles.Count;
TestState.AnalyzerConfigFiles.Add(("/.editorconfig", analyzerConfigSource));
}
else
{
TestState.AnalyzerConfigFiles[_analyzerConfigIndex.Value] = ("/.editorconfig", analyzerConfigSource);
}
}
else if (_analyzerConfigIndex is { } index)
{
_analyzerConfigIndex = null;
TestState.AnalyzerConfigFiles.RemoveAt(index);
}

_sharedState.Apply();
await base.RunImplAsync(cancellationToken);
}

Expand Down
Loading

0 comments on commit ac79a16

Please sign in to comment.