Meziantou.Framework.SnapshotTesting.Roslyn 1.0.4

Prefix Reserved
dotnet add package Meziantou.Framework.SnapshotTesting.Roslyn --version 1.0.4
                    
NuGet\Install-Package Meziantou.Framework.SnapshotTesting.Roslyn -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Meziantou.Framework.SnapshotTesting.Roslyn" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Meziantou.Framework.SnapshotTesting.Roslyn" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Meziantou.Framework.SnapshotTesting.Roslyn" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Meziantou.Framework.SnapshotTesting.Roslyn --version 1.0.4
                    
#r "nuget: Meziantou.Framework.SnapshotTesting.Roslyn, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Meziantou.Framework.SnapshotTesting.Roslyn@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Meziantou.Framework.SnapshotTesting.Roslyn&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=Meziantou.Framework.SnapshotTesting.Roslyn&version=1.0.4
                    
Install as a Cake Tool

Meziantou.Framework.SnapshotTesting.Roslyn

Meziantou.Framework.SnapshotTesting.Roslyn extends Meziantou.Framework.SnapshotTesting with support for Roslyn objects, so testing a source generator, a syntax rewriter or an analyzer is a single Snapshot.Validate call.

Setup

Call AddRoslyn() on your SnapshotSettings to register the serializers and converters:

using Meziantou.Framework.SnapshotTesting;
using Meziantou.Framework.SnapshotTesting.Roslyn;

internal static class SnapshotConfiguration
{
    [ModuleInitializer]
    internal static void Initialize()
    {
        SnapshotSettings.Default.AddRoslyn();
    }
}

Supported types

Type Snapshot
GeneratorDriverRunResult One source file per generated source, plus a text file with the diagnostics
SyntaxTree, SyntaxNode, SyntaxToken, SyntaxNodeOrToken, SyntaxTrivia, SyntaxTokenList, SyntaxTriviaList A single source file with its full text
SourceText A single file with its text
Diagnostic, and any collection of them A text file with one diagnostic per line

Source generators

[Fact]
public void GenerateCode()
{
    var compilation = CSharpCompilation.Create("compilation", [CSharpSyntaxTree.ParseText(source)], references);
    GeneratorDriver driver = CSharpGeneratorDriver.Create(new MyGenerator());
    driver = driver.RunGenerators(compilation);

    Snapshot.Validate(driver.GetRunResult());
}
  • One .cs file per generated source, ordered by hint name. The order in which the driver runs the generators is not a contract, so it is not used to name the files.
  • Each file starts with a // HintName: <name> comment, so renaming a generated file shows up as a diff.
  • A final .txt file listing the diagnostics reported by the generators and, if a generator threw, the exception it threw. The file is omitted when there is nothing to report.

Because a run usually produces several files, the snapshots are numbered: MyTests.GenerateCode_0.verified.cs, MyTests.GenerateCode_1.verified.cs, MyTests.GenerateCode_2.verified.txt, … Adding a generated source therefore shifts the files that come after it in hint-name order.

A run that generated no source and reported no diagnostic has nothing to compare, and fails with a SnapshotException.

Syntax trees, nodes, tokens and trivia

[Fact]
public void RewriteSyntaxTree()
{
    var tree = CSharpSyntaxTree.ParseText(source);

    Snapshot.Validate(new MyRewriter().Visit(tree.GetRoot()));
}

The value is stored as a single .cs file (.vb for Visual Basic) containing its full text, trivia included. The text is not reformatted, so a change in the generated whitespace shows up as a diff.

A SourceText, and an empty token or trivia list, have no language attached: they use the extension of the requested snapshot type, which defaults to .txt.

Snapshot.Validate(sourceText, SnapshotType.Create("cs"));

Diagnostics

[Fact]
public async Task ReportDiagnostics()
{
    var diagnostics = await compilation.WithAnalyzers([new MyAnalyzer()]).GetAnalyzerDiagnosticsAsync();

    Snapshot.Validate(diagnostics);
}

Each diagnostic is written on its own line, the way the compiler reports it:

Sample.cs(4,10): warning MY0001: Do not use this method
warning MY0002: This diagnostic has no location
  • The message is formatted with the invariant culture, so the snapshot does not depend on the machine's UI culture. Diagnostic.ToString() uses the current UI culture, which is why it is not used here.
  • Positions are one-based, like the compiler reports them.
  • The order is the one the collection was in. An assertion on a list of diagnostics is usually about the order they were reported in, so it is not sorted; sort the list yourself when its source does not guarantee an order.
  • An empty collection produces an empty file: that is the point when the test asserts no diagnostic is reported.
  • The path comes from the syntax tree. A tree parsed from a string has no path; a tree read from disk carries the path it was read with, which is machine-specific unless it is relative. Use a scrubber if that path ends up in the snapshot.

Nested values

Roslyn values nested inside another snapshot are written by the human-readable serializer, which would otherwise dump their object graph. AddRoslyn() registers converters for them:

Type Written as
Diagnostic Sample.cs(4,10): warning MY0001: message
Location Sample.cs(3,9)-(3,20), or its LocationKind when it is not in source
LinePosition 3,9
LinePositionSpan (3,9)-(3,20)
TextSpan [42..53)

LinePosition and LinePositionSpan keep the zero-based values Roslyn exposes. Only a diagnostic is reported one-based, because that is how the compiler reports it.

Line endings

Line endings are normalized to \n in every file, so snapshots do not depend on the platform the tests run on, nor on the line endings used by the source they were produced from.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed.  net11.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.4 0 9/3/2026
1.0.3 33 9/3/2026
1.0.2 83 8/30/2026
1.0.1 89 8/29/2026
1.0.0 96 8/24/2026