/// <summary> /// Verifies the output of a source generator. /// </summary> /// <typeparam name="TGenerator">The generator type to use.</typeparam> /// <param name="source">The input source to process.</param> /// <param name="index">The target index to check in the resulting output.</param> /// <param name="expectedBody">The expected body to compare with the generated code.</param> private static void VerifyGeneratedMethodLines <TGenerator>(string source, int index, string expectedBody) where TGenerator : class, IIncrementalGenerator, new() { SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source); IEnumerable <MetadataReference> references = from assembly in AppDomain.CurrentDomain.GetAssemblies() where !assembly.IsDynamic let reference = MetadataReference.CreateFromFile(assembly.Location) select reference; CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); IIncrementalGenerator generator = new TGenerator(); CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator); driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics); string outputBody = outputCompilation.SyntaxTrees.Skip(index + 1).First().ToString(); string[] outputLines = outputBody.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); string[] expectedLines = expectedBody.Replace("\r", "").Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); Assert.AreEqual(expectedLines.Length, outputLines.Length); for (int i = 0; i < outputLines.Length; i++) { Assert.AreEqual(expectedLines[i], outputLines[i]); } }
/// <summary> /// Verifies the output of a source generator. /// </summary> /// <typeparam name="TGenerator">The generator type to use.</typeparam> /// <param name="syntaxTree">The input source tree to process.</param> /// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param> private static void VerifyGeneratedDiagnostics <TGenerator>(SyntaxTree syntaxTree, params string[] diagnosticsIds) where TGenerator : class, ISourceGenerator, new() { Type observableObjectType = typeof(ObservableObject); Type validationAttributeType = typeof(ValidationAttribute); IEnumerable <MetadataReference> references = from assembly in AppDomain.CurrentDomain.GetAssemblies() where !assembly.IsDynamic let reference = MetadataReference.CreateFromFile(assembly.Location) select reference; CSharpCompilation compilation = CSharpCompilation.Create( "original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); ISourceGenerator generator = new TGenerator(); CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: (CSharpParseOptions)syntaxTree.Options); driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics); HashSet <string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet(); Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds)); GC.KeepAlive(observableObjectType); GC.KeepAlive(validationAttributeType); }
private void VerifyGeneratedMethodLines(string source, string expectedEnumName, string expectedBody) { SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source); List <MetadataReference> references = new List <MetadataReference>(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!assembly.IsDynamic) { references.Add(MetadataReference.CreateFromFile(assembly.Location)); } } CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); ISourceGenerator generator = new EnumValidationGenerator(); CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator); driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics); Assert.False(diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error), "Failed: " + diagnostics.FirstOrDefault()?.GetMessage()); string output = outputCompilation.SyntaxTrees.Skip(1).First().ToString(); List <string> lines = output.Split("\r\n").ToList(); AssertFirstLineAndRemove(lines, "// <auto-generated />"); AssertFirstLineAndRemove(lines, "namespace SourceGenerated"); AssertFirstLineAndRemove(lines, "{"); AssertFirstLineAndRemove(lines, "internal static partial class EnumValidator"); AssertFirstLineAndRemove(lines, "{"); AssertFirstLineAndRemove(lines, "/// <summary>Validates that the enum value passed in is valid for the enum type.</summary>"); AssertFirstLineAndRemove(lines, $"public static void Validate({expectedEnumName} enumToValidate, string parameterName = \"value\")"); AssertFirstLineAndRemove(lines, "{"); AssertFirstLineAndRemove(lines, "int intValue = (int)enumToValidate;"); foreach (string line in expectedBody.Split("\r\n")) { AssertFirstLineAndRemove(lines, line.Trim()); } AssertFirstLineAndRemove(lines, $"ReportEnumValidationError(parameterName, intValue, typeof({expectedEnumName}));"); AssertFirstLineAndRemove(lines, "}");
/// <summary> /// Performs a test on all <see cref="ISourceGenerator"/>s registered in the provided <paramref name="generatorDriver"/>. /// </summary> /// <param name="generatorDriver"><see cref="CSharpGeneratorDriver"/> to run a tests on all registered <see cref="ISourceGenerator"/> of.</param> /// <param name="resultProvider">A delegate that creates the target <see cref="IGeneratorTestResult"/> from the data provided by the tested <paramref name="generatorDriver"/>.</param> /// <param name="compilation">A <see cref="CSharpCompilation"/> to be used a input of the tested <paramref name="generatorDriver"/>.</param> /// <exception cref="ArgumentNullException"><paramref name="generatorDriver"/> is <see langword="null"/>. -or- <paramref name="resultProvider"/> is <see langword="null"/>. -or- <paramref name="compilation"/> is <see langword="null"/>.</exception> public static IGeneratorTestResult RunTest(this CSharpGeneratorDriver generatorDriver, GeneratorTestResultProvider resultProvider, CSharpCompilation compilation) { if (generatorDriver is null) { throw new ArgumentNullException(nameof(generatorDriver)); } if (resultProvider is null) { throw new ArgumentNullException(nameof(resultProvider)); } if (compilation is null) { throw new ArgumentNullException(nameof(compilation)); } CSharpGeneratorDriver driver = generatorDriver; driver = (CSharpGeneratorDriver)driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out _); return(resultProvider(driver, compilation, (CSharpCompilation)outputCompilation)); }
/// <summary> /// Verifies the output of a source generator. /// </summary> /// <typeparam name="TGenerator">The generator type to use.</typeparam> /// <param name="source">The input source to process.</param> /// <param name="diagnosticsIds">The expected diagnostics ids to be generated.</param> private static void VerifyGeneratedDiagnostics <TGenerator>(string source, params string[] diagnosticsIds) where TGenerator : class, IIncrementalGenerator, new() { SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source); IEnumerable <MetadataReference> references = from assembly in AppDomain.CurrentDomain.GetAssemblies() where !assembly.IsDynamic let reference = MetadataReference.CreateFromFile(assembly.Location) select reference; CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); IIncrementalGenerator generator = new TGenerator(); CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator); driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics); HashSet <string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet(); Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds)); }