Skip to content

Commit 0e7616d

Browse files
committed
Refactored test tooling for additional flexibility
1 parent 7cb2ce7 commit 0e7616d

8 files changed

+251
-163
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.Text;
3+
4+
namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
5+
6+
internal class InMemoryAdditionalText : AdditionalText
7+
{
8+
private readonly SourceText _content;
9+
10+
public InMemoryAdditionalText(string path, string content)
11+
{
12+
Path = path;
13+
_content = SourceText.From(content, Encoding.UTF8);
14+
}
15+
16+
public override string Path { get; }
17+
18+
public override SourceText GetText(CancellationToken cancellationToken = default) => _content;
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.CodeAnalysis;
6+
7+
namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
8+
9+
public record SourceGeneratorRunResult(Compilation Compilation, ImmutableArray<Diagnostic> Diagnostics);
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.CodeAnalysis;
6+
using Microsoft.CodeAnalysis.CSharp;
7+
8+
namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
9+
10+
public static partial class TestHelpers
11+
{
12+
internal static IEnumerable<MetadataReference> GetAllReferencedAssemblies()
13+
{
14+
return from assembly in AppDomain.CurrentDomain.GetAssemblies()
15+
where !assembly.IsDynamic
16+
let reference = MetadataReference.CreateFromFile(assembly.Location)
17+
select reference;
18+
}
19+
20+
internal static SyntaxTree ToSyntaxTree(this string source)
21+
{
22+
return CSharpSyntaxTree.ParseText(source,
23+
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10));
24+
}
25+
26+
internal static CSharpCompilation CreateCompilation(this SyntaxTree syntaxTree, string assemblyName, IEnumerable<MetadataReference>? references = null)
27+
{
28+
return CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, references ?? GetAllReferencedAssemblies(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
29+
}
30+
31+
internal static CSharpCompilation CreateCompilation(this IEnumerable<SyntaxTree> syntaxTree, string assemblyName, IEnumerable<MetadataReference>? references = null)
32+
{
33+
return CSharpCompilation.Create(assemblyName, syntaxTree, references ?? GetAllReferencedAssemblies(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
34+
}
35+
36+
internal static GeneratorDriver CreateSourceGeneratorDriver(this SyntaxTree syntaxTree, IIncrementalGenerator generator)
37+
{
38+
return CSharpGeneratorDriver.Create(generator).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
39+
}
40+
41+
internal static GeneratorDriver CreateSourceGeneratorDriver(this SyntaxTree syntaxTree, params IIncrementalGenerator[] generators)
42+
{
43+
return CSharpGeneratorDriver.Create(generators).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
44+
}
45+
46+
internal static GeneratorDriver WithMarkdown(this GeneratorDriver driver, params string[] markdownFilesToCreate)
47+
{
48+
foreach (var markdown in markdownFilesToCreate)
49+
{
50+
if (!string.IsNullOrWhiteSpace(markdown))
51+
{
52+
var text = new InMemoryAdditionalText(@"C:\pathtorepo\components\experiment\samples\experiment.Samples\documentation.md", markdown);
53+
driver = driver.AddAdditionalTexts(ImmutableArray.Create<AdditionalText>(text));
54+
}
55+
}
56+
57+
return driver;
58+
}
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
4+
namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
5+
6+
public static partial class TestHelpers
7+
{
8+
internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this string source, string assemblyName, string markdown = "") where TGenerator : class, IIncrementalGenerator, new() => RunSourceGenerator<TGenerator>(source.ToSyntaxTree(), assemblyName, markdown);
9+
10+
internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this SyntaxTree syntaxTree, string assemblyName, string markdown = "")
11+
where TGenerator : class, IIncrementalGenerator, new()
12+
{
13+
var references = GetAllReferencedAssemblies();
14+
var compilation = syntaxTree.CreateCompilation(assemblyName, references); // assembly name should always be supplied in param
15+
return RunSourceGenerator<TGenerator>(syntaxTree, compilation, markdown);
16+
}
17+
18+
internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this SyntaxTree syntaxTree, Compilation compilation, string markdown = "")
19+
where TGenerator : class, IIncrementalGenerator, new()
20+
{
21+
// Create a driver for the source generator
22+
var driver = syntaxTree
23+
.CreateSourceGeneratorDriver(new TGenerator())
24+
.WithMarkdown(markdown);
25+
26+
// Update the original compilation using the source generator
27+
_ = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation generatorCompilation, out ImmutableArray<Diagnostic> postGeneratorCompilationDiagnostics);
28+
29+
return new(generatorCompilation, postGeneratorCompilationDiagnostics);
30+
}
31+
32+
internal static void AssertDiagnosticsAre(this IEnumerable<Diagnostic> diagnostics, params DiagnosticDescriptor[] expectedDiagnosticDescriptors)
33+
{
34+
var expectedIds = expectedDiagnosticDescriptors.Select(x => x.Id).ToHashSet();
35+
var resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();
36+
37+
Assert.IsTrue(resultingIds.SetEquals(expectedIds), $"Expected [{string.Join(", ", expectedIds)}] diagnostic Ids. Got [{string.Join(", ", resultingIds)}]");
38+
}
39+
40+
internal static void AssertNoCompilationErrors(this Compilation outputCompilation)
41+
{
42+
var generatedCompilationDiagnostics = outputCompilation.GetDiagnostics();
43+
Assert.IsTrue(generatedCompilationDiagnostics.All(x => x.Severity != DiagnosticSeverity.Error), $"Expected no generated compilation errors. Got: \n{string.Join("\n", generatedCompilationDiagnostics.Where(x => x.Severity == DiagnosticSeverity.Error).Select(x => $"[{x.Id}: {x.GetMessage()}]"))}");
44+
}
45+
46+
internal static void AssertSourceGenerated(this Compilation compilation, string filename, string expectedContents)
47+
{
48+
var generatedTree = compilation.SyntaxTrees.SingleOrDefault(tree => Path.GetFileName(tree.FilePath) == filename);
49+
50+
Assert.IsNotNull(generatedTree, $"No file named {filename} was generated");
51+
Assert.AreEqual(expectedContents, generatedTree.ToString(), "Unexpected code generated");
52+
}
53+
54+
internal static void AssertDiagnosticsAre(this SourceGeneratorRunResult result, params DiagnosticDescriptor[] expectedDiagnosticDescriptors) => AssertDiagnosticsAre(result.Diagnostics, expectedDiagnosticDescriptors);
55+
56+
internal static void AssertNoCompilationErrors(this SourceGeneratorRunResult result) => AssertNoCompilationErrors(result.Compilation);
57+
58+
internal static void AssertSourceGenerated(this SourceGeneratorRunResult result, string filename, string expectedContents) => AssertSourceGenerated(result.Compilation, filename, expectedContents);
59+
}

CommunityToolkit.Tooling.SampleGen.Tests/SampleGenTestHelpers.cs

Lines changed: 0 additions & 117 deletions
This file was deleted.

0 commit comments

Comments
 (0)