Skip to content
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Test helpers and extension methods to simplify testing of .NET source generators
[![nuget](https://img.shields.io/nuget/v/SourceGeneratorTestHelpers)](https://www.nuget.org/packages/SourceGeneratorTestHelpers)
[![downloads](https://img.shields.io/nuget/dt/SourceGeneratorTestHelpers)](https://www.nuget.org/packages/SourceGeneratorTestHelpers)

# More languages
[Chinese](./doc/zh-Hans_README.md)

## Testing a source generator

```csharp
Expand Down
137 changes: 137 additions & 0 deletions doc/zh-Hans_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Source Generator Test Helpers(源生成器测试辅助工具)

用于简化 .NET 源生成器测试的测试辅助方法和扩展方法。

[![main](https://img.shields.io/github/actions/workflow/status/jscarle/SourceGeneratorTestHelpers/main.yml?logo=github)](https://github.com/jscarle/SourceGeneratorTestHelpers)
[![nuget](https://img.shields.io/nuget/v/SourceGeneratorTestHelpers)](https://www.nuget.org/packages/SourceGeneratorTestHelpers)
[![downloads](https://img.shields.io/nuget/dt/SourceGeneratorTestHelpers)](https://www.nuget.org/packages/SourceGeneratorTestHelpers)

## 测试一个源生成器

```csharp
var result = SourceGenerator.Run<YourSourceGenerator>("要测试的代码");
```

## 测试一个增量源生成器

```csharp
var result = IncrementalGenerator.Run<YourSourceGenerator>("要测试的代码");
```

## 添加.NET环境和依赖

```csharp
var references = new List<MetadataReference>();

// 添加 .NET 10 所有程序集(ReferenceAssemblies.Net.Net100)
ImmutableArray<MetadataReference> defaultReferences = ReferenceAssemblies.Net.Net100.ResolveAsync(null, default)。Result;
references.AddRange(defaultReferences);

//添加依赖
references.Add(MetadataReference.CreateFromFile(
Path.Combine("D:","C#", "Lib", "Debug", "net10.0", "XXX.dll")));

var result = IncrementalGenerator.Run<YourSourceGenerator>("要测试的代码", null, references);
```

## 获取创建的源生成器/增量源生成器
```csharp
var result = IncrementalGenerator.Run(sourceCode, out YourSourceGenerator generator, null, references);
```
```csharp
var result = SourceGenerator.Run(sourceCode, out YourSourceGenerator generator, null, references);
```
## 获取生成的源代码

### 获取所有生成的源代码

```csharp
var generatedSources = result.GetSources();
```

### 获取特定文件的源代码

```csharp
var generatedSource = result.GetSource("TestId.g.cs");
```

### 对比生成的源代码与期望的源代码

你可以对比生成的源代码与期望的源代码之间的差异。结果包含一个bool值 hasDifferences 以及按行区分的差异列表 differences。

```csharp
var (hasDifferences, differences) = Diff.Compare(generatedSource, expectedSource);
```

## 进行验证

### 使用断言

借助下面其中一个测试框架包,你还可以断言生成的源代码与期望源的代码之间的差异。

[![XUnit](https://img.shields.io/nuget/dt/SourceGeneratorTestHelpers.XUnit?label=XUnit)](https://www.nuget.org/packages/SourceGeneratorTestHelpers.XUnit)
[![NUnit](https://img.shields.io/nuget/dt/SourceGeneratorTestHelpers.NUnit?label=NUnit)](https://www.nuget.org/packages/SourceGeneratorTestHelpers.NUnit)
[![MSTest](https://img.shields.io/nuget/dt/SourceGeneratorTestHelpers.MSTest?label=MSTest)](https://www.nuget.org/packages/SourceGeneratorTestHelpers.MSTest)

```csharp
var result = IncrementalGenerator.Run<YourSourceGenerator>("要测试的代码");

result.ShouldProduce("TestId.g.cs", "预期的代码");
```

_注意:如果你不想断言源生成器运行期间的诊断错误,可以像下面这样直接禁用。_

```csharp
var result = IncrementalGenerator.Run<YourSourceGenerator>("要测试的代码");

result.ShouldProduce("TestId.g.cs", "预期的代码", false);
```

### 使用Verify

内置了对 [Verify](https://github.com/VerifyTests/Verify) 的支持,通过 VerifyAsync 方法实现。

#### XUnit

```cs
public class SourceGeneratorTests
{
[Fact]
public Task ShouldProductTestId()
{
var result = IncrementalGenerator.Run<YourSourceGenerator>("要测试的代码");
return result.VerifyAsync("TestId.g.cs");
}
}
```

#### NUnit

```cs
[TestFixture]
public class SourceGeneratorTests
{
[Test]
public Task ShouldProductTestId()
{
var result = IncrementalGenerator.Run<YourSourceGenerator>("要测试的代码");
return result.VerifyAsync("TestId.g.cs");
}
}
```

#### MSTest

```cs
[TestClass]
public class SourceGeneratorTests :
GeneratorDriverTestBase
{
[TestMethod]
public Task ShouldProductTestId()
{
var result = IncrementalGenerator.Run<YourSourceGenerator>("要测试的代码");
return VerifyAsync("TestId.g.cs");
}
}
```
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using SourceGeneratorTestHelpers.Common;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;

namespace SourceGeneratorTestHelpers.MSTest;

internal abstract class GeneratorDriverTestBase : VerifyBase
public abstract class GeneratorDriverTestBase : VerifyBase
{
/// <summary>Verifies that the generated source from a <see cref="GeneratorDriverRunResult"/> with a specific file path ending matches the expected source.</summary>
/// <param name="result">The <see cref="GeneratorDriverRunResult"/> to get the source from.</param>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks>
<ImplicitUsings>true</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>SourceGeneratorTestHelpers.MSTest</RootNamespace>
<LangVersion>latest</LangVersion>
<Version>10.0.0</Version>
<Version>10.1.0</Version>
<Title>SourceGeneratorTestHelpers.MSTest</Title>
<Authors>Jean-Sebastien Carle</Authors>
<Description>Test helpers and extension methods to simplify testing of .NET source generators.</Description>
<Copyright>Copyright © Jean-Sebastien Carle 2025</Copyright>
<Copyright>Copyright © Jean-Sebastien Carle 2026</Copyright>
<PackageId>SourceGeneratorTestHelpers.MSTest</PackageId>
<PackageProjectUrl>https://github.com/jscarle/SourceGeneratorTestHelpers</PackageProjectUrl>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/jscarle/SourceGeneratorTestHelpers</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>testing source-generators mstest</PackageTags>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.1.0.0</AssemblyVersion>
<FileVersion>10.1.0.0</FileVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AnalysisLevel>latest-All</AnalysisLevel>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<Optimize>true</Optimize>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
<PackageReference Include="SourceGeneratorTestHelpers" Version="10.0.0" />
<PackageReference Include="SourceGeneratorTestHelpers" Version="10.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="4.0.2" />
<PackageReference Include="Verify.MSTest" Version="20.8.2" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<None Include="..\..\LICENSE.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks>
<ImplicitUsings>true</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>SourceGeneratorTestHelpers.NUnit</RootNamespace>
<LangVersion>latest</LangVersion>
<Version>10.0.0</Version>
<Version>10.1.0</Version>
<Title>SourceGeneratorTestHelpers.NUnit</Title>
<Authors>Jean-Sebastien Carle</Authors>
<Description>Test helpers and extension methods to simplify testing of .NET source generators.</Description>
<Copyright>Copyright © Jean-Sebastien Carle 2025</Copyright>
<Copyright>Copyright © Jean-Sebastien Carle 2026</Copyright>
<PackageId>SourceGeneratorTestHelpers.NUnit</PackageId>
<PackageProjectUrl>https://github.com/jscarle/SourceGeneratorTestHelpers</PackageProjectUrl>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/jscarle/SourceGeneratorTestHelpers</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>testing source-generators nunit</PackageTags>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.1.0.0</AssemblyVersion>
<FileVersion>10.1.0.0</FileVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AnalysisLevel>latest-All</AnalysisLevel>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<Optimize>true</Optimize>
</PropertyGroup>

Expand All @@ -38,7 +36,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<None Include="..\..\LICENSE.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks>
<ImplicitUsings>true</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>SourceGeneratorTestHelpers.XUnit</RootNamespace>
<LangVersion>latest</LangVersion>
<Version>10.0.0</Version>
<Version>10.1.0</Version>
<Title>SourceGeneratorTestHelpers.XUnit</Title>
<Authors>Jean-Sebastien Carle</Authors>
<Description>Test helpers and extension methods to simplify testing of .NET source generators.</Description>
<Copyright>Copyright © Jean-Sebastien Carle 2025</Copyright>
<Copyright>Copyright © Jean-Sebastien Carle 2026</Copyright>
<PackageId>SourceGeneratorTestHelpers.XUnit</PackageId>
<PackageProjectUrl>https://github.com/jscarle/SourceGeneratorTestHelpers</PackageProjectUrl>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/jscarle/SourceGeneratorTestHelpers</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>testing source-generators xunit</PackageTags>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.1.0.0</AssemblyVersion>
<FileVersion>10.1.0.0</FileVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AnalysisLevel>latest-All</AnalysisLevel>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<Optimize>true</Optimize>
<NoWarn>$(NoWarn);NU1701</NoWarn>
</PropertyGroup>
Expand Down
9 changes: 5 additions & 4 deletions src/SourceGeneratorTestHelpers/Common/Diff.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Globalization;
using System.Text;
using DiffPlex;
using DiffPlex.DiffBuilder;
using DiffPlex.DiffBuilder.Model;
using System.Globalization;
using System.Text;

namespace SourceGeneratorTestHelpers.Common;

Expand Down Expand Up @@ -65,10 +65,11 @@ public static (bool HasDifferences, string Differences) Compare(
private static string? NormalizeLineEndings(string? str, bool normalize)
{
return normalize
? str?.Replace(
?
str?.Replace(
"\r\n",
"\n"
#if NET6_0_OR_GREATER
#if !NETSTANDARD2_0
, StringComparison.InvariantCulture
#endif
)
Expand Down
21 changes: 3 additions & 18 deletions src/SourceGeneratorTestHelpers/Common/Helpers.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Collections.Immutable;
using System.Text;
using Basic.Reference.Assemblies;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Immutable;
using System.Text;

namespace SourceGeneratorTestHelpers.Common;

Expand All @@ -14,19 +14,6 @@ internal static class Helpers
internal static CSharpCompilationOptions DefaultCSharpCompilationOptions { get; } =
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable);

internal static (ImmutableArray<Diagnostic> CompilationDiagnostics, GeneratorDriverRunResult Result) InternalRunGenerator(
ISourceGenerator generator,
string source,
CSharpParseOptions? cSharpParseOptions,
IEnumerable<MetadataReference>? metadataReferences,
CSharpCompilationOptions? cSharpCompilationOptions
)
{
var sources = new[] { source };

return InternalRunGenerator(generator, sources, cSharpParseOptions, metadataReferences, cSharpCompilationOptions);
}

internal static (ImmutableArray<Diagnostic> CompilationDiagnostics, GeneratorDriverRunResult Result) InternalRunGenerator(
ISourceGenerator generator,
IEnumerable<string> sources,
Expand Down Expand Up @@ -105,9 +92,7 @@ Action<string> assertAction
}

internal static ImmutableList<GeneratedSource> InternalGetSources(this GeneratorDriverRunResult result)
{
return result.GeneratedTrees.Select(GetGeneratedSource).ToImmutableList();
}
=> [.. result.GeneratedTrees.Select(GetGeneratedSource)];

private static string ToMessage(this IEnumerable<Diagnostic> diagnostics, string reason)
{
Expand Down
4 changes: 2 additions & 2 deletions src/SourceGeneratorTestHelpers/GeneratedSource.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace SourceGeneratorTestHelpers;
namespace SourceGeneratorTestHelpers;

/// <summary>Represents a generated source file.</summary>
public readonly struct GeneratedSource : IEquatable<GeneratedSource>
Expand Down Expand Up @@ -31,7 +31,7 @@ public override bool Equals(object? obj)
public override int GetHashCode()
{
return FilePath.GetHashCode(
#if NET6_0_OR_GREATER
#if !NETSTANDARD2_0
StringComparison.Ordinal
#endif
);
Expand Down
Loading