Skip to content

Commit b32c389

Browse files
authored
Merge pull request #69 from CommunityToolkit/refactor/samplegen/tests
Refactored SampleGen test tooling
2 parents a852f23 + f53878b commit b32c389

18 files changed

+740
-570
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616
workflow_dispatch:
1717

1818
env:
19-
DOTNET_VERSION: ${{ '6.0.x' }}
19+
DOTNET_VERSION: ${{ '7.0.x' }}
2020
ENABLE_DIAGNOSTICS: false
2121
#COREHOST_TRACE: 1
2222
COREHOST_TRACEFILE: corehosttrace.log

CommunityToolkit.App.Shared/Renderers/GeneratedSampleOptionsRenderer.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- 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. -->
1+
<!-- 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. -->
22
<UserControl x:Class="CommunityToolkit.App.Shared.Renderers.GeneratedSampleOptionsRenderer"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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 System.Collections.Immutable;
7+
8+
namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
9+
10+
public record SourceGeneratorRunResult(Compilation Compilation, ImmutableArray<Diagnostic> Diagnostics);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
using System.Collections.Immutable;
8+
9+
namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
10+
11+
public static partial class TestHelpers
12+
{
13+
internal static IEnumerable<MetadataReference> GetAllReferencedAssemblies()
14+
{
15+
return from assembly in AppDomain.CurrentDomain.GetAssemblies()
16+
where !assembly.IsDynamic
17+
let reference = MetadataReference.CreateFromFile(assembly.Location)
18+
select reference;
19+
}
20+
21+
internal static SyntaxTree ToSyntaxTree(this string source)
22+
{
23+
return CSharpSyntaxTree.ParseText(source,
24+
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10));
25+
}
26+
27+
internal static CSharpCompilation CreateCompilation(this SyntaxTree syntaxTree, string assemblyName, IEnumerable<MetadataReference>? references = null)
28+
{
29+
return CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, references ?? GetAllReferencedAssemblies(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
30+
}
31+
32+
internal static CSharpCompilation CreateCompilation(this IEnumerable<SyntaxTree> syntaxTree, string assemblyName, IEnumerable<MetadataReference>? references = null)
33+
{
34+
return CSharpCompilation.Create(assemblyName, syntaxTree, references ?? GetAllReferencedAssemblies(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
35+
}
36+
37+
internal static GeneratorDriver CreateSourceGeneratorDriver(this SyntaxTree syntaxTree, params IIncrementalGenerator[] generators)
38+
{
39+
return CSharpGeneratorDriver.Create(generators).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
40+
}
41+
42+
internal static GeneratorDriver CreateSourceGeneratorDriver(this Compilation compilation, params IIncrementalGenerator[] generators)
43+
{
44+
return CSharpGeneratorDriver.Create(generators).WithUpdatedParseOptions((CSharpParseOptions)compilation.SyntaxTrees.First().Options);
45+
}
46+
47+
internal static GeneratorDriver WithMarkdown(this GeneratorDriver driver, params string[] markdownFilesToCreate)
48+
{
49+
foreach (var markdown in markdownFilesToCreate)
50+
{
51+
if (!string.IsNullOrWhiteSpace(markdown))
52+
{
53+
var text = new InMemoryAdditionalText(@"C:\pathtorepo\components\experiment\samples\experiment.Samples\documentation.md", markdown);
54+
driver = driver.AddAdditionalTexts(ImmutableArray.Create<AdditionalText>(text));
55+
}
56+
}
57+
58+
return driver;
59+
}
60+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using System.Collections.Immutable;
4+
5+
namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
6+
7+
public static partial class TestHelpers
8+
{
9+
internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this string source, string assemblyName, string markdown = "") where TGenerator : class, IIncrementalGenerator, new() => RunSourceGenerator<TGenerator>(source.ToSyntaxTree(), assemblyName, markdown);
10+
11+
internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this SyntaxTree syntaxTree, string assemblyName, string markdown = "")
12+
where TGenerator : class, IIncrementalGenerator, new()
13+
{
14+
var compilation = syntaxTree.CreateCompilation(assemblyName); // assembly name should always be supplied in param
15+
return RunSourceGenerator<TGenerator>(compilation, markdown);
16+
}
17+
18+
internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this Compilation compilation, string markdown = "")
19+
where TGenerator : class, IIncrementalGenerator, new()
20+
{
21+
// Create a driver for the source generator
22+
var driver = compilation
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 string GetFileContentsByName(this Compilation compilation, string filename)
47+
{
48+
var generatedTree = compilation.SyntaxTrees.SingleOrDefault(tree => Path.GetFileName(tree.FilePath) == filename);
49+
Assert.IsNotNull(generatedTree, $"No file named {filename} was generated");
50+
51+
return generatedTree.ToString();
52+
}
53+
54+
internal static void AssertSourceGenerated(this Compilation compilation, string filename, string expectedContents)
55+
{
56+
}
57+
58+
internal static void AssertDiagnosticsAre(this SourceGeneratorRunResult result, params DiagnosticDescriptor[] expectedDiagnosticDescriptors) => AssertDiagnosticsAre(result.Diagnostics, expectedDiagnosticDescriptors);
59+
60+
internal static void AssertNoCompilationErrors(this SourceGeneratorRunResult result) => AssertNoCompilationErrors(result.Compilation);
61+
}

0 commit comments

Comments
 (0)