From 32d3742d34587775ace6448e02b072c374760186 Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Thu, 20 Jan 2022 13:52:18 -0500 Subject: [PATCH] Add support for IIncrementalGenerator --- .../IncrementalGeneratorVerifier.cs | 15 ++ .../IncrementalGeneratorVerifier`1.cs | 13 ++ ...arp.SourceGenerators.Testing.MSTest.csproj | 3 +- .../PublicAPI.Unshipped.txt | 4 + .../IncrementalGeneratorVerifier.cs | 15 ++ .../IncrementalGeneratorVerifier`1.cs | 13 ++ ...harp.SourceGenerators.Testing.NUnit.csproj | 3 +- .../PublicAPI.Unshipped.txt | 4 + .../IncrementalGeneratorVerifier.cs | 15 ++ .../IncrementalGeneratorVerifier`1.cs | 13 ++ ...harp.SourceGenerators.Testing.XUnit.csproj | 3 +- .../PublicAPI.Unshipped.txt | 4 + .../CSharpIncrementalGeneratorTest`2.cs | 43 +++++ .../CSharpIncrementalGeneratorVerifier`2.cs | 14 ++ ...sis.CSharp.SourceGenerators.Testing.csproj | 5 +- .../PublicAPI.Unshipped.txt | 10 ++ .../EmptyIncrementalGeneratorProvider.cs | 16 ++ .../IncrementalGeneratorTest`1.cs | 153 ++++++++++++++++++ .../IncrementalGeneratorVerifier`3.cs | 19 +++ ...deAnalysis.SourceGenerators.Testing.csproj | 3 +- .../PublicAPI.Unshipped.txt | 19 ++- .../SourceGeneratorTest`1.cs | 137 +--------------- 22 files changed, 383 insertions(+), 141 deletions(-) create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier`1.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier`1.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier`1.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorTest`2.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorVerifier`2.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/EmptyIncrementalGeneratorProvider.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorTest`1.cs create mode 100644 src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorVerifier`3.cs diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier.cs new file mode 100644 index 000000000..156aa57b4 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier.cs @@ -0,0 +1,15 @@ +// 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. + +namespace Microsoft.CodeAnalysis.CSharp.Testing.MSTest +{ + public static class IncrementalGeneratorVerifier + { + public static IncrementalGeneratorVerifier Create() + where TIncrementalGenerator : IIncrementalGenerator, new() + { + return new IncrementalGeneratorVerifier(); + } + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier`1.cs new file mode 100644 index 000000000..3260d399a --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/IncrementalGeneratorVerifier`1.cs @@ -0,0 +1,13 @@ +// 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. + +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Microsoft.CodeAnalysis.CSharp.Testing.MSTest +{ + public class IncrementalGeneratorVerifier : CSharpIncrementalGeneratorVerifier + where TIncrementalGenerator : IIncrementalGenerator, new() + { + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest.csproj b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest.csproj index 0593fa981..b36d06148 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest.csproj +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest.csproj @@ -14,7 +14,8 @@ - + + diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/PublicAPI.Unshipped.txt index 6a1123a97..61670ea93 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ +Microsoft.CodeAnalysis.CSharp.Testing.MSTest.IncrementalGeneratorVerifier +Microsoft.CodeAnalysis.CSharp.Testing.MSTest.IncrementalGeneratorVerifier +Microsoft.CodeAnalysis.CSharp.Testing.MSTest.IncrementalGeneratorVerifier.IncrementalGeneratorVerifier() -> void Microsoft.CodeAnalysis.CSharp.Testing.MSTest.SourceGeneratorVerifier Microsoft.CodeAnalysis.CSharp.Testing.MSTest.SourceGeneratorVerifier Microsoft.CodeAnalysis.CSharp.Testing.MSTest.SourceGeneratorVerifier.SourceGeneratorVerifier() -> void +static Microsoft.CodeAnalysis.CSharp.Testing.MSTest.IncrementalGeneratorVerifier.Create() -> Microsoft.CodeAnalysis.CSharp.Testing.MSTest.IncrementalGeneratorVerifier static Microsoft.CodeAnalysis.CSharp.Testing.MSTest.SourceGeneratorVerifier.Create() -> Microsoft.CodeAnalysis.CSharp.Testing.MSTest.SourceGeneratorVerifier diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier.cs new file mode 100644 index 000000000..6e6b2e001 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier.cs @@ -0,0 +1,15 @@ +// 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. + +namespace Microsoft.CodeAnalysis.CSharp.Testing.NUnit +{ + public static class IncrementalGeneratorVerifier + { + public static IncrementalGeneratorVerifier Create() + where TIncrementalGenerator : IIncrementalGenerator, new() + { + return new IncrementalGeneratorVerifier(); + } + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier`1.cs new file mode 100644 index 000000000..fb7e16410 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/IncrementalGeneratorVerifier`1.cs @@ -0,0 +1,13 @@ +// 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. + +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Microsoft.CodeAnalysis.CSharp.Testing.NUnit +{ + public class IncrementalGeneratorVerifier : CSharpIncrementalGeneratorVerifier + where TIncrementalGenerator : IIncrementalGenerator, new() + { + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit.csproj b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit.csproj index 3fbaf55db..d6245241d 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit.csproj +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit.csproj @@ -14,7 +14,8 @@ - + + diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/PublicAPI.Unshipped.txt index e6f762ae9..8ec0222fe 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ +Microsoft.CodeAnalysis.CSharp.Testing.NUnit.IncrementalGeneratorVerifier +Microsoft.CodeAnalysis.CSharp.Testing.NUnit.IncrementalGeneratorVerifier +Microsoft.CodeAnalysis.CSharp.Testing.NUnit.IncrementalGeneratorVerifier.IncrementalGeneratorVerifier() -> void Microsoft.CodeAnalysis.CSharp.Testing.NUnit.SourceGeneratorVerifier Microsoft.CodeAnalysis.CSharp.Testing.NUnit.SourceGeneratorVerifier Microsoft.CodeAnalysis.CSharp.Testing.NUnit.SourceGeneratorVerifier.SourceGeneratorVerifier() -> void +static Microsoft.CodeAnalysis.CSharp.Testing.NUnit.IncrementalGeneratorVerifier.Create() -> Microsoft.CodeAnalysis.CSharp.Testing.NUnit.IncrementalGeneratorVerifier static Microsoft.CodeAnalysis.CSharp.Testing.NUnit.SourceGeneratorVerifier.Create() -> Microsoft.CodeAnalysis.CSharp.Testing.NUnit.SourceGeneratorVerifier diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier.cs new file mode 100644 index 000000000..06e12e832 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier.cs @@ -0,0 +1,15 @@ +// 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. + +namespace Microsoft.CodeAnalysis.CSharp.Testing.XUnit +{ + public static class IncrementalGeneratorVerifier + { + public static IncrementalGeneratorVerifier Create() + where TIncrementalGenerator : IIncrementalGenerator, new() + { + return new IncrementalGeneratorVerifier(); + } + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier`1.cs new file mode 100644 index 000000000..382e816b4 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/IncrementalGeneratorVerifier`1.cs @@ -0,0 +1,13 @@ +// 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. + +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Microsoft.CodeAnalysis.CSharp.Testing.XUnit +{ + public class IncrementalGeneratorVerifier : CSharpIncrementalGeneratorVerifier + where TIncrementalGenerator : IIncrementalGenerator, new() + { + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit.csproj b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit.csproj index 435280807..4e1cf151c 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit.csproj +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit.csproj @@ -14,7 +14,8 @@ - + + diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/PublicAPI.Unshipped.txt index d625f5b80..9ffe5a02c 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ +Microsoft.CodeAnalysis.CSharp.Testing.XUnit.IncrementalGeneratorVerifier +Microsoft.CodeAnalysis.CSharp.Testing.XUnit.IncrementalGeneratorVerifier +Microsoft.CodeAnalysis.CSharp.Testing.XUnit.IncrementalGeneratorVerifier.IncrementalGeneratorVerifier() -> void Microsoft.CodeAnalysis.CSharp.Testing.XUnit.SourceGeneratorVerifier Microsoft.CodeAnalysis.CSharp.Testing.XUnit.SourceGeneratorVerifier Microsoft.CodeAnalysis.CSharp.Testing.XUnit.SourceGeneratorVerifier.SourceGeneratorVerifier() -> void +static Microsoft.CodeAnalysis.CSharp.Testing.XUnit.IncrementalGeneratorVerifier.Create() -> Microsoft.CodeAnalysis.CSharp.Testing.XUnit.IncrementalGeneratorVerifier static Microsoft.CodeAnalysis.CSharp.Testing.XUnit.SourceGeneratorVerifier.Create() -> Microsoft.CodeAnalysis.CSharp.Testing.XUnit.SourceGeneratorVerifier diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorTest`2.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorTest`2.cs new file mode 100644 index 000000000..0aaf43d44 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorTest`2.cs @@ -0,0 +1,43 @@ +// 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. + +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 TIncrementalGenerator : IIncrementalGenerator, new() + where TVerifier : IVerifier, new() + { + private static readonly LanguageVersion DefaultLanguageVersion = + Enum.TryParse("Default", out LanguageVersion version) ? version : LanguageVersion.CSharp6; + + protected override (IEnumerable sourceGenerators, IEnumerable incrementalGenerators) GetGenerators() + => (Enumerable.Empty(), new IIncrementalGenerator[] { new TIncrementalGenerator() }); + + protected override string DefaultFileExt => "cs"; + + public override string Language => LanguageNames.CSharp; + + protected override GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators, ImmutableArray incrementalGenerators) + { + return CSharpGeneratorDriver.Create( + sourceGenerators.Concat(incrementalGenerators.Select(g => g.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/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorVerifier`2.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorVerifier`2.cs new file mode 100644 index 000000000..b58bd47c1 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/CSharpIncrementalGeneratorVerifier`2.cs @@ -0,0 +1,14 @@ +// 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. + +using Microsoft.CodeAnalysis.Testing; + +namespace Microsoft.CodeAnalysis.CSharp.Testing +{ + public class CSharpIncrementalGeneratorVerifier : IncrementalGeneratorVerifier, TVerifier> + where TSourceGenerator : IIncrementalGenerator, new() + where TVerifier : IVerifier, new() + { + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.csproj b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.csproj index a1472a2b2..3e8a8651b 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.csproj +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.csproj @@ -15,9 +15,10 @@ - + + - + diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/PublicAPI.Unshipped.txt index c2fa56484..39762c1f5 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing/PublicAPI.Unshipped.txt @@ -1,7 +1,17 @@ +Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest +Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest.CSharpIncrementalGeneratorTest() -> void +Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorVerifier +Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorVerifier.CSharpIncrementalGeneratorVerifier() -> void Microsoft.CodeAnalysis.CSharp.Testing.CSharpSourceGeneratorTest Microsoft.CodeAnalysis.CSharp.Testing.CSharpSourceGeneratorTest.CSharpSourceGeneratorTest() -> void Microsoft.CodeAnalysis.CSharp.Testing.CSharpSourceGeneratorVerifier Microsoft.CodeAnalysis.CSharp.Testing.CSharpSourceGeneratorVerifier.CSharpSourceGeneratorVerifier() -> void +override Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest.CreateCompilationOptions() -> Microsoft.CodeAnalysis.CompilationOptions +override Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest.CreateGeneratorDriver(Microsoft.CodeAnalysis.Project project, System.Collections.Immutable.ImmutableArray sourceGenerators, System.Collections.Immutable.ImmutableArray incrementalGenerators) -> Microsoft.CodeAnalysis.GeneratorDriver +override Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest.CreateParseOptions() -> Microsoft.CodeAnalysis.ParseOptions +override Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest.DefaultFileExt.get -> string +override Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest.GetGenerators() -> (System.Collections.Generic.IEnumerable sourceGenerators, System.Collections.Generic.IEnumerable incrementalGenerators) +override Microsoft.CodeAnalysis.CSharp.Testing.CSharpIncrementalGeneratorTest.Language.get -> string override Microsoft.CodeAnalysis.CSharp.Testing.CSharpSourceGeneratorTest.CreateCompilationOptions() -> Microsoft.CodeAnalysis.CompilationOptions override Microsoft.CodeAnalysis.CSharp.Testing.CSharpSourceGeneratorTest.CreateGeneratorDriver(Microsoft.CodeAnalysis.Project project, System.Collections.Immutable.ImmutableArray sourceGenerators) -> Microsoft.CodeAnalysis.GeneratorDriver override Microsoft.CodeAnalysis.CSharp.Testing.CSharpSourceGeneratorTest.CreateParseOptions() -> Microsoft.CodeAnalysis.ParseOptions diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/EmptyIncrementalGeneratorProvider.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/EmptyIncrementalGeneratorProvider.cs new file mode 100644 index 000000000..77668d50d --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/EmptyIncrementalGeneratorProvider.cs @@ -0,0 +1,16 @@ +// 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. + +namespace Microsoft.CodeAnalysis.Testing +{ + /// + /// Defines a which does not add any sources. + /// + public sealed class EmptyIncrementalGeneratorProvider : IIncrementalGenerator + { + public void Initialize(IncrementalGeneratorInitializationContext context) + { + } + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorTest`1.cs new file mode 100644 index 000000000..e88a4fb34 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorTest`1.cs @@ -0,0 +1,153 @@ +// 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. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Testing.Model; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Testing +{ + public abstract class IncrementalGeneratorTest : AnalyzerTest + where TVerifier : IVerifier, new() + { + protected override IEnumerable GetDiagnosticAnalyzers() + => Enumerable.Empty(); + + /// + /// Returns the incremental source generators being tested - to be implemented in non-abstract class. + /// + /// The to be used. + protected abstract (IEnumerable sourceGenerators, IEnumerable incrementalGenerators) GetGenerators(); + + protected abstract GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators, ImmutableArray incrementalGenerators); + + 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 VerifyGeneratorAsync(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 (sourceGenerators, incrementalGenerators) = GetGenerators(); + var (finalProject, diagnostics) = await ApplyGeneratorsAsync(sourceGenerators.ToImmutableArray(), incrementalGenerators.ToImmutableArray(), project, verifier, cancellationToken).ConfigureAwait(false); + return (await finalProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!; + } + + /// + /// Called to test a C# incremental 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> VerifyGeneratorAsync(SolutionState testState, IVerifier verifier, CancellationToken cancellationToken) + { + var (sourceGenerators, incrementalGenerators) = GetGenerators(); + return await VerifyGeneratorAsync(Language, sourceGenerators.ToImmutableArray(), incrementalGenerators.ToImmutableArray(), testState, ApplyGeneratorsAsync, verifier.PushContext("Source generator application"), cancellationToken); + } + + private async Task> VerifyGeneratorAsync( + string language, + ImmutableArray sourceGenerators, + ImmutableArray incrementalGenerators, + SolutionState testState, + Func, ImmutableArray, 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, incrementalGenerators, 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)> ApplyGeneratorsAsync(ImmutableArray sourceGenerators, ImmutableArray incrementalGenerators, Project project, IVerifier verifier, CancellationToken cancellationToken) + { + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + verifier.True(compilation is { }); + + var driver = CreateGeneratorDriver(project, sourceGenerators, incrementalGenerators).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); + } + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorVerifier`3.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorVerifier`3.cs new file mode 100644 index 000000000..de31e92f9 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/IncrementalGeneratorVerifier`3.cs @@ -0,0 +1,19 @@ +// 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. + +namespace Microsoft.CodeAnalysis.Testing +{ + /// + /// A default verifier for incremental source generators. + /// + /// The to test. + /// The test implementation to use. + /// The type of verifier to use. + public class IncrementalGeneratorVerifier + where TIncrementalGenerator : IIncrementalGenerator, new() + where TTest : IncrementalGeneratorTest, new() + where TVerifier : IVerifier, new() + { + } +} diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing.csproj b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing.csproj index 42ecea0f4..9d48b7403 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing.csproj +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing.csproj @@ -14,7 +14,8 @@ - + + diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt index 09cd1e21f..061c4b083 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt @@ -1,14 +1,25 @@ +Microsoft.CodeAnalysis.Testing.EmptyIncrementalGeneratorProvider +Microsoft.CodeAnalysis.Testing.EmptyIncrementalGeneratorProvider.EmptyIncrementalGeneratorProvider() -> void +Microsoft.CodeAnalysis.Testing.EmptyIncrementalGeneratorProvider.Initialize(Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext context) -> void Microsoft.CodeAnalysis.Testing.EmptySourceGeneratorProvider Microsoft.CodeAnalysis.Testing.EmptySourceGeneratorProvider.EmptySourceGeneratorProvider() -> void Microsoft.CodeAnalysis.Testing.EmptySourceGeneratorProvider.Execute(Microsoft.CodeAnalysis.GeneratorExecutionContext context) -> void Microsoft.CodeAnalysis.Testing.EmptySourceGeneratorProvider.Initialize(Microsoft.CodeAnalysis.GeneratorInitializationContext context) -> void +Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest +Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest.IncrementalGeneratorTest() -> void +Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest.VerifyGeneratorAsync(Microsoft.CodeAnalysis.Testing.SolutionState testState, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> +Microsoft.CodeAnalysis.Testing.IncrementalGeneratorVerifier +Microsoft.CodeAnalysis.Testing.IncrementalGeneratorVerifier.IncrementalGeneratorVerifier() -> void Microsoft.CodeAnalysis.Testing.SourceGeneratorTest Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.SourceGeneratorTest() -> void -Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.VerifySourceGeneratorAsync(Microsoft.CodeAnalysis.Testing.SolutionState testState, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> Microsoft.CodeAnalysis.Testing.SourceGeneratorVerifier Microsoft.CodeAnalysis.Testing.SourceGeneratorVerifier.SourceGeneratorVerifier() -> void +abstract Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest.CreateGeneratorDriver(Microsoft.CodeAnalysis.Project project, System.Collections.Immutable.ImmutableArray sourceGenerators, System.Collections.Immutable.ImmutableArray incrementalGenerators) -> Microsoft.CodeAnalysis.GeneratorDriver +abstract Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest.GetGenerators() -> (System.Collections.Generic.IEnumerable sourceGenerators, System.Collections.Generic.IEnumerable incrementalGenerators) abstract Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.CreateGeneratorDriver(Microsoft.CodeAnalysis.Project project, System.Collections.Immutable.ImmutableArray sourceGenerators) -> Microsoft.CodeAnalysis.GeneratorDriver abstract Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetSourceGenerators() -> System.Collections.Generic.IEnumerable -override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetDiagnosticAnalyzers() -> System.Collections.Generic.IEnumerable -override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetProjectCompilationAsync(Microsoft.CodeAnalysis.Project project, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task -override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest.GetDiagnosticAnalyzers() -> System.Collections.Generic.IEnumerable +override Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest.GetProjectCompilationAsync(Microsoft.CodeAnalysis.Project project, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.IncrementalGeneratorTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +override sealed Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.CreateGeneratorDriver(Microsoft.CodeAnalysis.Project project, System.Collections.Immutable.ImmutableArray sourceGenerators, System.Collections.Immutable.ImmutableArray incrementalGenerators) -> Microsoft.CodeAnalysis.GeneratorDriver +override sealed Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetGenerators() -> (System.Collections.Generic.IEnumerable sourceGenerators, System.Collections.Generic.IEnumerable incrementalGenerators) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs index 394b9bae3..ede0ddcc6 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs @@ -2,152 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Testing.Model; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Testing { - public abstract class SourceGeneratorTest : AnalyzerTest + public abstract class SourceGeneratorTest : IncrementalGeneratorTest 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}'"); - } - } + protected sealed override (IEnumerable sourceGenerators, IEnumerable incrementalGenerators) GetGenerators() + => (GetSourceGenerators(), Enumerable.Empty()); - 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; - } + protected abstract GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators); - /// - /// 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); - } + protected sealed override GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators, ImmutableArray incrementalGenerators) + => CreateGeneratorDriver(project, sourceGenerators); } }