csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
4.8 KiB
115 lines
4.8 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using Avalonia.Generators.PropertyGenerator;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Xunit;
|
|
|
|
namespace Avalonia.Generators.Tests.PropertyGenerator;
|
|
|
|
internal static class PropertyGeneratorTestHelper
|
|
{
|
|
public static readonly CSharpParseOptions ParseOptions = new(LanguageVersion.CSharp14);
|
|
|
|
private static readonly Lazy<IReadOnlyList<MetadataReference>> s_references = new(() =>
|
|
((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")!)
|
|
.Split(Path.PathSeparator)
|
|
.Select(static MetadataReference (path) => MetadataReference.CreateFromFile(path))
|
|
.Append(MetadataReference.CreateFromFile(typeof(AvaloniaObject).Assembly.Location))
|
|
.ToList());
|
|
|
|
public static CSharpCompilation CreateCompilation(
|
|
string source,
|
|
CSharpParseOptions? parseOptions = null,
|
|
NullableContextOptions nullableContextOptions = NullableContextOptions.Enable) =>
|
|
CSharpCompilation.Create(
|
|
"PropertyGeneratorTests",
|
|
[CSharpSyntaxTree.ParseText(source, parseOptions ?? ParseOptions)],
|
|
s_references.Value,
|
|
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, nullableContextOptions: nullableContextOptions));
|
|
|
|
public static (GeneratorDriverRunResult Result, Compilation Output) RunGenerator(
|
|
CSharpCompilation compilation,
|
|
CSharpParseOptions? parseOptions = null)
|
|
{
|
|
var driver = CreateDriver(parseOptions);
|
|
driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var output, out _);
|
|
return (driver.GetRunResult(), output);
|
|
}
|
|
|
|
public static GeneratorDriver CreateDriver(CSharpParseOptions? parseOptions = null) =>
|
|
CSharpGeneratorDriver.Create(
|
|
[new AvaloniaPropertyIncrementalGenerator().AsSourceGenerator()],
|
|
parseOptions: parseOptions ?? ParseOptions,
|
|
driverOptions: new GeneratorDriverOptions(
|
|
IncrementalGeneratorOutputKind.None,
|
|
trackIncrementalGeneratorSteps: true));
|
|
|
|
/// <summary>
|
|
/// Runs the generator, asserts it reports no diagnostics and the updated compilation has no
|
|
/// errors, then compares the generated source against GeneratedCode/{sampleName}.txt.
|
|
/// </summary>
|
|
public static void AssertGeneratedCode(
|
|
string sampleName,
|
|
[StringSyntax("csharp")] string source,
|
|
string? expectedHintName = null,
|
|
LanguageVersion languageVersion = LanguageVersion.CSharp14,
|
|
NullableContextOptions nullableContextOptions = NullableContextOptions.Enable,
|
|
[CallerFilePath] string callerFilePath = "")
|
|
{
|
|
source = """
|
|
using Avalonia;
|
|
using Avalonia.Data;
|
|
|
|
""" + source;
|
|
var parseOptions = new CSharpParseOptions(languageVersion);
|
|
var (result, output) = RunGenerator(CreateCompilation(source, parseOptions, nullableContextOptions), parseOptions);
|
|
|
|
Assert.Empty(result.Diagnostics);
|
|
|
|
var errors = output.GetDiagnostics().Where(static d => d.Severity == DiagnosticSeverity.Error).ToList();
|
|
if (errors.Count > 0)
|
|
{
|
|
var generatedText = string.Join(
|
|
"\n\n",
|
|
result.GeneratedTrees.Select(static tree => $"// {tree.FilePath}\n{tree.GetText()}"));
|
|
Assert.Fail(
|
|
$"Generated compilation has errors:\n{string.Join("\n", errors)}\n\nGenerated source:\n{generatedText}");
|
|
}
|
|
|
|
SyntaxTree tree;
|
|
if (expectedHintName is not null)
|
|
{
|
|
tree = Assert.Single(
|
|
result.GeneratedTrees.Where(t => t.FilePath.Replace('\\', '/').EndsWith(expectedHintName, StringComparison.Ordinal)));
|
|
}
|
|
else
|
|
{
|
|
tree = Assert.Single(result.GeneratedTrees);
|
|
}
|
|
|
|
var actual = Normalize(tree.GetText().ToString());
|
|
var expectedPath = Path.Combine(Path.GetDirectoryName(callerFilePath)!, "GeneratedCode", sampleName + ".txt");
|
|
|
|
if (!File.Exists(expectedPath))
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(expectedPath)!);
|
|
File.WriteAllText(expectedPath, actual);
|
|
Assert.Fail($"Expected file did not exist and was created from actual output; review it: {expectedPath}");
|
|
}
|
|
|
|
var expected = Normalize(File.ReadAllText(expectedPath));
|
|
if (expected != actual)
|
|
{
|
|
File.WriteAllText(expectedPath + ".received", actual);
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
}
|
|
|
|
private static string Normalize(string text) => text.Replace("\r\n", "\n").TrimEnd('\n');
|
|
}
|
|
|