I have this private source generator that we use in our projects. We have these source generator tests separated out into two sections - unit tests and functional tests.
(when used in our projects, this source generator generates DI registrations, DI is not tested in unit tests)
- Functional tests execute the source generator in roslyn during compilation.
- Units tests execute the source generator using Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree using resource files - fullly managed.
Historically, I've run unit tests with NCrunch and functional tests with Resharper. With the latest update, code coverage is disabled in unit tests. This makes sense for when the project actually uses source generation during compilation, but less so with unit tests.
Is there a way to opt-out of this behavior and restore previous behavior?
How we test generators in unit tests - note the output is C# source code.
Code:
public static string GetOutputForGenerator<T>(string sourceResource, T? generator = null) where T : class, ISourceGenerator, new()
{
var source = GetResource(sourceResource);
var syntaxTree = CSharpSyntaxTree.ParseText(source);
var references = new List<MetadataReference>();
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
if (!assembly.IsDynamic && !string.IsNullOrWhiteSpace(assembly.Location))
{
references.Add(MetadataReference.CreateFromFile(assembly.Location));
}
}
var compilation = CSharpCompilation.Create(
"foo",
new[] { syntaxTree },
references,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
generator ??= new T();
var driver = CSharpGeneratorDriver.Create(generator);
driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generateDiagnostics);
if (generateDiagnostics.Any(d => d.Severity == DiagnosticSeverity.Error))
{
throw new Exception("Failed: " + generateDiagnostics.FirstOrDefault()?.GetMessage());
}
var builder = new StringBuilder();
foreach (var compilationSyntaxTree in outputCompilation.SyntaxTrees)
{
builder.AppendLine($"// Location: '{compilationSyntaxTree.FilePath}'");
builder.AppendLine();
builder.AppendLine(compilationSyntaxTree.ToString());
}
string output = builder.ToString();
return output;
}