Skip to content

Instantly share code, notes, and snippets.

@chsienki
Last active November 19, 2022 10:03
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chsienki/2955ed9336d7eb22bcb246840bfeb05c to your computer and use it in GitHub Desktop.
Save chsienki/2955ed9336d7eb22bcb246840bfeb05c to your computer and use it in GitHub Desktop.
Framework for unit testing generators
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Xunit;
namespace GeneratorTests.Tests
{
public class GeneratorTests
{
[Fact]
public void SimpleGeneratorTest()
{
string userSource = @"
namespace MyCode
{
public class Program
{
public static void Main(string[] args)
{
}
}
}
";
Compilation comp = CreateCompilation(userSource);
var newComp = RunGenerators(comp, out var generatorDiags, new SimpleGenerator());
Assert.Empty(generatorDiags);
Assert.Empty(newComp.GetDiagnostics());
}
private static Compilation CreateCompilation(string source)
=> CSharpCompilation.Create("compilation",
new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)) },
new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
new CSharpCompilationOptions(OutputKind.ConsoleApplication));
private static GeneratorDriver CreateDriver(Compilation c, params ISourceGenerator[] generators)
=> new CSharpGeneratorDriver(c.SyntaxTrees.First().Options,
ImmutableArray.Create(generators),
null,
ImmutableArray<AdditionalText>.Empty);
private static Compilation RunGenerators(Compilation c, out ImmutableArray<Diagnostic> diagnostics, params ISourceGenerator[] generators)
{
CreateDriver(c, generators).RunGeneratorsAndUpdateCompilation(c, out var d, out diagnostics);
return d;
}
}
}
@davidwengier
Copy link

davidwengier commented Aug 15, 2020

Note that due to an API change the CreateDriver method needs to change to:

        private static GeneratorDriver CreateDriver(Compilation c, params ISourceGenerator[] generators)
            => new CSharpGeneratorDriver(c.SyntaxTrees.First().Options,
                ImmutableArray.Create(generators),
                null,
                ImmutableArray<AdditionalText>.Empty);

@chsienki
Copy link
Author

Updated, thanks @davidwengier

@Youssef1313
Copy link

Youssef1313 commented Sep 25, 2020

Hi @chsienki

GeneratorDriver.RunFullGeneration is now obsolete. It needs to be updated with RunGeneratorsAndUpdateCompilation.

CSharpGeneratorDriver constructor is also obsolete. It needs to be updated with CSharpGeneratorDriver.Create.

Also, ParseOptions will need a cast to CSharpParseOptions.

@cabralRodrigo
Copy link

Is anyone is interested here is a version that works for me (with all the notes above):

private static Compilation CreateCompilation(string source) => CSharpCompilation.Create(
    assemblyName: "compilation",
    syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)) },
    references: new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
    options: new CSharpCompilationOptions(OutputKind.ConsoleApplication)
);

private static GeneratorDriver CreateDriver(Compilation compilation, params ISourceGenerator[] generators) => CSharpGeneratorDriver.Create(
    generators: ImmutableArray.Create(generators),
    additionalTexts: ImmutableArray<AdditionalText>.Empty,
    parseOptions: (CSharpParseOptions)compilation.SyntaxTrees.First().Options,
    optionsProvider: null
);

private static Compilation RunGenerators(Compilation compilation, out ImmutableArray<Diagnostic> diagnostics, params ISourceGenerator[] generators)
{
    CreateDriver(compilation, generators).RunGeneratorsAndUpdateCompilation(compilation, out var updatedCompilation, out diagnostics);
    return updatedCompilation;
}

@j0shuams
Copy link

j0shuams commented Aug 6, 2021

Would it be possible to pass AnalyzerConfigOptions using this model? I have a generator that depends on a project property being set, and to test it I am having to comment out the property check in the generator.

@Youssef1313
Copy link

Would it be possible to pass AnalyzerConfigOptions using this model? I have a generator that depends on a project property being set, and to test it I am having to comment out the property check in the generator.

@sharwell Does the testing library supports passing .editorconfig for generators? (it does for analyzers & codefixes, but not sure about generators)

@sharwell
Copy link

sharwell commented Aug 6, 2021

@sharwell Does the testing library supports passing .editorconfig for generators? (it does for analyzers & codefixes, but not sure about generators)

Yes, you can add them to TestState.AnalyzerConfigFiles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment