Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,27 @@ public class AssemblyLoaderGenerator : IIncrementalGenerator
];
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var enabledProvider = context.AnalyzerConfigOptionsProvider
.Select((options, _) =>
{
options.GlobalOptions.TryGetValue("build_property.EnableTUnitSourceGeneration", out var value);
return !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase);
});

var provider = context.CompilationProvider
.WithComparer(new PreventCompilationTriggerOnEveryKeystrokeComparer());
.WithComparer(new PreventCompilationTriggerOnEveryKeystrokeComparer())
.Combine(enabledProvider);

context.RegisterSourceOutput(provider, (sourceProductionContext, data) =>
{
var (compilation, isEnabled) = data;
if (!isEnabled)
{
return;
}

context.RegisterSourceOutput(provider, (sourceProductionContext, source) => GenerateCode(sourceProductionContext, source));
GenerateCode(sourceProductionContext, compilation);
});
}

private void GenerateCode(SourceProductionContext context, Compilation compilation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,27 @@ public class DisableReflectionScannerGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var enabledProvider = context.AnalyzerConfigOptionsProvider
.Select((options, _) =>
{
options.GlobalOptions.TryGetValue("build_property.EnableTUnitSourceGeneration", out var value);
return !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase);
});

var provider = context.CompilationProvider
.WithComparer(new PreventCompilationTriggerOnEveryKeystrokeComparer());
.WithComparer(new PreventCompilationTriggerOnEveryKeystrokeComparer())
.Combine(enabledProvider);

context.RegisterSourceOutput(provider, (sourceProductionContext, data) =>
{
var (_, isEnabled) = data;
if (!isEnabled)
{
return;
}

context.RegisterSourceOutput(provider, (sourceProductionContext, _) => GenerateCode(sourceProductionContext));
GenerateCode(sourceProductionContext);
});
}

private void GenerateCode(SourceProductionContext context)
Expand Down
21 changes: 19 additions & 2 deletions TUnit.Core.SourceGenerator/CodeGenerators/DynamicTestsGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,31 @@ public class DynamicTestsGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var enabledProvider = context.AnalyzerConfigOptionsProvider
.Select((options, _) =>
{
options.GlobalOptions.TryGetValue("build_property.EnableTUnitSourceGeneration", out var value);
return !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase);
});

var standardTests = context.SyntaxProvider
.ForAttributeWithMetadataName(
"TUnit.Core.DynamicTestBuilderAttribute",
predicate: static (_, _) => true,
transform: static (ctx, _) => GetSemanticTargetForTestMethodGeneration(ctx))
.Where(static m => m is not null);
.Where(static m => m is not null)
.Combine(enabledProvider);

context.RegisterSourceOutput(standardTests, (sourceContext, data) =>
{
var (testData, isEnabled) = data;
if (!isEnabled)
{
return;
}

context.RegisterSourceOutput(standardTests, (sourceContext, data) => GenerateTests(sourceContext, data!));
GenerateTests(sourceContext, testData!);
});
}

static DynamicTestSourceDataModel? GetSemanticTargetForTestMethodGeneration(GeneratorAttributeSyntaxContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ public class LanguageVersionCheckGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var enabledProvider = context.AnalyzerConfigOptionsProvider
.Select((options, _) =>
{
options.GlobalOptions.TryGetValue("build_property.EnableTUnitSourceGeneration", out var value);
return !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase);
});

var settings = context.CompilationProvider
.Select((c, _) =>
{
Expand All @@ -16,10 +23,18 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
: null;

return csharpVersion;
});
})
.Combine(enabledProvider);

context.RegisterSourceOutput(settings, static (sourceProductionContext, languageVersion) =>
context.RegisterSourceOutput(settings, static (sourceProductionContext, data) =>
{
var (languageVersion, isEnabled) = data;

if (!isEnabled)
{
return;
}

if (languageVersion is null)
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,31 @@ public class StaticPropertyInitializationGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var enabledProvider = context.AnalyzerConfigOptionsProvider
.Select((options, _) =>
{
options.GlobalOptions.TryGetValue("build_property.EnableTUnitSourceGeneration", out var value);
return !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase);
});

var testClasses = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (s, _) => s is ClassDeclarationSyntax,
transform: static (ctx, _) => GetSemanticTargetForGeneration(ctx))
.Where(static t => t is not null)
.Collect();
.Collect()
.Combine(enabledProvider);

context.RegisterSourceOutput(testClasses, (sourceProductionContext, data) =>
{
var (classes, isEnabled) = data;
if (!isEnabled)
{
return;
}

context.RegisterSourceOutput(testClasses, (sourceProductionContext, testClasses) =>
GenerateStaticPropertyInitialization(sourceProductionContext, testClasses.Where(t => t != null).ToImmutableArray()!));
GenerateStaticPropertyInitialization(sourceProductionContext, classes.Where(t => t != null).ToImmutableArray()!);
});
}

private static INamedTypeSymbol? GetSemanticTargetForGeneration(GeneratorSyntaxContext context)
Expand Down
6 changes: 6 additions & 0 deletions TUnit.Core/TUnit.Core.props
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@
<EnableTUnitPolyfills Condition="'$(EnableTUnitPolyfills)' == '' and ('$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFrameworkIdentifier)' == '.NETFramework')">true</EnableTUnitPolyfills>
</PropertyGroup>

<PropertyGroup>
<!-- Enable TUnit source generation (defaults to true). Set to false when using reflection mode to skip source generation and improve build performance. -->
<EnableTUnitSourceGeneration Condition="'$(EnableTUnitSourceGeneration)' == ''">true</EnableTUnitSourceGeneration>
</PropertyGroup>

<ItemGroup>
<CompilerVisibleProperty Include="EnableTUnitPolyfills" />
<CompilerVisibleProperty Include="EnableTUnitSourceGeneration" />
</ItemGroup>

</Project>
53 changes: 53 additions & 0 deletions docs/docs/execution/engine-modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,59 @@ Alternatively, you can configure this in a `.runsettings` file:
</RunSettings>
```

### Optimizing Build Performance in Reflection Mode

When using reflection mode exclusively (via `[assembly: ReflectionMode]`), you can improve build performance by disabling source generation entirely. Since the generated code won't be used at runtime in reflection mode, skipping source generation reduces compile times.

Add this MSBuild property to your test project file (`.csproj`):

```xml
<PropertyGroup>
<EnableTUnitSourceGeneration>false</EnableTUnitSourceGeneration>
</PropertyGroup>
```

**Example: bUnit Test Project with Optimized Build**
```xml
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<!-- Disable source generation since we're using reflection mode -->
<EnableTUnitSourceGeneration>false</EnableTUnitSourceGeneration>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="bunit" Version="1.x.x" />
<PackageReference Include="TUnit" Version="1.x.x" />
</ItemGroup>
</Project>
```

Then in your code:
```csharp
// Enable reflection mode for Razor component testing
[assembly: ReflectionMode]

namespace MyApp.Tests;

public class CounterComponentTests : TestContext
{
[Test]
public void CounterStartsAtZero()
{
var cut = RenderComponent<Counter>();
cut.Find("p").TextContent.ShouldBe("Current count: 0");
}
}
```

**Benefits:**
- **Faster Builds**: Eliminates source generator execution at compile time
- **Reduced Compiler Overhead**: Less work for the compiler to do
- **Clear Intent**: Explicitly indicates the project uses reflection mode

**Note:** This optimization is only beneficial when you're exclusively using reflection mode. If you're using source generation mode (the default), keep `EnableTUnitSourceGeneration` set to `true` (or omit it entirely, as `true` is the default).

## Native AOT Support

When publishing with Native AOT, TUnit's source generation mode provides additional benefits:
Expand Down
Loading