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
19 changes: 8 additions & 11 deletions src/TUnit.Engine/Capabilities/BannerCapability.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Testing.Platform.Capabilities.TestFramework;
using Microsoft.Testing.Platform.CommandLine;
Expand All @@ -8,6 +7,7 @@
using TUnit.Engine.CommandLineProviders;
using TUnit.Engine.Configuration;
using TUnit.Engine.Enums;
using TUnit.Engine.Helpers;
#if NET
using System.Runtime.CompilerServices;
#endif
Expand Down Expand Up @@ -65,16 +65,13 @@ AOT compilation detected. Dynamic code generation is not supported.
);
}

private EngineMode GetMode()
// Must agree with the mode TUnitServiceProvider actually selects, so share its decision
// (CLI flags, [ReflectionMode], TUNIT_EXECUTION_MODE, EnableTUnitSourceGeneration=false).
internal EngineMode GetMode()
{
if (commandLineOptions.IsOptionSet(ReflectionModeCommandProvider.ReflectionMode)
|| Assembly.GetEntryAssembly()?.GetCustomAttributes<AssemblyMetadataAttribute>()
.Any(x => x is { Key: "TUnitReflectionScanner", Value: "true" }) is true)
{
return EngineMode.Reflection;
}

return EngineMode.SourceGenerated;
return ExecutionModeHelper.IsSourceGenerationMode(commandLineOptions)
? EngineMode.SourceGenerated
: EngineMode.Reflection;
}

private string GetRuntimeDetails()
Expand Down
96 changes: 96 additions & 0 deletions tests/TUnit.UnitTests/BannerCapabilityTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.Testing.Platform.CommandLine;
using TUnit.Engine.Capabilities;
using TUnit.Engine.CommandLineProviders;
using TUnit.Engine.Configuration;
using TUnit.Engine.Enums;

namespace TUnit.UnitTests;

// Regression tests for https://github.com/thomhurst/TUnit/issues/7078: the banner must report the
// engine mode the engine actually selects. [NotInParallel] because tests change TUNIT_EXECUTION_MODE.
[NotInParallel]
public class BannerCapabilityTests
{
private string? _previousExecutionMode;

[Before(HookType.Test)]
public void ClearExecutionMode()
{
_previousExecutionMode = Environment.GetEnvironmentVariable(EnvironmentConstants.ExecutionMode);
Environment.SetEnvironmentVariable(EnvironmentConstants.ExecutionMode, null);
}

[After(HookType.Test)]
public void RestoreExecutionMode()
=> Environment.SetEnvironmentVariable(EnvironmentConstants.ExecutionMode, _previousExecutionMode);

[Test]
public async Task Reports_Reflection_When_Environment_Variable_Requests_Reflection()
{
SkipOnAot();
Environment.SetEnvironmentVariable(EnvironmentConstants.ExecutionMode, "reflection");

await Assert.That(CreateBanner(new FakeCommandLineOptions()).GetMode()).IsEqualTo(EngineMode.Reflection);
}

[Test]
public async Task Reports_SourceGenerated_When_Environment_Variable_Requests_SourceGeneration()
{
Environment.SetEnvironmentVariable(EnvironmentConstants.ExecutionMode, "sourcegeneration");

await Assert.That(CreateBanner(new FakeCommandLineOptions()).GetMode()).IsEqualTo(EngineMode.SourceGenerated);
}

[Test]
public async Task Reports_Reflection_When_Reflection_Flag_Is_Set()
{
SkipOnAot();
var options = new FakeCommandLineOptions(ReflectionModeCommandProvider.ReflectionMode);

await Assert.That(CreateBanner(options).GetMode()).IsEqualTo(EngineMode.Reflection);
}

[Test]
public async Task Falls_Back_To_Source_Registration_Without_Overrides()
{
// With no CLI or environment override, the engine falls back to whether generated sources
// registered themselves (false when EnableTUnitSourceGeneration=false strips the generator).
var options = new FakeCommandLineOptions();
var expected = SourceRegistrar.IsEnabled
? EngineMode.SourceGenerated
: EngineMode.Reflection;

await Assert.That(CreateBanner(options).GetMode()).IsEqualTo(expected);
}

private static BannerCapability CreateBanner(ICommandLineOptions options)
=> new(null!, options, null!);

private static void SkipOnAot()
{
#if NET
if (!System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported)
{
Skip.Test("Native AOT always forces source-generated mode.");
}
#endif
}

private sealed class FakeCommandLineOptions(params string[] setOptions) : ICommandLineOptions
{
public bool IsOptionSet(string optionName) => setOptions.Contains(optionName);

public bool TryGetOptionArgumentList(string optionName, [NotNullWhen(true)] out string[]? arguments)
{
if (setOptions.Contains(optionName))
{
arguments = [];
return true;
}

arguments = null;
return false;
}
}
}
Loading