@@ -19,6 +19,20 @@ public ClassAutoNSubstituteDataAttribute(Type @class)
1919 /// </summary>
2020 public new Type Class { get ; }
2121
22+ /// <summary>
23+ /// Combines class-provided data rows with AutoFixture generated specimens, honoring any <see cref="FrozenAttribute"/> parameters.
24+ /// </summary>
25+ /// <param name="testMethod">The target test method.</param>
26+ /// <param name="disposalTracker">xUnit disposal tracker (not directly used).</param>
27+ /// <returns>Augmented data rows with original supplied values followed by generated specimens.</returns>
28+ /// <remarks>
29+ /// For each row:
30+ /// 1. Create a fresh fixture.
31+ /// 2. Inject supplied values that map to [Frozen] parameters (positional only).
32+ /// 3. Generate remaining parameters via <see cref="GetSpecimen(IFixture, ParameterInfo)"/>.
33+ /// 4. Preserve original row metadata.
34+ /// Unlike member attribute handling, no promotion step is required because class data enumeration typically aligns positions directly.
35+ /// </remarks>
2236 public override async ValueTask < IReadOnlyCollection < ITheoryDataRow > > GetData (
2337 MethodInfo testMethod ,
2438 DisposalTracker disposalTracker )
@@ -33,22 +47,27 @@ public override async ValueTask<IReadOnlyCollection<ITheoryDataRow>> GetData(
3347 nameof ( FixtureRegistrar . Inject ) ,
3448 BindingFlags . Public | BindingFlags . Static ) ;
3549
36- var augmented = new List < ITheoryDataRow > ( baseRows . Count ) ;
37- foreach ( var row in baseRows )
50+ void InjectFrozen ( object ? [ ] originalData , IFixture f )
3851 {
39- var originalData = row . GetData ( ) ;
40- var fixture = FixtureFactory . Create ( ) ;
41-
42- // Inject frozen values if present in source data.
4352 foreach ( var frozenValue in frozenValues )
4453 {
4554 if ( originalData . Length > frozenValue . Index )
4655 {
4756 injectMethod ?
4857 . MakeGenericMethod ( frozenValue . ParameterType )
49- . Invoke ( null , [ fixture , originalData [ frozenValue . Index ] ] ) ;
58+ . Invoke ( null , [ f , originalData [ frozenValue . Index ] ] ) ;
5059 }
5160 }
61+ }
62+
63+ var augmented = new List < ITheoryDataRow > ( baseRows . Count ) ;
64+ foreach ( var row in baseRows )
65+ {
66+ var originalData = row . GetData ( ) ;
67+ var fixture = FixtureFactory . Create ( ) ;
68+
69+ // Inject frozen values if present in source data (positional only for class data).
70+ InjectFrozen ( originalData , fixture ) ;
5271
5372 var extendedData = originalData
5473 . Concat ( parameters
@@ -71,6 +90,16 @@ public override async ValueTask<IReadOnlyCollection<ITheoryDataRow>> GetData(
7190 return augmented ;
7291 }
7392
93+ /// <summary>
94+ /// Resolves a specimen for the given parameter applying parameter-level customizations prior to resolution.
95+ /// </summary>
96+ /// <param name="fixture">The per-row fixture instance.</param>
97+ /// <param name="parameter">The parameter to resolve.</param>
98+ /// <returns>The resolved specimen instance.</returns>
99+ /// <remarks>
100+ /// Customizations are ordered so non-frozen behaviors apply before any potential freezing to ensure
101+ /// a final form is captured when freezing occurs.
102+ /// </remarks>
74103 private static object GetSpecimen (
75104 IFixture fixture ,
76105 ParameterInfo parameter )
0 commit comments