diff --git a/TUnit.Core.SourceGenerator.Tests/MethodDataSourceDrivenWithCancellationTokenTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/MethodDataSourceDrivenWithCancellationTokenTests.Test.verified.txt index 91193caa00..a842404390 100644 --- a/TUnit.Core.SourceGenerator.Tests/MethodDataSourceDrivenWithCancellationTokenTests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/MethodDataSourceDrivenWithCancellationTokenTests.Test.verified.txt @@ -195,7 +195,7 @@ internal sealed class TUnit_TestProject_MethodDataSourceDrivenWithCancellationTo switch (args.Length) { case 1: - instance.MyTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.CancellationToken ?? System.Threading.CancellationToken.None); + instance.MyTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.Execution.CancellationToken ?? System.Threading.CancellationToken.None); return default(global::System.Threading.Tasks.ValueTask); default: throw new global::System.ArgumentException($"Expected exactly 1 argument, but got {args.Length}"); diff --git a/TUnit.Core.SourceGenerator.Tests/Tests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/Tests.Test.verified.txt index 62c0396286..ae338ab8db 100644 --- a/TUnit.Core.SourceGenerator.Tests/Tests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/Tests.Test.verified.txt @@ -87,7 +87,7 @@ internal sealed class TUnit_TestProject_Bugs__1304_Tests_TryParse_InvalidString_ switch (args.Length) { case 1: - return new global::System.Threading.Tasks.ValueTask(instance.TryParse_InvalidString_ReturnsFailure(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.CancellationToken ?? System.Threading.CancellationToken.None)); + return new global::System.Threading.Tasks.ValueTask(instance.TryParse_InvalidString_ReturnsFailure(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.Execution.CancellationToken ?? System.Threading.CancellationToken.None)); default: throw new global::System.ArgumentException($"Expected exactly 1 argument, but got {args.Length}"); } diff --git a/TUnit.Core.SourceGenerator.Tests/TimeoutCancellationTokenTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/TimeoutCancellationTokenTests.Test.verified.txt index 180fa355b9..5c46854523 100644 --- a/TUnit.Core.SourceGenerator.Tests/TimeoutCancellationTokenTests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/TimeoutCancellationTokenTests.Test.verified.txt @@ -527,7 +527,7 @@ internal sealed class TUnit_TestProject_TimeoutCancellationTokenTests_DataTest__ switch (args.Length) { case 1: - return new global::System.Threading.Tasks.ValueTask(instance.DataTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.CancellationToken ?? System.Threading.CancellationToken.None)); + return new global::System.Threading.Tasks.ValueTask(instance.DataTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.Execution.CancellationToken ?? System.Threading.CancellationToken.None)); default: throw new global::System.ArgumentException($"Expected exactly 1 argument, but got {args.Length}"); } @@ -700,7 +700,7 @@ internal sealed class TUnit_TestProject_TimeoutCancellationTokenTests_DataSource switch (args.Length) { case 1: - return new global::System.Threading.Tasks.ValueTask(instance.DataSourceTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.CancellationToken ?? System.Threading.CancellationToken.None)); + return new global::System.Threading.Tasks.ValueTask(instance.DataSourceTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.Execution.CancellationToken ?? System.Threading.CancellationToken.None)); default: throw new global::System.ArgumentException($"Expected exactly 1 argument, but got {args.Length}"); } @@ -853,7 +853,7 @@ internal sealed class TUnit_TestProject_TimeoutCancellationTokenTests_MatrixTest switch (args.Length) { case 1: - return new global::System.Threading.Tasks.ValueTask(instance.MatrixTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.CancellationToken ?? System.Threading.CancellationToken.None)); + return new global::System.Threading.Tasks.ValueTask(instance.MatrixTest(TUnit.Core.Helpers.CastHelper.Cast(args[0]), context?.Execution.CancellationToken ?? System.Threading.CancellationToken.None)); default: throw new global::System.ArgumentException($"Expected exactly 1 argument, but got {args.Length}"); } diff --git a/TUnit.Core.SourceGenerator.Tests/Verify.cs b/TUnit.Core.SourceGenerator.Tests/Verify.cs index 6ad5bde3d2..d1db167879 100644 --- a/TUnit.Core.SourceGenerator.Tests/Verify.cs +++ b/TUnit.Core.SourceGenerator.Tests/Verify.cs @@ -88,8 +88,8 @@ public async Task ToTask() if (testContext != null) { - testClassName = testContext.TestDetails.ClassType.Name; - testName = testContext.TestDetails.TestName; + testClassName = testContext.Metadata.TestDetails.ClassType.Name; + testName = testContext.Metadata.TestDetails.TestName; } else { diff --git a/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs b/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs index 4a65b807c1..566312525d 100644 --- a/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs +++ b/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs @@ -2002,7 +2002,7 @@ private static void GenerateConcreteTestInvoker(CodeWriter writer, TestMethodMet // Add CancellationToken if present if (hasCancellationToken) { - argsToPass.Add("context?.CancellationToken ?? System.Threading.CancellationToken.None"); + argsToPass.Add("context?.Execution.CancellationToken ?? System.Threading.CancellationToken.None"); } var typedMethodCall = $"instance.{methodName}({string.Join(", ", argsToPass)})"; diff --git a/TUnit.Core/AbstractExecutableTest.cs b/TUnit.Core/AbstractExecutableTest.cs index a668961b3a..bf6252ac85 100644 --- a/TUnit.Core/AbstractExecutableTest.cs +++ b/TUnit.Core/AbstractExecutableTest.cs @@ -44,8 +44,8 @@ public required TestContext Context public TestResult? Result { - get => Context.Result; - set => Context.Result = value; + get => Context.Execution.Result; + set => Context.Execution.Result = value; } public DateTimeOffset? StartTime @@ -61,7 +61,7 @@ public DateTimeOffset? StartTime public Task CompletionTask => ExecutionTask ?? Task.CompletedTask; - public DateTimeOffset? EndTime { get => Context.TestEnd; set => Context.TestEnd = value; } + public DateTimeOffset? EndTime { get => Context.Execution.TestEnd; set => Context.Execution.TestEnd = value; } public TimeSpan? Duration => StartTime.HasValue && EndTime.HasValue ? EndTime.Value - StartTime.Value @@ -70,7 +70,7 @@ public DateTimeOffset? StartTime public void SetResult(TestState state, Exception? exception = null) { State = state; - Context.Result ??= new TestResult + Context.Execution.Result ??= new TestResult { State = state, Exception = exception, diff --git a/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs b/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs index 66bc973a79..505f9cd0f9 100644 --- a/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs +++ b/TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs @@ -62,7 +62,7 @@ public ValueTask OnTestRegistered(TestRegisteredContext context) if (!string.IsNullOrEmpty(Skip)) { context.TestContext.SkipReason = Skip; - context.TestContext.TestDetails.ClassInstance = SkippedTestInstance.Instance; + context.TestContext.Metadata.TestDetails.ClassInstance = SkippedTestInstance.Instance; } return default; @@ -90,7 +90,7 @@ public ValueTask OnTestRegistered(TestRegisteredContext context) if (!string.IsNullOrEmpty(Skip)) { context.TestContext.SkipReason = Skip; - context.TestContext.TestDetails.ClassInstance = SkippedTestInstance.Instance; + context.TestContext.Metadata.TestDetails.ClassInstance = SkippedTestInstance.Instance; } return default; diff --git a/TUnit.Core/Attributes/TestMetadata/DisplayNameAttribute.cs b/TUnit.Core/Attributes/TestMetadata/DisplayNameAttribute.cs index 94570bcbb4..25e2e32420 100644 --- a/TUnit.Core/Attributes/TestMetadata/DisplayNameAttribute.cs +++ b/TUnit.Core/Attributes/TestMetadata/DisplayNameAttribute.cs @@ -41,7 +41,7 @@ public sealed class DisplayNameAttribute(string displayName) : DisplayNameFormat /// protected override string FormatDisplayName(DiscoveredTestContext context) { - var testDetails = context.TestDetails; + var testDetails = context.TestContext.Metadata.TestDetails; var mutableDisplayName = displayName; diff --git a/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs b/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs index a8c7f6defb..8bc727bdd5 100644 --- a/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs +++ b/TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs @@ -56,7 +56,7 @@ public async ValueTask OnTestRegistered(TestRegisteredContext context) { // Store skip reason directly on TestContext context.TestContext.SkipReason = Reason; - context.TestContext.TestDetails.ClassInstance = SkippedTestInstance.Instance; + context.TestContext.Metadata.TestDetails.ClassInstance = SkippedTestInstance.Instance; } } diff --git a/TUnit.Core/Attributes/TestMetadata/TimeoutAttribute.cs b/TUnit.Core/Attributes/TestMetadata/TimeoutAttribute.cs index 2cde57aa09..31546a1737 100644 --- a/TUnit.Core/Attributes/TestMetadata/TimeoutAttribute.cs +++ b/TUnit.Core/Attributes/TestMetadata/TimeoutAttribute.cs @@ -46,7 +46,7 @@ public class TimeoutAttribute(int timeoutInMilliseconds) : TUnitAttribute, ITest /// public ValueTask OnTestDiscovered(DiscoveredTestContext context) { - context.TestDetails.Timeout = Timeout; + context.TestContext.Metadata.TestDetails.Timeout = Timeout; return default(ValueTask); } diff --git a/TUnit.Core/Contexts/DiscoveredTestContext.cs b/TUnit.Core/Contexts/DiscoveredTestContext.cs index ac1e8e073f..7e929e2c77 100644 --- a/TUnit.Core/Contexts/DiscoveredTestContext.cs +++ b/TUnit.Core/Contexts/DiscoveredTestContext.cs @@ -11,7 +11,7 @@ public class DiscoveredTestContext public string TestName { get; } public TestContext TestContext { get; } - public TestDetails TestDetails => TestContext.TestDetails; + public TestDetails TestDetails => TestContext.Metadata.TestDetails; public DiscoveredTestContext(string testName, TestContext testContext) { @@ -21,7 +21,7 @@ public DiscoveredTestContext(string testName, TestContext testContext) public void AddCategory(string category) { - if (!string.IsNullOrWhiteSpace(category) && !TestContext.TestDetails.Categories.Contains(category)) + if (!string.IsNullOrWhiteSpace(category) && !TestContext.Metadata.TestDetails.Categories.Contains(category)) { TestDetails.Categories.Add(category); } @@ -57,7 +57,7 @@ public void SetRetryLimit(int retryLimit) public void SetRetryLimit(int retryCount, Func> shouldRetry) { TestContext.RetryFunc = shouldRetry; - TestContext.TestDetails.RetryLimit = retryCount; + TestContext.Metadata.TestDetails.RetryLimit = retryCount; } /// diff --git a/TUnit.Core/Contexts/TestRegisteredContext.cs b/TUnit.Core/Contexts/TestRegisteredContext.cs index ca42e6f333..4924981de0 100644 --- a/TUnit.Core/Contexts/TestRegisteredContext.cs +++ b/TUnit.Core/Contexts/TestRegisteredContext.cs @@ -16,19 +16,19 @@ public class TestRegisteredContext public TestRegisteredContext(TestContext testContext) { TestContext = testContext; - TestName = testContext.TestDetails.TestName; + TestName = testContext.Metadata.TestDetails.TestName; CustomDisplayName = testContext.CustomDisplayName; } /// /// Gets the object bag from the underlying TestContext /// - public ConcurrentDictionary ObjectBag => TestContext.ObjectBag; + public ConcurrentDictionary ObjectBag => TestContext.StateBag.Items; /// /// Gets the test details from the underlying TestContext /// - public TestDetails TestDetails => TestContext.TestDetails; + public TestDetails TestDetails => TestContext.Metadata.TestDetails; public void SetTestExecutor(ITestExecutor executor) { diff --git a/TUnit.Core/DataGeneratorMetadataCreator.cs b/TUnit.Core/DataGeneratorMetadataCreator.cs index 733039092a..63f3938cf2 100644 --- a/TUnit.Core/DataGeneratorMetadataCreator.cs +++ b/TUnit.Core/DataGeneratorMetadataCreator.cs @@ -194,8 +194,8 @@ public static DataGeneratorMetadata CreateForPropertyInjection( TestInformation = methodMetadata, Type = DataGeneratorType.Property, TestSessionId = TestSessionContext.Current?.Id ?? "property-injection", - TestClassInstance = testClassInstance ?? testContext?.TestDetails.ClassInstance, - ClassInstanceArguments = testContext?.TestDetails.TestClassArguments ?? [] + TestClassInstance = testClassInstance ?? testContext?.Metadata.TestDetails.ClassInstance, + ClassInstanceArguments = testContext?.Metadata.TestDetails.TestClassArguments ?? [] }; } diff --git a/TUnit.Core/DataSources/TestDataFormatter.cs b/TUnit.Core/DataSources/TestDataFormatter.cs index 028b5fb586..c7ecdf87cb 100644 --- a/TUnit.Core/DataSources/TestDataFormatter.cs +++ b/TUnit.Core/DataSources/TestDataFormatter.cs @@ -12,7 +12,7 @@ public static class TestDataFormatter /// public static string FormatArguments(TestContext context) { - var arguments = context.TestDetails.TestMethodArguments; + var arguments = context.Metadata.TestDetails.TestMethodArguments; return FormatArguments(arguments, context.ArgumentDisplayFormatters); } diff --git a/TUnit.Core/DiscoveredTest.cs b/TUnit.Core/DiscoveredTest.cs index 945faec8c4..7f1c8bb4d8 100644 --- a/TUnit.Core/DiscoveredTest.cs +++ b/TUnit.Core/DiscoveredTest.cs @@ -5,7 +5,7 @@ namespace TUnit.Core; public abstract class DiscoveredTest { public required TestContext TestContext { get; init; } - public TestDetails TestDetails => TestContext.TestDetails; + public TestDetails TestDetails => TestContext.Metadata.TestDetails; public ITestExecutor? TestExecutor { get; set; } } diff --git a/TUnit.Core/Extensions/TestContextExtensions.cs b/TUnit.Core/Extensions/TestContextExtensions.cs index 11f1b4b038..c550da72ff 100644 --- a/TUnit.Core/Extensions/TestContextExtensions.cs +++ b/TUnit.Core/Extensions/TestContextExtensions.cs @@ -13,22 +13,22 @@ public static class TestContextExtensions public static string GetClassTypeName(this TestContext context) { - var parameters = context.TestDetails.MethodMetadata.Class.Parameters; + var parameters = context.Metadata.TestDetails.MethodMetadata.Class.Parameters; if (parameters.Length == 0) { - return context.TestDetails.ClassType.Name; + return context.Metadata.TestDetails.ClassType.Name; } // Optimize: Use array instead of LINQ Select to reduce allocations - var args = context.TestDetails.TestClassArguments; + var args = context.Metadata.TestDetails.TestClassArguments; var formattedArgs = new string[args.Length]; for (int i = 0; i < args.Length; i++) { formattedArgs[i] = ArgumentFormatter.Format(args[i], context.ArgumentDisplayFormatters); } - return $"{context.TestDetails.ClassType.Name}({string.Join(", ", formattedArgs)})"; + return $"{context.Metadata.TestDetails.ClassType.Name}({string.Join(", ", formattedArgs)})"; } #if NET6_0_OR_GREATER diff --git a/TUnit.Core/GenericTestMetadata.cs b/TUnit.Core/GenericTestMetadata.cs index 4f588c8725..8bb798ef7c 100644 --- a/TUnit.Core/GenericTestMetadata.cs +++ b/TUnit.Core/GenericTestMetadata.cs @@ -123,7 +123,7 @@ public override Func().ToArray() ?? Type.EmptyTypes; + typeArgs = testContext.Metadata.TestDetails.TestClassArguments?.OfType().ToArray() ?? Type.EmptyTypes; } var instance = InstanceFactory(typeArgs, context.ClassArguments ?? []); diff --git a/TUnit.Core/Helpers/DataSourceHelpers.cs b/TUnit.Core/Helpers/DataSourceHelpers.cs index 0ff829916e..7c8b439ecf 100644 --- a/TUnit.Core/Helpers/DataSourceHelpers.cs +++ b/TUnit.Core/Helpers/DataSourceHelpers.cs @@ -562,9 +562,9 @@ public static void RegisterTypeCreator(Func> testInformation, dataSourceAttribute, TestContext.Current, - TestContext.Current?.TestDetails.ClassInstance, + TestContext.Current?.Metadata.TestDetails.ClassInstance, TestContext.Current?.Events, - TestContext.Current?.ObjectBag ?? new ConcurrentDictionary() + TestContext.Current?.StateBag.Items ?? new ConcurrentDictionary() ); // Generate the data source value using the attribute's GetDataRowsAsync method diff --git a/TUnit.Core/Hooks/InstanceHookMethod.cs b/TUnit.Core/Hooks/InstanceHookMethod.cs index 715e12eea3..d8fe0219ab 100644 --- a/TUnit.Core/Hooks/InstanceHookMethod.cs +++ b/TUnit.Core/Hooks/InstanceHookMethod.cs @@ -24,19 +24,19 @@ public required Type InitClassType public ValueTask ExecuteAsync(TestContext context, CancellationToken cancellationToken) { // Skip instance hooks if this is a pre-skipped test - if (context.TestDetails.ClassInstance is SkippedTestInstance) + if (context.Metadata.TestDetails.ClassInstance is SkippedTestInstance) { return new ValueTask(); } // If the instance is still a placeholder, we can't execute instance hooks - if (context.TestDetails.ClassInstance is PlaceholderInstance) + if (context.Metadata.TestDetails.ClassInstance is PlaceholderInstance) { throw new InvalidOperationException($"Cannot execute instance hook {Name} because the test instance has not been created yet. This is likely a framework bug."); } return HookExecutor.ExecuteBeforeTestHook(MethodInfo, context, - () => Body!.Invoke(context.TestDetails.ClassInstance, context, cancellationToken) + () => Body!.Invoke(context.Metadata.TestDetails.ClassInstance, context, cancellationToken) ); } } diff --git a/TUnit.Core/Interfaces/ITestExecution.cs b/TUnit.Core/Interfaces/ITestExecution.cs index 420ed4767d..88e12ea337 100644 --- a/TUnit.Core/Interfaces/ITestExecution.cs +++ b/TUnit.Core/Interfaces/ITestExecution.cs @@ -14,7 +14,7 @@ public interface ITestExecution /// /// Gets the test result after execution completes, or null if the test is still running. /// - TestResult? Result { get; } + TestResult? Result { get; internal set; } /// /// Gets the cancellation token for this test execution. @@ -25,17 +25,17 @@ public interface ITestExecution /// /// Gets the timestamp when test execution started, or null if not yet started. /// - DateTimeOffset? TestStart { get; } + DateTimeOffset? TestStart { get; internal set; } /// /// Gets the timestamp when test execution ended, or null if not yet completed. /// - DateTimeOffset? TestEnd { get; } + DateTimeOffset? TestEnd { get; internal set; } /// /// Gets the current retry attempt number (0 for first attempt, 1+ for retries). /// - int CurrentRetryAttempt { get; } + int CurrentRetryAttempt { get; internal set; } /// /// Gets the reason why this test was skipped, or null if not skipped. diff --git a/TUnit.Core/Interfaces/ITestMetadata.cs b/TUnit.Core/Interfaces/ITestMetadata.cs index fd27efa304..3101f3cd51 100644 --- a/TUnit.Core/Interfaces/ITestMetadata.cs +++ b/TUnit.Core/Interfaces/ITestMetadata.cs @@ -14,7 +14,7 @@ public interface ITestMetadata /// /// Gets the detailed metadata about this test, including class type, method info, and arguments. /// - TestDetails TestDetails { get; } + TestDetails TestDetails { get; internal set; } /// /// Gets the base name of the test method. diff --git a/TUnit.Core/Interfaces/ITestStateBag.cs b/TUnit.Core/Interfaces/ITestStateBag.cs index c58fc9d682..3b4face009 100644 --- a/TUnit.Core/Interfaces/ITestStateBag.cs +++ b/TUnit.Core/Interfaces/ITestStateBag.cs @@ -14,5 +14,5 @@ public interface ITestStateBag /// Use this to share state between hooks, data sources, and test methods within a single test execution. /// Thread-safe for concurrent access. /// - ConcurrentDictionary Bag { get; } + ConcurrentDictionary Items { get; } } diff --git a/TUnit.Core/TestBuilderContext.cs b/TUnit.Core/TestBuilderContext.cs index f25046e7f4..4aea369aa1 100644 --- a/TUnit.Core/TestBuilderContext.cs +++ b/TUnit.Core/TestBuilderContext.cs @@ -31,7 +31,7 @@ public static TestBuilderContext? Current public required MethodMetadata TestMetadata { get; init; } internal IClassConstructor? ClassConstructor { get; set; } - + /// /// Cached and initialized attributes for the test /// @@ -49,7 +49,7 @@ internal static TestBuilderContext FromTestContext(TestContext testContext, IDat { return new TestBuilderContext { - Events = testContext.Events, TestMetadata = testContext.TestDetails.MethodMetadata, DataSourceAttribute = dataSourceAttribute, ObjectBag = testContext.ObjectBag, + Events = testContext.Events, TestMetadata = testContext.Metadata.TestDetails.MethodMetadata, DataSourceAttribute = dataSourceAttribute, ObjectBag = testContext.StateBag.Items, }; } } diff --git a/TUnit.Core/TestContext.Dependencies.cs b/TUnit.Core/TestContext.Dependencies.cs index f2f4c70d54..dc63689a22 100644 --- a/TUnit.Core/TestContext.Dependencies.cs +++ b/TUnit.Core/TestContext.Dependencies.cs @@ -1,15 +1,15 @@ using TUnit.Core.Enums; using TUnit.Core.Interfaces; +using TUnit.Core.Services; namespace TUnit.Core; -/// -/// Test dependency information and relationships -/// Implements interface -/// public partial class TestContext { - // Explicit interface implementations for ITestDependencies + internal readonly List _dependencies = []; + internal string? ParentTestId { get; set; } + internal TestRelationship Relationship { get; set; } = TestRelationship.None; + IReadOnlyList ITestDependencies.DependsOn => _dependencies; string? ITestDependencies.ParentTestId => ParentTestId; TestRelationship ITestDependencies.Relationship => Relationship; @@ -18,6 +18,71 @@ public partial class TestContext List ITestDependencies.GetTests(string testName) => GetTests(testName); List ITestDependencies.GetTests(string testName, Type classType) => GetTests(testName, classType); - // Internal backing field for dependency collection - internal readonly List _dependencies = []; + internal IEnumerable GetTests(Func predicate) + { + var testFinder = ServiceProvider.GetService()!; + + var classType = TestDetails?.ClassType; + if (classType == null) + { + return []; + } + + var tests = testFinder.GetTests(classType).Where(predicate).ToList(); + + if (tests.Any(x => x.Result == null)) + { + throw new InvalidOperationException( + "Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?" + ); + } + + return tests; + } + + internal List GetTests(string testName) + { + var testFinder = ServiceProvider.GetService()!; + + var classType = TestDetails.ClassType; + + var tests = testFinder.GetTestsByNameAndParameters( + testName, + [], + classType, + [], + [] + ).ToList(); + + if (tests.Any(x => x.Result == null)) + { + throw new InvalidOperationException( + "Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?" + ); + } + + return tests; + } + + internal List GetTests(string testName, Type classType) + { + var testFinder = ServiceProvider.GetService()!; + + var tests = testFinder.GetTestsByNameAndParameters( + testName, + [], + classType, + [], + [] + ).ToList(); + + if (tests.Any(x => x.Result == null)) + { + throw new InvalidOperationException( + "Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?" + ); + } + + return tests; + } } diff --git a/TUnit.Core/TestContext.Events.cs b/TUnit.Core/TestContext.Events.cs index dccd7e1c41..702e959322 100644 --- a/TUnit.Core/TestContext.Events.cs +++ b/TUnit.Core/TestContext.Events.cs @@ -2,12 +2,9 @@ namespace TUnit.Core; -/// -/// Test events integration -/// Implements interface -/// public partial class TestContext { - // Explicit interface implementation for ITestEvents + internal TestContextEvents Events => _testBuilderContext.Events; + TestContextEvents ITestEvents.Events => Events; } diff --git a/TUnit.Core/TestContext.Execution.cs b/TUnit.Core/TestContext.Execution.cs index 88ddc6f112..bf5da16dec 100644 --- a/TUnit.Core/TestContext.Execution.cs +++ b/TUnit.Core/TestContext.Execution.cs @@ -9,13 +9,46 @@ namespace TUnit.Core; /// public partial class TestContext { + // Internal backing fields and properties + internal CancellationToken CancellationToken { get; set; } + internal CancellationTokenSource? LinkedCancellationTokens { get; set; } + internal TestPhase Phase { get; set; } = TestPhase.Execution; + internal TestResult? Result { get; set; } + internal string? SkipReason { get; set; } + internal DateTimeOffset? TestStart { get; set; } + internal DateTimeOffset? TestEnd { get; set; } + internal int CurrentRetryAttempt { get; set; } + internal Func>? RetryFunc { get; set; } + internal IHookExecutor? CustomHookExecutor { get; set; } + internal bool ReportResult { get; set; } = true; + // Explicit interface implementations for ITestExecution TestPhase ITestExecution.Phase => Phase; - TestResult? ITestExecution.Result => Result; + TestResult? ITestExecution.Result + { + get => Result; + set => Result = value; + } + CancellationToken ITestExecution.CancellationToken => CancellationToken; - DateTimeOffset? ITestExecution.TestStart => TestStart; - DateTimeOffset? ITestExecution.TestEnd => TestEnd; - int ITestExecution.CurrentRetryAttempt => CurrentRetryAttempt; + DateTimeOffset? ITestExecution.TestStart + { + get => TestStart; + set => TestStart = value; + } + + DateTimeOffset? ITestExecution.TestEnd + { + get => TestEnd; + set => TestEnd = value; + } + + int ITestExecution.CurrentRetryAttempt + { + get => CurrentRetryAttempt; + set => CurrentRetryAttempt = value; + } + string? ITestExecution.SkipReason => SkipReason; Func>? ITestExecution.RetryFunc => RetryFunc; IHookExecutor? ITestExecution.CustomHookExecutor @@ -32,4 +65,48 @@ bool ITestExecution.ReportResult void ITestExecution.OverrideResult(string reason) => OverrideResult(reason); void ITestExecution.OverrideResult(TestState state, string reason) => OverrideResult(state, reason); void ITestExecution.AddLinkedCancellationToken(CancellationToken cancellationToken) => AddLinkedCancellationToken(cancellationToken); + + // Internal implementation methods + internal void OverrideResult(string reason) + { + OverrideResult(TestState.Passed, reason); + } + + internal void OverrideResult(TestState state, string reason) + { + Result = new TestResult + { + State = state, + OverrideReason = reason, + IsOverridden = true, + Start = TestStart ?? DateTimeOffset.UtcNow, + End = DateTimeOffset.UtcNow, + Duration = DateTimeOffset.UtcNow - (TestStart ?? DateTimeOffset.UtcNow), + Exception = null, + ComputerName = Environment.MachineName, + TestContext = this + }; + + InternalExecutableTest.State = state; + } + + internal void AddLinkedCancellationToken(CancellationToken cancellationToken) + { + lock (Lock) + { + if (LinkedCancellationTokens == null) + { + LinkedCancellationTokens = CancellationTokenSource.CreateLinkedTokenSource(CancellationToken, cancellationToken); + } + else + { + var existingToken = LinkedCancellationTokens.Token; + var oldCts = LinkedCancellationTokens; + LinkedCancellationTokens = CancellationTokenSource.CreateLinkedTokenSource(existingToken, cancellationToken); + oldCts.Dispose(); + } + + CancellationToken = LinkedCancellationTokens.Token; + } + } } diff --git a/TUnit.Core/TestContext.Metadata.cs b/TUnit.Core/TestContext.Metadata.cs index d5e29fd52b..0206d4d439 100644 --- a/TUnit.Core/TestContext.Metadata.cs +++ b/TUnit.Core/TestContext.Metadata.cs @@ -1,16 +1,66 @@ +using TUnit.Core.Helpers; using TUnit.Core.Interfaces; namespace TUnit.Core; -/// -/// Test metadata and identity management -/// Implements interface -/// public partial class TestContext { - // Explicit interface implementations for ITestMetadata + internal string GetDisplayName() + { + if(!string.IsNullOrEmpty(CustomDisplayName)) + { + return CustomDisplayName!; + } + + if (_cachedDisplayName != null) + { + return _cachedDisplayName; + } + + if (TestDetails.TestMethodArguments.Length == 0) + { + _cachedDisplayName = TestDetails.TestName; + return TestDetails.TestName; + } + + var argsLength = TestDetails.TestMethodArguments.Length; + var sb = StringBuilderPool.Get(); + try + { + sb.Append(TestDetails.TestName); + sb.Append('('); + + for (var i = 0; i < argsLength; i++) + { + if (i > 0) + { + sb.Append(", "); + } + sb.Append(ArgumentFormatter.Format(TestDetails.TestMethodArguments[i], ArgumentDisplayFormatters)); + } + + sb.Append(')'); + _cachedDisplayName = sb.ToString(); + return _cachedDisplayName; + } + finally + { + StringBuilderPool.Return(sb); + } + } + + internal void InvalidateDisplayNameCache() + { + _cachedDisplayName = null; + } + Guid ITestMetadata.Id => Id; - TestDetails ITestMetadata.TestDetails => TestDetails; + TestDetails ITestMetadata.TestDetails + { + get => TestDetails; + set => TestDetails = value; + } + string ITestMetadata.TestName => TestDetails.TestName; string ITestMetadata.DisplayName diff --git a/TUnit.Core/TestContext.Output.cs b/TUnit.Core/TestContext.Output.cs index 844f68ca7b..e3ee62cddf 100644 --- a/TUnit.Core/TestContext.Output.cs +++ b/TUnit.Core/TestContext.Output.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using TUnit.Core.Interfaces; namespace TUnit.Core; @@ -8,6 +9,11 @@ namespace TUnit.Core; /// public partial class TestContext { + // Internal backing fields and properties + internal ConcurrentBag Timings { get; } = []; + private readonly ConcurrentBag _artifactsBag = new(); + internal IReadOnlyList Artifacts => _artifactsBag.ToList(); + // Explicit interface implementations for ITestOutput TextWriter ITestOutput.StandardOutput => OutputWriter; TextWriter ITestOutput.ErrorOutput => ErrorOutputWriter; @@ -26,4 +32,21 @@ void ITestOutput.AttachArtifact(Artifact artifact) string ITestOutput.GetStandardOutput() => GetOutput(); string ITestOutput.GetErrorOutput() => GetErrorOutput(); + + // Internal methods for output capture (used by base Context class) + internal void WriteLine(string message) + { + _outputWriter ??= new StringWriter(); + _outputWriter.WriteLine(message); + } + + internal void WriteError(string message) + { + _errorWriter ??= new StringWriter(); + _errorWriter.WriteLine(message); + } + + internal string GetOutput() => _outputWriter?.ToString() ?? string.Empty; + + internal new string GetErrorOutput() => _errorWriter?.ToString() ?? string.Empty; } diff --git a/TUnit.Core/TestContext.Parallelization.cs b/TUnit.Core/TestContext.Parallelization.cs index 676003af3b..8bb935a56c 100644 --- a/TUnit.Core/TestContext.Parallelization.cs +++ b/TUnit.Core/TestContext.Parallelization.cs @@ -3,13 +3,11 @@ namespace TUnit.Core; -/// -/// Test parallelization control and configuration -/// Implements interface -/// public partial class TestContext { - // Explicit interface implementations for ITestParallelization + internal IReadOnlyList ParallelConstraints => _parallelConstraints; + internal Priority ExecutionPriority { get; set; } = Priority.Normal; + IReadOnlyList ITestParallelization.Constraints => ParallelConstraints; Priority ITestParallelization.ExecutionPriority { diff --git a/TUnit.Core/TestContext.StateBag.cs b/TUnit.Core/TestContext.StateBag.cs index f716095c65..20312230dc 100644 --- a/TUnit.Core/TestContext.StateBag.cs +++ b/TUnit.Core/TestContext.StateBag.cs @@ -3,12 +3,7 @@ namespace TUnit.Core; -/// -/// Test runtime state storage for sharing values across hooks and test methods -/// Implements interface -/// public partial class TestContext { - // Explicit interface implementation for ITestStateBag - ConcurrentDictionary ITestStateBag.Bag => ObjectBag; + ConcurrentDictionary ITestStateBag.Items => ObjectBag; } diff --git a/TUnit.Core/TestContext.cs b/TUnit.Core/TestContext.cs index 9b0b058b67..da8c809378 100644 --- a/TUnit.Core/TestContext.cs +++ b/TUnit.Core/TestContext.cs @@ -96,64 +96,25 @@ public static string WorkingDirectory internal string? CustomDisplayName { get; set; } - public CancellationToken CancellationToken { get; set; } - - public TestDetails TestDetails { get; set; } = null!; - - public TestPhase Phase { get; set; } = TestPhase.Execution; - - public TestResult? Result { get; set; } - - public string? SkipReason { get; set; } + internal TestDetails TestDetails { get; set; } = null!; internal IParallelLimit? ParallelLimiter { get; private set; } - public Type? DisplayNameFormatter { get; set; } - - /// - /// Custom hook executor that overrides the default hook executor for all test-level hooks. - /// Set via TestRegisteredContext.SetHookExecutor() during test registration. - /// - public IHookExecutor? CustomHookExecutor { get; set; } - - public Func>? RetryFunc { get; set; } + internal Type? DisplayNameFormatter { get; set; } // New: Support multiple parallel constraints private readonly List _parallelConstraints = []; - /// - /// Gets the collection of parallel constraints applied to this test. - /// Multiple constraints can be combined (e.g., ParallelGroup + NotInParallel). - /// - internal IReadOnlyList ParallelConstraints => _parallelConstraints; - - - internal Priority ExecutionPriority { get; set; } = Priority.Normal; - - /// - /// The test ID of the parent test, if this test is a variant or child of another test. - /// Used for tracking test hierarchies in property-based testing shrinking and retry scenarios. - /// - public string? ParentTestId { get; set; } - - /// - /// Defines the relationship between this test and its parent test (if ParentTestId is set). - /// Used by test explorers to display hierarchical relationships. - /// - public TestRelationship Relationship { get; set; } = TestRelationship.None; /// /// Will be null until initialized by TestOrchestrator /// public ClassHookContext ClassContext { get; } - public CancellationTokenSource? LinkedCancellationTokens { get; set; } - internal List> ArgumentDisplayFormatters { get; } = [ ]; - public TestContextEvents Events => _testBuilderContext.Events; internal DiscoveredTest? InternalDiscoveredTest { get; set; } @@ -162,21 +123,6 @@ internal IServiceProvider ServiceProvider get; } - public void WriteLine(string message) - { - _outputWriter ??= new StringWriter(); - _outputWriter.WriteLine(message); - } - - public void WriteError(string message) - { - _errorWriter ??= new StringWriter(); - _errorWriter.WriteLine(message); - } - - public string GetOutput() => _outputWriter?.ToString() ?? string.Empty; - - public new string GetErrorOutput() => _errorWriter?.ToString() ?? string.Empty; public T? GetService() where T : class { @@ -192,201 +138,18 @@ internal override void SetAsyncLocalContext() public object Lock { get; } = new(); - public ConcurrentBag Timings { get; } = []; - - private readonly ConcurrentBag _artifactsBag = new(); - public IReadOnlyList Artifacts => _artifactsBag.ToList(); internal IClassConstructor? ClassConstructor => _testBuilderContext.ClassConstructor; internal object[]? CachedEligibleEventObjects { get; set; } - public string GetDisplayName() - { - if(!string.IsNullOrEmpty(CustomDisplayName)) - { - return CustomDisplayName!; - } - - if (_cachedDisplayName != null) - { - return _cachedDisplayName; - } - - if (TestDetails.TestMethodArguments.Length == 0) - { - _cachedDisplayName = TestDetails.TestName; - return TestDetails.TestName; - } - - var argsLength = TestDetails.TestMethodArguments.Length; - var sb = StringBuilderPool.Get(); - try - { - sb.Append(TestDetails.TestName); - sb.Append('('); - - for (var i = 0; i < argsLength; i++) - { - if (i > 0) - { - sb.Append(", "); - } - sb.Append(ArgumentFormatter.Format(TestDetails.TestMethodArguments[i], ArgumentDisplayFormatters)); - } - - sb.Append(')'); - _cachedDisplayName = sb.ToString(); - return _cachedDisplayName; - } - finally - { - StringBuilderPool.Return(sb); - } - } - - /// - /// Clears the cached display name, forcing it to be recomputed on next access. - /// This is called after discovery event receivers run to ensure custom argument formatters are applied. - /// - internal void InvalidateDisplayNameCache() - { - _cachedDisplayName = null; - } - - public ConcurrentDictionary ObjectBag => _testBuilderContext.ObjectBag; - - public bool ReportResult { get; set; } = true; - - public void AddLinkedCancellationToken(CancellationToken cancellationToken) - { - lock (Lock) - { - if (LinkedCancellationTokens == null) - { - LinkedCancellationTokens = CancellationTokenSource.CreateLinkedTokenSource(CancellationToken, cancellationToken); - } - else - { - var existingToken = LinkedCancellationTokens.Token; - var oldCts = LinkedCancellationTokens; - LinkedCancellationTokens = CancellationTokenSource.CreateLinkedTokenSource(existingToken, cancellationToken); - oldCts.Dispose(); - } - - CancellationToken = LinkedCancellationTokens.Token; - } - } - - public DateTimeOffset? TestStart { get; set; } - - public void OverrideResult(string reason) - { - OverrideResult(TestState.Passed, reason); - } - public void OverrideResult(TestState state, string reason) - { - Result = new TestResult - { - State = state, - OverrideReason = reason, - IsOverridden = true, - Start = TestStart ?? DateTimeOffset.UtcNow, - End = DateTimeOffset.UtcNow, - Duration = DateTimeOffset.UtcNow - (TestStart ?? DateTimeOffset.UtcNow), - Exception = null, - ComputerName = Environment.MachineName, - TestContext = this - }; - - InternalExecutableTest.State = state; - } + internal ConcurrentDictionary ObjectBag => _testBuilderContext.ObjectBag; internal AbstractExecutableTest InternalExecutableTest { get; set; } = null!; internal ConcurrentDictionary> TrackedObjects { get; } = []; - public DateTimeOffset? TestEnd { get; set; } - - public int CurrentRetryAttempt { get; internal set; } - - public IEnumerable GetTests(Func predicate) - { - var testFinder = ServiceProvider.GetService()!; - - // Get all tests from the current class and filter using the predicate - var classType = TestDetails?.ClassType; - if (classType == null) - { - return [ - ]; - } - - var tests = testFinder.GetTests(classType).Where(predicate).ToList(); - - if (tests.Any(x => x.Result == null)) - { - throw new InvalidOperationException( - "Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?" - ); - } - - return tests; - } - - public List GetTests(string testName) - { - var testFinder = ServiceProvider.GetService()!; - - // Use the current test's class type by default - var classType = TestDetails.ClassType; - - var tests = testFinder.GetTestsByNameAndParameters( - testName, - [ - ], - classType, - [ - ], - [ - ] - ).ToList(); - - if (tests.Any(x => x.Result == null)) - { - throw new InvalidOperationException( - "Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?" - ); - } - - return tests; - } - - public List GetTests(string testName, Type classType) - { - var testFinder = ServiceProvider.GetService()!; - - var tests = testFinder.GetTestsByNameAndParameters( - testName, - [ - ], - classType, - [ - ], - [ - ] - ).ToList(); - - if (tests.Any(x => x.Result == null)) - { - throw new InvalidOperationException( - "Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?" - ); - } - - return tests; - } } diff --git a/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs b/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs index 6aefd20244..97301e53f8 100644 --- a/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs +++ b/TUnit.Core/Tracking/TrackableObjectGraphProvider.cs @@ -11,7 +11,7 @@ public ConcurrentDictionary> GetTrackableObjects(TestContex { var visitedObjects = testContext.TrackedObjects; - var testDetails = testContext.TestDetails; + var testDetails = testContext.Metadata.TestDetails; foreach (var classArgument in testDetails.TestClassArguments) { diff --git a/TUnit.Engine.Tests/Attributes/SetDisplayNameWithClassAttribute.cs b/TUnit.Engine.Tests/Attributes/SetDisplayNameWithClassAttribute.cs index 75a739119d..b442a211b3 100644 --- a/TUnit.Engine.Tests/Attributes/SetDisplayNameWithClassAttribute.cs +++ b/TUnit.Engine.Tests/Attributes/SetDisplayNameWithClassAttribute.cs @@ -9,7 +9,7 @@ public class SetDisplayNameWithClassAttribute : Attribute, ITestDiscoveryEventRe public ValueTask OnTestDiscovered(DiscoveredTestContext context) { context.SetDisplayName( - $"{context.TestDetails.MethodMetadata.Class.Name}.{context.GetDisplayName()}"); + $"{context.TestContext.Metadata.TestDetails.MethodMetadata.Class.Name}.{context.TestContext.Metadata.DisplayName}"); return default(ValueTask); } } diff --git a/TUnit.Engine.Tests/InvokableTestBase.cs b/TUnit.Engine.Tests/InvokableTestBase.cs index a5b210f868..bc20a0e4a1 100644 --- a/TUnit.Engine.Tests/InvokableTestBase.cs +++ b/TUnit.Engine.Tests/InvokableTestBase.cs @@ -166,7 +166,7 @@ private async Task RunWithFailureLogging(Command command, string trxFilename, Li catch (Exception e) { throw new Exception($""" - Error asserting results for {TestContext.Current!.TestDetails.MethodMetadata.Class.Name}: {e.Message} + Error asserting results for {TestContext.Current!.Metadata.TestDetails.MethodMetadata.Class.Name}: {e.Message} $@"Mode: {testMode}", @$"Command Input: {command}", diff --git a/TUnit.Engine/Building/TestBuilder.cs b/TUnit.Engine/Building/TestBuilder.cs index 67b5472a0e..680512d4ae 100644 --- a/TUnit.Engine/Building/TestBuilder.cs +++ b/TUnit.Engine/Building/TestBuilder.cs @@ -751,9 +751,9 @@ private async Task GetDataSourcesAsync(IDataSourceAttrib // This includes property injection and IAsyncInitializer.InitializeAsync var initializedDataSource = await _dataSourceInitializer.EnsureInitializedAsync( dataSource, - dataGeneratorMetadata.TestBuilderContext?.Current.ObjectBag, + dataGeneratorMetadata.TestBuilderContext.Current.ObjectBag, dataGeneratorMetadata.TestInformation, - dataGeneratorMetadata.TestBuilderContext?.Current.Events); + dataGeneratorMetadata.TestBuilderContext.Current.Events); // Now get data rows from the initialized data source await foreach (var dataRow in initializedDataSource.GetDataRowsAsync(dataGeneratorMetadata)) @@ -776,7 +776,7 @@ public async Task BuildTestAsync(TestMetadata metadata, var context = await CreateTestContextAsync(testId, metadata, testData, testBuilderContext); - context.TestDetails.ClassInstance = PlaceholderInstance.Instance; + context.Metadata.TestDetails.ClassInstance = PlaceholderInstance.Instance; // Arguments will be tracked by TestArgumentTrackingService during TestRegistered event // This ensures proper reference counting for shared instances @@ -890,7 +890,7 @@ private async ValueTask CreateTestContextAsync(string testId, TestM testBuilderContext, CancellationToken.None); - context.TestDetails = testDetails; + context.Metadata.TestDetails = testDetails; return context; } @@ -929,7 +929,7 @@ private async Task InvokeTestRegisteredEventReceiversAsync(TestContext context) private async Task InvokeDiscoveryEventReceiversAsync(TestContext context) { var discoveredContext = new DiscoveredTestContext( - context.TestDetails.TestName, + context.Metadata.TestDetails.TestName, context); { @@ -1006,7 +1006,7 @@ private TestContext CreateFailedTestContext(TestMetadata metadata, TestDetails t }, CancellationToken.None); - context.TestDetails = testDetails; + context.Metadata.TestDetails = testDetails; return context; } diff --git a/TUnit.Engine/Building/TestBuilderPipeline.cs b/TUnit.Engine/Building/TestBuilderPipeline.cs index 1e0c0019ba..6c2312c760 100644 --- a/TUnit.Engine/Building/TestBuilderPipeline.cs +++ b/TUnit.Engine/Building/TestBuilderPipeline.cs @@ -184,7 +184,7 @@ private async Task GenerateDynamicTests(TestMetadata m CancellationToken.None); // Set the TestDetails on the context - context.TestDetails = testDetails; + context.Metadata.TestDetails = testDetails; // Invoke discovery event receivers to properly handle all attribute behaviors await InvokeDiscoveryEventReceiversAsync(context).ConfigureAwait(false); @@ -300,7 +300,7 @@ private async IAsyncEnumerable BuildTestsFromSingleMetad CancellationToken.None); // Set the TestDetails on the context - context.TestDetails = testDetails; + context.Metadata.TestDetails = testDetails; // Invoke discovery event receivers to properly handle all attribute behaviors await InvokeDiscoveryEventReceiversAsync(context).ConfigureAwait(false); @@ -372,7 +372,7 @@ private AbstractExecutableTest CreateFailedTestForDataGenerationError(TestMetada CreateTestBuilderContext(metadata), CancellationToken.None); - context.TestDetails = testDetails; + context.Metadata.TestDetails = testDetails; return new FailedExecutableTest(exception) @@ -424,7 +424,7 @@ private AbstractExecutableTest CreateFailedTestForGenericResolutionError(TestMet CreateTestBuilderContext(metadata), CancellationToken.None); - context.TestDetails = testDetails; + context.Metadata.TestDetails = testDetails; return new FailedExecutableTest(exception) { @@ -450,7 +450,7 @@ private AbstractExecutableTest CreateFailedTestForGenericResolutionError(TestMet private async Task InvokeDiscoveryEventReceiversAsync(TestContext context) { var discoveredContext = new DiscoveredTestContext( - context.TestDetails.TestName, + context.Metadata.TestDetails.TestName, context); await _eventReceiverOrchestrator.InvokeTestDiscoveryEventReceiversAsync(context, discoveredContext, CancellationToken.None).ConfigureAwait(false); diff --git a/TUnit.Engine/Discovery/ReflectionTestMetadata.cs b/TUnit.Engine/Discovery/ReflectionTestMetadata.cs index 4866d23e2e..02111b7f1d 100644 --- a/TUnit.Engine/Discovery/ReflectionTestMetadata.cs +++ b/TUnit.Engine/Discovery/ReflectionTestMetadata.cs @@ -52,7 +52,7 @@ async Task CreateInstance(TestContext testContext) // Otherwise fall back to creating instance normally // Try to create instance with ClassConstructor attribute - var attributes = testContext.TestDetails.GetAllAttributes(); + var attributes = testContext.Metadata.TestDetails.GetAllAttributes(); var classConstructorInstance = await ClassConstructorHelper.TryCreateInstanceWithClassConstructor( attributes, TestClassType, diff --git a/TUnit.Engine/Extensions/JsonExtensions.cs b/TUnit.Engine/Extensions/JsonExtensions.cs index 9b7461c9f1..b01e75aa5b 100644 --- a/TUnit.Engine/Extensions/JsonExtensions.cs +++ b/TUnit.Engine/Extensions/JsonExtensions.cs @@ -52,7 +52,7 @@ public static TestClassJson ToJsonModel(this ClassHookContext context) public static TestJson ToJsonModel(this TestContext context) { - var testDetails = context.TestDetails; + var testDetails = context.Metadata.TestDetails; if (testDetails == null) { throw new InvalidOperationException("TestDetails is null"); @@ -84,13 +84,13 @@ public static TestJson ToJsonModel(this TestContext context) { Categories = testDetails.Categories, ClassType = testDetails.MethodMetadata.Class.Type.FullName ?? testDetails.ClassType.FullName ?? "Unknown", - Result = context.Result?.ToJsonModel(), + Result = context.Execution.Result?.ToJsonModel(), Timeout = testDetails.Timeout, CustomProperties = testDetails.CustomProperties.ToDictionary( kvp => kvp.Key, kvp => (IReadOnlyList) kvp.Value.AsReadOnly()), DisplayName = context.GetDisplayName(), - ObjectBag = context.ObjectBag, + ObjectBag = context.StateBag.Items, RetryLimit = testDetails.RetryLimit, ReturnType = testDetails.ReturnType?.FullName ?? "void", TestId = testDetails.TestId, diff --git a/TUnit.Engine/Extensions/TestContextExtensions.cs b/TUnit.Engine/Extensions/TestContextExtensions.cs index c7fe2d3dcb..aceb5accd7 100644 --- a/TUnit.Engine/Extensions/TestContextExtensions.cs +++ b/TUnit.Engine/Extensions/TestContextExtensions.cs @@ -8,11 +8,11 @@ internal static class TestContextExtensions [ testContext.ClassConstructor, testContext.Events, - ..testContext.TestDetails.TestClassArguments, - testContext.TestDetails.ClassInstance, - ..testContext.TestDetails.GetAllAttributes(), - ..testContext.TestDetails.TestMethodArguments, - ..testContext.TestDetails.TestClassInjectedPropertyArguments.Select(x => x.Value), + ..testContext.Metadata.TestDetails.TestClassArguments, + testContext.Metadata.TestDetails.ClassInstance, + ..testContext.Metadata.TestDetails.GetAllAttributes(), + ..testContext.Metadata.TestDetails.TestMethodArguments, + ..testContext.Metadata.TestDetails.TestClassInjectedPropertyArguments.Select(x => x.Value), ]; public static IEnumerable GetEligibleEventObjects(this TestContext testContext) diff --git a/TUnit.Engine/Extensions/TestExtensions.cs b/TUnit.Engine/Extensions/TestExtensions.cs index 0b7df1b17b..0d944ea576 100644 --- a/TUnit.Engine/Extensions/TestExtensions.cs +++ b/TUnit.Engine/Extensions/TestExtensions.cs @@ -9,7 +9,7 @@ internal static class TestExtensions { internal static TestNode ToTestNode(this TestContext testContext) { - var testDetails = testContext.TestDetails ?? throw new ArgumentNullException(nameof(testContext.TestDetails)); + var testDetails = testContext.Metadata.TestDetails ?? throw new ArgumentNullException(nameof(testContext.Metadata.TestDetails)); var testNode = new TestNode { diff --git a/TUnit.Engine/Services/HookCollectionService.cs b/TUnit.Engine/Services/HookCollectionService.cs index eec9d45b23..57ecd0b633 100644 --- a/TUnit.Engine/Services/HookCollectionService.cs +++ b/TUnit.Engine/Services/HookCollectionService.cs @@ -640,12 +640,12 @@ private async Task> CreateInstanceHoo var customExecutor = context.CustomHookExecutor; // Skip skipped test instances - if (context.TestDetails.ClassInstance is SkippedTestInstance) + if (context.Metadata.TestDetails.ClassInstance is SkippedTestInstance) { return; } - if (context.TestDetails.ClassInstance is PlaceholderInstance) + if (context.Metadata.TestDetails.ClassInstance is PlaceholderInstance) { throw new InvalidOperationException($"Cannot execute instance hook {hook.Name} because the test instance has not been created yet. This is likely a framework bug."); } @@ -653,7 +653,7 @@ private async Task> CreateInstanceHoo await customExecutor.ExecuteBeforeTestHook( hook.MethodInfo, context, - () => hook.Body!.Invoke(context.TestDetails.ClassInstance, context, cancellationToken) + () => hook.Body!.Invoke(context.Metadata.TestDetails.ClassInstance, context, cancellationToken) ); } else diff --git a/TUnit.Engine/Services/PropertyDataResolver.cs b/TUnit.Engine/Services/PropertyDataResolver.cs index d16889d07a..d3a2c30e2f 100644 --- a/TUnit.Engine/Services/PropertyDataResolver.cs +++ b/TUnit.Engine/Services/PropertyDataResolver.cs @@ -139,7 +139,7 @@ private static DataGeneratorMetadata CreateDataGeneratorMetadata( context.MethodMetadata, dataSource, context.TestContext, - context.TestContext?.TestDetails.ClassInstance, + context.TestContext?.Metadata.TestDetails.ClassInstance, context.Events, context.ObjectBag); } diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs index 248ab7d66c..afb59dd889 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/ReflectionPropertyStrategy.cs @@ -50,7 +50,7 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) object? resolvedValue = null; // Check if property was pre-resolved during registration - if (context.TestContext?.TestDetails.TestClassInjectedPropertyArguments.TryGetValue(context.PropertyName, out resolvedValue) == true) + if (context.TestContext?.Metadata.TestDetails.TestClassInjectedPropertyArguments.TryGetValue(context.PropertyName, out resolvedValue) == true) { // Use pre-resolved value - it was already initialized during first resolution context.ResolvedValue = resolvedValue; @@ -72,9 +72,9 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) context.PropertySetter(context.Instance, resolvedValue); // Step 4: Add to test context tracking (if not already there) - if (context.TestContext != null && !context.TestContext.TestDetails.TestClassInjectedPropertyArguments.ContainsKey(context.PropertyName)) + if (context.TestContext != null && !context.TestContext.Metadata.TestDetails.TestClassInjectedPropertyArguments.ContainsKey(context.PropertyName)) { - context.TestContext.TestDetails.TestClassInjectedPropertyArguments[context.PropertyName] = resolvedValue; + context.TestContext.Metadata.TestDetails.TestClassInjectedPropertyArguments[context.PropertyName] = resolvedValue; } } diff --git a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs index 92752ca513..d6625d44d0 100644 --- a/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs +++ b/TUnit.Engine/Services/PropertyInitialization/Strategies/SourceGeneratedPropertyStrategy.cs @@ -42,7 +42,7 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) object? resolvedValue = null; // Check if property was pre-resolved during registration - if (context.TestContext?.TestDetails.TestClassInjectedPropertyArguments.TryGetValue(context.PropertyName, out resolvedValue) == true) + if (context.TestContext?.Metadata.TestDetails.TestClassInjectedPropertyArguments.TryGetValue(context.PropertyName, out resolvedValue) == true) { // Use pre-resolved value - it was already initialized during first resolution context.ResolvedValue = resolvedValue; @@ -60,9 +60,9 @@ public async Task InitializePropertyAsync(PropertyInitializationContext context) context.SourceGeneratedMetadata.SetProperty(context.Instance, resolvedValue); - if (context.TestContext != null && !context.TestContext.TestDetails.TestClassInjectedPropertyArguments.ContainsKey(context.PropertyName)) + if (context.TestContext != null && !context.TestContext.Metadata.TestDetails.TestClassInjectedPropertyArguments.ContainsKey(context.PropertyName)) { - context.TestContext.TestDetails.TestClassInjectedPropertyArguments[context.PropertyName] = resolvedValue; + context.TestContext.Metadata.TestDetails.TestClassInjectedPropertyArguments[context.PropertyName] = resolvedValue; } } diff --git a/TUnit.Engine/Services/TestArgumentRegistrationService.cs b/TUnit.Engine/Services/TestArgumentRegistrationService.cs index e015a0ef1d..89cac70f2a 100644 --- a/TUnit.Engine/Services/TestArgumentRegistrationService.cs +++ b/TUnit.Engine/Services/TestArgumentRegistrationService.cs @@ -38,21 +38,21 @@ public TestArgumentRegistrationService(ObjectRegistrationService objectRegistrat public async ValueTask OnTestRegistered(TestRegisteredContext context) { var testContext = context.TestContext; - var classArguments = testContext.TestDetails.TestClassArguments; - var methodArguments = testContext.TestDetails.TestMethodArguments; + var classArguments = testContext.Metadata.TestDetails.TestClassArguments; + var methodArguments = testContext.Metadata.TestDetails.TestMethodArguments; // Register class arguments (registration phase - property injection + tracking, NO IAsyncInitializer) await _objectRegistrationService.RegisterArgumentsAsync( classArguments, - testContext.ObjectBag, - testContext.TestDetails.MethodMetadata, + testContext.StateBag.Items, + testContext.Metadata.TestDetails.MethodMetadata, testContext.Events); // Register method arguments (registration phase) await _objectRegistrationService.RegisterArgumentsAsync( methodArguments, - testContext.ObjectBag, - testContext.TestDetails.MethodMetadata, + testContext.StateBag.Items, + testContext.Metadata.TestDetails.MethodMetadata, testContext.Events); // Register properties that will be injected into the test class @@ -70,7 +70,7 @@ private async ValueTask RegisterPropertiesAsync(TestContext testContext) { try { - var classType = testContext.TestDetails.ClassType; + var classType = testContext.Metadata.TestDetails.ClassType; // Get the property source for the class var propertySource = PropertySourceRegistry.GetSource(classType); @@ -93,21 +93,21 @@ private async ValueTask RegisterPropertiesAsync(TestContext testContext) // Create minimal DataGeneratorMetadata for property resolution during registration var testBuilderContext = new TestBuilderContext { - TestMetadata = testContext.TestDetails.MethodMetadata, + TestMetadata = testContext.Metadata.TestDetails.MethodMetadata, DataSourceAttribute = dataSource, Events = testContext.Events, - ObjectBag = testContext.ObjectBag + ObjectBag = testContext.StateBag.Items }; var dataGenMetadata = new DataGeneratorMetadata { TestBuilderContext = new TestBuilderContextAccessor(testBuilderContext), MembersToGenerate = [], // Properties don't use member generation - TestInformation = testContext.TestDetails.MethodMetadata, + TestInformation = testContext.Metadata.TestDetails.MethodMetadata, Type = DataGeneratorType.Property, TestSessionId = TestSessionContext.Current?.Id ?? "registration", TestClassInstance = null, // Not available during registration - ClassInstanceArguments = testContext.TestDetails.TestClassArguments + ClassInstanceArguments = testContext.Metadata.TestDetails.TestClassArguments }; // Get the data rows from the data source @@ -124,14 +124,14 @@ private async ValueTask RegisterPropertiesAsync(TestContext testContext) if (data != null) { // Store for later injection - testContext.TestDetails.TestClassInjectedPropertyArguments[metadata.PropertyName] = data; + testContext.Metadata.TestDetails.TestClassInjectedPropertyArguments[metadata.PropertyName] = data; // Register the ClassDataSource instance during registration phase // This does: property injection + tracking (NO IAsyncInitializer - deferred to execution) await _objectRegistrationService.RegisterObjectAsync( data, - testContext.ObjectBag, - testContext.TestDetails.MethodMetadata, + testContext.StateBag.Items, + testContext.Metadata.TestDetails.MethodMetadata, testContext.Events); } } @@ -152,7 +152,7 @@ await _objectRegistrationService.RegisterObjectAsync( { // Capture any top-level exceptions (e.g., getting property source) and re-throw // The test building process will handle marking it as failed - var exceptionMessage = $"Failed to register properties for test '{testContext.TestDetails.TestName}': {ex.Message}"; + var exceptionMessage = $"Failed to register properties for test '{testContext.Metadata.TestDetails.TestName}': {ex.Message}"; var registrationException = new InvalidOperationException(exceptionMessage, ex); throw registrationException; } diff --git a/TUnit.Engine/Services/TestDependencyResolver.cs b/TUnit.Engine/Services/TestDependencyResolver.cs index 803fb4d4ba..2c4c83bbf5 100644 --- a/TUnit.Engine/Services/TestDependencyResolver.cs +++ b/TUnit.Engine/Services/TestDependencyResolver.cs @@ -59,7 +59,7 @@ public bool TryResolveDependencies(AbstractExecutableTest test) { return true; } - + return ResolveDependenciesForTest(test); } } @@ -75,7 +75,7 @@ private bool ResolveDependenciesForTest(AbstractExecutableTest test) { var resolvedDependencies = new List(); var allResolved = true; - + foreach (var dependencyMetadata in test.Metadata.Dependencies) { var matchingTests = FindMatchingTests(dependencyMetadata, test); @@ -97,7 +97,7 @@ private bool ResolveDependenciesForTest(AbstractExecutableTest test) } } } - + if (allResolved) { var uniqueDependencies = new Dictionary(capacity: 8); @@ -107,20 +107,20 @@ private bool ResolveDependenciesForTest(AbstractExecutableTest test) { continue; } - + if (!uniqueDependencies.ContainsKey(dep.Test)) { uniqueDependencies[dep.Test] = dep; } } - + test.Dependencies = uniqueDependencies.Values.ToArray(); - + _testsWithPendingDependencies.Remove(test); - + return true; } - + return false; } finally @@ -128,13 +128,13 @@ private bool ResolveDependenciesForTest(AbstractExecutableTest test) _testsBeingResolved.Remove(test); } } - + private List FindMatchingTests(TestDependency dependency, AbstractExecutableTest dependentTest) { var matches = new List(); - + IEnumerable searchScope; - + if (dependency.ClassType != null && string.IsNullOrEmpty(dependency.MethodName)) { if (_testsByType.TryGetValue(dependency.ClassType, out var testsInType)) @@ -161,7 +161,7 @@ private List FindMatchingTests(TestDependency dependency { searchScope = _allTests; } - + foreach (var test in searchScope) { if (dependency.Matches(test.Metadata, dependentTest.Metadata)) @@ -169,14 +169,14 @@ private List FindMatchingTests(TestDependency dependency matches.Add(test); } } - + return matches; } - + private void ResolvePendingDependencies() { var pendingTests = _testsWithPendingDependencies.ToList(); - + foreach (var test in pendingTests) { if (test.Dependencies.Length > 0) @@ -184,11 +184,11 @@ private void ResolvePendingDependencies() _testsWithPendingDependencies.Remove(test); continue; } - + ResolveDependenciesForTest(test); } } - + public void ResolveAllDependencies() { lock (_resolutionLock) @@ -200,13 +200,13 @@ public void ResolveAllDependencies() ResolveDependenciesForTest(test); } } - + var maxRetries = 3; for (var retry = 0; retry < maxRetries && _testsWithPendingDependencies.Count > 0; retry++) { ResolvePendingDependencies(); } - + if (_testsWithPendingDependencies.Count > 0) { foreach (var test in _testsWithPendingDependencies) @@ -216,13 +216,13 @@ public void ResolveAllDependencies() } } } - - + + public IReadOnlyList GetTransitiveDependencies(TestDetails testDetails) { var visited = new HashSet(); var result = new List(); - + void CollectDependencies(TestDetails current) { if (!visited.Add(current)) @@ -240,13 +240,13 @@ void CollectDependencies(TestDetails current) { foreach (var dep in test.Dependencies) { - var depDetails = dep.Test.Context.TestDetails; + var depDetails = dep.Test.Context.Metadata.TestDetails; result.Add(depDetails); CollectDependencies(depDetails); } } } - + CollectDependencies(testDetails); return result; } @@ -266,4 +266,4 @@ private static void CreateDependencyResolutionFailedResult(AbstractExecutableTes ComputerName = Environment.MachineName }; } -} \ No newline at end of file +} diff --git a/TUnit.Engine/Services/TestExecution/RetryHelper.cs b/TUnit.Engine/Services/TestExecution/RetryHelper.cs index d9f7cb8919..1437dac232 100644 --- a/TUnit.Engine/Services/TestExecution/RetryHelper.cs +++ b/TUnit.Engine/Services/TestExecution/RetryHelper.cs @@ -6,7 +6,7 @@ internal static class RetryHelper { public static async Task ExecuteWithRetry(TestContext testContext, Func action) { - var maxRetries = testContext.TestDetails.RetryLimit; + var maxRetries = testContext.Metadata.TestDetails.RetryLimit; for (var attempt = 0; attempt < maxRetries + 1; attempt++) { @@ -27,9 +27,9 @@ public static async Task ExecuteWithRetry(TestContext testContext, Func ac if (await ShouldRetry(testContext, ex, attempt)) { // Clear the previous result before retrying - testContext.Result = null; + testContext.Execution.Result = null; testContext.TestStart = null; - testContext.TestEnd = null; + testContext.Execution.TestEnd = null; continue; } @@ -40,7 +40,7 @@ public static async Task ExecuteWithRetry(TestContext testContext, Func ac private static async Task ShouldRetry(TestContext testContext, Exception ex, int attempt) { - if (attempt >= testContext.TestDetails.RetryLimit) + if (attempt >= testContext.Metadata.TestDetails.RetryLimit) { return false; } diff --git a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs index 819fcf28c5..ea413cd0a0 100644 --- a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs +++ b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs @@ -65,9 +65,9 @@ private async Task ExecuteTestInternalAsync(AbstractExecutableTest test, Cancell _contextRestorer.RestoreContext(test); // Clear Result and timing from any previous execution (important for repeated tests) - test.Context.Result = null; + test.Context.Execution.Result = null; test.Context.TestStart = null; - test.Context.TestEnd = null; + test.Context.Execution.TestEnd = null; TestContext.Current = test.Context; @@ -94,13 +94,13 @@ private async Task ExecuteTestInternalAsync(AbstractExecutableTest test, Cancell // Execute test with retry logic - each retry gets a fresh instance await RetryHelper.ExecuteWithRetry(test.Context, async () => { - test.Context.TestDetails.ClassInstance = await test.CreateInstanceAsync(); + test.Context.Metadata.TestDetails.ClassInstance = await test.CreateInstanceAsync(); // Invalidate cached eligible event objects since ClassInstance changed test.Context.CachedEligibleEventObjects = null; // Check if this test should be skipped (after creating instance) - if (test.Context.TestDetails.ClassInstance is SkippedTestInstance || + if (test.Context.Metadata.TestDetails.ClassInstance is SkippedTestInstance || !string.IsNullOrEmpty(test.Context.SkipReason)) { await _stateManager.MarkSkippedAsync(test, test.Context.SkipReason ?? "Test was skipped"); @@ -245,7 +245,7 @@ await _eventReceiverOrchestrator.InvokeLastTestInSessionEventReceiversAsync( break; case TestState.Timeout: case TestState.Failed: - await _messageBus.Failed(test.Context, test.Context.Result?.Exception!, test.StartTime.GetValueOrDefault()); + await _messageBus.Failed(test.Context, test.Context.Execution.Result?.Exception!, test.StartTime.GetValueOrDefault()); break; case TestState.Skipped: await _messageBus.Skipped(test.Context, test.Context.SkipReason ?? "Skipped"); @@ -269,7 +269,7 @@ private void CollectAllDependencies(AbstractExecutableTest test, HashSet await test.InvokeTestAsync(test.Context.TestDetails.ClassInstance, cancellationToken)) + async () => await test.InvokeTestAsync(test.Context.Metadata.TestDetails.ClassInstance, cancellationToken)) .ConfigureAwait(false); } else { - await test.InvokeTestAsync(test.Context.TestDetails.ClassInstance, cancellationToken) + await test.InvokeTestAsync(test.Context.Metadata.TestDetails.ClassInstance, cancellationToken) .ConfigureAwait(false); } } diff --git a/TUnit.Engine/Services/TestExecution/TestStateManager.cs b/TUnit.Engine/Services/TestExecution/TestStateManager.cs index 31ad555a33..bfb0ef6486 100644 --- a/TUnit.Engine/Services/TestExecution/TestStateManager.cs +++ b/TUnit.Engine/Services/TestExecution/TestStateManager.cs @@ -39,10 +39,10 @@ public Task MarkCompletedAsync(AbstractExecutableTest test) public Task MarkFailedAsync(AbstractExecutableTest test, Exception exception) { // Check if result has been overridden - if so, respect the override - if (test.Context.Result?.IsOverridden == true) + if (test.Context.Execution.Result?.IsOverridden == true) { - test.State = test.Context.Result.State; - test.EndTime = test.Context.Result.End ?? DateTimeOffset.UtcNow; + test.State = test.Context.Execution.Result.State; + test.EndTime = test.Context.Execution.Result.End ?? DateTimeOffset.UtcNow; } else { diff --git a/TUnit.Engine/Services/TestFilterService.cs b/TUnit.Engine/Services/TestFilterService.cs index af261cd7e9..ee091095fd 100644 --- a/TUnit.Engine/Services/TestFilterService.cs +++ b/TUnit.Engine/Services/TestFilterService.cs @@ -134,7 +134,7 @@ private string BuildPath(AbstractExecutableTest test) var metadata = test.Metadata; - var classMetadata = test.Context.TestDetails.MethodMetadata.Class; + var classMetadata = test.Context.Metadata.TestDetails.MethodMetadata.Class; var assemblyName = classMetadata.Assembly.Name ?? metadata.TestClassType.Assembly.GetName().Name ?? "*"; var namespaceName = classMetadata.Namespace ?? "*"; var classTypeName = classMetadata.Name; @@ -182,18 +182,18 @@ private PropertyBag BuildPropertyBag(AbstractExecutableTest test) } // Pre-calculate capacity: 2 properties per category + custom properties - var categoryCount = test.Context.TestDetails.Categories.Count; - var customPropCount = test.Context.TestDetails.CustomProperties.Sum(p => p.Value.Count); + var categoryCount = test.Context.Metadata.TestDetails.Categories.Count; + var customPropCount = test.Context.Metadata.TestDetails.CustomProperties.Sum(p => p.Value.Count); var properties = new List(categoryCount * 2 + customPropCount); - foreach (var category in test.Context.TestDetails.Categories) + foreach (var category in test.Context.Metadata.TestDetails.Categories) { properties.Add(new TestMetadataProperty(category)); properties.Add(new TestMetadataProperty("Category", category)); } // Replace LINQ with manual loop for better performance in hot path - foreach (var propertyEntry in test.Context.TestDetails.CustomProperties) + foreach (var propertyEntry in test.Context.Metadata.TestDetails.CustomProperties) { foreach (var value in propertyEntry.Value) { @@ -211,12 +211,12 @@ private PropertyBag BuildPropertyBag(AbstractExecutableTest test) private bool IsExplicitTest(AbstractExecutableTest test) { - if (test.Context.TestDetails.HasAttribute()) + if (test.Context.Metadata.TestDetails.HasAttribute()) { return true; } - var testClassType = test.Context.TestDetails.ClassType; + var testClassType = test.Context.Metadata.TestDetails.ClassType; return testClassType.GetCustomAttributes(typeof(ExplicitAttribute), true).Length > 0; } diff --git a/TUnit.Engine/Services/TestFinder.cs b/TUnit.Engine/Services/TestFinder.cs index e7b067a13c..bd96c1974c 100644 --- a/TUnit.Engine/Services/TestFinder.cs +++ b/TUnit.Engine/Services/TestFinder.cs @@ -38,8 +38,8 @@ private void EnsureIndexesBuilt() continue; } - var classType = test.TestDetails.ClassType; - var testName = test.TestDetails.TestName; + var classType = test.Metadata.TestDetails.ClassType; + var testName = test.Metadata.TestDetails.TestName; // Index by type if (!testsByType.TryGetValue(classType, out var testsForType)) @@ -161,7 +161,7 @@ private bool ClassParametersMatch(TestContext context, Type[] classParamTypes, I argCount = classArguments.Count(); } - var actualArgCount = context.TestDetails?.TestClassArguments?.Length ?? 0; + var actualArgCount = context.Metadata.TestDetails?.TestClassArguments?.Length ?? 0; return argCount == actualArgCount; } } diff --git a/TUnit.Engine/Services/TestRegistry.cs b/TUnit.Engine/Services/TestRegistry.cs index 98cfa207af..a1538e5e98 100644 --- a/TUnit.Engine/Services/TestRegistry.cs +++ b/TUnit.Engine/Services/TestRegistry.cs @@ -122,7 +122,7 @@ public async Task CreateTestVariant( TUnit.Core.Enums.TestRelationship relationship, string? displayName) { - var testDetails = currentContext.TestDetails; + var testDetails = currentContext.Metadata.TestDetails; var testClassType = testDetails.ClassType; var variantMethodArguments = arguments ?? testDetails.TestMethodArguments; @@ -202,7 +202,7 @@ public async Task CreateTestVariant( } var lambda = Expression.Lambda>(body, parameter); - var attributes = new List(currentContext.TestDetails.GetAllAttributes()); + var attributes = new List(currentContext.Metadata.TestDetails.GetAllAttributes()); var discoveryResult = new DynamicDiscoveryResult { @@ -211,9 +211,9 @@ public async Task CreateTestVariant( TestMethodArguments = variantMethodArguments, TestMethod = lambda, Attributes = attributes, - CreatorFilePath = currentContext.TestDetails.TestFilePath, - CreatorLineNumber = currentContext.TestDetails.TestLineNumber, - ParentTestId = currentContext.TestDetails.TestId, + CreatorFilePath = currentContext.Metadata.TestDetails.TestFilePath, + CreatorLineNumber = currentContext.Metadata.TestDetails.TestLineNumber, + ParentTestId = currentContext.Metadata.TestDetails.TestId, Relationship = relationship, Properties = properties, DisplayName = displayName @@ -380,7 +380,7 @@ public override Func= testContext.TestDetails.Timeout.Value) + && duration >= testContext.Metadata.TestDetails.Timeout.Value) { - return new TimeoutTestNodeStateProperty($"Test timed out after {testContext.TestDetails.Timeout.Value.TotalMilliseconds}ms"); + return new TimeoutTestNodeStateProperty($"Test timed out after {testContext.Metadata.TestDetails.Timeout.Value.TotalMilliseconds}ms"); } if (e.GetType().Name.Contains("Assertion", StringComparison.InvariantCulture)) diff --git a/TUnit.Engine/TestExecutor.cs b/TUnit.Engine/TestExecutor.cs index 19d60c4c55..bde883ffac 100644 --- a/TUnit.Engine/TestExecutor.cs +++ b/TUnit.Engine/TestExecutor.cs @@ -98,9 +98,9 @@ await _eventReceiverOrchestrator.InvokeFirstTestInClassEventReceiversAsync( executableTest.Context.RestoreExecutionContext(); // Only wrap the actual test execution with timeout, not the hooks - var testTimeout = executableTest.Context.TestDetails.Timeout; + var testTimeout = executableTest.Context.Metadata.TestDetails.Timeout; var timeoutMessage = testTimeout.HasValue - ? $"Test '{executableTest.Context.TestDetails.TestName}' execution timed out after {testTimeout.Value}" + ? $"Test '{executableTest.Context.Metadata.TestDetails.TestName}' execution timed out after {testTimeout.Value}" : null; await TimeoutHelper.ExecuteWithTimeoutAsync( @@ -134,7 +134,7 @@ await TimeoutHelper.ExecuteWithTimeoutAsync( } // Check if the result was overridden - if so, don't re-throw - if (executableTest.Context.Result is { IsOverridden: true, State: TestState.Passed }) + if (executableTest.Context.Execution.Result is { IsOverridden: true, State: TestState.Passed }) { // Result was overridden to passed, don't re-throw the exception executableTest.SetResult(TestState.Passed); @@ -162,7 +162,7 @@ await TimeoutHelper.ExecuteWithTimeoutAsync( private static async Task ExecuteTestAsync(AbstractExecutableTest executableTest, CancellationToken cancellationToken) { // Skip the actual test invocation for skipped tests - if (executableTest.Context.TestDetails.ClassInstance is SkippedTestInstance || + if (executableTest.Context.Metadata.TestDetails.ClassInstance is SkippedTestInstance || !string.IsNullOrEmpty(executableTest.Context.SkipReason)) { return; @@ -174,11 +174,11 @@ private static async Task ExecuteTestAsync(AbstractExecutableTest executableTest if (executableTest.Context.InternalDiscoveredTest?.TestExecutor is { } testExecutor) { await testExecutor.ExecuteTest(executableTest.Context, - async () => await executableTest.InvokeTestAsync(executableTest.Context.TestDetails.ClassInstance, cancellationToken)).ConfigureAwait(false); + async () => await executableTest.InvokeTestAsync(executableTest.Context.Metadata.TestDetails.ClassInstance, cancellationToken)).ConfigureAwait(false); } else { - await executableTest.InvokeTestAsync(executableTest.Context.TestDetails.ClassInstance, cancellationToken).ConfigureAwait(false); + await executableTest.InvokeTestAsync(executableTest.Context.Metadata.TestDetails.ClassInstance, cancellationToken).ConfigureAwait(false); } } @@ -241,11 +241,11 @@ public IContextProvider GetContextProvider() internal static async Task DisposeTestInstance(AbstractExecutableTest test) { // Dispose the test instance if it's disposable - if (test.Context.TestDetails.ClassInstance is not SkippedTestInstance) + if (test.Context.Metadata.TestDetails.ClassInstance is not SkippedTestInstance) { try { - var instance = test.Context.TestDetails.ClassInstance; + var instance = test.Context.Metadata.TestDetails.ClassInstance; switch (instance) { diff --git a/TUnit.Engine/TestInitializer.cs b/TUnit.Engine/TestInitializer.cs index db6117b5a8..914456581c 100644 --- a/TUnit.Engine/TestInitializer.cs +++ b/TUnit.Engine/TestInitializer.cs @@ -23,12 +23,12 @@ public TestInitializer(EventReceiverOrchestrator eventReceiverOrchestrator, public async Task InitializeTest(AbstractExecutableTest test, CancellationToken cancellationToken) { - var testClassInstance = test.Context.TestDetails.ClassInstance; + var testClassInstance = test.Context.Metadata.TestDetails.ClassInstance; await _propertyInjectionService.InjectPropertiesIntoObjectAsync( testClassInstance, - test.Context.ObjectBag, - test.Context.TestDetails.MethodMetadata, + test.Context.StateBag.Items, + test.Context.Metadata.TestDetails.MethodMetadata, test.Context.Events); _eventReceiverOrchestrator.RegisterReceivers(test.Context, cancellationToken); @@ -51,6 +51,6 @@ private async Task InitializeTrackedObjects(TestContext testContext) } // Finally, ensure the test class itself is initialized - await ObjectInitializer.InitializeAsync(testContext.TestDetails.ClassInstance); + await ObjectInitializer.InitializeAsync(testContext.Metadata.TestDetails.ClassInstance); } } diff --git a/TUnit.Playwright/PlaywrightSkipAttribute.cs b/TUnit.Playwright/PlaywrightSkipAttribute.cs index abb8136dc6..e60eace3b3 100644 --- a/TUnit.Playwright/PlaywrightSkipAttribute.cs +++ b/TUnit.Playwright/PlaywrightSkipAttribute.cs @@ -32,7 +32,7 @@ public PlaywrightSkipAttribute(params Targets[] combinations) : base("Skipped by public override Task ShouldSkip(TestRegisteredContext context) { - var browserName = GetBrowserName(context.TestDetails); + var browserName = GetBrowserName(context.TestContext.Metadata.TestDetails); return Task.FromResult(_combinations.Any(combination => { diff --git a/TUnit.Playwright/WorkerAwareTest.cs b/TUnit.Playwright/WorkerAwareTest.cs index 2291ce1616..d83475c10c 100644 --- a/TUnit.Playwright/WorkerAwareTest.cs +++ b/TUnit.Playwright/WorkerAwareTest.cs @@ -66,7 +66,7 @@ public async Task WorkerTeardown(TestContext testContext) protected bool TestOk(TestContext testContext) { - return testContext.Result?.State is TestState.Passed or TestState.Skipped; + return testContext.Execution.Result?.State is TestState.Passed or TestState.Skipped; } public ValueTask OnTestRegistered(TestRegisteredContext context) diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt index 1ea6d22961..89f8aef8ae 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt @@ -1265,53 +1265,23 @@ namespace public class TestContext : .Context, ., ., ., ., ., ., . { public TestContext(string testName, serviceProvider, .ClassHookContext classContext, .TestBuilderContext testBuilderContext, .CancellationToken cancellationToken) { } - public .<.Artifact> Artifacts { get; } - public .CancellationToken CancellationToken { get; set; } public .ClassHookContext ClassContext { get; } - public int CurrentRetryAttempt { get; } - public .? CustomHookExecutor { get; set; } public . Dependencies { get; } - public ? DisplayNameFormatter { get; set; } - public .TestContextEvents Events { get; } public . Execution { get; } public Id { get; } - public .CancellationTokenSource? LinkedCancellationTokens { get; set; } public object Lock { get; } public . Metadata { get; } - public . ObjectBag { get; } public . Output { get; } public . Parallelism { get; } - public string? ParentTestId { get; set; } - public .TestPhase Phase { get; set; } - public . Relationship { get; set; } - public bool ReportResult { get; set; } - public .TestResult? Result { get; set; } - public <.TestContext, , int, .>? RetryFunc { get; set; } public Services { get; } - public string? SkipReason { get; set; } public . StateBag { get; } - public .TestDetails TestDetails { get; set; } - public ? TestEnd { get; set; } - public ? TestStart { get; set; } - public .<.Timing> Timings { get; } public static . Configuration { get; } public new static .TestContext? Current { get; } public static string? OutputDirectory { get; } public static .> Parameters { get; } public static string WorkingDirectory { get; set; } - public void AddLinkedCancellationToken(.CancellationToken cancellationToken) { } - public string GetDisplayName() { } - public new string GetErrorOutput() { } - public string GetOutput() { } public T? GetService() where T : class { } - public .<.TestContext> GetTests(<.TestContext, bool> predicate) { } - public .<.TestContext> GetTests(string testName) { } - public .<.TestContext> GetTests(string testName, classType) { } - public void OverrideResult(string reason) { } - public void OverrideResult(.TestState state, string reason) { } - public void WriteError(string message) { } - public void WriteLine(string message) { } public static .TestContext? GetById( id) { } } public class TestContextEvents @@ -2450,7 +2420,7 @@ namespace .Interfaces } public interface ITestStateBag { - . Bag { get; } + . Items { get; } } public interface ITypedTestMetadata { diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt index 11e912817a..3b5e11f8a7 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -1265,53 +1265,23 @@ namespace public class TestContext : .Context, ., ., ., ., ., ., . { public TestContext(string testName, serviceProvider, .ClassHookContext classContext, .TestBuilderContext testBuilderContext, .CancellationToken cancellationToken) { } - public .<.Artifact> Artifacts { get; } - public .CancellationToken CancellationToken { get; set; } public .ClassHookContext ClassContext { get; } - public int CurrentRetryAttempt { get; } - public .? CustomHookExecutor { get; set; } public . Dependencies { get; } - public ? DisplayNameFormatter { get; set; } - public .TestContextEvents Events { get; } public . Execution { get; } public Id { get; } - public .CancellationTokenSource? LinkedCancellationTokens { get; set; } public object Lock { get; } public . Metadata { get; } - public . ObjectBag { get; } public . Output { get; } public . Parallelism { get; } - public string? ParentTestId { get; set; } - public .TestPhase Phase { get; set; } - public . Relationship { get; set; } - public bool ReportResult { get; set; } - public .TestResult? Result { get; set; } - public <.TestContext, , int, .>? RetryFunc { get; set; } public Services { get; } - public string? SkipReason { get; set; } public . StateBag { get; } - public .TestDetails TestDetails { get; set; } - public ? TestEnd { get; set; } - public ? TestStart { get; set; } - public .<.Timing> Timings { get; } public static . Configuration { get; } public new static .TestContext? Current { get; } public static string? OutputDirectory { get; } public static .> Parameters { get; } public static string WorkingDirectory { get; set; } - public void AddLinkedCancellationToken(.CancellationToken cancellationToken) { } - public string GetDisplayName() { } - public new string GetErrorOutput() { } - public string GetOutput() { } public T? GetService() where T : class { } - public .<.TestContext> GetTests(<.TestContext, bool> predicate) { } - public .<.TestContext> GetTests(string testName) { } - public .<.TestContext> GetTests(string testName, classType) { } - public void OverrideResult(string reason) { } - public void OverrideResult(.TestState state, string reason) { } - public void WriteError(string message) { } - public void WriteLine(string message) { } public static .TestContext? GetById( id) { } } public class TestContextEvents @@ -2450,7 +2420,7 @@ namespace .Interfaces } public interface ITestStateBag { - . Bag { get; } + . Items { get; } } public interface ITypedTestMetadata { diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt index c512a750dd..f18ebe2c0f 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -1265,53 +1265,23 @@ namespace public class TestContext : .Context, ., ., ., ., ., ., . { public TestContext(string testName, serviceProvider, .ClassHookContext classContext, .TestBuilderContext testBuilderContext, .CancellationToken cancellationToken) { } - public .<.Artifact> Artifacts { get; } - public .CancellationToken CancellationToken { get; set; } public .ClassHookContext ClassContext { get; } - public int CurrentRetryAttempt { get; } - public .? CustomHookExecutor { get; set; } public . Dependencies { get; } - public ? DisplayNameFormatter { get; set; } - public .TestContextEvents Events { get; } public . Execution { get; } public Id { get; } - public .CancellationTokenSource? LinkedCancellationTokens { get; set; } public object Lock { get; } public . Metadata { get; } - public . ObjectBag { get; } public . Output { get; } public . Parallelism { get; } - public string? ParentTestId { get; set; } - public .TestPhase Phase { get; set; } - public . Relationship { get; set; } - public bool ReportResult { get; set; } - public .TestResult? Result { get; set; } - public <.TestContext, , int, .>? RetryFunc { get; set; } public Services { get; } - public string? SkipReason { get; set; } public . StateBag { get; } - public .TestDetails TestDetails { get; set; } - public ? TestEnd { get; set; } - public ? TestStart { get; set; } - public .<.Timing> Timings { get; } public static . Configuration { get; } public new static .TestContext? Current { get; } public static string? OutputDirectory { get; } public static .> Parameters { get; } public static string WorkingDirectory { get; set; } - public void AddLinkedCancellationToken(.CancellationToken cancellationToken) { } - public string GetDisplayName() { } - public new string GetErrorOutput() { } - public string GetOutput() { } public T? GetService() where T : class { } - public .<.TestContext> GetTests(<.TestContext, bool> predicate) { } - public .<.TestContext> GetTests(string testName) { } - public .<.TestContext> GetTests(string testName, classType) { } - public void OverrideResult(string reason) { } - public void OverrideResult(.TestState state, string reason) { } - public void WriteError(string message) { } - public void WriteLine(string message) { } public static .TestContext? GetById( id) { } } public class TestContextEvents @@ -2450,7 +2420,7 @@ namespace .Interfaces } public interface ITestStateBag { - . Bag { get; } + . Items { get; } } public interface ITypedTestMetadata { diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt index 8524beb1c5..e7c1406e71 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt @@ -1220,53 +1220,23 @@ namespace public class TestContext : .Context, ., ., ., ., ., ., . { public TestContext(string testName, serviceProvider, .ClassHookContext classContext, .TestBuilderContext testBuilderContext, .CancellationToken cancellationToken) { } - public .<.Artifact> Artifacts { get; } - public .CancellationToken CancellationToken { get; set; } public .ClassHookContext ClassContext { get; } - public int CurrentRetryAttempt { get; } - public .? CustomHookExecutor { get; set; } public . Dependencies { get; } - public ? DisplayNameFormatter { get; set; } - public .TestContextEvents Events { get; } public . Execution { get; } public Id { get; } - public .CancellationTokenSource? LinkedCancellationTokens { get; set; } public object Lock { get; } public . Metadata { get; } - public . ObjectBag { get; } public . Output { get; } public . Parallelism { get; } - public string? ParentTestId { get; set; } - public .TestPhase Phase { get; set; } - public . Relationship { get; set; } - public bool ReportResult { get; set; } - public .TestResult? Result { get; set; } - public <.TestContext, , int, .>? RetryFunc { get; set; } public Services { get; } - public string? SkipReason { get; set; } public . StateBag { get; } - public .TestDetails TestDetails { get; set; } - public ? TestEnd { get; set; } - public ? TestStart { get; set; } - public .<.Timing> Timings { get; } public static . Configuration { get; } public new static .TestContext? Current { get; } public static string? OutputDirectory { get; } public static .> Parameters { get; } public static string WorkingDirectory { get; set; } - public void AddLinkedCancellationToken(.CancellationToken cancellationToken) { } - public string GetDisplayName() { } - public new string GetErrorOutput() { } - public string GetOutput() { } public T? GetService() where T : class { } - public .<.TestContext> GetTests(<.TestContext, bool> predicate) { } - public .<.TestContext> GetTests(string testName) { } - public .<.TestContext> GetTests(string testName, classType) { } - public void OverrideResult(string reason) { } - public void OverrideResult(.TestState state, string reason) { } - public void WriteError(string message) { } - public void WriteLine(string message) { } public static .TestContext? GetById( id) { } } public class TestContextEvents @@ -2377,7 +2347,7 @@ namespace .Interfaces } public interface ITestStateBag { - . Bag { get; } + . Items { get; } } public interface ITypedTestMetadata { diff --git a/TUnit.PublicAPI/Verify.cs b/TUnit.PublicAPI/Verify.cs index 17d3fadd11..d057db9a0b 100644 --- a/TUnit.PublicAPI/Verify.cs +++ b/TUnit.PublicAPI/Verify.cs @@ -79,8 +79,8 @@ public VerifySettingsTask ScrubFilePaths() public async Task ToTask() { var testContext = TestContext.Current!; - var testClassName = testContext.TestDetails.MethodMetadata.Class.Name; - var testName = testContext.TestDetails.TestName; + var testClassName = testContext.Metadata.TestDetails.MethodMetadata.Class.Name; + var testName = testContext.Metadata.TestDetails.TestName; var name = $"{testClassName}.{testName}{_uniqueSuffix}"; var dir = Sourcy.DotNet.Projects.TUnit_PublicAPI.DirectoryName!; _receivedPath = Path.Combine(dir, $"{name}.received.txt"); diff --git a/TUnit.TestProject.Library/Hooks.cs b/TUnit.TestProject.Library/Hooks.cs index 983fc1b62e..217d5b6d0c 100644 --- a/TUnit.TestProject.Library/Hooks.cs +++ b/TUnit.TestProject.Library/Hooks.cs @@ -5,12 +5,12 @@ public class Hooks [Before(Test)] public void BeforeTests(TestContext testContext) { - testContext.ObjectBag["BeforeHit"] = true; + testContext.StateBag.Items["BeforeHit"] = true; } [After(Test)] public void AfterTests(TestContext testContext) { - testContext.ObjectBag["AfterHit"] = true; + testContext.StateBag.Items["AfterHit"] = true; } } diff --git a/TUnit.TestProject/AfterTestDisposalOrderTest.cs b/TUnit.TestProject/AfterTestDisposalOrderTest.cs index bd1e0058ec..5c2acc69c2 100644 --- a/TUnit.TestProject/AfterTestDisposalOrderTest.cs +++ b/TUnit.TestProject/AfterTestDisposalOrderTest.cs @@ -37,8 +37,8 @@ public async Task AfterTest_ShouldAccessResourcesBeforeDisposal(TestContext cont await Assert.That(_testResource).IsEqualTo("TestResource"); // Mark that we successfully accessed resources - context.ObjectBag["AfterTestExecuted"] = true; - context.ObjectBag["ResourceValue"] = _testResource; + context.StateBag.Items["AfterTestExecuted"] = true; + context.StateBag.Items["ResourceValue"] = _testResource; } [After(Class)] @@ -47,9 +47,9 @@ public static async Task AfterClass_VerifyDisposalCompleted(ClassHookContext con // Verify that After(Test) hooks were executed foreach (var test in context.Tests) { - await Assert.That(test.ObjectBag.ContainsKey("AfterTestExecuted")).IsTrue().Because("After(Test) hook should have executed"); - await Assert.That(test.ObjectBag["AfterTestExecuted"]).IsEqualTo(true); - await Assert.That(test.ObjectBag["ResourceValue"]).IsEqualTo("TestResource"); + await Assert.That(test.StateBag.Items.ContainsKey("AfterTestExecuted")).IsTrue().Because("After(Test) hook should have executed"); + await Assert.That(test.StateBag.Items["AfterTestExecuted"]).IsEqualTo(true); + await Assert.That(test.StateBag.Items["ResourceValue"]).IsEqualTo("TestResource"); } // By the time After(Class) runs, all test instances should be disposed diff --git a/TUnit.TestProject/AfterTests/AfterTests.cs b/TUnit.TestProject/AfterTests/AfterTests.cs index 7669a34204..9c0189e82c 100644 --- a/TUnit.TestProject/AfterTests/AfterTests.cs +++ b/TUnit.TestProject/AfterTests/AfterTests.cs @@ -92,7 +92,7 @@ public async Task CleanupWithContext(TestContext testContext) [After(Test), Timeout(30_000)] public async Task CleanupWithContext(TestContext testContext, CancellationToken cancellationToken) { - await Assert.That(testContext.Result).IsNotNull(); + await Assert.That(testContext.Execution.Result).IsNotNull(); } [Test] diff --git a/TUnit.TestProject/AfterTests/TestDiscoveryAfterTests.cs b/TUnit.TestProject/AfterTests/TestDiscoveryAfterTests.cs index 040f295356..9a7b82e62a 100644 --- a/TUnit.TestProject/AfterTests/TestDiscoveryAfterTests.cs +++ b/TUnit.TestProject/AfterTests/TestDiscoveryAfterTests.cs @@ -14,11 +14,11 @@ public static async Task AfterEveryTestDiscovery(TestDiscoveryContext context) await FilePolyfill.WriteAllTextAsync($"TestDiscoveryAfterTests{Guid.NewGuid():N}.txt", $"{context.AllTests.Count()} tests found"); var test = context.AllTests.FirstOrDefault(x => - x.TestDetails.TestName == nameof(TestDiscoveryAfterTests.EnsureAfterEveryTestDiscoveryHit)); + x.Metadata.TestDetails.TestName == nameof(TestDiscoveryAfterTests.EnsureAfterEveryTestDiscoveryHit)); if (test is not null) { - test.ObjectBag["AfterEveryTestDiscoveryHit"] = true; + test.StateBag.Items["AfterEveryTestDiscoveryHit"] = true; } } } @@ -28,6 +28,6 @@ public class TestDiscoveryAfterTests [Test] public async Task EnsureAfterEveryTestDiscoveryHit() { - await Assert.That(TestContext.Current?.ObjectBag["AfterEveryTestDiscoveryHit"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current?.StateBag.Items["AfterEveryTestDiscoveryHit"]).IsEquatableOrEqualTo(true); } } diff --git a/TUnit.TestProject/AfterTests/TestSessionAfterTests.cs b/TUnit.TestProject/AfterTests/TestSessionAfterTests.cs index 2b48701214..384c5f3ba2 100644 --- a/TUnit.TestProject/AfterTests/TestSessionAfterTests.cs +++ b/TUnit.TestProject/AfterTests/TestSessionAfterTests.cs @@ -14,15 +14,15 @@ public static async Task AfterEveryTestSession(TestSessionContext context) await FilePolyfill.WriteAllTextAsync($"TestSessionAfterTests{Guid.NewGuid():N}.txt", $"{context.AllTests.Count()} tests in session"); var test = context.AllTests.FirstOrDefault(x => - x.TestDetails.TestName == nameof(TestSessionAfterTests.PepareForAfterSession)); + x.Metadata.TestDetails.TestName == nameof(TestSessionAfterTests.PepareForAfterSession)); - if (test?.Result == null) + if (test?.Execution.Result == null) { // This test might not have been executed due to filters, so the below exception would cause problems. return; } - await Assert.That(test.ObjectBag["AfterEveryTestSessionHit"]).IsEquatableOrEqualTo(true); + await Assert.That(test.StateBag.Items["AfterEveryTestSessionHit"]).IsEquatableOrEqualTo(true); } } @@ -33,8 +33,8 @@ public async Task PepareForAfterSession() { if (TestContext.Current != null) { - TestContext.Current.ObjectBag["AfterEveryTestSessionHit"] = true; + TestContext.Current.StateBag.Items["AfterEveryTestSessionHit"] = true; } - await Assert.That(TestContext.Current?.ObjectBag["AfterEveryTestSessionHit"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current?.StateBag.Items["AfterEveryTestSessionHit"]).IsEquatableOrEqualTo(true); } } diff --git a/TUnit.TestProject/ArgumentDisplayFormatterTests.cs b/TUnit.TestProject/ArgumentDisplayFormatterTests.cs index e0e581e6bb..3f45f02ec5 100644 --- a/TUnit.TestProject/ArgumentDisplayFormatterTests.cs +++ b/TUnit.TestProject/ArgumentDisplayFormatterTests.cs @@ -11,7 +11,7 @@ public class ArgumentDisplayFormatterTests public async Task FormatterShouldBeAppliedToMethodDataSource(Foo foo) { // Verify the formatter was applied by checking the display name - var displayName = TestContext.Current!.GetDisplayName(); + var displayName = TestContext.Current!. Metadata.DisplayName; await Assert.That(displayName).IsEqualTo("FormatterShouldBeAppliedToMethodDataSource(FooFormatterValue)"); } @@ -21,7 +21,7 @@ public async Task FormatterShouldBeAppliedToMethodDataSource(Foo foo) public async Task FormatterShouldBeAppliedToArguments(int a, int b, int c) { // Verify the formatter was applied by checking the display name - var displayName = TestContext.Current!.GetDisplayName(); + var displayName = TestContext.Current!. Metadata.DisplayName; await Assert.That(displayName).IsEqualTo("FormatterShouldBeAppliedToArguments(INT:1, INT:2, INT:3)"); } @@ -31,7 +31,7 @@ public async Task FormatterShouldBeAppliedToArguments(int a, int b, int c) public async Task FormatterShouldBeAppliedToBarData(Bar bar) { // Verify the Bar formatter was applied by checking the display name - var displayName = TestContext.Current!.GetDisplayName(); + var displayName = TestContext.Current!. Metadata.DisplayName; await Assert.That(displayName).IsEqualTo("FormatterShouldBeAppliedToBarData(BarFormatterValue)"); } diff --git a/TUnit.TestProject/Attributes/ClassDisplayNameAttribute.cs b/TUnit.TestProject/Attributes/ClassDisplayNameAttribute.cs index b91685ddff..7fa7197abe 100644 --- a/TUnit.TestProject/Attributes/ClassDisplayNameAttribute.cs +++ b/TUnit.TestProject/Attributes/ClassDisplayNameAttribute.cs @@ -7,7 +7,7 @@ public class ClassDisplayNameAttribute : Attribute, ITestDiscoveryEventReceiver { public ValueTask OnTestDiscovered(DiscoveredTestContext context) { - context.SetDisplayName($"{context.TestDetails.MethodMetadata.Class.Name}.{context.GetDisplayName()}"); + context.SetDisplayName($"{context.TestContext.Metadata.TestDetails.MethodMetadata.Class.Name}.{context.TestContext.Metadata.DisplayName}"); return default(ValueTask); } diff --git a/TUnit.TestProject/BasicTests_HooksFromLibrary.cs b/TUnit.TestProject/BasicTests_HooksFromLibrary.cs index 1c0f289348..a38b31f19a 100644 --- a/TUnit.TestProject/BasicTests_HooksFromLibrary.cs +++ b/TUnit.TestProject/BasicTests_HooksFromLibrary.cs @@ -5,12 +5,12 @@ public class BasicTestsHooksFromLibrary : TUnit.TestProject.Library.Hooks [Test] public async Task Test() { - await Assert.That(TestContext.Current!.ObjectBag["BeforeHit"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current!.StateBag.Items["BeforeHit"]).IsEquatableOrEqualTo(true); } [After(Class)] public static async Task AfterClass(ClassHookContext context) { - await Assert.That(context.Tests.First().ObjectBag["AfterHit"]).IsEquatableOrEqualTo(true); + await Assert.That(context.Tests.First().StateBag.Items["AfterHit"]).IsEquatableOrEqualTo(true); } } diff --git a/TUnit.TestProject/BeforeTests/TestSessionBeforeTests.cs b/TUnit.TestProject/BeforeTests/TestSessionBeforeTests.cs index 03b493dc32..8c443ef421 100644 --- a/TUnit.TestProject/BeforeTests/TestSessionBeforeTests.cs +++ b/TUnit.TestProject/BeforeTests/TestSessionBeforeTests.cs @@ -14,11 +14,11 @@ public static async Task BeforeEveryTestSession(TestSessionContext context) await FilePolyfill.WriteAllTextAsync($"TestSessionBeforeTests{Guid.NewGuid():N}.txt", $"{context.AllTests.Count()} tests in session"); var test = context.AllTests.FirstOrDefault(x => - x.TestDetails.TestName == nameof(TestSessionBeforeTests.EnsureBeforeEveryTestSessionHit)); + x.Metadata.TestDetails.TestName == nameof(TestSessionBeforeTests.EnsureBeforeEveryTestSessionHit)); if (test != null) { - test.ObjectBag["BeforeEveryTestSession"] = true; + test.StateBag.Items["BeforeEveryTestSession"] = true; } } } @@ -28,6 +28,6 @@ public class TestSessionBeforeTests [Test] public async Task EnsureBeforeEveryTestSessionHit() { - await Assert.That(TestContext.Current?.ObjectBag["BeforeEveryTestSession"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current?.StateBag.Items["BeforeEveryTestSession"]).IsEquatableOrEqualTo(true); } } diff --git a/TUnit.TestProject/Bugs/1570/Tests.cs b/TUnit.TestProject/Bugs/1570/Tests.cs index 48d317db0d..12d696215f 100644 --- a/TUnit.TestProject/Bugs/1570/Tests.cs +++ b/TUnit.TestProject/Bugs/1570/Tests.cs @@ -13,7 +13,7 @@ public async Task Dependency() { await Task.Delay(TimeSpan.FromSeconds(number)); - TestContext.Current!.ObjectBag["number"] = number; + TestContext.Current!.StateBag.Items["number"] = number; } [Test] @@ -27,6 +27,6 @@ public async Task GetTests_Without_Filtering_On_TestClassArguments_Test() // .GetTests(nameof(Dependency)) // .First(); // - // await Assert.That(dependencyContext.ObjectBag["number"]).IsEqualTo(number); + // await Assert.That(dependencyContext.StateBag.Items["number"]).IsEqualTo(number); } } diff --git a/TUnit.TestProject/Bugs/1939/Tests.cs b/TUnit.TestProject/Bugs/1939/Tests.cs index 1f81bb799d..ae41010133 100644 --- a/TUnit.TestProject/Bugs/1939/Tests.cs +++ b/TUnit.TestProject/Bugs/1939/Tests.cs @@ -31,7 +31,7 @@ public static async Task AssertAllDataClassesDisposed(TestSessionContext context .FirstOrDefault(x => x.ClassType == typeof(Tests)) ?.Tests; - if (tests is null || tests.Any(x => x.Result == null)) + if (tests is null || tests.Any(x => x.Execution.Result == null)) { // If the test did not run, we cannot check if the classes were disposed. // This can happen if the test was filtered out or not executed for some reason. @@ -39,7 +39,7 @@ public static async Task AssertAllDataClassesDisposed(TestSessionContext context } var dataClasses = tests - .SelectMany(x => x.TestDetails.TestClassArguments) + .SelectMany(x => x.Metadata.TestDetails.TestClassArguments) .OfType() .ToArray(); @@ -48,14 +48,14 @@ public static async Task AssertAllDataClassesDisposed(TestSessionContext context await Assert.That(dataClasses).HasCount().EqualTo(6); await Assert.That(dataClasses.Where(x => x.Disposed)).HasCount().EqualTo(6); - foreach (var test in tests.Where(x => x.Result != null)) + foreach (var test in tests.Where(x => x.Execution.Result != null)) { - var dataClass = test.TestDetails.TestClassArguments.OfType().First(); + var dataClass = test.Metadata.TestDetails.TestClassArguments.OfType().First(); if (!dataClass.Disposed) { var classDataSourceAttribute = - test.TestDetails.GetAttributes>() + test.Metadata.TestDetails.GetAttributes>() .First(); throw new Exception($"Not Disposed: {classDataSourceAttribute.Shared}"); diff --git a/TUnit.TestProject/Bugs/2067/Tests.cs b/TUnit.TestProject/Bugs/2067/Tests.cs index 40b093468e..ce5b82bf17 100644 --- a/TUnit.TestProject/Bugs/2067/Tests.cs +++ b/TUnit.TestProject/Bugs/2067/Tests.cs @@ -22,13 +22,13 @@ public static async Task AssertAllDataClassesDisposed(TestSessionContext context .FirstOrDefault(x => x.ClassType == typeof(Tests)) ?.Tests; - if (tests is null || tests.Any(x => x.Result == null)) + if (tests is null || tests.Any(x => x.Execution.Result == null)) { return; } var dataClasses = tests - .SelectMany(x => x.TestDetails.TestClassArguments) + .SelectMany(x => x.Metadata.TestDetails.TestClassArguments) .OfType() .ToArray(); diff --git a/TUnit.TestProject/Bugs/2481/Tests.cs b/TUnit.TestProject/Bugs/2481/Tests.cs index 95d37bd0b7..341dea72e9 100644 --- a/TUnit.TestProject/Bugs/2481/Tests.cs +++ b/TUnit.TestProject/Bugs/2481/Tests.cs @@ -11,7 +11,7 @@ public class Tests [Property("Group", "TUnit")] public async Task Test() { - var properties = TestContext.Current!.TestDetails.CustomProperties; + var properties = TestContext.Current!.Metadata.TestDetails.CustomProperties; var array = properties["Group"].ToArray(); diff --git a/TUnit.TestProject/Bugs/2867/DisposalNotCalledTests.cs b/TUnit.TestProject/Bugs/2867/DisposalNotCalledTests.cs index e7cc0641e1..8bb8257730 100644 --- a/TUnit.TestProject/Bugs/2867/DisposalNotCalledTests.cs +++ b/TUnit.TestProject/Bugs/2867/DisposalNotCalledTests.cs @@ -215,7 +215,7 @@ public static async Task VerifyDisposalAfterClass(ClassHookContext context) await Assert.That(_serviceIds.Distinct().Count()).IsEqualTo(1); // Verify all test instances themselves are disposed - var testInstances = context.Tests.Select(t => t.TestDetails.ClassInstance).OfType().ToList(); + var testInstances = context.Tests.Select(t => t.Metadata.TestDetails.ClassInstance).OfType().ToList(); foreach (var instance in testInstances) { await Assert.That(instance._isDisposed).IsTrue(); diff --git a/TUnit.TestProject/Bugs/3077/Tests.cs b/TUnit.TestProject/Bugs/3077/Tests.cs index 8283714a2f..86faca9f8d 100644 --- a/TUnit.TestProject/Bugs/3077/Tests.cs +++ b/TUnit.TestProject/Bugs/3077/Tests.cs @@ -13,7 +13,7 @@ public Task Create([DynamicallyAccessedMembers(DynamicallyAccessedMember public ValueTask OnTestStart(TestContext context) { - ((Tests)context.TestDetails.ClassInstance).SomeValue = "Initialized"; + ((Tests)context.Metadata.TestDetails.ClassInstance).SomeValue = "Initialized"; return default; } diff --git a/TUnit.TestProject/Bugs/3219/ClassDataSourceRetryTests.cs b/TUnit.TestProject/Bugs/3219/ClassDataSourceRetryTests.cs index 80589d5ee9..878e1b6a81 100644 --- a/TUnit.TestProject/Bugs/3219/ClassDataSourceRetryTests.cs +++ b/TUnit.TestProject/Bugs/3219/ClassDataSourceRetryTests.cs @@ -75,7 +75,7 @@ public async Task VerifyNotDisposedDuringTests() [After(TestSession)] public static async Task VerifyDisposalAfterTestSession(TestSessionContext context) { - var classInstance = context.TestClasses.FirstOrDefault(x => x.ClassType == typeof(ClassDataSourceRetryTests))?.Tests.FirstOrDefault()?.TestDetails.ClassInstance as ClassDataSourceRetryTests; + var classInstance = context.TestClasses.FirstOrDefault(x => x.ClassType == typeof(ClassDataSourceRetryTests))?.Tests.FirstOrDefault()?.Metadata.TestDetails.ClassInstance as ClassDataSourceRetryTests; var dataClass = classInstance?.DataClass; diff --git a/TUnit.TestProject/Bugs/HookOrchestratorDeadlockTests.cs b/TUnit.TestProject/Bugs/HookOrchestratorDeadlockTests.cs index 15e1f3dfd5..e8961ea029 100644 --- a/TUnit.TestProject/Bugs/HookOrchestratorDeadlockTests.cs +++ b/TUnit.TestProject/Bugs/HookOrchestratorDeadlockTests.cs @@ -79,9 +79,9 @@ public async Task ConcurrentTest_3() [BeforeEvery(Test)] public static async Task BeforeEveryTest_Hook(TestContext context) { - if (context.TestDetails.ClassType == typeof(HookOrchestratorDeadlockTests)) + if (context.Metadata.TestDetails.ClassType == typeof(HookOrchestratorDeadlockTests)) { - ExecutionLog.Add($"BeforeTest_{context.TestDetails.TestName}"); + ExecutionLog.Add($"BeforeTest_{context.Metadata.TestDetails.TestName}"); await Task.Delay(5); // Small delay to potentially trigger coordination issues } } @@ -89,9 +89,9 @@ public static async Task BeforeEveryTest_Hook(TestContext context) [AfterEvery(Test)] public static async Task AfterEveryTest_Hook(TestContext context) { - if (context.TestDetails.ClassType == typeof(HookOrchestratorDeadlockTests)) + if (context.Metadata.TestDetails.ClassType == typeof(HookOrchestratorDeadlockTests)) { - ExecutionLog.Add($"AfterTest_{context.TestDetails.TestName}"); + ExecutionLog.Add($"AfterTest_{context.Metadata.TestDetails.TestName}"); await Task.Delay(5); // Small delay to potentially trigger coordination issues } } @@ -152,9 +152,9 @@ public async Task SequentialTest_2() [BeforeEvery(Test)] public static async Task SequentialBeforeTest(TestContext context) { - if (context.TestDetails.ClassType == typeof(SequentialCoordinationDeadlockTests)) + if (context.Metadata.TestDetails.ClassType == typeof(SequentialCoordinationDeadlockTests)) { - SequentialExecutionLog.Add($"SequentialBeforeTest_{context.TestDetails.TestName}"); + SequentialExecutionLog.Add($"SequentialBeforeTest_{context.Metadata.TestDetails.TestName}"); await Task.Delay(10); } } @@ -162,9 +162,9 @@ public static async Task SequentialBeforeTest(TestContext context) [AfterEvery(Test)] public static async Task SequentialAfterTest(TestContext context) { - if (context.TestDetails.ClassType == typeof(SequentialCoordinationDeadlockTests)) + if (context.Metadata.TestDetails.ClassType == typeof(SequentialCoordinationDeadlockTests)) { - SequentialExecutionLog.Add($"SequentialAfterTest_{context.TestDetails.TestName}"); + SequentialExecutionLog.Add($"SequentialAfterTest_{context.Metadata.TestDetails.TestName}"); await Task.Delay(10); } } @@ -229,10 +229,10 @@ public static void VerifyNoDeadlocksOccurred(TestSessionContext context) // In a deadlock scenario, the test run would hang and never complete var deadlockTestsRan = context.AllTests.Any(t => - t.TestDetails.ClassType == typeof(HookOrchestratorDeadlockTests) || - t.TestDetails.ClassType == typeof(SequentialCoordinationDeadlockTests) || - t.TestDetails.ClassType == typeof(KeyedSequentialDeadlockTests_Group1) || - t.TestDetails.ClassType == typeof(KeyedSequentialDeadlockTests_Group2)); + t.Metadata.TestDetails.ClassType == typeof(HookOrchestratorDeadlockTests) || + t.Metadata.TestDetails.ClassType == typeof(SequentialCoordinationDeadlockTests) || + t.Metadata.TestDetails.ClassType == typeof(KeyedSequentialDeadlockTests_Group1) || + t.Metadata.TestDetails.ClassType == typeof(KeyedSequentialDeadlockTests_Group2)); if (deadlockTestsRan) { diff --git a/TUnit.TestProject/Bugs/_2804/CriticalHookChainExecutionTests.cs b/TUnit.TestProject/Bugs/_2804/CriticalHookChainExecutionTests.cs index d8d2b521f4..ec4bae0265 100644 --- a/TUnit.TestProject/Bugs/_2804/CriticalHookChainExecutionTests.cs +++ b/TUnit.TestProject/Bugs/_2804/CriticalHookChainExecutionTests.cs @@ -58,9 +58,9 @@ public async Task LastTest_In_Class() [AfterEvery(Test)] public static async Task AfterEveryTest_That_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(CriticalHookChainExecutionTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CriticalHookChainExecutionTests)) { - ExecutedHooks.Add($"AfterEveryTest_{context.TestDetails.TestName}"); + ExecutedHooks.Add($"AfterEveryTest_{context.Metadata.TestDetails.TestName}"); // AfterEveryTest executing if (_afterTestShouldFail) @@ -126,7 +126,7 @@ public async Task HelperTest_To_Trigger_Assembly_Hooks() [AfterEvery(Test)] public static async Task HelperAfterTest(TestContext context) { - if (context.TestDetails.ClassType == typeof(CriticalHookChainHelperTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CriticalHookChainHelperTests)) { SharedExecutedHooks.Add("HelperAfterTest"); // Helper AfterTest executed @@ -160,7 +160,7 @@ public static async Task AfterEveryAssembly_Should_Run_Despite_All_Failures(Asse public static void VerifyCriticalChainExecution(TestSessionContext context) { // Check if our critical test ran - if (context.AllTests.Any(t => t.TestDetails.ClassType == typeof(CriticalHookChainExecutionTests))) + if (context.AllTests.Any(t => t.Metadata.TestDetails.ClassType == typeof(CriticalHookChainExecutionTests))) { // Critical verification @@ -222,7 +222,7 @@ public class CounterDecrementVerificationTests [BeforeEvery(Test)] public static async Task TrackBeforeTest(TestContext context) { - if (context.TestDetails.ClassType == typeof(CounterDecrementVerificationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CounterDecrementVerificationTests)) { Interlocked.Increment(ref _beforeTestCount); CounterEvents.Add($"BeforeTest_{_beforeTestCount}"); @@ -255,7 +255,7 @@ public async Task Test3_Last_Test() [AfterEvery(Test)] public static async Task AfterTest_That_Always_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(CounterDecrementVerificationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CounterDecrementVerificationTests)) { Interlocked.Increment(ref _afterTestCount); CounterEvents.Add($"AfterTest_{_afterTestCount}_Failing"); @@ -309,7 +309,7 @@ public async Task Test_Where_Every_Hook_Level_Fails() [After(Test)] public async Task AfterTest_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(ExtremeFailureCascadeTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ExtremeFailureCascadeTests)) { ExecutionTrace.Add("AfterTest_Failed"); // After(Test) executing and failing @@ -321,7 +321,7 @@ public async Task AfterTest_Fails(TestContext context) [AfterEvery(Test)] public static async Task AfterEveryTest_AlsoFails(TestContext context) { - if (context.TestDetails.ClassType == typeof(ExtremeFailureCascadeTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ExtremeFailureCascadeTests)) { ExecutionTrace.Add("AfterEveryTest_Failed"); // AfterEvery(Test) executing and failing @@ -357,7 +357,7 @@ public static async Task AfterEveryClass_AlsoFails(ClassHookContext context) [After(TestSession)] public static void VerifyExtremeCascade(TestSessionContext context) { - if (context.AllTests.Any(t => t.TestDetails.ClassType == typeof(ExtremeFailureCascadeTests))) + if (context.AllTests.Any(t => t.Metadata.TestDetails.ClassType == typeof(ExtremeFailureCascadeTests))) { // Extreme cascade verification // Execution trace verified diff --git a/TUnit.TestProject/Bugs/_2804/HookCleanupOnFailureTests.cs b/TUnit.TestProject/Bugs/_2804/HookCleanupOnFailureTests.cs index b27a919be3..1564c5c3c2 100644 --- a/TUnit.TestProject/Bugs/_2804/HookCleanupOnFailureTests.cs +++ b/TUnit.TestProject/Bugs/_2804/HookCleanupOnFailureTests.cs @@ -200,7 +200,7 @@ public void Test_With_Assembly_Hooks_That_Passes() public static void VerifyAssemblyHooksExecuted(TestSessionContext context) { // Only check if we're in the context of these specific tests - if (context.AllTests.Any(t => t.TestDetails.ClassType == typeof(AssemblyHookCleanupTests))) + if (context.AllTests.Any(t => t.Metadata.TestDetails.ClassType == typeof(AssemblyHookCleanupTests))) { // Hook executed($"[ASSEMBLY] Verification - Assembly hooks executed: {_assemblyHookExecuted}"); // Hook executed($"[ASSEMBLY] Total hooks recorded: {AssemblyHooks.Count}"); diff --git a/TUnit.TestProject/Bugs/_2804/HookExceptionHandlingTests.cs b/TUnit.TestProject/Bugs/_2804/HookExceptionHandlingTests.cs index 7de1090989..d5e8d8df62 100644 --- a/TUnit.TestProject/Bugs/_2804/HookExceptionHandlingTests.cs +++ b/TUnit.TestProject/Bugs/_2804/HookExceptionHandlingTests.cs @@ -51,16 +51,16 @@ public static void AfterClassMustExecute(ClassHookContext context) [BeforeEvery(Test)] public static void BeforeEveryTestWithPotentialFailure(TestContext context) { - if (context.TestDetails.ClassType == typeof(HookExceptionHandlingTests)) + if (context.Metadata.TestDetails.ClassType == typeof(HookExceptionHandlingTests)) { - ExecutionLog.Add($"BeforeEveryTest:{context.TestDetails.TestName}"); - // Hook executed($"[HOOK-EXCEPTION] BeforeEveryTest for {context.TestDetails.TestName}"); + ExecutionLog.Add($"BeforeEveryTest:{context.Metadata.TestDetails.TestName}"); + // Hook executed($"[HOOK-EXCEPTION] BeforeEveryTest for {context.Metadata.TestDetails.TestName}"); // Simulate a hook that fails for a specific test - if (context.TestDetails.TestName.Contains("HookFailure")) + if (context.Metadata.TestDetails.TestName.Contains("HookFailure")) { - // Hook executed($"[HOOK-EXCEPTION] BeforeEveryTest throwing exception for {context.TestDetails.TestName}"); - throw new Exception($"BeforeEveryTest intentionally failed for {context.TestDetails.TestName}"); + // Hook executed($"[HOOK-EXCEPTION] BeforeEveryTest throwing exception for {context.Metadata.TestDetails.TestName}"); + throw new Exception($"BeforeEveryTest intentionally failed for {context.Metadata.TestDetails.TestName}"); } } } @@ -68,10 +68,10 @@ public static void BeforeEveryTestWithPotentialFailure(TestContext context) [AfterEvery(Test)] public static void AfterEveryTestMustExecute(TestContext context) { - if (context.TestDetails.ClassType == typeof(HookExceptionHandlingTests)) + if (context.Metadata.TestDetails.ClassType == typeof(HookExceptionHandlingTests)) { - ExecutionLog.Add($"AfterEveryTest:{context.TestDetails.TestName}"); - // Hook executed($"[HOOK-EXCEPTION] AfterEveryTest executed for {context.TestDetails.TestName}"); + ExecutionLog.Add($"AfterEveryTest:{context.Metadata.TestDetails.TestName}"); + // Hook executed($"[HOOK-EXCEPTION] AfterEveryTest executed for {context.Metadata.TestDetails.TestName}"); } } @@ -106,7 +106,7 @@ public async Task Test_That_Fails_After_Successful_Hook() public static void VerifyHookCleanupOccurred(TestSessionContext context) { // Only verify if our tests ran - if (context.AllTests.Any(t => t.TestDetails.ClassType == typeof(HookExceptionHandlingTests))) + if (context.AllTests.Any(t => t.Metadata.TestDetails.ClassType == typeof(HookExceptionHandlingTests))) { // Hook executed("\n[HOOK-EXCEPTION] === VERIFICATION ==="); // Hook executed($"[HOOK-EXCEPTION] AfterClass executed: {_afterClassExecuted}"); @@ -196,7 +196,7 @@ public void Critical_Test_3_After_Hook_Failure() [After(TestSession)] public static void VerifyCriticalScenario(TestSessionContext context) { - if (context.AllTests.Any(t => t.TestDetails.ClassType == typeof(CriticalCounterScenarioTests))) + if (context.AllTests.Any(t => t.Metadata.TestDetails.ClassType == typeof(CriticalCounterScenarioTests))) { // Hook executed("\n[CRITICAL] === CRITICAL SCENARIO VERIFICATION ==="); // Hook executed($"[CRITICAL] BeforeClass count: {_criticalBeforeClassCount}"); diff --git a/TUnit.TestProject/Bugs/_2804/MultipleAfterHooksFailureTests.cs b/TUnit.TestProject/Bugs/_2804/MultipleAfterHooksFailureTests.cs index d5501ca4b8..aa164cc203 100644 --- a/TUnit.TestProject/Bugs/_2804/MultipleAfterHooksFailureTests.cs +++ b/TUnit.TestProject/Bugs/_2804/MultipleAfterHooksFailureTests.cs @@ -53,7 +53,7 @@ public class MultipleAfterEveryTestHooks [AfterEvery(Test)] public static async Task AfterEveryTest_Hook1_Success(TestContext context) { - if (context.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) { TestHookExecutions.Add("AfterEveryTest_Hook1"); // Hook executed("[AFTER-TEST] Hook 1 executing successfully"); @@ -64,7 +64,7 @@ public static async Task AfterEveryTest_Hook1_Success(TestContext context) [AfterEvery(Test)] public static async Task AfterEveryTest_Hook2_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) { TestHookExecutions.Add("AfterEveryTest_Hook2"); // Hook executed("[AFTER-TEST] Hook 2 executing and will fail"); @@ -76,7 +76,7 @@ public static async Task AfterEveryTest_Hook2_Fails(TestContext context) [AfterEvery(Test)] public static async Task AfterEveryTest_Hook3_Success(TestContext context) { - if (context.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) { TestHookExecutions.Add("AfterEveryTest_Hook3"); // Hook executed("[AFTER-TEST] Hook 3 executing successfully (after Hook 2 failed)"); @@ -87,7 +87,7 @@ public static async Task AfterEveryTest_Hook3_Success(TestContext context) [AfterEvery(Test)] public static async Task AfterEveryTest_Hook4_AlsoFails(TestContext context) { - if (context.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) { TestHookExecutions.Add("AfterEveryTest_Hook4"); // Hook executed("[AFTER-TEST] Hook 4 executing and will also fail"); @@ -99,7 +99,7 @@ public static async Task AfterEveryTest_Hook4_AlsoFails(TestContext context) [AfterEvery(Test)] public static async Task AfterEveryTest_Hook5_StillExecutes(TestContext context) { - if (context.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MultipleAfterHooksFailureTests)) { TestHookExecutions.Add("AfterEveryTest_Hook5"); // Hook executed("[AFTER-TEST] Hook 5 still executing (after Hooks 2 and 4 failed)"); @@ -315,7 +315,7 @@ public async Task Test_That_Triggers_Multiple_Hook_Failures() [AfterEvery(Test)] public static async Task CaptureExceptions_Hook1_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests)) { // Hook executed("[AGGREGATE] Hook 1 failing with InvalidOperationException"); await Task.CompletedTask; @@ -326,7 +326,7 @@ public static async Task CaptureExceptions_Hook1_Fails(TestContext context) [AfterEvery(Test)] public static async Task CaptureExceptions_Hook2_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests)) { // Hook executed("[AGGREGATE] Hook 2 failing with ArgumentException"); await Task.CompletedTask; @@ -337,7 +337,7 @@ public static async Task CaptureExceptions_Hook2_Fails(TestContext context) [AfterEvery(Test)] public static async Task CaptureExceptions_Hook3_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests)) { // Hook executed("[AGGREGATE] Hook 3 failing with NotImplementedException"); await Task.CompletedTask; @@ -351,7 +351,7 @@ public static void VerifyAggregateException(TestSessionContext context) // Note: We can't easily verify the AggregateException from within the test framework, // but we've set up the scenario where multiple hooks fail, which should result in // an AggregateException being thrown by the framework - if (context.AllTests.Any(t => t.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests))) + if (context.AllTests.Any(t => t.Metadata.TestDetails.ClassType == typeof(AggregateExceptionVerificationTests))) { // Hook executed("[AGGREGATE] Test scenario completed - framework should have thrown AggregateException with 3 inner exceptions"); } @@ -376,7 +376,7 @@ public async Task Test_With_Hooks_At_All_Levels() [AfterEvery(Test)] public static async Task TestLevel_Hook1_Success(TestContext context) { - if (context.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests)) { AllHookExecutions.Add("TestLevel_Hook1"); // Hook executed("[COMPREHENSIVE-TEST] Test-level Hook 1 success"); @@ -387,7 +387,7 @@ public static async Task TestLevel_Hook1_Success(TestContext context) [AfterEvery(Test)] public static async Task TestLevel_Hook2_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests)) { AllHookExecutions.Add("TestLevel_Hook2"); // Hook executed("[COMPREHENSIVE-TEST] Test-level Hook 2 fails"); @@ -399,7 +399,7 @@ public static async Task TestLevel_Hook2_Fails(TestContext context) [AfterEvery(Test)] public static async Task TestLevel_Hook3_Success(TestContext context) { - if (context.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests)) { AllHookExecutions.Add("TestLevel_Hook3"); // Hook executed("[COMPREHENSIVE-TEST] Test-level Hook 3 success (after failure)"); @@ -445,7 +445,7 @@ public static async Task ClassLevel_Hook3_Success(ClassHookContext context) [After(TestSession)] public static void VerifyAllLevelsExecuted(TestSessionContext context) { - if (context.AllTests.Any(t => t.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests))) + if (context.AllTests.Any(t => t.Metadata.TestDetails.ClassType == typeof(ComprehensiveMultiLevelHookFailureTests))) { // Hook executed("\n[COMPREHENSIVE] === VERIFICATION ==="); // Hook executed($"[COMPREHENSIVE] Total hooks executed across all levels: {AllHookExecutions.Count}"); diff --git a/TUnit.TestProject/Bugs/_2804/TestSpecificAfterHooksTests.cs b/TUnit.TestProject/Bugs/_2804/TestSpecificAfterHooksTests.cs index ae12c12c3e..02b32fdf80 100644 --- a/TUnit.TestProject/Bugs/_2804/TestSpecificAfterHooksTests.cs +++ b/TUnit.TestProject/Bugs/_2804/TestSpecificAfterHooksTests.cs @@ -22,7 +22,7 @@ public async Task Test_With_Multiple_After_Hooks_Some_Failing() [After(Test)] public async Task AfterTest_Hook1_Success(TestContext context) { - if (context.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) + if (context.Metadata.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) { ExecutedHooks.Add("AfterTest_Hook1"); // After(Test) Hook 1 executing successfully @@ -33,7 +33,7 @@ public async Task AfterTest_Hook1_Success(TestContext context) [After(Test)] public async Task AfterTest_Hook2_Fails(TestContext context) { - if (context.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) + if (context.Metadata.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) { ExecutedHooks.Add("AfterTest_Hook2"); // After(Test) Hook 2 executing and will fail @@ -47,7 +47,7 @@ public async Task AfterTest_Hook2_Fails(TestContext context) [After(Test)] public async Task AfterTest_Hook3_Success(TestContext context) { - if (context.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) + if (context.Metadata.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) { ExecutedHooks.Add("AfterTest_Hook3"); // After(Test) Hook 3 still executing after Hook 2 failed @@ -58,7 +58,7 @@ public async Task AfterTest_Hook3_Success(TestContext context) [After(Test)] public async Task AfterTest_Hook4_AlsoFails(TestContext context) { - if (context.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) + if (context.Metadata.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) { ExecutedHooks.Add("AfterTest_Hook4"); // After(Test) Hook 4 executing and will also fail @@ -72,7 +72,7 @@ public async Task AfterTest_Hook4_AlsoFails(TestContext context) [After(Test)] public async Task AfterTest_Hook5_StillExecutes(TestContext context) { - if (context.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) + if (context.Metadata.TestDetails.TestName == nameof(Test_With_Multiple_After_Hooks_Some_Failing)) { ExecutedHooks.Add("AfterTest_Hook5"); // After(Test) Hook 5 still executing after multiple failures @@ -108,7 +108,7 @@ public class MixedBeforeAfterHooksTests [Before(Test)] public async Task BeforeTest_Hook1(TestContext context) { - if (context.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) { HookSequence.Add("Before_Hook1"); // Before(Test) Hook 1 executing @@ -119,14 +119,14 @@ public async Task BeforeTest_Hook1(TestContext context) [Before(Test)] public async Task BeforeTest_Hook2_MightFail(TestContext context) { - if (context.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) { HookSequence.Add("Before_Hook2"); // Before(Test) Hook 2 executing await Task.CompletedTask; // Fail on specific test - if (context.TestDetails.TestName == nameof(Test_With_Before_Hook_Failure)) + if (context.Metadata.TestDetails.TestName == nameof(Test_With_Before_Hook_Failure)) { _beforeHookFailed = true; // Before(Test) Hook 2 failing @@ -156,7 +156,7 @@ public async Task Test_Without_Hook_Failure() [After(Test)] public async Task AfterTest_Hook1_AlwaysRuns(TestContext context) { - if (context.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) { HookSequence.Add("After_Hook1"); // After(Test) Hook 1 executing (should run even if Before failed) @@ -167,7 +167,7 @@ public async Task AfterTest_Hook1_AlwaysRuns(TestContext context) [After(Test)] public async Task AfterTest_Hook2_Fails(TestContext context) { - if (context.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) { HookSequence.Add("After_Hook2"); // After(Test) Hook 2 executing and will fail @@ -179,7 +179,7 @@ public async Task AfterTest_Hook2_Fails(TestContext context) [After(Test)] public async Task AfterTest_Hook3_StillRuns(TestContext context) { - if (context.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) + if (context.Metadata.TestDetails.ClassType == typeof(MixedBeforeAfterHooksTests)) { HookSequence.Add("After_Hook3"); // After(Test) Hook 3 still executing @@ -218,7 +218,7 @@ public async Task Test_That_Collects_Exception_Details() [AfterEvery(Test)] public static async Task Hook1_ThrowsInvalidOperation(TestContext context) { - if (context.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) { var message = "InvalidOperationException from Hook 1"; var exType = typeof(InvalidOperationException); @@ -233,7 +233,7 @@ public static async Task Hook1_ThrowsInvalidOperation(TestContext context) [AfterEvery(Test)] public static async Task Hook2_ThrowsArgument(TestContext context) { - if (context.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) { var message = "ArgumentException from Hook 2"; var exType = typeof(ArgumentException); @@ -248,7 +248,7 @@ public static async Task Hook2_ThrowsArgument(TestContext context) [AfterEvery(Test)] public static async Task Hook3_ThrowsNotImplemented(TestContext context) { - if (context.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) { var message = "NotImplementedException from Hook 3"; var exType = typeof(NotImplementedException); @@ -263,7 +263,7 @@ public static async Task Hook3_ThrowsNotImplemented(TestContext context) [AfterEvery(Test)] public static async Task Hook4_ThrowsCustom(TestContext context) { - if (context.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) { var message = "Custom exception from Hook 4"; var exType = typeof(CustomTestException); @@ -278,7 +278,7 @@ public static async Task Hook4_ThrowsCustom(TestContext context) [AfterEvery(Test)] public static async Task Hook5_VerifiesExceptions(TestContext context) { - if (context.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) + if (context.Metadata.TestDetails.ClassType == typeof(ExceptionDetailsPreservationTests)) { // Hook 5 executing (after 4 exceptions) // Exception types thrown verified @@ -306,7 +306,7 @@ public class CatastrophicFailureRecoveryTests [Before(Test)] public void SetupResources(TestContext context) { - if (context.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) { // Simulate resource allocation ResourcesToClean.Add(new DummyResource("Resource1")); @@ -326,7 +326,7 @@ public async Task Test_With_Resources_Needing_Cleanup() [After(Test)] public async Task Cleanup_Hook1_Partial_Success(TestContext context) { - if (context.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) { // Cleanup Hook 1 - cleaning first resource if (ResourcesToClean.Count > 0) @@ -341,7 +341,7 @@ public async Task Cleanup_Hook1_Partial_Success(TestContext context) [After(Test)] public async Task Cleanup_Hook2_Fails_Catastrophically(TestContext context) { - if (context.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) { // Cleanup Hook 2 - will fail catastrophically await Task.CompletedTask; @@ -352,7 +352,7 @@ public async Task Cleanup_Hook2_Fails_Catastrophically(TestContext context) [After(Test)] public async Task Cleanup_Hook3_Still_Cleans_Resources(TestContext context) { - if (context.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) { // Cleanup Hook 3 - still cleaning remaining resources after catastrophic failure @@ -374,7 +374,7 @@ public async Task Cleanup_Hook3_Still_Cleans_Resources(TestContext context) [After(Test)] public async Task Cleanup_Hook4_Verifies_Cleanup(TestContext context) { - if (context.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) + if (context.Metadata.TestDetails.ClassType == typeof(CatastrophicFailureRecoveryTests)) { // Cleanup Hook 4 - verifying cleanup status // Cleanup operations completed diff --git a/TUnit.TestProject/CaptureOutputTests.cs b/TUnit.TestProject/CaptureOutputTests.cs index 29c2b10ac2..69a89d0c9d 100644 --- a/TUnit.TestProject/CaptureOutputTests.cs +++ b/TUnit.TestProject/CaptureOutputTests.cs @@ -12,7 +12,7 @@ public async Task Test() using (Assert.Multiple()) { - await Assert.That(TestContext.Current!.TestDetails.TestName).IsEqualTo("Test"); + await Assert.That(TestContext.Current!.Metadata.TestDetails.TestName).IsEqualTo("Test"); await Assert.That(TestContext.Current.GetStandardOutput()).IsEqualTo("Blah1"); } } @@ -24,7 +24,7 @@ public async Task Test2() using (Assert.Multiple()) { - await Assert.That(TestContext.Current!.TestDetails.TestName).IsEqualTo("Test2"); + await Assert.That(TestContext.Current!.Metadata.TestDetails.TestName).IsEqualTo("Test2"); await Assert.That(TestContext.Current.GetStandardOutput()).IsEqualTo("Blah2"); } } @@ -36,7 +36,7 @@ public async Task Test3() using (Assert.Multiple()) { - await Assert.That(TestContext.Current!.TestDetails.TestName).IsEqualTo("Test3"); + await Assert.That(TestContext.Current!.Metadata.TestDetails.TestName).IsEqualTo("Test3"); await Assert.That(TestContext.Current.GetStandardOutput()).IsEqualTo("Blah3"); } } @@ -48,7 +48,7 @@ public async Task Test4() using (Assert.Multiple()) { - await Assert.That(TestContext.Current!.TestDetails.TestName).IsEqualTo("Test4"); + await Assert.That(TestContext.Current!.Metadata.TestDetails.TestName).IsEqualTo("Test4"); await Assert.That(TestContext.Current.GetStandardOutput()).IsEqualTo("Blah4"); } } @@ -60,7 +60,7 @@ public async Task Test5() using (Assert.Multiple()) { - await Assert.That(TestContext.Current!.TestDetails.TestName).IsEqualTo("Test5"); + await Assert.That(TestContext.Current!.Metadata.TestDetails.TestName).IsEqualTo("Test5"); await Assert.That(TestContext.Current.GetStandardOutput()).IsEqualTo("Blah5"); } } @@ -70,7 +70,7 @@ public static void Log(ClassHookContext context) { foreach (var test in context.Tests) { - Console.WriteLine(@$"Test {test.TestDetails.TestId} has output: {test.GetStandardOutput()}"); + Console.WriteLine(@$"Test {test.Metadata.TestDetails.TestId} has output: {test.GetStandardOutput()}"); } } diff --git a/TUnit.TestProject/CategoryTests.cs b/TUnit.TestProject/CategoryTests.cs index 5951475218..654fb058d1 100644 --- a/TUnit.TestProject/CategoryTests.cs +++ b/TUnit.TestProject/CategoryTests.cs @@ -41,7 +41,7 @@ public void C() private static IEnumerable GetDictionary() { - return TestContext.Current?.TestDetails.Categories ?? []; + return TestContext.Current?.Metadata.TestDetails.Categories ?? []; } public class ClassCategoryAttribute() : CategoryAttribute("ClassCategory2"); diff --git a/TUnit.TestProject/ClassDisplayNameAttributeTests.cs b/TUnit.TestProject/ClassDisplayNameAttributeTests.cs index eaac35581f..a4f0118494 100644 --- a/TUnit.TestProject/ClassDisplayNameAttributeTests.cs +++ b/TUnit.TestProject/ClassDisplayNameAttributeTests.cs @@ -12,7 +12,7 @@ public class ClassDisplayNameAttributeTests public async Task Test() { // This test should inherit the class display name as a prefix or part of the test name - await Assert.That(TestContext.Current!.GetDisplayName()) + await Assert.That(TestContext.Current!. Metadata.DisplayName) .DoesNotContain("ClassDisplayNameAttributeTests"); } } @@ -26,7 +26,7 @@ public class ClassDisplayNameWithParametersTests(string value) public async Task Test() { // This test should show the class display name with parameter substitution - var displayName = TestContext.Current!.GetDisplayName(); + var displayName = TestContext.Current!. Metadata.DisplayName; await Assert.That(displayName) .Contains("TestValue"); } diff --git a/TUnit.TestProject/ClassHooks.cs b/TUnit.TestProject/ClassHooks.cs index 5378d5e1a9..3d30c10cc6 100644 --- a/TUnit.TestProject/ClassHooks.cs +++ b/TUnit.TestProject/ClassHooks.cs @@ -39,7 +39,7 @@ public static void AfterHook1() public static async Task AfterHook2(ClassHookContext context) { await Assert.That(context.TestCount).IsEqualTo(1); - await Assert.That(context.Tests.Where(x => x.Result?.State == TestState.Passed)).HasCount().EqualTo(1); + await Assert.That(context.Tests.Where(x => x.Execution.Result?.State == TestState.Passed)).HasCount().EqualTo(1); } [After(Class), Timeout(30_000)] @@ -52,7 +52,7 @@ public static void AfterHook3(CancellationToken cancellationToken) public static async Task AfterHook4(ClassHookContext context, CancellationToken cancellationToken) { await Assert.That(context.TestCount).IsEqualTo(1); - await Assert.That(context.Tests.Where(x => x.Result?.State == TestState.Passed)).HasCount().EqualTo(1); + await Assert.That(context.Tests.Where(x => x.Execution.Result?.State == TestState.Passed)).HasCount().EqualTo(1); } [Test] diff --git a/TUnit.TestProject/ConsoleTests.cs b/TUnit.TestProject/ConsoleTests.cs index 89255e1bf0..a525c7a500 100644 --- a/TUnit.TestProject/ConsoleTests.cs +++ b/TUnit.TestProject/ConsoleTests.cs @@ -8,7 +8,7 @@ public class ConsoleTests [Test] public async Task Write_Source_Gen_Information() { - Console.WriteLine(TestContext.Current!.TestDetails.MethodMetadata); - await Assert.That(TestContext.Current.GetStandardOutput()).IsEqualTo(TestContext.Current.TestDetails.MethodMetadata.ToString()); + Console.WriteLine(TestContext.Current!.Metadata.TestDetails.MethodMetadata); + await Assert.That(TestContext.Current.GetStandardOutput()).IsEqualTo(TestContext.Current.Metadata.TestDetails.MethodMetadata.ToString()); } } diff --git a/TUnit.TestProject/CustomClassDisplayNameTests.cs b/TUnit.TestProject/CustomClassDisplayNameTests.cs index 627987876f..ded819214f 100644 --- a/TUnit.TestProject/CustomClassDisplayNameTests.cs +++ b/TUnit.TestProject/CustomClassDisplayNameTests.cs @@ -15,7 +15,7 @@ public class CustomClassDisplayNameTests(Base1 base1) [Test] public async Task Test() { - await Assert.That(TestContext.Current!.GetDisplayName()) + await Assert.That(TestContext.Current!. Metadata.DisplayName) .IsEqualTo("Test"); } } diff --git a/TUnit.TestProject/CustomDisplayNameTests.cs b/TUnit.TestProject/CustomDisplayNameTests.cs index c203a79977..66ebccdb92 100644 --- a/TUnit.TestProject/CustomDisplayNameTests.cs +++ b/TUnit.TestProject/CustomDisplayNameTests.cs @@ -12,14 +12,14 @@ public class CustomDisplayNameTests [DisplayName("A super important test!")] public async Task Test() { - await Assert.That(TestContext.Current!.GetDisplayName()).IsEqualTo("A super important test!"); + await Assert.That(TestContext.Current!. Metadata.DisplayName).IsEqualTo("A super important test!"); } [Test] [DisplayName("Another super important test!")] public async Task Test2() { - await Assert.That(TestContext.Current!.GetDisplayName()).IsEqualTo("Another super important test!"); + await Assert.That(TestContext.Current!. Metadata.DisplayName).IsEqualTo("Another super important test!"); } [Test] @@ -28,7 +28,7 @@ public async Task Test2() [DisplayName("Test with: $value1 $value2 $value3!")] public async Task Test3(string value1, int value2, bool value3) { - await Assert.That(TestContext.Current!.GetDisplayName()) + await Assert.That(TestContext.Current!. Metadata.DisplayName) .IsEqualTo("Test with: foo 1 True!") .Or .IsEqualTo("Test with: bar 2 False!"); @@ -39,7 +39,7 @@ await Assert.That(TestContext.Current!.GetDisplayName()) [DisplayName("Test using MethodDataSource")] public async Task MethodDataSourceTest(string foo) { - await Assert.That(TestContext.Current!.GetDisplayName()).IsEqualTo("Test using MethodDataSource"); + await Assert.That(TestContext.Current!. Metadata.DisplayName).IsEqualTo("Test using MethodDataSource"); } [Test] @@ -49,7 +49,7 @@ public async Task MethodDataSourceTest(string foo) [Arguments(300, "Type1")] public async Task TestParameterNamePrefixBug(int someValue, string someValueType) { - var displayName = TestContext.Current!.GetDisplayName(); + var displayName = TestContext.Current!. Metadata.DisplayName; // This should produce: // Test this(100, Type1), Test this(200, Type2), Test this(300, Type1) // But currently produces: @@ -66,28 +66,28 @@ await Assert.That(displayName) [MyGenerator] public async Task PasswordTest(string password) { - await Assert.That(TestContext.Current!.GetDisplayName()).IsEqualTo("PasswordTest(REDACTED)"); + await Assert.That(TestContext.Current!. Metadata.DisplayName).IsEqualTo("PasswordTest(REDACTED)"); } [Test] [DisplayName($"My test {SameClassConstant}")] public async Task SameClassConstantTest() { - await Assert.That(TestContext.Current!.GetDisplayName()).IsEqualTo("My test My constant"); + await Assert.That(TestContext.Current!. Metadata.DisplayName).IsEqualTo("My test My constant"); } [Test] [DisplayName($"My test {DifferentClassConstants.Constant}")] public async Task DifferentClassConstantTest() { - await Assert.That(TestContext.Current!.GetDisplayName()).IsEqualTo("My test My constant"); + await Assert.That(TestContext.Current!. Metadata.DisplayName).IsEqualTo("My test My constant"); } [Test] [DisplayName($"My test {NestedClassConstants.Constant}")] public async Task NestedClassConstantTest() { - await Assert.That(TestContext.Current!.GetDisplayName()).IsEqualTo("My test My constant"); + await Assert.That(TestContext.Current!. Metadata.DisplayName).IsEqualTo("My test My constant"); } public class MyGenerator : DataSourceGeneratorAttribute, ITestDiscoveryEventReceiver @@ -99,7 +99,7 @@ protected override IEnumerable> GenerateDataSources(DataGeneratorMe public ValueTask OnTestDiscovered(DiscoveredTestContext context) { - context.SetDisplayName($"{context.TestDetails.TestName}(REDACTED)"); + context.SetDisplayName($"{context.TestContext.Metadata.TestDetails.TestName}(REDACTED)"); return default(ValueTask); } diff --git a/TUnit.TestProject/CustomPropertyTests.cs b/TUnit.TestProject/CustomPropertyTests.cs index 9878fe26b0..9b93f713ac 100644 --- a/TUnit.TestProject/CustomPropertyTests.cs +++ b/TUnit.TestProject/CustomPropertyTests.cs @@ -28,7 +28,7 @@ public async Task Test() private static ImmutableDictionary> GetDictionary() { - return TestContext.Current?.TestDetails.CustomProperties.ToImmutableDictionary(x => x.Key, x => (IReadOnlyList) x.Value) + return TestContext.Current?.Metadata.TestDetails.CustomProperties.ToImmutableDictionary(x => x.Key, x => (IReadOnlyList) x.Value) ?? ImmutableDictionary>.Empty; } diff --git a/TUnit.TestProject/DebugRepeatTest.cs b/TUnit.TestProject/DebugRepeatTest.cs index 59c07f4ddf..824d97e4c1 100644 --- a/TUnit.TestProject/DebugRepeatTest.cs +++ b/TUnit.TestProject/DebugRepeatTest.cs @@ -16,8 +16,8 @@ public async Task TestWithRepeat() var context = TestContext.Current!; Console.WriteLine($"Execution #{count}:"); - Console.WriteLine($" TestId: {context.TestDetails.TestId}"); - Console.WriteLine($" TestName: {context.TestDetails.TestName}"); + Console.WriteLine($" TestId: {context.Metadata.TestDetails.TestId}"); + Console.WriteLine($" TestName: {context.Metadata.TestDetails.TestName}"); Console.WriteLine($" Thread: {Thread.CurrentThread.ManagedThreadId}"); await Task.Delay(100); diff --git a/TUnit.TestProject/DebugTimingTest.cs b/TUnit.TestProject/DebugTimingTest.cs index 5219d72773..ccb7df3d12 100644 --- a/TUnit.TestProject/DebugTimingTest.cs +++ b/TUnit.TestProject/DebugTimingTest.cs @@ -10,13 +10,13 @@ public class DebugTimingTest public async Task CheckTimingProperties() { var context = TestContext.Current!; - - Console.WriteLine($"TestStart at test start: {context.TestStart?.ToString("O") ?? "NULL"}"); - Console.WriteLine($"TestEnd at test start: {context.TestEnd?.ToString("O") ?? "NULL"}"); - + + Console.WriteLine($"TestStart at test start: {context.Execution.TestStart?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"TestEnd at test start: {context.Execution.TestEnd?.ToString("O") ?? "NULL"}"); + await Task.Delay(100); - - Console.WriteLine($"TestStart after delay: {context.TestStart?.ToString("O") ?? "NULL"}"); - Console.WriteLine($"TestEnd after delay: {context.TestEnd?.ToString("O") ?? "NULL"}"); + + Console.WriteLine($"TestStart after delay: {context.Execution.TestStart?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"TestEnd after delay: {context.Execution.TestEnd?.ToString("O") ?? "NULL"}"); } -} \ No newline at end of file +} diff --git a/TUnit.TestProject/DebugTimingTest2.cs b/TUnit.TestProject/DebugTimingTest2.cs index d663bea452..94715ec0b6 100644 --- a/TUnit.TestProject/DebugTimingTest2.cs +++ b/TUnit.TestProject/DebugTimingTest2.cs @@ -10,29 +10,29 @@ public class DebugTimingTest2 public async Task CheckRepeatedTestTiming() { var context = TestContext.Current!; - var testId = context.TestDetails.TestId; - + var testId = context.Metadata.TestDetails.TestId; + Console.WriteLine($"[During Test] TestId: {testId}"); - Console.WriteLine($"[During Test] TestStart: {context.TestStart?.ToString("O") ?? "NULL"}"); - Console.WriteLine($"[During Test] TestEnd: {context.TestEnd?.ToString("O") ?? "NULL"}"); - Console.WriteLine($"[During Test] Result: {context.Result?.ToString() ?? "NULL"}"); - + Console.WriteLine($"[During Test] TestStart: {context.Execution.TestStart?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"[During Test] TestEnd: {context.Execution.TestEnd?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"[During Test] Result: {context.Execution.Result?.ToString() ?? "NULL"}"); + await Task.Delay(300); } - + [After(Test)] public async Task AfterTestHook() { var context = TestContext.Current!; - var testId = context.TestDetails.TestId; - + var testId = context.Metadata.TestDetails.TestId; + Console.WriteLine($"[After Hook] TestId: {testId}"); - Console.WriteLine($"[After Hook] TestStart: {context.TestStart?.ToString("O") ?? "NULL"}"); - Console.WriteLine($"[After Hook] TestEnd: {context.TestEnd?.ToString("O") ?? "NULL"}"); - Console.WriteLine($"[After Hook] Result.Start: {context.Result?.Start?.ToString("O") ?? "NULL"}"); - Console.WriteLine($"[After Hook] Result.End: {context.Result?.End?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"[After Hook] TestStart: {context.Execution.TestStart?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"[After Hook] TestEnd: {context.Execution.TestEnd?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"[After Hook] Result.Start: {context.Execution.Result?.Start?.ToString("O") ?? "NULL"}"); + Console.WriteLine($"[After Hook] Result.End: {context.Execution.Result?.End?.ToString("O") ?? "NULL"}"); Console.WriteLine("---"); - + await Task.CompletedTask; } -} \ No newline at end of file +} diff --git a/TUnit.TestProject/DependsOnTests2.cs b/TUnit.TestProject/DependsOnTests2.cs index b16d202f31..d93bcfc696 100644 --- a/TUnit.TestProject/DependsOnTests2.cs +++ b/TUnit.TestProject/DependsOnTests2.cs @@ -12,21 +12,21 @@ public class DependsOnTests2 [Arguments("1", 2, true)] public async Task Test1(string one, int two, bool three) { - _test1Start = TestContext.Current!.TestStart!.Value.DateTime; + _test1Start = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.Delay(TimeSpan.FromSeconds(5)); } [Test, DependsOn(nameof(Test1), parameterTypes: [typeof(string), typeof(int), typeof(bool)])] public async Task Test2() { - _test2Start = TestContext.Current!.TestStart!.Value.DateTime; + _test2Start = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.CompletedTask; } [Test] public async Task Test3() { - await Assert.That(() => TestContext.Current!.GetTests(nameof(Test1))).ThrowsException().WithMessage("Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?"); + await Assert.That(() => TestContext.Current!.Dependencies.GetTests(nameof(Test1))).ThrowsException().WithMessage("Cannot get unfinished tests - Did you mean to add a [DependsOn] attribute?"); } [After(Class)] diff --git a/TUnit.TestProject/DependsOnTests3.cs b/TUnit.TestProject/DependsOnTests3.cs index 35c5c56819..247f322522 100644 --- a/TUnit.TestProject/DependsOnTests3.cs +++ b/TUnit.TestProject/DependsOnTests3.cs @@ -15,7 +15,7 @@ public async Task Test1() { await Task.Delay(TimeSpan.FromSeconds(1)); - TestContext.Current!.ObjectBag["Test1"] = "1"; + TestContext.Current!.StateBag.Items["Test1"] = "1"; _test1End = DateTime.UtcNow; } @@ -25,7 +25,7 @@ public async Task Test2() { await Task.Delay(TimeSpan.FromSeconds(1)); - TestContext.Current!.ObjectBag["Test2"] = "2"; + TestContext.Current!.StateBag.Items["Test2"] = "2"; _test2End = DateTime.UtcNow; } @@ -39,14 +39,14 @@ public async Task Test3() await Task.Delay(TimeSpan.FromSeconds(1)); - var test1 = TestContext.Current!.GetTests(nameof(Test1)); - var test2 = TestContext.Current.GetTests(nameof(Test2)); + var test1 = TestContext.Current!.Dependencies.GetTests(nameof(Test1)); + var test2 = TestContext.Current.Dependencies.GetTests(nameof(Test2)); await Assert.That(test1).HasCount().EqualTo(1); await Assert.That(test2).HasCount().EqualTo(1); - await Assert.That(test1[0].ObjectBag).ContainsKey("Test1"); - await Assert.That(test2[0].ObjectBag).ContainsKey("Test2"); + await Assert.That(test1[0].StateBag.Items).ContainsKey("Test1"); + await Assert.That(test2[0].StateBag.Items).ContainsKey("Test2"); } [After(Class)] diff --git a/TUnit.TestProject/DependsOnTestsWithClass.cs b/TUnit.TestProject/DependsOnTestsWithClass.cs index ab9d9a3c19..e9825bd313 100644 --- a/TUnit.TestProject/DependsOnTestsWithClass.cs +++ b/TUnit.TestProject/DependsOnTestsWithClass.cs @@ -9,7 +9,7 @@ public class DependsOnTestsOtherClass [Test] public async Task Test1() { - Test1Start = TestContext.Current!.TestStart!.Value.DateTime; + Test1Start = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.Delay(TimeSpan.FromSeconds(5)); } } @@ -22,7 +22,7 @@ public class DependsOnTestsWithClass [Test, DependsOn(typeof(DependsOnTestsOtherClass), nameof(DependsOnTestsOtherClass.Test1))] public async Task Test2() { - _test2Start = TestContext.Current!.TestStart!.Value.DateTime; + _test2Start = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.CompletedTask; } diff --git a/TUnit.TestProject/DependsOnTestsWithClass2.cs b/TUnit.TestProject/DependsOnTestsWithClass2.cs index 4754ce85ff..d775a1057a 100644 --- a/TUnit.TestProject/DependsOnTestsWithClass2.cs +++ b/TUnit.TestProject/DependsOnTestsWithClass2.cs @@ -9,7 +9,7 @@ public class DependsOnTestsOtherClass2 [Test] public async Task Test1() { - Test1Start = TestContext.Current!.TestStart!.Value.DateTime; + Test1Start = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.Delay(TimeSpan.FromSeconds(5)); } } @@ -22,7 +22,7 @@ public class DependsOnTestsWithClass2 [Test, DependsOn(typeof(DependsOnTestsOtherClass2))] public async Task Test2() { - _test2Start = TestContext.Current!.TestStart!.Value.DateTime; + _test2Start = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.CompletedTask; } diff --git a/TUnit.TestProject/DependsOnWithBaseTests.cs b/TUnit.TestProject/DependsOnWithBaseTests.cs index d094d47801..cca59b5330 100644 --- a/TUnit.TestProject/DependsOnWithBaseTests.cs +++ b/TUnit.TestProject/DependsOnWithBaseTests.cs @@ -11,7 +11,7 @@ public class DependsOnWithBaseTests : DependsOnBase [Test, DependsOn(nameof(BaseTest))] public async Task SubTypeTest() { - _subTypeTestStart = TestContext.Current!.TestStart!.Value.DateTime; + _subTypeTestStart = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.CompletedTask; } @@ -30,7 +30,7 @@ public abstract class DependsOnBase [Test] public async Task BaseTest() { - BaseTestStart = TestContext.Current!.TestStart!.Value.DateTime; + BaseTestStart = TestContext.Current!.Execution.TestStart!.Value.DateTime; await Task.Delay(TimeSpan.FromSeconds(5)); } } diff --git a/TUnit.TestProject/DisposalRegressionTests.cs b/TUnit.TestProject/DisposalRegressionTests.cs index 33a6b086b4..bf4c3cd933 100644 --- a/TUnit.TestProject/DisposalRegressionTests.cs +++ b/TUnit.TestProject/DisposalRegressionTests.cs @@ -32,7 +32,7 @@ public async Task TestExecutes() public static async Task VerifyDisposal(ClassHookContext context) { // After the test class is done, both the test instance and injected property should be disposed - foreach (var testInstance in context.Tests.Select(x => x.TestDetails.ClassInstance).OfType()) + foreach (var testInstance in context.Tests.Select(x => x.Metadata.TestDetails.ClassInstance).OfType()) { await Assert.That(testInstance.IsDisposed).IsTrue(); await Assert.That(testInstance.InjectedData.IsDisposed).IsTrue(); diff --git a/TUnit.TestProject/EventReceiverTests.cs b/TUnit.TestProject/EventReceiverTests.cs index 2cc16af9f9..e1c4f8fb0c 100644 --- a/TUnit.TestProject/EventReceiverTests.cs +++ b/TUnit.TestProject/EventReceiverTests.cs @@ -13,19 +13,19 @@ public class EventReceiverAttribute : Attribute, ITestStartEventReceiver, ITestE public ValueTask OnTestStart(TestContext context) { - Events.Add($"TestStart: {context.GetDisplayName()}"); + Events.Add($"TestStart: {context. Metadata.DisplayName}"); return default(ValueTask); } public ValueTask OnTestEnd(TestContext context) { - Events.Add($"TestEnd: {context.GetDisplayName()}"); + Events.Add($"TestEnd: {context. Metadata.DisplayName}"); return default(ValueTask); } public ValueTask OnTestSkipped(TestContext context) { - Events.Add($"TestSkipped: {context.GetDisplayName()}"); + Events.Add($"TestSkipped: {context. Metadata.DisplayName}"); return default(ValueTask); } } @@ -58,7 +58,7 @@ public async Task VerifyEventsReceived(TestContext context) { await Task.Delay(50); // Give time for event to be recorded - var displayName = context.GetDisplayName(); + var displayName = context. Metadata.DisplayName; if (displayName.Contains("Skipped")) { diff --git a/TUnit.TestProject/ExecutionContextRestorationTests.cs b/TUnit.TestProject/ExecutionContextRestorationTests.cs index 205c9f03e8..0c3ec57f31 100644 --- a/TUnit.TestProject/ExecutionContextRestorationTests.cs +++ b/TUnit.TestProject/ExecutionContextRestorationTests.cs @@ -21,7 +21,7 @@ public async Task AfterTest(TestContext context) { // The async local should be accessible here var value = TestAsyncLocal.Value; - context.WriteLine($"AfterTest AsyncLocal value: {value}"); + context.Output.StandardOutput.WriteLine($"AfterTest AsyncLocal value: {value}"); await Task.Yield(); } diff --git a/TUnit.TestProject/FirstEventTrackerTest.cs b/TUnit.TestProject/FirstEventTrackerTest.cs index 5c24a127e2..f203563034 100644 --- a/TUnit.TestProject/FirstEventTrackerTest.cs +++ b/TUnit.TestProject/FirstEventTrackerTest.cs @@ -13,8 +13,8 @@ public class FirstEventTracker : IFirstTestInAssemblyEventReceiver, IFirstTestIn public ValueTask OnFirstTestInAssembly(AssemblyHookContext context, TestContext testContext) { var assembly = context.Assembly.GetName().FullName ?? "Unknown"; - var className = testContext.TestDetails.ClassType.FullName ?? "Unknown"; - var testName = testContext.TestDetails.TestName; + var className = testContext.Metadata.TestDetails.ClassType.FullName ?? "Unknown"; + var testName = testContext.Metadata.TestDetails.TestName; Events.Add(("FirstAssembly", assembly, className, testName, DateTime.UtcNow)); Console.WriteLine($"[{DateTime.UtcNow:HH:mm:ss.fff}] FirstTestInAssembly: {assembly} - {className}.{testName}"); @@ -25,7 +25,7 @@ public ValueTask OnFirstTestInClass(ClassHookContext context, TestContext testCo { var assembly = context.AssemblyContext.Assembly.GetName().FullName ?? "Unknown"; var className = context.ClassType.FullName ?? "Unknown"; - var testName = testContext.TestDetails.TestName; + var testName = testContext.Metadata.TestDetails.TestName; Events.Add(("FirstClass", assembly, className, testName, DateTime.UtcNow)); Console.WriteLine($"[{DateTime.UtcNow:HH:mm:ss.fff}] FirstTestInClass: {className} - {testName}"); diff --git a/TUnit.TestProject/GlobalTestHooks.cs b/TUnit.TestProject/GlobalTestHooks.cs index dc48e6bf4a..5f6cb4cca4 100644 --- a/TUnit.TestProject/GlobalTestHooks.cs +++ b/TUnit.TestProject/GlobalTestHooks.cs @@ -5,17 +5,17 @@ public class GlobalTestHooks [BeforeEvery(Test)] public static void SetUp(TestContext testContext) { - testContext.ObjectBag.TryAdd("SetUpCustomTestNameProperty", testContext.TestDetails.TestName); + testContext.StateBag.Items.TryAdd("SetUpCustomTestNameProperty", testContext.Metadata.TestDetails.TestName); } [AfterEvery(Test)] public static async Task CleanUp(TestContext testContext) { - testContext.ObjectBag.TryAdd("CleanUpCustomTestNameProperty", testContext.TestDetails.TestName); + testContext.StateBag.Items.TryAdd("CleanUpCustomTestNameProperty", testContext.Metadata.TestDetails.TestName); // Result may be null for skipped tests or tests that fail during initialization // Only validate Result for tests that actually executed - if (testContext.Result != null) + if (testContext.Execution.Result != null) { // We can add assertions here if needed for executed tests await Task.CompletedTask; @@ -48,8 +48,8 @@ public class GlobalTestHooksTests [Test] public async Task SetUpTest1() { - await Assert.That(TestContext.Current?.ObjectBag).HasCount().EqualTo(1); - await Assert.That(TestContext.Current?.ObjectBag.First().Key).IsEqualTo("SetUpCustomTestNameProperty"); - await Assert.That(TestContext.Current?.ObjectBag.First().Value).IsEquatableOrEqualTo("SetUpTest1"); + await Assert.That(TestContext.Current?.StateBag.Items).HasCount().EqualTo(1); + await Assert.That(TestContext.Current?.StateBag.Items.First().Key).IsEqualTo("SetUpCustomTestNameProperty"); + await Assert.That(TestContext.Current?.StateBag.Items.First().Value).IsEquatableOrEqualTo("SetUpTest1"); } } diff --git a/TUnit.TestProject/HookContextRestorationTests.cs b/TUnit.TestProject/HookContextRestorationTests.cs index 13e3ccd778..17ad41f5f9 100644 --- a/TUnit.TestProject/HookContextRestorationTests.cs +++ b/TUnit.TestProject/HookContextRestorationTests.cs @@ -72,6 +72,6 @@ public async Task AfterTest(TestContext context) await Assert.That(assemblyContext).IsNotNull(); await Assert.That(classContext).IsNotNull(); - context.WriteLine($"AfterTest - Assembly: {assemblyContext?.Assembly.GetName().Name}, Class: {classContext?.ClassType.Name}"); + context.Output.StandardOutput.WriteLine($"AfterTest - Assembly: {assemblyContext?.Assembly.GetName().Name}, Class: {classContext?.ClassType.Name}"); } } \ No newline at end of file diff --git a/TUnit.TestProject/HookExecutorTests.cs b/TUnit.TestProject/HookExecutorTests.cs index c533694097..3d13292874 100644 --- a/TUnit.TestProject/HookExecutorTests.cs +++ b/TUnit.TestProject/HookExecutorTests.cs @@ -16,11 +16,11 @@ public static async Task BeforeTestSessionWithCustomExecutor(TestSessionContext await Assert.That(CrossPlatformTestExecutor.IsRunningInTestExecutor.Value).IsTrue(); var test = context.AllTests.FirstOrDefault(x => - x.TestDetails.TestName == nameof(VerifyBeforeTestSessionExecutorExecuted)); + x.Metadata.TestDetails.TestName == nameof(VerifyBeforeTestSessionExecutorExecuted)); if (test != null) { - test.ObjectBag["BeforeTestSessionExecutorExecuted"] = true; + test.StateBag.Items["BeforeTestSessionExecutorExecuted"] = true; } } @@ -96,7 +96,7 @@ public async Task BeforeTestWithCustomExecutor(TestContext context) { await Assert.That(Thread.CurrentThread.Name).IsEqualTo("CrossPlatformTestExecutor"); await Assert.That(CrossPlatformTestExecutor.IsRunningInTestExecutor.Value).IsTrue(); - context.ObjectBag["BeforeTestExecutorExecuted"] = true; + context.StateBag.Items["BeforeTestExecutorExecuted"] = true; } [After(Test)] @@ -115,9 +115,9 @@ public static async Task BeforeEveryTestWithCustomExecutor(TestContext context) await Assert.That(Thread.CurrentThread.Name).IsEqualTo("CrossPlatformTestExecutor"); await Assert.That(CrossPlatformTestExecutor.IsRunningInTestExecutor.Value).IsTrue(); - if (context.TestDetails.TestName == nameof(VerifyStaticTestHooksExecutorExecuted)) + if (context.Metadata.TestDetails.TestName == nameof(VerifyStaticTestHooksExecutorExecuted)) { - context.ObjectBag["BeforeEveryTestExecutorExecuted"] = true; + context.StateBag.Items["BeforeEveryTestExecutorExecuted"] = true; } } @@ -133,7 +133,7 @@ public static async Task AfterEveryTestWithCustomExecutor(TestContext context) [Test] public async Task VerifyBeforeTestSessionExecutorExecuted() { - await Assert.That(TestContext.Current?.ObjectBag["BeforeTestSessionExecutorExecuted"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current?.StateBag.Items["BeforeTestSessionExecutorExecuted"]).IsEquatableOrEqualTo(true); } [Test] @@ -151,12 +151,12 @@ public async Task VerifyBeforeClassExecutorExecuted() [Test] public async Task VerifyBeforeTestExecutorExecuted() { - await Assert.That(TestContext.Current?.ObjectBag["BeforeTestExecutorExecuted"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current?.StateBag.Items["BeforeTestExecutorExecuted"]).IsEquatableOrEqualTo(true); } [Test] public async Task VerifyStaticTestHooksExecutorExecuted() { - await Assert.That(TestContext.Current?.ObjectBag["BeforeEveryTestExecutorExecuted"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current?.StateBag.Items["BeforeEveryTestExecutorExecuted"]).IsEquatableOrEqualTo(true); } } diff --git a/TUnit.TestProject/HookOrderTest.cs b/TUnit.TestProject/HookOrderTest.cs index d4fa673951..a169de59ff 100644 --- a/TUnit.TestProject/HookOrderTest.cs +++ b/TUnit.TestProject/HookOrderTest.cs @@ -23,7 +23,7 @@ public sealed class GlobalHooks public static void BeforeTest(TestContext testContext) { // Only output for our specific test class to avoid polluting other tests - if (testContext.TestDetails.ClassType == typeof(HookOrderTests)) + if (testContext.Metadata.TestDetails.ClassType == typeof(HookOrderTests)) { Console.WriteLine("Before every test"); } diff --git a/TUnit.TestProject/HumanizerDisplayNameTests.cs b/TUnit.TestProject/HumanizerDisplayNameTests.cs index 19924fed7d..f13c3587ee 100644 --- a/TUnit.TestProject/HumanizerDisplayNameTests.cs +++ b/TUnit.TestProject/HumanizerDisplayNameTests.cs @@ -11,14 +11,14 @@ public class HumanizerDisplayNameTests public void This_test_name_is_formatted_nicely() { // Dummy method - Console.WriteLine(TestContext.Current!.GetDisplayName()); + Console.WriteLine(TestContext.Current!. Metadata.DisplayName); } public class HumanizerDisplayNameAttribute : DisplayNameFormatterAttribute { protected override string FormatDisplayName(DiscoveredTestContext context) { - return context.TestDetails.TestName.Humanize(); + return context.TestContext.Metadata.TestDetails.TestName.Humanize(); } } } diff --git a/TUnit.TestProject/IDisposableTests.cs b/TUnit.TestProject/IDisposableTests.cs index f6b32a831a..a1dc7a1be3 100644 --- a/TUnit.TestProject/IDisposableTests.cs +++ b/TUnit.TestProject/IDisposableTests.cs @@ -26,7 +26,7 @@ public async Task Three() [After(Class)] public static async Task AssertDisposed(ClassHookContext context) { - foreach (var disposableTestse in context.Tests.Select(x => x.TestDetails.ClassInstance).OfType()) + foreach (var disposableTestse in context.Tests.Select(x => x.Metadata.TestDetails.ClassInstance).OfType()) { await Assert.That(disposableTestse.IsDisposed).IsTrue(); } diff --git a/TUnit.TestProject/InheritedCategoryTestValidation.cs b/TUnit.TestProject/InheritedCategoryTestValidation.cs index 2d65d822d9..d6b543383e 100644 --- a/TUnit.TestProject/InheritedCategoryTestValidation.cs +++ b/TUnit.TestProject/InheritedCategoryTestValidation.cs @@ -12,7 +12,7 @@ public async Task TestInheritedMultipleCategoriesMethod() { // This test verifies that the class inherits the BaseCategoriesOnClass category from the base class // and has its own TestCategory - await Assert.That(TestContext.Current!.TestDetails.Categories).Contains("BaseCategoriesOnClass"); - await Assert.That(TestContext.Current!.TestDetails.Categories).Contains("TestCategory"); + await Assert.That(TestContext.Current!.Metadata.TestDetails.Categories).Contains("BaseCategoriesOnClass"); + await Assert.That(TestContext.Current!.Metadata.TestDetails.Categories).Contains("TestCategory"); } } diff --git a/TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs b/TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs index 9a347004f8..7f6924f8e9 100644 --- a/TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs +++ b/TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs @@ -26,7 +26,7 @@ public void NonGenericMethodDataSource(string value) [Test] public async Task VerifyInheritedCategoriesAreAvailable() { - var categories = TestContext.Current?.TestDetails.Categories; + var categories = TestContext.Current?.Metadata.TestDetails.Categories; await Assert.That(categories).Contains("BaseCategoriesOnClass"); } } diff --git a/TUnit.TestProject/Inject_SharedInstancePerKey.cs b/TUnit.TestProject/Inject_SharedInstancePerKey.cs index b4c1800410..e705a4b3be 100644 --- a/TUnit.TestProject/Inject_SharedInstancePerKey.cs +++ b/TUnit.TestProject/Inject_SharedInstancePerKey.cs @@ -29,7 +29,7 @@ public static string Key { throw new InvalidOperationException("TestContext.Current is null. This can happen if the test is not run in a TUnit test environment."); } - return TestContext.Current.TestDetails.MethodMetadata.Class.Namespace + "." + TestContext.Current.TestDetails.MethodMetadata.Class.Name + "_" + TestContext.Current.TestDetails.TestName; + return TestContext.Current.Metadata.TestDetails.MethodMetadata.Class.Namespace + "." + TestContext.Current.Metadata.TestDetails.MethodMetadata.Class.Name + "_" + TestContext.Current.Metadata.TestDetails.TestName; } } @@ -55,7 +55,7 @@ public async Task Test3() [ClassDataSource(Shared = SharedType.PerClass), NotInParallel] public class InjectSharedPerKey2(DummyReferenceTypeClass dummyReferenceTypeClass) { - public static string Key => TestContext.Current!.TestDetails.MethodMetadata.Class.Namespace + "." + TestContext.Current.TestDetails.MethodMetadata.Class.Name + "_" + TestContext.Current.TestDetails.TestName; + public static string Key => TestContext.Current!.Metadata.TestDetails.MethodMetadata.Class.Namespace + "." + TestContext.Current.Metadata.TestDetails.MethodMetadata.Class.Name + "_" + TestContext.Current.Metadata.TestDetails.TestName; [Test, Repeat(5)] public async Task Test1() @@ -79,8 +79,8 @@ public async Task Test3() [ClassDataSource(Shared = SharedType.PerClass), NotInParallel] public class InjectSharedPerKey3(DummyReferenceTypeClass dummyReferenceTypeClass) { - public static string Key => TestContext.Current!.TestDetails.MethodMetadata.Class.Namespace + "." + TestContext.Current.TestDetails.MethodMetadata.Class.Name + "_" - + TestContext.Current.TestDetails.TestName; + public static string Key => TestContext.Current!.Metadata.TestDetails.MethodMetadata.Class.Namespace + "." + TestContext.Current.Metadata.TestDetails.MethodMetadata.Class.Name + "_" + + TestContext.Current.Metadata.TestDetails.TestName; [Test, Repeat(5)] public async Task Test1() diff --git a/TUnit.TestProject/KeyedNotInParallelTests.cs b/TUnit.TestProject/KeyedNotInParallelTests.cs index 555e412d9c..4688dafd49 100644 --- a/TUnit.TestProject/KeyedNotInParallelTests.cs +++ b/TUnit.TestProject/KeyedNotInParallelTests.cs @@ -12,7 +12,7 @@ public class KeyedNotInParallelTests [After(Test)] public async Task TestOverlaps() { - TestDateTimeRanges.Add(new ConstraintDateTimeRange(TestContext.Current!.TestDetails.TestName, TestContext.Current.TestStart!.Value.DateTime, TestContext.Current.Result!.End!.Value.DateTime)); + TestDateTimeRanges.Add(new ConstraintDateTimeRange(TestContext.Current!.Metadata.TestDetails.TestName, TestContext.Current.Execution.TestStart!.Value.DateTime, TestContext.Current.Execution.Result!.End!.Value.DateTime)); await AssertNoOverlaps(); } diff --git a/TUnit.TestProject/LastTestEventReceiverTests.cs b/TUnit.TestProject/LastTestEventReceiverTests.cs index 6c00671593..2bd365ff8b 100644 --- a/TUnit.TestProject/LastTestEventReceiverTests.cs +++ b/TUnit.TestProject/LastTestEventReceiverTests.cs @@ -40,7 +40,7 @@ public async Task VerifyLastTestEventFired(TestContext context) // Give some time for async event receivers to complete await Task.Delay(100); - var displayName = context.GetDisplayName(); + var displayName = context. Metadata.DisplayName; // After the last test (Test3), we should have the last test event recorded if (displayName.Contains("Test3")) @@ -60,13 +60,13 @@ public class LastTestEventReceiverAttribute : Attribute, public ValueTask OnTestStart(TestContext context) { - LastTestEventReceiverTests.Events.Add($"TestStart: {context.GetDisplayName()}"); + LastTestEventReceiverTests.Events.Add($"TestStart: {context. Metadata.DisplayName}"); return default; } public ValueTask OnTestEnd(TestContext context) { - LastTestEventReceiverTests.Events.Add($"TestEnd: {context.GetDisplayName()}"); + LastTestEventReceiverTests.Events.Add($"TestEnd: {context. Metadata.DisplayName}"); return default; } @@ -135,7 +135,7 @@ public async Task VerifySkipEventFired(TestContext context) // Give some time for async event receivers to complete await Task.Delay(100); - if (context.GetDisplayName().Contains("SkippedTestWithCustomReason")) + if (context. Metadata.DisplayName.Contains("SkippedTestWithCustomReason")) { await Assert.That(Events).Contains("TestSkipped"); await Assert.That(Events).Contains("TestEnd"); @@ -154,7 +154,7 @@ public class SkipEventReceiverAttribute : Attribute, public ValueTask OnTestSkipped(TestContext context) { SkippedEventReceiverTests.Events.Add("TestSkipped"); - SkippedEventReceiverTests.CapturedSkipReason = context.SkipReason; + SkippedEventReceiverTests.CapturedSkipReason = context.Execution.SkipReason; return default; } @@ -191,7 +191,7 @@ public async Task VerifyRuntimeSkipEventFired(TestContext context) // Give some time for async event receivers to complete await Task.Delay(100); - if (context.GetDisplayName().Contains("RuntimeSkippedTestWithCustomReason")) + if (context. Metadata.DisplayName.Contains("RuntimeSkippedTestWithCustomReason")) { // Verify skip reason is preserved await Assert.That(CapturedSkipReason).IsEqualTo("Custom runtime skip reason"); @@ -217,7 +217,7 @@ public class RuntimeSkipEventReceiverAttribute : Attribute, public ValueTask OnTestSkipped(TestContext context) { RuntimeSkipEventReceiverTests.Events.Add("TestSkipped"); - RuntimeSkipEventReceiverTests.CapturedSkipReason = context.SkipReason; + RuntimeSkipEventReceiverTests.CapturedSkipReason = context.Execution.SkipReason; return default; } diff --git a/TUnit.TestProject/MEDITest.cs b/TUnit.TestProject/MEDITest.cs index 49f02baf56..c1bd61659c 100644 --- a/TUnit.TestProject/MEDITest.cs +++ b/TUnit.TestProject/MEDITest.cs @@ -47,14 +47,15 @@ public static async Task CheckDisposed(TestSessionContext testSessionContext) ?.Tests .FirstOrDefault(); - if (test?.Result == null) + if (test?.Execution.Result == null) { // If the test did not run, we cannot check if the class was disposed. return; } var mediClass = test - ?.TestDetails + .Metadata + .TestDetails .TestClassArguments .OfType() .First(); diff --git a/TUnit.TestProject/NestedBaseTests.cs b/TUnit.TestProject/NestedBaseTests.cs index ab256347bf..22aead9f3c 100644 --- a/TUnit.TestProject/NestedBaseTests.cs +++ b/TUnit.TestProject/NestedBaseTests.cs @@ -17,13 +17,13 @@ public static async Task AssertCounts(ClassHookContext context) using (Assert.Multiple()) { - await Assert.That(test.ObjectBag[nameof(Before1)]).IsEqualTo(1); - await Assert.That(test.ObjectBag[nameof(Before2)]).IsEqualTo(1); - await Assert.That(test.ObjectBag[nameof(Before3)]).IsEqualTo(1); + await Assert.That(test.StateBag.Items[nameof(Before1)]).IsEqualTo(1); + await Assert.That(test.StateBag.Items[nameof(Before2)]).IsEqualTo(1); + await Assert.That(test.StateBag.Items[nameof(Before3)]).IsEqualTo(1); - await Assert.That(test.ObjectBag[nameof(After1)]).IsEqualTo(1); - await Assert.That(test.ObjectBag[nameof(After2)]).IsEqualTo(1); - await Assert.That(test.ObjectBag[nameof(After3)]).IsEqualTo(1); + await Assert.That(test.StateBag.Items[nameof(After1)]).IsEqualTo(1); + await Assert.That(test.StateBag.Items[nameof(After2)]).IsEqualTo(1); + await Assert.That(test.StateBag.Items[nameof(After3)]).IsEqualTo(1); } } } @@ -33,15 +33,15 @@ public class NestedBase1 : NestedBase2 [Before(Test)] public void Before1(TestContext context) { - var count = context.ObjectBag.GetValueOrDefault(nameof(Before1)) as int? ?? 0; - context.ObjectBag[nameof(Before1)] = count + 1; + var count = context.StateBag.Items.GetValueOrDefault(nameof(Before1)) as int? ?? 0; + context.StateBag.Items[nameof(Before1)] = count + 1; } [After(Test)] public void After1(TestContext context) { - var count = context.ObjectBag.GetValueOrDefault(nameof(After1)) as int? ?? 0; - context.ObjectBag[nameof(After1)] = count + 1; + var count = context.StateBag.Items.GetValueOrDefault(nameof(After1)) as int? ?? 0; + context.StateBag.Items[nameof(After1)] = count + 1; } } @@ -50,15 +50,15 @@ public class NestedBase2 : NestedBase3 [Before(Test)] public void Before2(TestContext context) { - var count = context.ObjectBag.GetValueOrDefault(nameof(Before2)) as int? ?? 0; - context.ObjectBag[nameof(Before2)] = count + 1; + var count = context.StateBag.Items.GetValueOrDefault(nameof(Before2)) as int? ?? 0; + context.StateBag.Items[nameof(Before2)] = count + 1; } [After(Test)] public void After2(TestContext context) { - var count = context.ObjectBag.GetValueOrDefault(nameof(After2)) as int? ?? 0; - context.ObjectBag[nameof(After2)] = count + 1; + var count = context.StateBag.Items.GetValueOrDefault(nameof(After2)) as int? ?? 0; + context.StateBag.Items[nameof(After2)] = count + 1; } } @@ -67,14 +67,14 @@ public class NestedBase3 [Before(Test)] public void Before3(TestContext context) { - var count = context.ObjectBag.GetValueOrDefault(nameof(Before3)) as int? ?? 0; - context.ObjectBag[nameof(Before3)] = count + 1; + var count = context.StateBag.Items.GetValueOrDefault(nameof(Before3)) as int? ?? 0; + context.StateBag.Items[nameof(Before3)] = count + 1; } [After(Test)] public void After3(TestContext context) { - var count = context.ObjectBag.GetValueOrDefault(nameof(After3)) as int? ?? 0; - context.ObjectBag[nameof(After3)] = count + 1; + var count = context.StateBag.Items.GetValueOrDefault(nameof(After3)) as int? ?? 0; + context.StateBag.Items[nameof(After3)] = count + 1; } } diff --git a/TUnit.TestProject/NotInParallelExecutionTests.cs b/TUnit.TestProject/NotInParallelExecutionTests.cs index 6a195662ab..548a7214c6 100644 --- a/TUnit.TestProject/NotInParallelExecutionTests.cs +++ b/TUnit.TestProject/NotInParallelExecutionTests.cs @@ -23,12 +23,12 @@ public void RecordTestStart() MaxConcurrentTests = CurrentlyRunning; } } - + // Use TestStart if available, otherwise use DateTime.Now - var startTime = TestContext.Current.TestStart?.DateTime ?? DateTime.Now; - + var startTime = TestContext.Current.Execution.TestStart?.DateTime ?? DateTime.Now; + ExecutionRecords.Add(new TestExecutionRecord( - TestContext.Current!.TestDetails.TestName, + TestContext.Current!.Metadata.TestDetails.TestName, startTime, null, CurrentlyRunning @@ -43,14 +43,14 @@ public async Task RecordTestEnd() CurrentlyRunning--; } - var record = ExecutionRecords.FirstOrDefault(r => - r.TestName == TestContext.Current!.TestDetails.TestName && + var record = ExecutionRecords.FirstOrDefault(r => + r.TestName == TestContext.Current!.Metadata.TestDetails.TestName && r.EndTime == null); - + if (record != null) { // Use Result.End if available, otherwise use DateTime.Now - record.EndTime = TestContext.Current.Result?.End?.DateTime ?? DateTime.Now; + record.EndTime = TestContext.Current.Execution.Result?.End?.DateTime ?? DateTime.Now; } await AssertNoParallelExecution(); @@ -93,7 +93,7 @@ await Assert.That(MaxConcurrentTests) .Because($"Tests with NotInParallel should not run concurrently. Max concurrent: {MaxConcurrentTests}"); var completedRecords = ExecutionRecords.Where(r => r.EndTime != null).ToList(); - + foreach (var record in completedRecords) { var overlappingTests = completedRecords @@ -132,4 +132,4 @@ public bool OverlapsWith(TestExecutionRecord other) return StartTime < other.EndTime.Value && other.StartTime < EndTime.Value; } } -} \ No newline at end of file +} diff --git a/TUnit.TestProject/NotInParallelMixedTests.cs b/TUnit.TestProject/NotInParallelMixedTests.cs index bad68f8ccb..29310d7c00 100644 --- a/TUnit.TestProject/NotInParallelMixedTests.cs +++ b/TUnit.TestProject/NotInParallelMixedTests.cs @@ -17,7 +17,7 @@ public class NotInParallelMixedTests [Before(Test)] public void RecordTestStart() { - var testName = TestContext.Current!.TestDetails.TestName; + var testName = TestContext.Current!.Metadata.TestDetails.TestName; var groupKey = GetGroupKeyForTest(testName); var startTime = DateTime.Now; @@ -46,7 +46,7 @@ public void RecordTestStart() [After(Test)] public async Task RecordTestEnd() { - var testName = TestContext.Current!.TestDetails.TestName; + var testName = TestContext.Current!.Metadata.TestDetails.TestName; var groupKey = GetGroupKeyForTest(testName); var endTime = DateTime.Now; diff --git a/TUnit.TestProject/NotInParallelOrderExecutionTests.cs b/TUnit.TestProject/NotInParallelOrderExecutionTests.cs index cac9e5f8b5..2a1ab0cbf9 100644 --- a/TUnit.TestProject/NotInParallelOrderExecutionTests.cs +++ b/TUnit.TestProject/NotInParallelOrderExecutionTests.cs @@ -16,22 +16,22 @@ public class NotInParallelOrderExecutionTests [Before(Test)] public void RecordOrderedTestStart() { - var testName = TestContext.Current!.TestDetails.TestName; + var testName = TestContext.Current!.Metadata.TestDetails.TestName; var groupKey = GetGroupKey(testName); - + var groupLock = GroupLocks.GetOrAdd(groupKey, new object()); lock (groupLock) { var current = CurrentlyExecutingPerGroup.AddOrUpdate(groupKey, 1, (_, v) => v + 1); MaxConcurrentPerGroup.AddOrUpdate(groupKey, current, (_, v) => Math.Max(v, current)); - + var orderList = ExecutionOrderByGroup.GetOrAdd(groupKey, new List()); orderList.Add(testName); } // Use TestStart if available, otherwise use DateTime.Now - var startTime = TestContext.Current.TestStart?.DateTime ?? DateTime.Now; - + var startTime = TestContext.Current.Execution.TestStart?.DateTime ?? DateTime.Now; + OrderedExecutionRecords.Add(new OrderedExecutionRecord( testName, groupKey, @@ -43,9 +43,9 @@ public void RecordOrderedTestStart() [After(Test)] public async Task RecordOrderedTestEnd() { - var testName = TestContext.Current!.TestDetails.TestName; + var testName = TestContext.Current!.Metadata.TestDetails.TestName; var groupKey = GetGroupKey(testName); - + var groupLock = GroupLocks.GetOrAdd(groupKey, new object()); lock (groupLock) { @@ -59,7 +59,7 @@ public async Task RecordOrderedTestEnd() if (record != null) { // Use Result.End if available, otherwise use DateTime.Now - record.EndTime = TestContext.Current.Result?.End?.DateTime ?? DateTime.Now; + record.EndTime = TestContext.Current.Execution.Result?.End?.DateTime ?? DateTime.Now; } await AssertOrderedExecutionWithinGroup(groupKey); @@ -224,4 +224,4 @@ public bool OverlapsWith(OrderedExecutionRecord other) return StartTime < other.EndTime.Value && other.StartTime < EndTime.Value; } } -} \ No newline at end of file +} diff --git a/TUnit.TestProject/NotInParallelTests.cs b/TUnit.TestProject/NotInParallelTests.cs index bfe69511bd..4997a5aaa0 100644 --- a/TUnit.TestProject/NotInParallelTests.cs +++ b/TUnit.TestProject/NotInParallelTests.cs @@ -12,7 +12,7 @@ public class NotInParallelTests [After(Test)] public async Task TestOverlaps() { - TestDateTimeRanges.Add(new DateTimeRange(TestContext.Current!.TestStart!.Value.DateTime, TestContext.Current.Result!.End!.Value.DateTime)); + TestDateTimeRanges.Add(new DateTimeRange(TestContext.Current!.Execution.TestStart!.Value.DateTime, TestContext.Current.Execution.Result!.End!.Value.DateTime)); await AssertNoOverlaps(); } diff --git a/TUnit.TestProject/OverrideResultsTests.cs b/TUnit.TestProject/OverrideResultsTests.cs index bd7d095b98..167a5a758a 100644 --- a/TUnit.TestProject/OverrideResultsTests.cs +++ b/TUnit.TestProject/OverrideResultsTests.cs @@ -16,14 +16,14 @@ public void OverrideResult_Throws_When_TestResult_Is_Null() public static async Task AfterClass(ClassHookContext classHookContext) { await Assert.That(classHookContext.Tests).HasSingleItem(); - await Assert.That(classHookContext.Tests).ContainsOnly(t => t.Result?.State == TestState.Passed); + await Assert.That(classHookContext.Tests).ContainsOnly(t => t.Execution.Result?.State == TestState.Passed); } public class OverridePassAttribute : Attribute, ITestEndEventReceiver { public ValueTask OnTestEnd(TestContext afterTestContext) { - afterTestContext.OverrideResult(TestState.Passed, "Because I said so"); + afterTestContext.Execution.OverrideResult(TestState.Passed, "Because I said so"); return default(ValueTask); } diff --git a/TUnit.TestProject/ParallelTests.cs b/TUnit.TestProject/ParallelTests.cs index d70e2d4722..6b52a03119 100644 --- a/TUnit.TestProject/ParallelTests.cs +++ b/TUnit.TestProject/ParallelTests.cs @@ -12,7 +12,7 @@ public class ParallelTests [After(Test)] public async Task TestOverlaps() { - TestDateTimeRanges.Add(new DateTimeRange(TestContext.Current!.TestStart!.Value.DateTime, TestContext.Current.Result!.End!.Value.DateTime)); + TestDateTimeRanges.Add(new DateTimeRange(TestContext.Current!.Execution.TestStart!.Value.DateTime, TestContext.Current.Execution.Result!.End!.Value.DateTime)); await AssertOverlaps(); } diff --git a/TUnit.TestProject/ParallelismValidationTests.cs b/TUnit.TestProject/ParallelismValidationTests.cs index 96d6f1568c..0e04d347c8 100644 --- a/TUnit.TestProject/ParallelismValidationTests.cs +++ b/TUnit.TestProject/ParallelismValidationTests.cs @@ -18,9 +18,9 @@ public class UnconstrainedParallelTests public async Task RecordExecution() { var context = TestContext.Current!; - _executionTimes.Add((context.TestDetails.TestName, - context.TestStart!.Value, - context.Result!.End!.Value)); + _executionTimes.Add((context.Metadata.TestDetails.TestName, + context.Execution.TestStart!.Value, + context.Execution.Result!.End!.Value)); await Task.CompletedTask; } @@ -120,9 +120,9 @@ public class LimitedParallelTests public async Task RecordExecution() { var context = TestContext.Current!; - _executionTimes.Add((context.TestDetails.TestName, - context.TestStart!.Value, - context.Result!.End!.Value)); + _executionTimes.Add((context.Metadata.TestDetails.TestName, + context.Execution.TestStart!.Value, + context.Execution.Result!.End!.Value)); await Task.CompletedTask; } @@ -231,9 +231,9 @@ public class StrictlySerialTests public async Task RecordExecution() { var context = TestContext.Current!; - _executionTimes.Add((context.TestDetails.TestName, - context.TestStart!.Value, - context.Result!.End!.Value)); + _executionTimes.Add((context.Metadata.TestDetails.TestName, + context.Execution.TestStart!.Value, + context.Execution.Result!.End!.Value)); await Task.CompletedTask; } @@ -339,9 +339,9 @@ public class HighParallelismTests public async Task RecordExecution() { var context = TestContext.Current!; - _executionTimes.Add((context.TestDetails.TestName, - context.TestStart!.Value, - context.Result!.End!.Value)); + _executionTimes.Add((context.Metadata.TestDetails.TestName, + context.Execution.TestStart!.Value, + context.Execution.Result!.End!.Value)); await Task.CompletedTask; } @@ -416,4 +416,4 @@ private static void TrackConcurrency() Thread.Sleep(50); Interlocked.Decrement(ref _concurrentCount); } -} \ No newline at end of file +} diff --git a/TUnit.TestProject/RepeatIndexVerificationTest.cs b/TUnit.TestProject/RepeatIndexVerificationTest.cs index 3e1d2bb957..dbf4a5c1b7 100644 --- a/TUnit.TestProject/RepeatIndexVerificationTest.cs +++ b/TUnit.TestProject/RepeatIndexVerificationTest.cs @@ -17,11 +17,11 @@ public class RepeatIndexVerificationTest public async Task VerifyRepeatCreatesUniqueTestIds() { await Task.Yield(); - + var context = TestContext.Current!; - var testId = context.TestDetails.TestId; - var testStart = context.TestStart; - + var testId = context.Metadata.TestDetails.TestId; + var testStart = context.Execution.TestStart; + lock (Lock) { RunCount++; @@ -29,18 +29,18 @@ public async Task VerifyRepeatCreatesUniqueTestIds() Console.WriteLine($"Test ID: {testId}"); Console.WriteLine($"Test Start: {testStart}"); Console.WriteLine("---"); - + // Verify unique test IDs if (!SeenTestIds.Add(testId)) { throw new Exception($"Duplicate TestId detected: {testId}. This means RepeatIndex is not being incremented properly!"); } - + // Track start times SeenStartTimes.Add(testStart); } } - + [Test] [DependsOn(nameof(VerifyRepeatCreatesUniqueTestIds))] public void VerifyAllRepeatsRan() @@ -54,13 +54,13 @@ public void VerifyAllRepeatsRan() { Console.WriteLine($" {id}"); } - + // We should have 4 runs (repeat count of 3 means 0, 1, 2, 3) if (RunCount != 4) { throw new Exception($"Expected 4 test runs with Repeat(3), but got {RunCount}"); } - + // We should have 4 unique test IDs if (SeenTestIds.Count != 4) { @@ -68,4 +68,4 @@ public void VerifyAllRepeatsRan() } } } -} \ No newline at end of file +} diff --git a/TUnit.TestProject/ScopedEventReceiverTests.cs b/TUnit.TestProject/ScopedEventReceiverTests.cs index cd514b3246..1bb9fc711b 100644 --- a/TUnit.TestProject/ScopedEventReceiverTests.cs +++ b/TUnit.TestProject/ScopedEventReceiverTests.cs @@ -129,7 +129,7 @@ public TestStartLoggerAttribute(string source) public ValueTask OnTestStart(TestContext context) { - ScopedEventReceiverTests.RecordStartEvent(context.TestDetails.MethodName, _source); + ScopedEventReceiverTests.RecordStartEvent(context.Metadata.TestDetails.MethodName, _source); return default; } @@ -149,7 +149,7 @@ public TestEndLoggerAttribute(string source) public ValueTask OnTestEnd(TestContext context) { - ScopedEventReceiverTests.RecordEndEvent(context.TestDetails.MethodName, _source); + ScopedEventReceiverTests.RecordEndEvent(context.Metadata.TestDetails.MethodName, _source); return default; } diff --git a/TUnit.TestProject/SetHookExecutorTests.cs b/TUnit.TestProject/SetHookExecutorTests.cs index 420fbe9ae5..5d11036a32 100644 --- a/TUnit.TestProject/SetHookExecutorTests.cs +++ b/TUnit.TestProject/SetHookExecutorTests.cs @@ -85,12 +85,12 @@ public static async Task BeforeEveryTest(TestContext context) { // This static hook is GLOBAL and runs for ALL tests in the assembly // Only run assertions for tests in SetHookExecutorWithStaticHooksTests class - if (context.TestDetails.ClassType == typeof(SetHookExecutorWithStaticHooksTests)) + if (context.Metadata.TestDetails.ClassType == typeof(SetHookExecutorWithStaticHooksTests)) { // This static hook should execute with the custom executor when CustomHookExecutor is set await Assert.That(Thread.CurrentThread.Name).IsEqualTo("CrossPlatformTestExecutor"); await Assert.That(CrossPlatformTestExecutor.IsRunningInTestExecutor.Value).IsTrue(); - context.ObjectBag["BeforeEveryExecuted"] = true; + context.StateBag.Items["BeforeEveryExecuted"] = true; } } @@ -99,7 +99,7 @@ public static async Task AfterEveryTest(TestContext context) { // This static hook is GLOBAL and runs for ALL tests in the assembly // Only run assertions for tests in SetHookExecutorWithStaticHooksTests class - if (context.TestDetails.ClassType == typeof(SetHookExecutorWithStaticHooksTests)) + if (context.Metadata.TestDetails.ClassType == typeof(SetHookExecutorWithStaticHooksTests)) { // This static hook should execute with the custom executor when CustomHookExecutor is set await Assert.That(Thread.CurrentThread.Name).IsEqualTo("CrossPlatformTestExecutor"); @@ -111,7 +111,7 @@ public static async Task AfterEveryTest(TestContext context) public async Task Test_StaticHooksExecuteInCustomExecutor() { // Verify the BeforeEvery hook ran - await Assert.That(TestContext.Current?.ObjectBag["BeforeEveryExecuted"]).IsEquatableOrEqualTo(true); + await Assert.That(TestContext.Current?.StateBag.Items["BeforeEveryExecuted"]).IsEquatableOrEqualTo(true); // Test itself runs in custom executor await Assert.That(Thread.CurrentThread.Name).IsEqualTo("CrossPlatformTestExecutor"); diff --git a/TUnit.TestProject/SharedDisposalTest.cs b/TUnit.TestProject/SharedDisposalTest.cs index 5c816252d3..3e348864e2 100644 --- a/TUnit.TestProject/SharedDisposalTest.cs +++ b/TUnit.TestProject/SharedDisposalTest.cs @@ -102,7 +102,7 @@ public static async Task VerifySharedInstanceDisposal(ClassHookContext context) } // Print the test instances to see if they were using the same shared instance - var testInstances = context.Tests.Select(t => t.TestDetails.ClassInstance).OfType().ToList(); + var testInstances = context.Tests.Select(t => t.Metadata.TestDetails.ClassInstance).OfType().ToList(); Console.WriteLine($"[AfterClass] Test instances: {testInstances.Count}"); for (var i = 0; i < testInstances.Count; i++) { diff --git a/TUnit.TestProject/SimplePropertyFilterTest.cs b/TUnit.TestProject/SimplePropertyFilterTest.cs index 3bae733ec3..9ae1fbcd8f 100644 --- a/TUnit.TestProject/SimplePropertyFilterTest.cs +++ b/TUnit.TestProject/SimplePropertyFilterTest.cs @@ -6,6 +6,6 @@ public class SimplePropertyFilterTest [Test] public void TestWithPropertyAttribute() { - Console.WriteLine($"Test executed! Properties: {string.Join(", ", TestContext.Current?.TestDetails.CustomProperties.Select(kvp => $"{kvp.Key}={string.Join(",", kvp.Value)}") ?? [])}"); + Console.WriteLine($"Test executed! Properties: {string.Join(", ", TestContext.Current?.Metadata.TestDetails.CustomProperties.Select(kvp => $"{kvp.Key}={string.Join(",", kvp.Value)}") ?? [])}"); } } diff --git a/TUnit.TestProject/TestContextIsolationTests.cs b/TUnit.TestProject/TestContextIsolationTests.cs index 9e58390915..116abad064 100644 --- a/TUnit.TestProject/TestContextIsolationTests.cs +++ b/TUnit.TestProject/TestContextIsolationTests.cs @@ -27,11 +27,11 @@ public void BeforeEachTest(TestContext context) context.AddAsyncLocalValues(); // Store mapping for later verification - TestIdToTestName[testId] = context.TestDetails.TestName; + TestIdToTestName[testId] = context.Metadata.TestDetails.TestName; // Add to context for verification in test - context.ObjectBag["TestLocalId"] = testId; - context.ObjectBag["TestStartThread"] = Thread.CurrentThread.ManagedThreadId; + context.StateBag.Items["TestLocalId"] = testId; + context.StateBag.Items["TestStartThread"] = Thread.CurrentThread.ManagedThreadId; } [Test] @@ -41,7 +41,7 @@ public async Task TestContext_Should_Be_Isolated_In_Parallel_Test1() var context = TestContext.Current; await Assert.That(context).IsNotNull(); - var testId = context!.ObjectBag["TestLocalId"] as string; + var testId = context!.StateBag.Items["TestLocalId"] as string; await Assert.That(testId).IsNotNull(); // Simulate some async work @@ -49,7 +49,7 @@ public async Task TestContext_Should_Be_Isolated_In_Parallel_Test1() // Verify context hasn't changed await Assert.That(TestContext.Current).IsSameReferenceAs(context); - await Assert.That(TestContext.Current!.ObjectBag["TestLocalId"]).IsEqualTo(testId); + await Assert.That(TestContext.Current!.StateBag.Items["TestLocalId"]).IsEqualTo(testId); // Verify AsyncLocal is preserved await Assert.That(TestLocalValue.Value).IsEqualTo(testId); @@ -71,7 +71,7 @@ public async Task TestContext_Should_Be_Isolated_In_Parallel_Test2() var context = TestContext.Current; await Assert.That(context).IsNotNull(); - var testId = context!.ObjectBag["TestLocalId"] as string; + var testId = context!.StateBag.Items["TestLocalId"] as string; await Assert.That(testId).IsNotNull(); // Different delay pattern @@ -79,7 +79,7 @@ public async Task TestContext_Should_Be_Isolated_In_Parallel_Test2() // Verify isolation await Assert.That(TestContext.Current).IsSameReferenceAs(context); - await Assert.That(TestContext.Current!.ObjectBag["TestLocalId"]).IsEqualTo(testId); + await Assert.That(TestContext.Current!.StateBag.Items["TestLocalId"]).IsEqualTo(testId); await Assert.That(TestLocalValue.Value).IsEqualTo(testId); CapturedContexts[testId!] = context; @@ -95,7 +95,7 @@ public async Task TestContext_Should_Be_Isolated_In_Sync_Test() var context = TestContext.Current; await Assert.That(context).IsNotNull(); - var testId = context!.ObjectBag["TestLocalId"] as string; + var testId = context!.StateBag.Items["TestLocalId"] as string; await Assert.That(testId).IsNotNull(); // Simulate work @@ -103,7 +103,7 @@ public async Task TestContext_Should_Be_Isolated_In_Sync_Test() // Verify context remains the same await Assert.That(TestContext.Current).IsSameReferenceAs(context); - await Assert.That(TestContext.Current!.ObjectBag["TestLocalId"]).IsEqualTo(testId); + await Assert.That(TestContext.Current!.StateBag.Items["TestLocalId"]).IsEqualTo(testId); await Assert.That(TestLocalValue.Value).IsEqualTo(testId); CapturedContexts[testId!] = context; @@ -150,7 +150,7 @@ public async Task Context_Should_Be_Preserved_Through_Nested_Async_Calls_Test1() var initialContext = TestContext.Current; await Assert.That(initialContext).IsNotNull(); - var testName = initialContext!.TestDetails.TestName; + var testName = initialContext!.Metadata.TestDetails.TestName; ObservedContexts.Add((testName, initialContext, Thread.CurrentThread.ManagedThreadId)); await NestedAsyncMethod1(initialContext); @@ -166,7 +166,7 @@ public async Task Context_Should_Be_Preserved_Through_Nested_Async_Calls_Test2() var initialContext = TestContext.Current; await Assert.That(initialContext).IsNotNull(); - var testName = initialContext!.TestDetails.TestName; + var testName = initialContext!.Metadata.TestDetails.TestName; ObservedContexts.Add((testName, initialContext, Thread.CurrentThread.ManagedThreadId)); await NestedAsyncMethod2(initialContext); @@ -224,9 +224,9 @@ public async Task Concurrent_Tests_Should_Not_Share_Context() var myContext = TestContext.Current; await Assert.That(myContext).IsNotNull(); - var myTestName = myContext!.TestDetails.TestName; + var myTestName = myContext!.Metadata.TestDetails.TestName; var myTestId = Guid.NewGuid().ToString(); - myContext.ObjectBag["UniqueTestId"] = myTestId; + myContext.StateBag.Items["UniqueTestId"] = myTestId; Interlocked.Increment(ref ConcurrentTestCount); @@ -244,12 +244,12 @@ public async Task Concurrent_Tests_Should_Not_Share_Context() var currentContext = TestContext.Current; if (currentContext != myContext) { - DetectedContextMismatches.Add($"Context mismatch in {myTestName}: Expected {myTestId}, Current context: {currentContext?.ObjectBag.GetValueOrDefault("UniqueTestId")}"); + DetectedContextMismatches.Add($"Context mismatch in {myTestName}: Expected {myTestId}, Current context: {currentContext?.StateBag.Items.GetValueOrDefault("UniqueTestId")}"); } - if (currentContext?.ObjectBag.GetValueOrDefault("UniqueTestId") as string != myTestId) + if (currentContext?.StateBag.Items.GetValueOrDefault("UniqueTestId") as string != myTestId) { - DetectedContextMismatches.Add($"TestId mismatch in {myTestName}: Expected {myTestId}, Got {currentContext?.ObjectBag.GetValueOrDefault("UniqueTestId")}"); + DetectedContextMismatches.Add($"TestId mismatch in {myTestName}: Expected {myTestId}, Got {currentContext?.StateBag.Items.GetValueOrDefault("UniqueTestId")}"); } await Task.Delay(1); @@ -261,7 +261,7 @@ public async Task Concurrent_Tests_Should_Not_Share_Context() // Final verification await Assert.That(TestContext.Current).IsSameReferenceAs(myContext); - await Assert.That(TestContext.Current!.ObjectBag["UniqueTestId"]).IsEqualTo(myTestId); + await Assert.That(TestContext.Current!.StateBag.Items["UniqueTestId"]).IsEqualTo(myTestId); } [Test] diff --git a/TUnit.TestProject/TestIdDebugTest.cs b/TUnit.TestProject/TestIdDebugTest.cs index 7c250f190d..72d65b94d5 100644 --- a/TUnit.TestProject/TestIdDebugTest.cs +++ b/TUnit.TestProject/TestIdDebugTest.cs @@ -16,13 +16,13 @@ public class TestIdDebugTest public async Task DebugTestIdGeneration() { await Task.Yield(); - + var context = TestContext.Current!; - var testDetails = context.TestDetails; - + var testDetails = context.Metadata.TestDetails; + // Use reflection to see if there's a RepeatIndex property we're missing var properties = testDetails.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - + lock (Lock) { Console.WriteLine($"=== Test Execution ==="); @@ -33,7 +33,7 @@ public async Task DebugTestIdGeneration() // Check all properties foreach (var prop in properties) { - if (prop.Name.Contains("Repeat", StringComparison.OrdinalIgnoreCase) || + if (prop.Name.Contains("Repeat", StringComparison.OrdinalIgnoreCase) || prop.Name.Contains("Index", StringComparison.OrdinalIgnoreCase)) { try @@ -47,10 +47,10 @@ public async Task DebugTestIdGeneration() } } } - + TestIds.Add(testDetails.TestId); Console.WriteLine($"Total unique TestIds so far: {new HashSet(TestIds).Count}"); Console.WriteLine("---"); } } -} \ No newline at end of file +} diff --git a/TUnit.TestProject/TestVariantTests.cs b/TUnit.TestProject/TestVariantTests.cs index db1007848a..85d36ddf6e 100644 --- a/TUnit.TestProject/TestVariantTests.cs +++ b/TUnit.TestProject/TestVariantTests.cs @@ -42,17 +42,17 @@ public async Task VariantTarget_WithArguments(int value) throw new InvalidOperationException($"Expected non-negative value but got {value}"); } - if (context.ObjectBag.ContainsKey("AttemptNumber")) + if (context.StateBag.Items.ContainsKey("AttemptNumber")) { - var attemptNumber = context.ObjectBag["AttemptNumber"]; - context.WriteLine($"Shrink attempt {attemptNumber} with value {value}"); + var attemptNumber = context.StateBag.Items["AttemptNumber"]; + context.Output.StandardOutput.WriteLine($"Shrink attempt {attemptNumber} with value {value}"); - if (context.Relationship != TUnit.Core.Enums.TestRelationship.Derived) + if (context.Dependencies.Relationship != TUnit.Core.Enums.TestRelationship.Derived) { - throw new InvalidOperationException($"Expected Derived relationship but got {context.Relationship}"); + throw new InvalidOperationException($"Expected Derived relationship but got {context.Dependencies.Relationship}"); } - if (context.ParentTestId == null) + if (context.Dependencies.ParentTestId == null) { throw new InvalidOperationException("Expected ParentTestId to be set for shrink attempt"); } diff --git a/TUnit.TestProject/Tests.cs b/TUnit.TestProject/Tests.cs index 7ee28ca7d5..5806c3102a 100644 --- a/TUnit.TestProject/Tests.cs +++ b/TUnit.TestProject/Tests.cs @@ -186,14 +186,14 @@ public async Task TestDataSource8(int value) [Category("Pass")] public async Task TestContext1() { - await Assert.That(TestContext.Current?.TestDetails.TestName).IsEqualTo(nameof(TestContext1)); + await Assert.That(TestContext.Current?.Metadata.TestDetails.TestName).IsEqualTo(nameof(TestContext1)); } [Test] [Category("Fail")] public async Task TestContext2() { - await Assert.That(TestContext.Current?.TestDetails.TestName).IsEqualTo(nameof(TestContext1)); + await Assert.That(TestContext.Current?.Metadata.TestDetails.TestName).IsEqualTo(nameof(TestContext1)); } [Test] diff --git a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TestBase.cs b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TestBase.cs index dcd7b83103..5b19d8919e 100644 --- a/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TestBase.cs +++ b/tools/tunit-nuget-tester/TUnit.NugetTester/TUnit.NugetTester.Library/TestBase.cs @@ -7,12 +7,12 @@ public class TestBase [Before(Test)] public void Setup(TestContext testContext) { - Console.WriteLine($"Starting test: {testContext.GetDisplayName()}"); + Console.WriteLine($"Starting test: {testContext.Metadata.DisplayName}"); } [After(Test)] public void Teardown(TestContext testContext) { - Console.WriteLine($"Finishing test: {testContext.GetDisplayName()}"); + Console.WriteLine($"Finishing test: {testContext.Metadata.DisplayName}"); } }