From d7aa90588f110a5dac4f1f650b427ed4402d33d2 Mon Sep 17 00:00:00 2001 From: g7ed6e Date: Thu, 2 Nov 2023 16:50:22 +0100 Subject: [PATCH] Unify CSharpSourceGeneratorTest according to https://github.com/dotnet/roslyn-sdk/issues/941 --- .../tests/CSharpGeneratorVerifier.cs | 19 ++- .../tests/CSharpIncrementalGeneratorTest`2.cs | 42 ----- .../tests/IncrementalGeneratorTest`1.cs | 151 ------------------ 3 files changed, 14 insertions(+), 198 deletions(-) delete mode 100644 src/System.ServiceModel.BuildTools/tests/CSharpIncrementalGeneratorTest`2.cs delete mode 100644 src/System.ServiceModel.BuildTools/tests/IncrementalGeneratorTest`1.cs diff --git a/src/System.ServiceModel.BuildTools/tests/CSharpGeneratorVerifier.cs b/src/System.ServiceModel.BuildTools/tests/CSharpGeneratorVerifier.cs index 1411770432a..5c85c641de0 100644 --- a/src/System.ServiceModel.BuildTools/tests/CSharpGeneratorVerifier.cs +++ b/src/System.ServiceModel.BuildTools/tests/CSharpGeneratorVerifier.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -15,11 +16,7 @@ public static class CSharpGeneratorVerifier where TSourceGenerator : ISourceGenerator, new() #endif { -#if ROSLYN4_0_OR_GREATER - public class Test : CSharpIncrementalGeneratorTest -#else - public class Test : CSharpSourceGeneratorTest -#endif + public class Test : CSharpSourceGeneratorTest { public Test() { @@ -48,6 +45,18 @@ private static ImmutableDictionary GetNullableWarnings protected override ParseOptions CreateParseOptions() => ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion); +#if ROSLYN4_0_OR_GREATER + protected override IEnumerable GetSourceGenerators() + { + yield return new TSourceGenerator().AsSourceGenerator(); + } +#else + protected override IEnumerable GetSourceGenerators() + { + yield return new TSourceGenerator(); + } +#endif + protected override bool IsCompilerDiagnosticIncluded(Diagnostic diagnostic, CompilerDiagnostics compilerDiagnostics) => false; } } diff --git a/src/System.ServiceModel.BuildTools/tests/CSharpIncrementalGeneratorTest`2.cs b/src/System.ServiceModel.BuildTools/tests/CSharpIncrementalGeneratorTest`2.cs deleted file mode 100644 index bcf9851b100..00000000000 --- a/src/System.ServiceModel.BuildTools/tests/CSharpIncrementalGeneratorTest`2.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; - -using Microsoft.CodeAnalysis.Testing; - -namespace Microsoft.CodeAnalysis.CSharp.Testing -{ - public class CSharpIncrementalGeneratorTest : IncrementalGeneratorTest - where TSourceGenerator : IIncrementalGenerator, new() - where TVerifier : IVerifier, new() - { - private static readonly LanguageVersion DefaultLanguageVersion = - Enum.TryParse("Default", out LanguageVersion version) ? version : LanguageVersion.CSharp6; - - protected override IEnumerable GetSourceGenerators() - => new IIncrementalGenerator[] { new TSourceGenerator() }; - - protected override string DefaultFileExt => "cs"; - - public override string Language => LanguageNames.CSharp; - - protected override GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators) - { - return CSharpGeneratorDriver.Create( - sourceGenerators.Select(s => s.AsSourceGenerator()), - project.AnalyzerOptions.AdditionalFiles, - (CSharpParseOptions)project.ParseOptions!, - project.AnalyzerOptions.AnalyzerConfigOptionsProvider); - } - - protected override CompilationOptions CreateCompilationOptions() - => new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true); - - protected override ParseOptions CreateParseOptions() - => new CSharpParseOptions(DefaultLanguageVersion, DocumentationMode.Diagnose); - } -} diff --git a/src/System.ServiceModel.BuildTools/tests/IncrementalGeneratorTest`1.cs b/src/System.ServiceModel.BuildTools/tests/IncrementalGeneratorTest`1.cs deleted file mode 100644 index e3d964153b7..00000000000 --- a/src/System.ServiceModel.BuildTools/tests/IncrementalGeneratorTest`1.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Model; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.CSharp.Testing -{ - public abstract class IncrementalGeneratorTest : AnalyzerTest - where TVerifier : IVerifier, new() - { - protected override IEnumerable GetDiagnosticAnalyzers() - => Enumerable.Empty(); - - /// - /// Returns the source generators being tested - to be implemented in non-abstract class. - /// - /// The to be used. - protected abstract IEnumerable GetSourceGenerators(); - - protected abstract GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators); - - protected override async Task RunImplAsync(CancellationToken cancellationToken) - { - var analyzers = GetDiagnosticAnalyzers().ToArray(); - var defaultDiagnostic = GetDefaultDiagnostic(analyzers); - var supportedDiagnostics = analyzers.SelectMany(analyzer => analyzer.SupportedDiagnostics).ToImmutableArray(); - var fixableDiagnostics = ImmutableArray.Empty; - var testState = TestState.WithInheritedValuesApplied(null, fixableDiagnostics).WithProcessedMarkup(MarkupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, DefaultFilePath); - - var diagnostics = await VerifySourceGeneratorAsync(testState, Verify, cancellationToken).ConfigureAwait(false); - await VerifyDiagnosticsAsync(new EvaluatedProjectState(testState, ReferenceAssemblies).WithAdditionalDiagnostics(diagnostics), testState.AdditionalProjects.Values.Select(additionalProject => new EvaluatedProjectState(additionalProject, ReferenceAssemblies)).ToImmutableArray(), testState.ExpectedDiagnostics.ToArray(), Verify.PushContext("Diagnostics of test state"), cancellationToken).ConfigureAwait(false); - } - - protected override async Task GetProjectCompilationAsync(Project project, IVerifier verifier, CancellationToken cancellationToken) - { - var (finalProject, diagnostics) = await ApplySourceGeneratorAsync(GetSourceGenerators().ToImmutableArray(), project, verifier, cancellationToken).ConfigureAwait(false); - return (await finalProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!; - } - - /// - /// Called to test a C# source generator when applied on the input source as a string. - /// - /// The effective input test state. - /// The verifier to use for test assertions. - /// The that the task will observe. - /// A representing the asynchronous operation. - protected async Task> VerifySourceGeneratorAsync(SolutionState testState, IVerifier verifier, CancellationToken cancellationToken) - { - return await VerifySourceGeneratorAsync(Language, GetSourceGenerators().ToImmutableArray(), testState, ApplySourceGeneratorAsync, verifier.PushContext("Source generator application"), cancellationToken); - } - - private async Task> VerifySourceGeneratorAsync( - string language, - ImmutableArray sourceGenerators, - SolutionState testState, - Func, Project, IVerifier, CancellationToken, Task<(Project project, ImmutableArray diagnostics)>> getFixedProject, - IVerifier verifier, - CancellationToken cancellationToken) - { - var project = await CreateProjectAsync(new EvaluatedProjectState(testState, ReferenceAssemblies), testState.AdditionalProjects.Values.Select(additionalProject => new EvaluatedProjectState(additionalProject, ReferenceAssemblies)).ToImmutableArray(), cancellationToken); - _ = await GetCompilerDiagnosticsAsync(project, verifier, cancellationToken).ConfigureAwait(false); - - ImmutableArray diagnostics; - (project, diagnostics) = await getFixedProject(sourceGenerators, project, verifier, cancellationToken).ConfigureAwait(false); - - // After applying the source generator, compare the resulting string to the inputted one - if (!TestBehaviors.HasFlag(TestBehaviors.SkipGeneratedSourcesCheck)) - { - var updatedDocuments = project.Documents.ToArray(); - var expectedSources = testState.Sources.Concat(testState.GeneratedSources).ToArray(); - - verifier.Equal(expectedSources.Length, updatedDocuments.Length, $"expected '{nameof(testState)}.{nameof(SolutionState.Sources)}' with '{nameof(testState)}.{nameof(SolutionState.GeneratedSources)}' to match '{nameof(updatedDocuments)}', but '{nameof(testState)}.{nameof(SolutionState.Sources)}' with '{nameof(testState)}.{nameof(SolutionState.GeneratedSources)}' contains '{expectedSources.Length}' documents and '{nameof(updatedDocuments)}' contains '{updatedDocuments.Length}' documents"); - - for (var i = 0; i < updatedDocuments.Length; i++) - { - var actual = await GetSourceTextFromDocumentAsync(updatedDocuments[i], cancellationToken).ConfigureAwait(false); - verifier.EqualOrDiff(expectedSources[i].content.ToString(), actual.ToString(), $"content of '{expectedSources[i].filename}' did not match. Diff shown with expected as baseline:"); - verifier.Equal(expectedSources[i].content.Encoding, actual.Encoding, $"encoding of '{expectedSources[i].filename}' was expected to be '{expectedSources[i].content.Encoding?.WebName}' but was '{actual.Encoding?.WebName}'"); - verifier.Equal(expectedSources[i].content.ChecksumAlgorithm, actual.ChecksumAlgorithm, $"checksum algorithm of '{expectedSources[i].filename}' was expected to be '{expectedSources[i].content.ChecksumAlgorithm}' but was '{actual.ChecksumAlgorithm}'"); - verifier.Equal(expectedSources[i].filename, updatedDocuments[i].Name, $"file name was expected to be '{expectedSources[i].filename}' but was '{updatedDocuments[i].Name}'"); - } - } - - return diagnostics; - } - - private async Task<(Project project, ImmutableArray diagnostics)> ApplySourceGeneratorAsync(ImmutableArray sourceGenerators, Project project, IVerifier verifier, CancellationToken cancellationToken) - { - var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); - verifier.True(compilation is { }); - - var driver = CreateGeneratorDriver(project, sourceGenerators).RunGenerators(compilation, cancellationToken); - var result = driver.GetRunResult(); - - var updatedProject = project; - foreach (var tree in result.GeneratedTrees) - { - updatedProject = updatedProject.AddDocument(tree.FilePath, await tree.GetTextAsync(cancellationToken).ConfigureAwait(false), filePath: tree.FilePath).Project; - } - - return (updatedProject, result.Diagnostics); - } - - /// - /// Get the existing compiler diagnostics on the input document. - /// - /// The to run the compiler diagnostic analyzers on. - /// The verifier to use for test assertions. - /// The that the task will observe. - /// The compiler diagnostics that were found in the code. - private static async Task> GetCompilerDiagnosticsAsync(Project project, IVerifier verifier, CancellationToken cancellationToken) - { - var allDiagnostics = ImmutableArray.Create(); - - foreach (var document in project.Documents) - { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - verifier.True(semanticModel is { }); - - allDiagnostics = allDiagnostics.AddRange(semanticModel.GetDiagnostics(cancellationToken: cancellationToken)); - } - - return allDiagnostics; - } - - /// - /// Given a document, turn it into a string based on the syntax root. - /// - /// The to be converted to a string. - /// The that the task will observe. - /// A containing the syntax of the after formatting. - private static async Task GetSourceTextFromDocumentAsync(Document document, CancellationToken cancellationToken) - { - var simplifiedDoc = await Simplifier.ReduceAsync(document, Simplifier.Annotation, cancellationToken: cancellationToken).ConfigureAwait(false); - var formatted = await Formatter.FormatAsync(simplifiedDoc, Formatter.Annotation, cancellationToken: cancellationToken).ConfigureAwait(false); - return await formatted.GetTextAsync(cancellationToken).ConfigureAwait(false); - } - } -}