Skip to content
Merged
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
23 changes: 14 additions & 9 deletions TUnit.Engine/Services/AfterHookPairTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ public void RegisterAfterTestSessionHook(
_sessionHookRegistered = true;

// Register callback to run After hook on cancellation
var registration = cancellationToken.Register(() =>
var registration = cancellationToken.Register(static state =>
{
var (pairTracker, afterHookExecutor) = ((AfterHookPairTracker, Func<ValueTask<List<Exception>>>))state!;
// Use sync-over-async here because CancellationToken.Register requires Action (not Func<Task>)
// Fire-and-forget is acceptable here - exceptions will be collected when hooks run normally
_ = GetOrCreateAfterTestSessionTask(afterHookExecutor);
});
_ = pairTracker.GetOrCreateAfterTestSessionTask(afterHookExecutor);
}, (this, afterHookExecutor));

_registrations.Add(registration);
}
Expand All @@ -64,10 +65,11 @@ public void RegisterAfterAssemblyHook(
CancellationToken cancellationToken,
Func<Assembly, ValueTask<List<Exception>>> afterHookExecutor)
{
var registration = cancellationToken.Register(() =>
var registration = cancellationToken.Register(static state =>
{
_ = GetOrCreateAfterAssemblyTask(assembly, afterHookExecutor);
});
var (pairTracker, assembly, afterHookExecutor) = ((AfterHookPairTracker, Assembly, Func<Assembly, ValueTask<List<Exception>>>))state!;
_ = pairTracker.GetOrCreateAfterAssemblyTask(assembly, afterHookExecutor);
}, (this, assembly, afterHookExecutor));

_registrations.Add(registration);
}
Expand All @@ -76,16 +78,19 @@ public void RegisterAfterAssemblyHook(
/// Registers Class After hooks to run on cancellation or normal completion.
/// Ensures After hooks run exactly once even if called both ways.
/// </summary>
[UnconditionalSuppressMessage("Trimming", "IL2077",
Justification = "Type parameter is annotated at the method boundary.")]
public void RegisterAfterClassHook(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicMethods)]
Type testClass,
HookExecutor hookExecutor,
CancellationToken cancellationToken)
{
var registration = cancellationToken.Register(() =>
var registration = cancellationToken.Register(static state =>
{
_ = GetOrCreateAfterClassTask(testClass, hookExecutor, CancellationToken.None);
});
var (pairTracker, testClass, hookExecutor) = ((AfterHookPairTracker, Type, HookExecutor))state!;
_ = pairTracker.GetOrCreateAfterClassTask(testClass, hookExecutor, CancellationToken.None);
}, (this, testClass, hookExecutor));

_registrations.Add(registration);
}
Expand Down
Loading