Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Dena.CodeAnalysis.Testing can read metadata. #10

Merged
merged 5 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions src/Dena.CodeAnalysis.Testing/AnalyzerRunner.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
Expand All @@ -12,7 +13,6 @@
using Microsoft.VisualStudio.Composition;



namespace Dena.CodeAnalysis.CSharp.Testing
{
/// <summary>
Expand All @@ -31,22 +31,24 @@ public static class DiagnosticAnalyzerRunner
/// Run the specified <see cref="DiagnosticAnalyzer" />.
/// </summary>
/// <param name="analyzer">The <see cref="DiagnosticAnalyzer" /> to run.</param>
/// <param name="types">The type of metadata you want to add.</param>
/// <param name="codes">The target code that the <paramref name="analyzer" /> analyze.</param>
/// <returns>ImmutableArray contains all reported <see cref="Diagnostic" />.</returns>
/// <throws>Throws <c cref="AtLeastOneCodeMustBeRequired" /> if <paramref name="codes" /> are empty.</throws>
public static async Task<ImmutableArray<Diagnostic>> Run(
DiagnosticAnalyzer analyzer,
Type[] types = default,
params string[] codes
) =>
await Run(
analyzer,
CancellationToken.None,
ParseOptionsForLanguageVersionsDefault(),
CompilationOptionsForDynamicClassLibrary(),
MetadataReferencesDefault(types),
codes
);


/// <summary>
/// Run the specified <see cref="DiagnosticAnalyzer" />.
/// </summary>
Expand All @@ -63,6 +65,7 @@ public static async Task<ImmutableArray<Diagnostic>> Run(
CancellationToken cancellationToken,
ParseOptions parseOptions,
CompilationOptions compilationOptions,
IEnumerable<MetadataReference> metadataReferences,
params string[] codes
)
{
Expand All @@ -89,10 +92,6 @@ params string[] codes

var noMetadataReferencedProject = solution.Projects.First();

// NOTE: Make .NET standard libraries visible to the specified codes to analyze.
var metadataReferences =
await ReferenceAssemblies.Default.ResolveAsync(Language, CancellationToken.None);

var project = noMetadataReferencedProject
.AddMetadataReferences(metadataReferences)
.WithParseOptions(parseOptions)
Expand Down Expand Up @@ -120,6 +119,21 @@ public static CompilationOptions CompilationOptionsForDynamicClassLibrary() =>
public static ParseOptions ParseOptionsForLanguageVersionsDefault() =>
new CSharpParseOptions(DefaultLanguageVersion, DocumentationMode.Diagnose);

private static IEnumerable<MetadataReference> MetadataReferencesDefault(Type[] types)
{
var metadataReferences = ReferenceAssemblies.Default.ResolveAsync(Language, CancellationToken.None).Result
.ToList();
if (types != null)
{
foreach (var type in types)
{
metadataReferences.Add(MetadataReference.CreateFromFile(type.Assembly.Location));
}
}

return metadataReferences;
}


/// <summary>
/// This value is equivalent to <see cref="Microsoft.CodeAnalysis.Testing.AnalyzerTest{IVerifier}.DefaultFilePathPrefix" />
Expand Down Expand Up @@ -191,7 +205,6 @@ static DiagnosticAnalyzerRunner()
}



/// <summary>
/// None of codes specified but at least one code must be required.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/Dena.CodeAnalysis.Testing/ExampleCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ internal static void Bar()
}
";

public const string UniTaskImport = @"
using Cysharp.Threading.Tasks;
internal static class Foo
{
internal static void Bar()
{
System.Console.WriteLine(""Hello, World!"");
}
}";

/// <summary>
/// An example code that contains a syntax error.
/// </summary>
Expand Down
19 changes: 16 additions & 3 deletions tests/Dena.CodeAnalysis.Testing.Tests/AnalyzerRunnerTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MSTestAssert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;

Expand All @@ -25,20 +26,32 @@ public async Task WhenGivenDiagnosticCleanCode_ItShouldReturnNoDiagnostics()
var anyAnalyzer = new NullAnalyzer();
var diagnostics = await DiagnosticAnalyzerRunner.Run(
anyAnalyzer,
ExampleCode.DiagnosticsFreeClassLibrary
codes: ExampleCode.DiagnosticsFreeClassLibrary
);

