Skip to content

Commit 18ca742

Browse files
authored
Merge pull request #545 from sharwell/custom-verifiers
Add custom verifiers to the test project
2 parents 10af48b + cf4327d commit 18ca742

32 files changed

+881
-30
lines changed

src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
1212
<PackageReference Include="MSTest.TestAdapter" Version="1.3.2" />
1313
<PackageReference Include="MSTest.TestFramework" Version="1.3.2" />
14+
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.3.1" />
1415
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.MSTest" Version="1.0.1-beta1.*" />
1516
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.MSTest" Version="1.0.1-beta1.*" />
1617
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeRefactoring.Testing.MSTest" Version="1.0.1-beta1.*" />
18+
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Analyzer.Testing.MSTest" Version="1.0.1-beta1.*" />
19+
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.CodeFix.Testing.MSTest" Version="1.0.1-beta1.*" />
20+
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.CodeRefactoring.Testing.MSTest" Version="1.0.1-beta1.*" />
1721
</ItemGroup>
1822

1923
<ItemGroup>

src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.vstemplate

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@
1919
<TemplateContent>
2020
<Project TargetFileName="$safeprojectname$.csproj" File="Test.csproj" ReplaceParameters="true">
2121
<ProjectItem ReplaceParameters="true" TargetFileName="$saferootidentifiername$UnitTests.cs">UnitTests.cs</ProjectItem>
22+
23+
<!-- File names are shortened to avoid PathTooLongException on project creation... -->
24+
<ProjectItem ReplaceParameters="true" TargetFileName="CSharpAnalyzerVerifier`1.cs">Verifiers\CSAnalyzerVerifier`1.cs</ProjectItem>
25+
<ProjectItem ReplaceParameters="true" TargetFileName="CSharpAnalyzerVerifier`1+Test.cs">Verifiers\CSAnalyzerVerifier`1+Test.cs</ProjectItem>
26+
<ProjectItem ReplaceParameters="true" TargetFileName="CSharpCodeFixVerifier`2.cs">Verifiers\CSCodeFixVerifier`2.cs</ProjectItem>
27+
<ProjectItem ReplaceParameters="true" TargetFileName="CSharpCodeFixVerifier`2+Test.cs">Verifiers\CSCodeFixVerifier`2+Test.cs</ProjectItem>
28+
<ProjectItem ReplaceParameters="true" TargetFileName="CSharpCodeRefactoringVerifier`1.cs">Verifiers\CSRefactoringVerifier`1.cs</ProjectItem>
29+
<ProjectItem ReplaceParameters="true" TargetFileName="CSharpCodeRefactoringVerifier`1+Test.cs">Verifiers\CSRefactoringVerifier`1+Test.cs</ProjectItem>
30+
<ProjectItem ReplaceParameters="true" TargetFileName="CSharpVerifierHelper.cs">Verifiers\CSVerifierHelper.cs</ProjectItem>
31+
<ProjectItem ReplaceParameters="true" TargetFileName="VisualBasicAnalyzerVerifier`1.cs">Verifiers\VBAnalyzerVerifier`1.cs</ProjectItem>
32+
<ProjectItem ReplaceParameters="true" TargetFileName="VisualBasicAnalyzerVerifier`1+Test.cs">Verifiers\VBAnalyzerVerifier`1+Test.cs</ProjectItem>
33+
<ProjectItem ReplaceParameters="true" TargetFileName="VisualBasicCodeFixVerifier`2.cs">Verifiers\VBCodeFixVerifier`2.cs</ProjectItem>
34+
<ProjectItem ReplaceParameters="true" TargetFileName="VisualBasicCodeFixVerifier`2+Test.cs">Verifiers\VBCodeFixVerifier`2+Test.cs</ProjectItem>
35+
<ProjectItem ReplaceParameters="true" TargetFileName="VisualBasicCodeRefactoringVerifier`1.cs">Verifiers\VBRefactoringVerifier`1.cs</ProjectItem>
36+
<ProjectItem ReplaceParameters="true" TargetFileName="VisualBasicCodeRefactoringVerifier`1+Test.cs">Verifiers\VBRefactoringVerifier`1+Test.cs</ProjectItem>
2237
</Project>
2338
</TemplateContent>
2439
<WizardExtension>

