Skip to content

Extends Verify to allow verification of C# Source Generators.

License

Notifications You must be signed in to change notification settings

VerifyTests/Verify.SourceGenerators

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 Cannot retrieve latest commit at this time.
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Verify.SourceGenerators

Discussions Build status NuGet Status

Extends Verify to allow verification of C# Source Generators.

See Milestones for release notes.

NuGet package

https://nuget.org/packages/Verify.SourceGenerators/

Install one of the Verify testing framework adapters NuGet packages.

Initialize

[ModuleInitializer]
public static void Init() =>
    VerifySourceGenerators.Initialize();

snippet source | anchor

Generator

Given a Source Generator:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

[Generator]
public class HelloWorldGenerator :
    ISourceGenerator
{
    public void Execute(GeneratorExecutionContext context)
    {
        var source1 = """
                      using System;
                      public static class Helper
                      {
                          public static void Method()
                          {
                          }
                      }
                      """;
        context.AddSource("helper", SourceText.From(source1, Encoding.UTF8));

        var source2 = """
                      using System;
                      public static class HelloWorld
                      {
                          public static void SayHello()
                          {
                              Console.WriteLine("Hello from generated code!");
                          }
                      }
                      """;
        var sourceText = SourceText.From(source2, Encoding.UTF8);
        context.AddSource("helloWorld", sourceText);

        var descriptor = new DiagnosticDescriptor(
            id: "theId",
            title: "the title",
            messageFormat: "the message from {0}",
            category: "the category",
            DiagnosticSeverity.Info,
            isEnabledByDefault: true);

        var location = Location.Create(
            Path.Combine("dir", "theFile.cs"),
            new(1, 2),
            new(
                new(1, 2),
                new(3, 4)));
        var diagnostic = Diagnostic.Create(descriptor, location, "hello world generator");
        context.ReportDiagnostic(diagnostic);
    }

    public void Initialize(GeneratorInitializationContext context)
    {
    }
}

snippet source | anchor

Test

Can be tested as follows:

This snippets assumes use of the XUnit Verify adapter, change the using VerifyXUnit if using other testing frameworks.

public class SampleTest
{
    [Fact]
    public Task Driver()
    {
        var driver = BuildDriver();

        return Verify(driver);
    }

    [Fact]
    public Task RunResults()
    {
        var driver = BuildDriver();

        var results = driver.GetRunResult();
        return Verify(results);
    }

    [Fact]
    public Task RunResult()
    {
        var driver = BuildDriver();

        var result = driver.GetRunResult().Results.Single();
        return Verify(result);
    }

    static GeneratorDriver BuildDriver()
    {
        var compilation = CSharpCompilation.Create("name");
        var generator = new HelloWorldGenerator();

        var driver = CSharpGeneratorDriver.Create(generator);
        return driver.RunGenerators(compilation);
    }
}

snippet source | anchor

Results

And will result in the following verified files:

Info file

An info file containing all metadata about the current state. eg any Diagnostics.

{
  Diagnostics: [
    {
      Location: dir\theFile.cs: (1,2)-(3,4),
      Message: the message from hello world generator,
      Severity: Info,
      WarningLevel: 1,
      Descriptor: {
        Id: theId,
        Title: the title,
        MessageFormat: the message from {0},
        Category: the category,
        DefaultSeverity: Info,
        IsEnabledByDefault: true
      }
    }
  ]
}

snippet source | anchor

Source Files

Multiple source files. One for each GeneratorDriverRunResult.Results.GeneratedSources.

//HintName: helloWorld.cs
using System;
public static class HelloWorld
{
    public static void SayHello()
    {
        Console.WriteLine("Hello from generated code!");
    }
}

snippet source | anchor

Manipulating Source

To manipulating the source of the generated cs files, use Scrubbers.

For example to remove all lines start with using:

[Fact]
public Task ScrubLines()
{
    var driver = GeneratorDriver();

    return Verify(driver)
        .ScrubLines(_ => _.StartsWith("using "));
}

snippet source | anchor

Ignoring Files

To ignore specific source text use IgnoreGeneratedResult. This uses an expression of type Func<GeneratedSourceResult, bool> to determine which outputs are ignored.

For example to ignore files with the name helper or that contain the text static void SayHello():

[Fact]
public Task IgnoreFile()
{
    var driver = GeneratorDriver();

    return Verify(driver)
        .IgnoreGeneratedResult(
            _ => _.HintName.Contains("helper") ||
                 _.SourceText
                     .ToString()
                     .Contains("static void SayHello()"));
}

snippet source | anchor

Notes:

Icon

Sauce designed by April Hsuan from The Noun Project.