MSTestAssert.AreEqual(0, diagnostics.Length, DiagnosticsFormatter.Format(diagnostics));
}

[TestMethod]
public async Task WhenGivenUniTaskImport_ItShouldReturnNoDiagnostics()
{
var anyAnalyzer = new NullAnalyzer();
var diagnostics = await DiagnosticAnalyzerRunner.Run(
anyAnalyzer,
new[] { typeof(UniTask) },
ExampleCode.UniTaskImport
);

MSTestAssert.AreEqual(1, diagnostics.Length, DiagnosticsFormatter.Format(diagnostics));
}

[TestMethod]
public async Task WhenGivenContainingASyntaxError_ItShouldReturnSeveralDiagnostics()
{
var anyAnalyzer = new NullAnalyzer();
var diagnostics = await DiagnosticAnalyzerRunner.Run(
anyAnalyzer,
ExampleCode.ContainingSyntaxError
codes: ExampleCode.ContainingSyntaxError
);

MSTestAssert.AreNotEqual(0, diagnostics.Length);
Expand All @@ -50,7 +63,7 @@ public async Task WhenGivenAnyCodes_ItShouldCallAnalyzerInitialize()
{
var spyAnalyzer = new SpyAnalyzer();

await DiagnosticAnalyzerRunner.Run(spyAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(spyAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.IsTrue(spyAnalyzer.IsInitialized);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>

<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="UniTask" Version="2.3.3" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using MSTestAssert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;



namespace Dena.CodeAnalysis.CSharp.Testing
{
[TestClass]
Expand All @@ -14,7 +13,7 @@ public async Task Format()
{
var diagnostics = await DiagnosticAnalyzerRunner.Run(
new NullAnalyzer(),
ExampleCode.ContainingSyntaxError
codes: ExampleCode.ContainingSyntaxError
);

var actual = DiagnosticsFormatter.Format(diagnostics);
Expand Down
2 changes: 1 addition & 1 deletion tests/Dena.CodeAnalysis.Testing.Tests/LocationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static async Task<Location> Create()
{
var ds = await DiagnosticAnalyzerRunner.Run(
new NullAnalyzer(),
ExampleCode.ContainingSyntaxError
codes: ExampleCode.ContainingSyntaxError
);
return ds[0].Location;
}
Expand Down
3 changes: 1 addition & 2 deletions tests/Dena.CodeAnalysis.Testing.Tests/SpyAnalyzerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using MSTestAssert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;



namespace Dena.CodeAnalysis.CSharp.Testing
{
[TestClass]
Expand All @@ -17,7 +16,7 @@ public async Task WhenGivenAnyCodes_RecordAllActionHistory()
var builder = new StringBuilder();
var failed = false;

await DiagnosticAnalyzerRunner.Run(spy, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(spy, codes: ExampleCode.DiagnosticsFreeClassLibrary);

if (0 == spy.CodeBlockActionHistory.Count)
{
Expand Down
25 changes: 12 additions & 13 deletions tests/Dena.CodeAnalysis.Testing.Tests/StubAnalyzerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using MSTestAssert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;



namespace Dena.CodeAnalysis.CSharp.Testing
{
[TestClass]
Expand All @@ -20,7 +19,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallCodeBlockAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -37,7 +36,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallCodeBlockStartAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -54,7 +53,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallCompilationAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -71,7 +70,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallCompilationStartAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -88,7 +87,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallOperationAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -105,7 +104,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallOperationBlockAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -122,7 +121,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallOperationBlockStartAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -139,7 +138,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallSemanticModelAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -156,7 +155,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallSymbolAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -173,7 +172,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallSymbolStartAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -190,7 +189,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallSyntaxNodeAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand All @@ -207,7 +206,7 @@ public async Task WhenGivenAnyCodes_ItShouldGetToCallSyntaxTreeAction()
}
);

await DiagnosticAnalyzerRunner.Run(stubAnalyzer, ExampleCode.DiagnosticsFreeClassLibrary);
await DiagnosticAnalyzerRunner.Run(stubAnalyzer, codes: ExampleCode.DiagnosticsFreeClassLibrary);

MSTestAssert.AreNotEqual(0, callCount);
}
Expand Down
Loading