src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/UnitTests.cs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,21 @@
1-
using Microsoft.CodeAnalysis;
2-
using Microsoft.CodeAnalysis.CodeFixes;
3-
using Microsoft.CodeAnalysis.Diagnostics;
4-
using Microsoft.VisualStudio.TestTools.UnitTesting;
5-
using System;
6-
using System.Threading;
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
72
using System.Threading.Tasks;
8-
using $saferootprojectname$;
9-
using Verify = Microsoft.CodeAnalysis.CSharp.Testing.MSTest.CodeFixVerifier<
3+
using VerifyCS = $safeprojectname$.CSharpCodeFixVerifier<
104
$saferootprojectname$.$saferootidentifiername$Analyzer,
115
$saferootprojectname$.$saferootidentifiername$CodeFixProvider>;
126

137
namespace $safeprojectname$
148
{
159
[TestClass]
16-
public class UnitTest
10+
public class $saferootidentifiername$UnitTest
1711
{
1812
//No diagnostics expected to show up
1913
[TestMethod]
2014
public async Task TestMethod1()
2115
{
2216
var test = @"";
2317

24-
await Verify.VerifyAnalyzerAsync(test);
18+
await VerifyCS.VerifyAnalyzerAsync(test);
2519
}
2620

2721
//Diagnostic and CodeFix both triggered and checked for
@@ -38,7 +32,7 @@ public async Task TestMethod2()
3832
3933
namespace ConsoleApplication1
4034
{
41-
class TypeName
35+
class {|#0:TypeName|}
4236
{
4337
}
4438
}";
@@ -58,8 +52,8 @@ class TYPENAME
5852
}
5953
}";
6054

61-
var expected = Verify.Diagnostic("$saferootidentifiername$").WithLocation(11, 15).WithArguments("TypeName");
62-
await Verify.VerifyCodeFixAsync(test, expected, fixtest);
55+
var expected = VerifyCS.Diagnostic("$saferootidentifiername$").WithLocation(0).WithArguments("TypeName");
56+
await VerifyCS.VerifyCodeFixAsync(test, expected, fixtest);
6357
}
6458
}
6559
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Microsoft.CodeAnalysis.CSharp.Testing;
2+
using Microsoft.CodeAnalysis.Diagnostics;
3+
using Microsoft.CodeAnalysis.Testing.Verifiers;
4+
5+
namespace $safeprojectname$
6+
{
7+
public static partial class CSharpAnalyzerVerifier<TAnalyzer>
8+
where TAnalyzer : DiagnosticAnalyzer, new()
9+
{
10+
public class Test : CSharpAnalyzerTest<TAnalyzer, MSTestVerifier>
11+
{
12+
public Test()
13+
{
14+
SolutionTransforms.Add((solution, projectId) =>
15+
{
16+
var compilationOptions = solution.GetProject(projectId).CompilationOptions;
17+
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
18+
compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
19+
solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
20+
21+
return solution;
22+
});
23+
}
24+
}
25+
}
26+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.CSharp.Testing;
5+
using Microsoft.CodeAnalysis.Diagnostics;
6+
using Microsoft.CodeAnalysis.Testing;
7+
using Microsoft.CodeAnalysis.Testing.Verifiers;
8+
9+
namespace $safeprojectname$
10+
{
11+
public static partial class CSharpAnalyzerVerifier<TAnalyzer>
12+
where TAnalyzer : DiagnosticAnalyzer, new()
13+
{
14+
/// <inheritdoc cref="AnalyzerVerifier{TAnalyzer, TTest, TVerifier}.Diagnostic()"/>
15+
public static DiagnosticResult Diagnostic()
16+
=> CSharpAnalyzerVerifier<TAnalyzer, MSTestVerifier>.Diagnostic();
17+
18+
/// <inheritdoc cref="AnalyzerVerifier{TAnalyzer, TTest, TVerifier}.Diagnostic(string)"/>
19+
public static DiagnosticResult Diagnostic(string diagnosticId)
20+
=> CSharpAnalyzerVerifier<TAnalyzer, MSTestVerifier>.Diagnostic(diagnosticId);
21+
22+
/// <inheritdoc cref="AnalyzerVerifier{TAnalyzer, TTest, TVerifier}.Diagnostic(DiagnosticDescriptor)"/>
23+
public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
24+
=> CSharpAnalyzerVerifier<TAnalyzer, MSTestVerifier>.Diagnostic(descriptor);
25+
26+
/// <inheritdoc cref="AnalyzerVerifier{TAnalyzer, TTest, TVerifier}.VerifyAnalyzerAsync(string, DiagnosticResult[])"/>
27+
public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
28+
{
29+
var test = new Test
30+
{
31+
TestCode = source,
32+
};
33+
34+
test.ExpectedDiagnostics.AddRange(expected);
35+
await test.RunAsync(CancellationToken.None);
36+
}
37+
}
38+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Microsoft.CodeAnalysis.CodeFixes;
2+
using Microsoft.CodeAnalysis.CSharp.Testing;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
using Microsoft.CodeAnalysis.Testing.Verifiers;
5+
6+
namespace $safeprojectname$
7+
{
8+
public static partial class CSharpCodeFixVerifier<TAnalyzer, TCodeFix>
9+
where TAnalyzer : DiagnosticAnalyzer, new()
10+
where TCodeFix : CodeFixProvider, new()
11+
{
12+
public class Test : CSharpCodeFixTest<TAnalyzer, TCodeFix, MSTestVerifier>
13+
{
14+
public Test()
15+
{
16+
SolutionTransforms.Add((solution, projectId) =>
17+
{
18+
var compilationOptions = solution.GetProject(projectId).CompilationOptions;
19+
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
20+
compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
21+
solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
22+
23+
return solution;
24+
});
25+
}
26+
}
27+
}
28+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.CodeFixes;
5+
using Microsoft.CodeAnalysis.CSharp.Testing;
6+
using Microsoft.CodeAnalysis.Diagnostics;
7+
using Microsoft.CodeAnalysis.Testing;
8+
using Microsoft.CodeAnalysis.Testing.Verifiers;
9+
10+
namespace $safeprojectname$
11+
{
12+
public static partial class CSharpCodeFixVerifier<TAnalyzer, TCodeFix>
13+
where TAnalyzer : DiagnosticAnalyzer, new()
14+
where TCodeFix : CodeFixProvider, new()
15+
{
16+
/// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.Diagnostic()"/>
17+
public static DiagnosticResult Diagnostic()
18+
=> CSharpCodeFixVerifier<TAnalyzer, TCodeFix, MSTestVerifier>.Diagnostic();
19+
20+
/// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.Diagnostic(string)"/>
21+
public static DiagnosticResult Diagnostic(string diagnosticId)
22+
=> CSharpCodeFixVerifier<TAnalyzer, TCodeFix, MSTestVerifier>.Diagnostic(diagnosticId);
23+
24+
/// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.Diagnostic(DiagnosticDescriptor)"/>
25+
public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
26+
=> CSharpCodeFixVerifier<TAnalyzer, TCodeFix, MSTestVerifier>.Diagnostic(descriptor);
27+
28+
/// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.VerifyAnalyzerAsync(string, DiagnosticResult[])"/>
29+
public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
30+
{
31+
var test = new Test
32+
{
33+
TestCode = source,
34+
};
35+
36+
test.ExpectedDiagnostics.AddRange(expected);
37+
await test.RunAsync(CancellationToken.None);
38+
}
39+
40+
/// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.VerifyCodeFixAsync(string, string)"/>
41+
public static async Task VerifyCodeFixAsync(string source, string fixedSource)
42+
=> await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
43+
44+
/// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.VerifyCodeFixAsync(string, DiagnosticResult, string)"/>
45+
public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
46+
=> await VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
47+
48+
/// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.VerifyCodeFixAsync(string, DiagnosticResult[], string)"/>
49+
public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
50+
{
51+
var test = new Test
52+
{
53+
TestCode = source,
54+
FixedCode = fixedSource,
55+
};
56+
57+
test.ExpectedDiagnostics.AddRange(expected);
58+
await test.RunAsync(CancellationToken.None);
59+
}
60+
}
61+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Microsoft.CodeAnalysis.CodeRefactorings;
2+
using Microsoft.CodeAnalysis.CSharp.Testing;
3+
using Microsoft.CodeAnalysis.Testing.Verifiers;
4+
5+
namespace $safeprojectname$
6+
{
7+
public static partial class CSharpCodeRefactoringVerifier<TCodeRefactoring>
8+
where TCodeRefactoring : CodeRefactoringProvider, new()
9+
{
10+
public class Test : CSharpCodeRefactoringTest<TCodeRefactoring, MSTestVerifier>
11+
{
12+
public Test()
13+
{
14+
SolutionTransforms.Add((solution, projectId) =>
15+
{
16+
var compilationOptions = solution.GetProject(projectId).CompilationOptions;
17+
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
18+
compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
19+
solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
20+
21+
return solution;
22+
});
23+
}
24+
}
25+
}
26+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using Microsoft.CodeAnalysis.CodeRefactorings;
4+
using Microsoft.CodeAnalysis.Testing;
5+
6+
namespace $safeprojectname$
7+
{
8+
public static partial class CSharpCodeRefactoringVerifier<TCodeRefactoring>
9+
where TCodeRefactoring : CodeRefactoringProvider, new()
10+
{
11+
/// <inheritdoc cref="CodeRefactoringVerifier{TCodeRefactoring, TTest, TVerifier}.VerifyRefactoringAsync(string, string)"/>
12+
public static async Task VerifyRefactoringAsync(string source, string fixedSource)
13+
{
14+
await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
15+
}
16+
17+
/// <inheritdoc cref="CodeRefactoringVerifier{TCodeRefactoring, TTest, TVerifier}.VerifyRefactoringAsync(string, DiagnosticResult, string)"/>
18+
public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource)
19+
{
20+
await VerifyRefactoringAsync(source, new[] { expected }, fixedSource);
21+
}
22+
23+
/// <inheritdoc cref="CodeRefactoringVerifier{TCodeRefactoring, TTest, TVerifier}.VerifyRefactoringAsync(string, DiagnosticResult[], string)"/>
24+
public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource)
25+
{
26+
var test = new Test
27+
{
28+
TestCode = source,
29+
FixedCode = fixedSource,
30+
};
31+
32+
test.ExpectedDiagnostics.AddRange(expected);
33+
await test.RunAsync(CancellationToken.None);
34+
}
35+
}
36+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Collections.Immutable;
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.CSharp;
5+
6+
namespace $safeprojectname$
7+
{
8+
internal static class CSharpVerifierHelper
9+
{
10+
/// <summary>
11+
/// By default, the compiler reports diagnostics for nullable reference types at
12+
/// <see cref="DiagnosticSeverity.Warning"/>, and the analyzer test framework defaults to only validating
13+
/// diagnostics at <see cref="DiagnosticSeverity.Error"/>. This map contains all compiler diagnostic IDs
14+
/// related to nullability mapped to <see cref="ReportDiagnostic.Error"/>, which is then used to enable all
15+
/// of these warnings for default validation during analyzer and code fix tests.
16+
/// </summary>
17+
internal static ImmutableDictionary<string, ReportDiagnostic> NullableWarnings { get; } = GetNullableWarningsFromCompiler();
18+
19+
private static ImmutableDictionary<string, ReportDiagnostic> GetNullableWarningsFromCompiler()
20+
{
21+
string[] args = { "/warnaserror:nullable" };
22+
var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory);
23+
var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
24+
25+
// Workaround for https://github.com/dotnet/roslyn/issues/41610
26+
nullableWarnings = nullableWarnings
27+
.SetItem("CS8632", ReportDiagnostic.Error)
28+
.SetItem("CS8669", ReportDiagnostic.Error);
29+
30+
return nullableWarnings;
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)