diff --git a/TUnit.Core.SourceGenerator.Tests/MatrixTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/MatrixTests.Test.verified.txt
index ea365df2ae..9b3fa0a86d 100644
--- a/TUnit.Core.SourceGenerator.Tests/MatrixTests.Test.verified.txt
+++ b/TUnit.Core.SourceGenerator.Tests/MatrixTests.Test.verified.txt
@@ -1365,3 +1365,117 @@ internal static class TUnit_TestProject_MatrixTests_Exclusion__int_int_ModuleIni
global::TUnit.Core.SourceRegistrar.Register(typeof(global::TUnit.TestProject.MatrixTests), new TUnit_TestProject_MatrixTests_Exclusion__int_int_TestSource());
}
}
+
+
+// ===== FILE SEPARATOR =====
+
+//
+#pragma warning disable
+
+#nullable enable
+namespace TUnit.Generated;
+internal sealed class TUnit_TestProject_MatrixTests_MatrixMethod_WithEnumParameter_UsesOnlyMethodValues__bool_CountToTenEnum_TestSource : global::TUnit.Core.Interfaces.SourceGenerator.ITestSource
+{
+ public async global::System.Collections.Generic.IAsyncEnumerable GetTestsAsync(string testSessionId, [global::System.Runtime.CompilerServices.EnumeratorCancellation] global::System.Threading.CancellationToken cancellationToken = default)
+ {
+ var metadata = new global::TUnit.Core.TestMetadata
+ {
+ TestName = "MatrixMethod_WithEnumParameter_UsesOnlyMethodValues",
+ TestClassType = typeof(global::TUnit.TestProject.MatrixTests),
+ TestMethodName = "MatrixMethod_WithEnumParameter_UsesOnlyMethodValues",
+ Dependencies = global::System.Array.Empty(),
+ AttributeFactory = static () =>
+ [
+ new global::TUnit.Core.TestAttribute(),
+ new global::TUnit.TestProject.Attributes.EngineTest(global::TUnit.TestProject.Attributes.ExpectedResult.Pass)
+ ],
+ DataSources = new global::TUnit.Core.IDataSourceAttribute[]
+ {
+ new global::TUnit.Core.MatrixDataSourceAttribute(),
+ },
+ ClassDataSources = global::System.Array.Empty(),
+ PropertyDataSources = global::System.Array.Empty(),
+ PropertyInjections = global::System.Array.Empty(),
+ InheritanceDepth = 0,
+ FilePath = @"",
+ LineNumber = 197,
+ MethodMetadata = new global::TUnit.Core.MethodMetadata
+ {
+ Type = typeof(global::TUnit.TestProject.MatrixTests),
+ TypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::TUnit.TestProject.MatrixTests)),
+ Name = "MatrixMethod_WithEnumParameter_UsesOnlyMethodValues",
+ GenericTypeCount = 0,
+ ReturnType = typeof(global::System.Threading.Tasks.Task),
+ ReturnTypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::System.Threading.Tasks.Task)),
+ Parameters = new global::TUnit.Core.ParameterMetadata[]
+ {
+ new global::TUnit.Core.ParameterMetadata(typeof(bool))
+ {
+ Name = "flag",
+ TypeInfo = new global::TUnit.Core.ConcreteType(typeof(bool)),
+ IsNullable = false,
+ ReflectionInfo = typeof(global::TUnit.TestProject.MatrixTests).GetMethod("MatrixMethod_WithEnumParameter_UsesOnlyMethodValues", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(bool), typeof(global::TUnit.TestProject.MatrixTests.CountToTenEnum) }, null)!.GetParameters()[0]
+ },
+ new global::TUnit.Core.ParameterMetadata(typeof(global::TUnit.TestProject.MatrixTests.CountToTenEnum))
+ {
+ Name = "enum",
+ TypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::TUnit.TestProject.MatrixTests.CountToTenEnum)),
+ IsNullable = false,
+ ReflectionInfo = typeof(global::TUnit.TestProject.MatrixTests).GetMethod("MatrixMethod_WithEnumParameter_UsesOnlyMethodValues", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(bool), typeof(global::TUnit.TestProject.MatrixTests.CountToTenEnum) }, null)!.GetParameters()[1]
+ }
+ },
+ Class = global::TUnit.Core.ClassMetadata.GetOrAdd("TestsBase`1:global::TUnit.TestProject.MatrixTests", static () =>
+ {
+ var classMetadata = new global::TUnit.Core.ClassMetadata
+ {
+ Type = typeof(global::TUnit.TestProject.MatrixTests),
+ TypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::TUnit.TestProject.MatrixTests)),
+ Name = "MatrixTests",
+ Namespace = "TUnit.TestProject",
+ Assembly = global::TUnit.Core.AssemblyMetadata.GetOrAdd("TestsBase`1", static () => new global::TUnit.Core.AssemblyMetadata { Name = "TestsBase`1" }),
+ Parameters = global::System.Array.Empty(),
+ Properties = global::System.Array.Empty(),
+ Parent = null
+ };
+ foreach (var prop in classMetadata.Properties)
+ {
+ prop.ClassMetadata = classMetadata;
+ prop.ContainingTypeMetadata = classMetadata;
+ }
+ return classMetadata;
+ })
+ },
+ InstanceFactory = (typeArgs, args) => new global::TUnit.TestProject.MatrixTests(),
+ InvokeTypedTest = static (instance, args, cancellationToken) =>
+ {
+ try
+ {
+ switch (args.Length)
+ {
+ case 2:
+ {
+ return new global::System.Threading.Tasks.ValueTask(instance.MatrixMethod_WithEnumParameter_UsesOnlyMethodValues(TUnit.Core.Helpers.CastHelper.Cast(args[0]), TUnit.Core.Helpers.CastHelper.Cast(args[1])));
+ }
+ default:
+ throw new global::System.ArgumentException($"Expected exactly 2 arguments, but got {args.Length}");
+ }
+ }
+ catch (global::System.Exception ex)
+ {
+ return new global::System.Threading.Tasks.ValueTask(global::System.Threading.Tasks.Task.FromException(ex));
+ }
+ },
+ };
+ metadata.UseRuntimeDataGeneration(testSessionId);
+ yield return metadata;
+ yield break;
+ }
+}
+internal static class TUnit_TestProject_MatrixTests_MatrixMethod_WithEnumParameter_UsesOnlyMethodValues__bool_CountToTenEnum_ModuleInitializer
+{
+ [global::System.Runtime.CompilerServices.ModuleInitializer]
+ public static void Initialize()
+ {
+ global::TUnit.Core.SourceRegistrar.Register(typeof(global::TUnit.TestProject.MatrixTests), new TUnit_TestProject_MatrixTests_MatrixMethod_WithEnumParameter_UsesOnlyMethodValues__bool_CountToTenEnum_TestSource());
+ }
+}
diff --git a/TUnit.Core.SourceGenerator/CodeGenerationHelpers.cs b/TUnit.Core.SourceGenerator/CodeGenerationHelpers.cs
index 31ecc4b5e8..7555f29138 100644
--- a/TUnit.Core.SourceGenerator/CodeGenerationHelpers.cs
+++ b/TUnit.Core.SourceGenerator/CodeGenerationHelpers.cs
@@ -49,14 +49,16 @@ public static string GenerateParameterMetadataArray(IMethodSymbol method)
}
// Generate cached data source attributes for AOT compatibility
+ // Include both IDataSourceAttribute and IDataSourceMemberAttribute implementations
var dataSourceAttributes = param.GetAttributes()
.Where(attr => attr.AttributeClass != null &&
- attr.AttributeClass.AllInterfaces.Any(i => i.Name == "IDataSourceAttribute"))
+ attr.AttributeClass.AllInterfaces.Any(i =>
+ i.Name == "IDataSourceAttribute" || i.Name == "IDataSourceMemberAttribute"))
.ToArray();
if (dataSourceAttributes.Length > 0)
{
- writer.AppendLine($"CachedDataSourceAttributes = new global::TUnit.Core.IDataSourceAttribute[]");
+ writer.AppendLine($"CachedDataSourceAttributes = new global::System.Attribute[]");
writer.AppendLine("{");
writer.SetIndentLevel(3);
foreach (var attr in dataSourceAttributes)
diff --git a/TUnit.Core/Attributes/TestData/CombinedDataSourcesAttribute.cs b/TUnit.Core/Attributes/TestData/CombinedDataSourcesAttribute.cs
index 4d8ab15ef5..53a1a697ee 100644
--- a/TUnit.Core/Attributes/TestData/CombinedDataSourcesAttribute.cs
+++ b/TUnit.Core/Attributes/TestData/CombinedDataSourcesAttribute.cs
@@ -126,7 +126,9 @@ public sealed class CombinedDataSourcesAttribute : AsyncUntypedDataSourceGenerat
if (parameterMetadata.CachedDataSourceAttributes != null)
{
// Source-generated mode: use cached attributes (no reflection!)
- dataSourceAttributes = parameterMetadata.CachedDataSourceAttributes;
+ dataSourceAttributes = parameterMetadata.CachedDataSourceAttributes
+ .OfType()
+ .ToArray();
}
else
{
diff --git a/TUnit.Core/Attributes/TestData/IDataSourceMemberAttribute.cs b/TUnit.Core/Attributes/TestData/IDataSourceMemberAttribute.cs
new file mode 100644
index 0000000000..dcb9c3db5c
--- /dev/null
+++ b/TUnit.Core/Attributes/TestData/IDataSourceMemberAttribute.cs
@@ -0,0 +1,9 @@
+namespace TUnit.Core;
+
+///
+/// Marker interface for attributes that provide data values for individual parameters
+/// within a data source context (e.g., matrix testing).
+/// Attributes implementing this interface will be cached by the source generator
+/// for AOT-compatible runtime access.
+///
+public interface IDataSourceMemberAttribute;
diff --git a/TUnit.Core/Attributes/TestData/MatrixSourceAttribute.cs b/TUnit.Core/Attributes/TestData/MatrixSourceAttribute.cs
index 7417dcb421..d1a7ccac7c 100644
--- a/TUnit.Core/Attributes/TestData/MatrixSourceAttribute.cs
+++ b/TUnit.Core/Attributes/TestData/MatrixSourceAttribute.cs
@@ -42,7 +42,7 @@ namespace TUnit.Core;
///
/// The values to be used for this parameter in the test matrix.
[AttributeUsage(AttributeTargets.Parameter)]
-public class MatrixAttribute(params object?[]? objects) : TUnitAttribute
+public class MatrixAttribute(params object?[]? objects) : TUnitAttribute, IDataSourceMemberAttribute
{
protected MatrixAttribute() : this(null)
{
diff --git a/TUnit.Core/Models/TestModels/ParameterMetadata.cs b/TUnit.Core/Models/TestModels/ParameterMetadata.cs
index 6816a4e497..f3b24c53e4 100644
--- a/TUnit.Core/Models/TestModels/ParameterMetadata.cs
+++ b/TUnit.Core/Models/TestModels/ParameterMetadata.cs
@@ -56,9 +56,10 @@ public record ParameterMetadata([DynamicallyAccessedMembers(DynamicallyAccessedM
/// Cached data source attributes to avoid reflection call.
/// Set by source generator for AOT compatibility.
/// When null, falls back to using ReflectionInfo.GetCustomAttributes().
+ /// Includes attributes implementing IDataSourceAttribute or IDataSourceMemberAttribute.
///
[EditorBrowsable(EditorBrowsableState.Never)]
- public IDataSourceAttribute[]? CachedDataSourceAttributes { get; internal init; }
+ public Attribute[]? CachedDataSourceAttributes { get; internal init; }
///
/// Position of this parameter in the method/constructor signature.
diff --git a/TUnit.Engine.Tests/MatrixTests.cs b/TUnit.Engine.Tests/MatrixTests.cs
index 0daaafa2ec..d50a5bda37 100644
--- a/TUnit.Engine.Tests/MatrixTests.cs
+++ b/TUnit.Engine.Tests/MatrixTests.cs
@@ -8,7 +8,7 @@ public class MatrixTests(TestMode testMode) : InvokableTestBase(testMode)
[Test]
public async Task Test()
{
- var expectedCount = IsNetFramework ? 133 : 271;
+ var expectedCount = IsNetFramework ? 137 : 275;
await RunTestsWithFilter(
"/*/*/MatrixTests/*",
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 d17dfa1d33..23efc08b5c 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
@@ -864,6 +864,7 @@ namespace
bool SkipIfEmpty { get; set; }
.<<.