diff --git a/TUnit.Core/Extensions/TupleExtensions.cs b/TUnit.Core/Extensions/TupleExtensions.cs index 3041606db3..e9d885ab3d 100644 --- a/TUnit.Core/Extensions/TupleExtensions.cs +++ b/TUnit.Core/Extensions/TupleExtensions.cs @@ -1,4 +1,6 @@ -namespace TUnit.Core.Extensions; +using System.Runtime.CompilerServices; + +namespace TUnit.Core.Extensions; internal static class TupleExtensions { @@ -7,7 +9,18 @@ internal static class TupleExtensions { return [value]; } - + +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP + public static object?[] ToObjectArray(this ITuple tuple) + { + var result = new object?[tuple.Length]; + for (var i = 0; i < tuple.Length; i++) + { + result[i] = tuple[i]; + } + return result; + } +#else public static object?[] ToObjectArray(this (T1, T2) tuple) { return [tuple.Item1, tuple.Item2]; @@ -27,19 +40,20 @@ internal static class TupleExtensions { return [tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5]; } - + public static object?[] ToObjectArray(this (T1, T2, T3, T4, T5, T6) tuple) { return [tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6]; } - + public static object?[] ToObjectArray(this (T1, T2, T3, T4, T5, T6, T7) tuple) { return [tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7]; } - + public static object?[] ToObjectArray(this (T1, T2, T3, T4, T5, T6, T7, T8) tuple) { return [tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7, tuple.Item8]; } +#endif } diff --git a/TUnit.Core/Helpers/DataConversionHelper.cs b/TUnit.Core/Helpers/DataConversionHelper.cs index 7816d1d53e..dd469187fd 100644 --- a/TUnit.Core/Helpers/DataConversionHelper.cs +++ b/TUnit.Core/Helpers/DataConversionHelper.cs @@ -153,6 +153,25 @@ public static class DataConversionHelper } } +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP + /// + /// Converts IAsyncEnumerable of any tuple type to IAsyncEnumerable using ITuple + /// + public static async IAsyncEnumerable ConvertAsyncEnumerableTupleToObjectArrays( + IAsyncEnumerable source, + [EnumeratorCancellation] CancellationToken ct = default) where T : ITuple + { + await foreach (var tuple in source.WithCancellation(ct)) + { + var items = new object?[tuple.Length]; + for (var i = 0; i < tuple.Length; i++) + { + items[i] = tuple[i]; + } + yield return items; + } + } +#else /// /// Converts IAsyncEnumerable<(T1, T2)> to IAsyncEnumerable /// @@ -204,6 +223,7 @@ public static class DataConversionHelper yield return [item1, item2, item3, item4, item5]; } } +#endif /// /// Wraps a Task> to ensure it returns object arrays @@ -232,8 +252,7 @@ public static class DataConversionHelper } return result; } -#endif - +#else /// /// Unwraps a ValueTuple to an object?[] array (optimized for 2-tuples) /// @@ -305,4 +324,5 @@ public static class DataConversionHelper { return [tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7, tuple.Item8, tuple.Item9, tuple.Item10]; } +#endif } diff --git a/TUnit.Core/Helpers/DataSourceHelpers.cs b/TUnit.Core/Helpers/DataSourceHelpers.cs index fc7ba158e6..8e094b2d64 100644 --- a/TUnit.Core/Helpers/DataSourceHelpers.cs +++ b/TUnit.Core/Helpers/DataSourceHelpers.cs @@ -141,6 +141,7 @@ public static T InvokeIfFunc(object? value) } } +#if !NETSTANDARD2_1_OR_GREATER && !NETCOREAPP /// /// Generic tuple unwrapping for when types are known at compile time /// @@ -164,6 +165,7 @@ public static T InvokeIfFunc(object? value) public static object?[] UnwrapTuple(ValueTuple tuple) => [tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7]; +#endif /// /// AOT-compatible data source processor for when the return type is known at compile time @@ -378,7 +380,7 @@ public static T InvokeIfFunc(object? value) { // Special case: If there's a single parameter that expects a tuple type, // and the item is a tuple, don't unwrap - if (expectedTypes.Length == 1 && IsTupleType(expectedTypes[0])) + if (expectedTypes.Length == 1 && TupleHelper.IsTupleType(expectedTypes[0])) { return [item]; } @@ -417,7 +419,7 @@ public static T InvokeIfFunc(object? value) var expectedType = expectedTypes[typeIndex]; // Check if the expected type is a tuple type - if (IsTupleType(expectedType) && IsTuple(element)) + if (TupleHelper.IsTupleType(expectedType) && IsTuple(element)) { // Keep nested tuple as-is result.Add(element); @@ -439,34 +441,6 @@ public static T InvokeIfFunc(object? value) return UnwrapTupleAot(value); } - /// - /// Checks if a Type represents a tuple type. - /// - private static bool IsTupleType(Type type) - { - if (!type.IsGenericType) - { - return false; - } - - var genericType = type.GetGenericTypeDefinition(); - return genericType == typeof(ValueTuple<>) || - genericType == typeof(ValueTuple<,>) || - genericType == typeof(ValueTuple<,,>) || - genericType == typeof(ValueTuple<,,,>) || - genericType == typeof(ValueTuple<,,,,>) || - genericType == typeof(ValueTuple<,,,,,>) || - genericType == typeof(ValueTuple<,,,,,,>) || - genericType == typeof(ValueTuple<,,,,,,,>) || - genericType == typeof(Tuple<>) || - genericType == typeof(Tuple<,>) || - genericType == typeof(Tuple<,,>) || - genericType == typeof(Tuple<,,,>) || - genericType == typeof(Tuple<,,,,>) || - genericType == typeof(Tuple<,,,,,>) || - genericType == typeof(Tuple<,,,,,,>) || - genericType == typeof(Tuple<,,,,,,,>); - } public static bool IsTuple(object? obj) { diff --git a/TUnit.Engine/Helpers/DataUnwrapper.cs b/TUnit.Engine/Helpers/DataUnwrapper.cs index 02a4d5dc19..3786fdae43 100644 --- a/TUnit.Engine/Helpers/DataUnwrapper.cs +++ b/TUnit.Engine/Helpers/DataUnwrapper.cs @@ -80,7 +80,7 @@ public static (object?[] Data, TestDataRowMetadata? Metadata) UnwrapWithTypesAnd if (values.Length == 1 && expectedParameters.Length == 1 && DataSourceHelpers.IsTuple(values[0]) && - IsTupleType(expectedParameters[0].Type)) + TupleHelper.IsTupleType(expectedParameters[0].Type)) { return values; } @@ -99,30 +99,4 @@ public static (object?[] Data, TestDataRowMetadata? Metadata) UnwrapWithTypesAnd return values; } - - private static bool IsTupleType(Type type) - { - if (!type.IsGenericType) - { - return false; - } - - var genericType = type.GetGenericTypeDefinition(); - return genericType == typeof(ValueTuple<>) || - genericType == typeof(ValueTuple<,>) || - genericType == typeof(ValueTuple<,,>) || - genericType == typeof(ValueTuple<,,,>) || - genericType == typeof(ValueTuple<,,,,>) || - genericType == typeof(ValueTuple<,,,,,>) || - genericType == typeof(ValueTuple<,,,,,,>) || - genericType == typeof(ValueTuple<,,,,,,,>) || - genericType == typeof(Tuple<>) || - genericType == typeof(Tuple<,>) || - genericType == typeof(Tuple<,,>) || - genericType == typeof(Tuple<,,,>) || - genericType == typeof(Tuple<,,,,>) || - genericType == typeof(Tuple<,,,,,>) || - genericType == typeof(Tuple<,,,,,,>) || - genericType == typeof(Tuple<,,,,,,,>); - } } 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 0cc53f2a25..76bad876d9 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 @@ -2046,27 +2046,13 @@ namespace .Helpers { [.(typeof(..d__2))] public static . ConvertAsyncEnumerableToObjectArrays(. source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__3?))] - public static . ConvertAsyncEnumerableTuple2ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__4?))] - public static . ConvertAsyncEnumerableTuple3ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__5?))] - public static . ConvertAsyncEnumerableTuple4ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__6?))] - public static . ConvertAsyncEnumerableTuple5ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__1?))] + [.(typeof(..d__3))] + public static . ConvertAsyncEnumerableTupleToObjectArrays(. source, [.] .CancellationToken ct = default) + where T : . { } + [.(typeof(..d__1))] public static . ConvertToAsyncEnumerableInternal(. data, [.] .CancellationToken ct = default) { } public static . ConvertToObjectArrays(object? data) { } public static object?[] UnwrapTuple(. tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple(> tuple) { } - public static object?[] UnwrapTuple(> tuple) { } - public static object?[] UnwrapTuple(> tuple) { } public static .<.> WrapTaskEnumerableAsObjectArrays(.<.> task) { } } public static class DataSourceHelpers @@ -2093,13 +2079,6 @@ namespace .Helpers "success", "createdInstance"})] public static .<> TryCreateWithInitializerAsync( type, .MethodMetadata testInformation, string testSessionId) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } public static object?[] UnwrapTupleAot(object? value) { } } public static class DecimalParsingHelper 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 1c555a47d5..72c3b943a5 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 @@ -2046,27 +2046,13 @@ namespace .Helpers { [.(typeof(..d__2))] public static . ConvertAsyncEnumerableToObjectArrays(. source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__3?))] - public static . ConvertAsyncEnumerableTuple2ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__4?))] - public static . ConvertAsyncEnumerableTuple3ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__5?))] - public static . ConvertAsyncEnumerableTuple4ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__6?))] - public static . ConvertAsyncEnumerableTuple5ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__1?))] + [.(typeof(..d__3))] + public static . ConvertAsyncEnumerableTupleToObjectArrays(. source, [.] .CancellationToken ct = default) + where T : . { } + [.(typeof(..d__1))] public static . ConvertToAsyncEnumerableInternal(. data, [.] .CancellationToken ct = default) { } public static . ConvertToObjectArrays(object? data) { } public static object?[] UnwrapTuple(. tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple(> tuple) { } - public static object?[] UnwrapTuple(> tuple) { } - public static object?[] UnwrapTuple(> tuple) { } public static .<.> WrapTaskEnumerableAsObjectArrays(.<.> task) { } } public static class DataSourceHelpers @@ -2093,13 +2079,6 @@ namespace .Helpers "success", "createdInstance"})] public static .<> TryCreateWithInitializerAsync( type, .MethodMetadata testInformation, string testSessionId) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } public static object?[] UnwrapTupleAot(object? value) { } } public static class DecimalParsingHelper 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 de1cb1bc62..1caf4068ab 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 @@ -2046,27 +2046,13 @@ namespace .Helpers { [.(typeof(..d__2))] public static . ConvertAsyncEnumerableToObjectArrays(. source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__3?))] - public static . ConvertAsyncEnumerableTuple2ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__4?))] - public static . ConvertAsyncEnumerableTuple3ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__5?))] - public static . ConvertAsyncEnumerableTuple4ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__6?))] - public static . ConvertAsyncEnumerableTuple5ToObjectArrays(.<> source, [.] .CancellationToken ct = default) { } - [.(typeof(..d__1?))] + [.(typeof(..d__3))] + public static . ConvertAsyncEnumerableTupleToObjectArrays(. source, [.] .CancellationToken ct = default) + where T : . { } + [.(typeof(..d__1))] public static . ConvertToAsyncEnumerableInternal(. data, [.] .CancellationToken ct = default) { } public static . ConvertToObjectArrays(object? data) { } public static object?[] UnwrapTuple(. tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple(> tuple) { } - public static object?[] UnwrapTuple(> tuple) { } - public static object?[] UnwrapTuple(> tuple) { } public static .<.> WrapTaskEnumerableAsObjectArrays(.<.> task) { } } public static class DataSourceHelpers @@ -2093,13 +2079,6 @@ namespace .Helpers "success", "createdInstance"})] public static .<> TryCreateWithInitializerAsync( type, .MethodMetadata testInformation, string testSessionId) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } - public static object?[] UnwrapTuple( tuple) { } public static object?[] UnwrapTupleAot(object? value) { } } public static class DecimalParsingHelper