Skip to content

Commit 2bfd67e

Browse files
committed
Use Test attribute
1 parent aa37166 commit 2bfd67e

6 files changed

Lines changed: 74 additions & 141 deletions

File tree

TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

Lines changed: 16 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
3636
.Where(static m => m is not null)
3737
.Combine(enabledProvider);
3838

39-
// Custom test attributes that inherit from BaseTestAttribute
40-
var customTestMethodsProvider = context.SyntaxProvider
41-
.CreateSyntaxProvider(
42-
predicate: static (node, _) => node is MethodDeclarationSyntax { AttributeLists.Count: > 0 },
43-
transform: static (ctx, _) => GetCustomTestMethodMetadata(ctx))
44-
.Where(static m => m is not null)
45-
.Combine(enabledProvider);
46-
4739
var inheritsTestsClassesProvider = context.SyntaxProvider
4840
.ForAttributeWithMetadataName(
4941
"TUnit.Core.InheritsTestsAttribute",
@@ -63,17 +55,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
6355
GenerateTestMethodSource(context, testMethod);
6456
});
6557

66-
context.RegisterSourceOutput(customTestMethodsProvider,
67-
static (context, data) =>
68-
{
69-
var (testMethod, isEnabled) = data;
70-
if (!isEnabled)
71-
{
72-
return;
73-
}
74-
GenerateTestMethodSource(context, testMethod);
75-
});
76-
7758
context.RegisterSourceOutput(inheritsTestsClassesProvider,
7859
static (context, data) =>
7960
{
@@ -86,86 +67,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8667
});
8768
}
8869

89-
private static TestMethodMetadata? GetCustomTestMethodMetadata(GeneratorSyntaxContext context)
90-
{
91-
var methodSyntax = (MethodDeclarationSyntax)context.Node;
92-
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodSyntax) as IMethodSymbol;
93-
94-
if (methodSymbol == null)
95-
{
96-
return null;
97-
}
98-
99-
// Find the custom test attribute that inherits from BaseTestAttribute
100-
// Skip any attributes defined in TUnit.Core namespace (handled by built-in providers)
101-
AttributeData? testAttribute = null;
102-
foreach (var attr in methodSymbol.GetAttributes())
103-
{
104-
var attrType = attr.AttributeClass;
105-
if (attrType == null)
106-
{
107-
continue;
108-
}
109-
110-
// Skip built-in TUnit.Core attributes - they're handled by other providers
111-
if (attrType.ContainingNamespace?.ToDisplayString() == "TUnit.Core")
112-
{
113-
continue;
114-
}
115-
116-
var baseType = attrType.BaseType;
117-
while (baseType != null)
118-
{
119-
if (baseType.ToDisplayString() == "TUnit.Core.BaseTestAttribute")
120-
{
121-
testAttribute = attr;
122-
break;
123-
}
124-
baseType = baseType.BaseType;
125-
}
126-
if (testAttribute != null)
127-
{
128-
break;
129-
}
130-
}
131-
132-
if (testAttribute == null)
133-
{
134-
return null;
135-
}
136-
137-
var containingType = methodSymbol.ContainingType;
138-
139-
if (containingType == null)
140-
{
141-
return null;
142-
}
143-
144-
if (containingType.IsAbstract)
145-
{
146-
return null;
147-
}
148-
149-
var isGenericType = containingType is { IsGenericType: true, TypeParameters.Length: > 0 };
150-
var isGenericMethod = methodSymbol is { IsGenericMethod: true };
151-
152-
var (filePath, lineNumber) = GetTestMethodSourceLocation(methodSyntax, testAttribute);
153-
154-
return new TestMethodMetadata
155-
{
156-
MethodSymbol = methodSymbol,
157-
TypeSymbol = containingType,
158-
FilePath = filePath,
159-
LineNumber = lineNumber,
160-
TestAttribute = testAttribute,
161-
SemanticModel = context.SemanticModel,
162-
MethodSyntax = methodSyntax,
163-
IsGenericType = isGenericType,
164-
IsGenericMethod = isGenericMethod,
165-
MethodAttributes = methodSymbol.GetAttributes()
166-
};
167-
}
168-
16970
private static InheritsTestsClassMetadata? GetInheritsTestsClassMetadata(GeneratorAttributeSyntaxContext context)
17071
{
17172
var classSyntax = (ClassDeclarationSyntax)context.TargetNode;
@@ -184,7 +85,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
18485
{
18586
TypeSymbol = classSymbol,
18687
ClassSyntax = classSyntax,
187-
SemanticModel = context.SemanticModel
88+
Context = context
18889
};
18990
}
19091

@@ -219,7 +120,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
219120
FilePath = filePath,
220121
LineNumber = lineNumber,
221122
TestAttribute = context.Attributes.First(),
222-
SemanticModel = context.SemanticModel,
123+
Context = context,
223124
MethodSyntax = methodSyntax,
224125
IsGenericType = isGenericType,
225126
IsGenericMethod = isGenericMethod,
@@ -284,7 +185,7 @@ private static void GenerateInheritedTestSources(SourceProductionContext context
284185
FilePath = filePath,
285186
LineNumber = lineNumber,
286187
TestAttribute = testAttribute,
287-
SemanticModel = classInfo.SemanticModel, // Use class context to access Compilation
188+
Context = classInfo.Context, // Use class context to access Compilation
288189
MethodSyntax = null, // No syntax for inherited methods
289190
IsGenericType = typeForMetadata.IsGenericType,
290191
IsGenericMethod = (concreteMethod ?? method).IsGenericMethod,
@@ -327,7 +228,7 @@ private static void GenerateTestMethodSource(SourceProductionContext context, Te
327228
{
328229
try
329230
{
330-
if (testMethod?.MethodSymbol == null || testMethod.SemanticModel?.Compilation == null)
231+
if (testMethod?.MethodSymbol == null || testMethod.Context == null)
331232
{
332233
return;
333234
}
@@ -370,7 +271,7 @@ private static void GenerateFileHeader(CodeWriter writer)
370271

371272
private static void GenerateTestMetadata(CodeWriter writer, TestMethodMetadata testMethod)
372273
{
373-
var compilation = testMethod.SemanticModel?.Compilation!;
274+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
374275

375276
var className = testMethod.TypeSymbol.GloballyQualified();
376277
var methodName = testMethod.MethodSymbol.Name;
@@ -448,7 +349,7 @@ private static void GenerateSpecificGenericInstantiation(
448349
string combinationGuid,
449350
ImmutableArray<ITypeSymbol> typeArguments)
450351
{
451-
var compilation = testMethod.SemanticModel?.Compilation!;
352+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
452353
var methodName = testMethod.MethodSymbol.Name;
453354
var typeArgsString = string.Join(", ", typeArguments.Select(t => t.GloballyQualified()));
454355
var instantiatedMethodName = $"{methodName}<{typeArgsString}>";
@@ -460,7 +361,7 @@ private static void GenerateSpecificGenericInstantiation(
460361
FilePath = testMethod.FilePath,
461362
LineNumber = testMethod.LineNumber,
462363
TestAttribute = testMethod.TestAttribute,
463-
SemanticModel = testMethod.SemanticModel,
364+
Context = testMethod.Context,
464365
MethodSyntax = testMethod.MethodSyntax,
465366
IsGenericType = testMethod.IsGenericType,
466367
IsGenericMethod = false, // We're creating a concrete instantiation
@@ -667,7 +568,7 @@ private static void GenerateTestMetadataInstance(CodeWriter writer, TestMethodMe
667568

668569
private static void GenerateMetadata(CodeWriter writer, TestMethodMetadata testMethod)
669570
{
670-
var compilation = testMethod.SemanticModel?.Compilation!;
571+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
671572
var methodSymbol = testMethod.MethodSymbol;
672573

673574

@@ -713,7 +614,7 @@ private static void GenerateMetadata(CodeWriter writer, TestMethodMetadata testM
713614

714615
private static void GenerateMetadataForConcreteInstantiation(CodeWriter writer, TestMethodMetadata testMethod)
715616
{
716-
var compilation = testMethod.SemanticModel?.Compilation!;
617+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
717618
var methodSymbol = testMethod.MethodSymbol;
718619

719620

@@ -765,7 +666,7 @@ private static void GenerateMetadataForConcreteInstantiation(CodeWriter writer,
765666

766667
private static void GenerateDataSources(CodeWriter writer, TestMethodMetadata testMethod)
767668
{
768-
var compilation = testMethod.SemanticModel?.Compilation!;
669+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
769670
var methodSymbol = testMethod.MethodSymbol;
770671
var typeSymbol = testMethod.TypeSymbol;
771672

@@ -1669,7 +1570,7 @@ private static void GeneratePropertyInjections(CodeWriter writer, INamedTypeSymb
16691570

16701571
private static void GeneratePropertyDataSources(CodeWriter writer, TestMethodMetadata testMethod)
16711572
{
1672-
var compilation = testMethod.SemanticModel?.Compilation!;
1573+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
16731574
var typeSymbol = testMethod.TypeSymbol;
16741575
var currentType = typeSymbol;
16751576
var processedProperties = new HashSet<string>();
@@ -2887,7 +2788,7 @@ private static void GenerateGenericTestWithConcreteTypes(
28872788
string className,
28882789
string combinationGuid)
28892790
{
2890-
var compilation = testMethod.SemanticModel?.Compilation!;
2791+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
28912792
var methodName = testMethod.MethodSymbol.Name;
28922793

28932794
writer.AppendLine("// Create generic metadata with concrete type registrations");
@@ -4366,7 +4267,7 @@ private static void GenerateConcreteTestMetadata(
43664267
ITypeSymbol[] typeArguments,
43674268
AttributeData? specificArgumentsAttribute = null)
43684269
{
4369-
var compilation = testMethod.SemanticModel?.Compilation!;
4270+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
43704271
var methodName = testMethod.MethodSymbol.Name;
43714272

43724273
// Separate class type arguments from method type arguments
@@ -4586,7 +4487,7 @@ private static void GenerateConcreteMetadataWithFilteredDataSources(
45864487
AttributeData? specificArgumentsAttribute,
45874488
ITypeSymbol[] typeArguments)
45884489
{
4589-
var compilation = testMethod.SemanticModel?.Compilation!;
4490+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
45904491
var methodSymbol = testMethod.MethodSymbol;
45914492
var typeSymbol = testMethod.TypeSymbol;
45924493

@@ -4905,7 +4806,7 @@ private static void GenerateConcreteTestMetadataForNonGeneric(
49054806
AttributeData? classDataSourceAttribute,
49064807
AttributeData? methodDataSourceAttribute)
49074808
{
4908-
var compilation = testMethod.SemanticModel?.Compilation!;
4809+
var compilation = testMethod.Context!.Value.SemanticModel.Compilation;
49094810
var methodName = testMethod.MethodSymbol.Name;
49104811

49114812
writer.AppendLine($"var metadata = new global::TUnit.Core.TestMetadata<{className}>");
@@ -5098,6 +4999,6 @@ public class InheritsTestsClassMetadata
50984999
{
50995000
public required INamedTypeSymbol TypeSymbol { get; init; }
51005001
public required ClassDeclarationSyntax ClassSyntax { get; init; }
5101-
public SemanticModel SemanticModel { get; init; }
5002+
public GeneratorAttributeSyntaxContext Context { get; init; }
51025003
}
51035004

TUnit.Core.SourceGenerator/Models/TestMethodMetadata.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ public class TestMethodMetadata : IEquatable<TestMethodMetadata>
1111
{
1212
public required IMethodSymbol MethodSymbol { get; init; }
1313
public required INamedTypeSymbol TypeSymbol { get; init; }
14-
public required SemanticModel SemanticModel { get; init; }
1514
public required string FilePath { get; init; }
1615
public required int LineNumber { get; init; }
1716
public required AttributeData TestAttribute { get; init; }
17+
public GeneratorAttributeSyntaxContext? Context { get; init; }
1818
public required MethodDeclarationSyntax? MethodSyntax { get; init; }
1919
public bool IsGenericType { get; init; }
2020
public bool IsGenericMethod { get; init; }

TUnit.Engine/Discovery/ReflectionTestDataCollector.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,18 +1018,17 @@ private static bool HasTestMethods([DynamicallyAccessedMembers(DynamicallyAccess
10181018

10191019
private static bool IsTestMethod(MethodInfo method)
10201020
{
1021-
// Check if method has any attribute that inherits from BaseTestAttribute
1022-
return method.GetCustomAttributes(typeof(BaseTestAttribute), inherit: false).Length > 0;
1021+
return method.IsDefined(typeof(TestAttribute), inherit: false);
10231022
}
10241023

10251024
private static string? ExtractFilePath(MethodInfo method)
10261025
{
1027-
return method.GetCustomAttribute<BaseTestAttribute>()?.File;
1026+
return method.GetCustomAttribute<TestAttribute>()?.File;
10281027
}
10291028

10301029
private static int? ExtractLineNumber(MethodInfo method)
10311030
{
1032-
return method.GetCustomAttribute<BaseTestAttribute>()?.Line;
1031+
return method.GetCustomAttribute<TestAttribute>()?.Line;
10331032
}
10341033

10351034
private static TestMetadata CreateFailedTestMetadataForAssembly(Assembly assembly, Exception ex)

TUnit.Example.FsCheck.TestProject/PropertyTests.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1+
using TUnit.Core;
12
using TUnit.FsCheck;
23

34
namespace TUnit.Example.FsCheck.TestProject;
45

56
public class PropertyTests
67
{
7-
[FsCheckProperty]
8+
[Test, FsCheckProperty]
89
public bool ReverseReverseIsOriginal(int[] array)
910
{
1011
var reversed = array.AsEnumerable().Reverse().Reverse().ToArray();
1112
return array.SequenceEqual(reversed);
1213
}
1314

14-
[FsCheckProperty]
15+
[Test, FsCheckProperty]
1516
public bool AbsoluteValueIsNonNegative(int value)
1617
{
1718
return Math.Abs((long)value) >= 0;
1819
}
1920

20-
[FsCheckProperty]
21+
[Test, FsCheckProperty]
2122
public bool StringConcatenationLength(string a, string b)
2223
{
2324
if (a == null || b == null)
@@ -28,14 +29,14 @@ public bool StringConcatenationLength(string a, string b)
2829
return (a + b).Length == a.Length + b.Length;
2930
}
3031

31-
[FsCheckProperty(MaxTest = 50)]
32+
[Test, FsCheckProperty(MaxTest = 50)]
3233
public bool ListConcatenationPreservesElements(int[] first, int[] second)
3334
{
3435
var combined = first.Concat(second).ToArray();
3536
return combined.Length == first.Length + second.Length;
3637
}
3738

38-
[FsCheckProperty]
39+
[Test, FsCheckProperty]
3940
public void AdditionIsCommutative(int a, int b)
4041
{
4142
var result1 = a + b;
@@ -47,7 +48,7 @@ public void AdditionIsCommutative(int a, int b)
4748
}
4849
}
4950

50-
[FsCheckProperty]
51+
[Test, FsCheckProperty]
5152
public async Task AsyncPropertyTest(int value)
5253
{
5354
await Task.Delay(1); // Simulate async work
@@ -58,7 +59,7 @@ public async Task AsyncPropertyTest(int value)
5859
}
5960
}
6061

61-
[FsCheckProperty]
62+
[Test, FsCheckProperty]
6263
public bool MultiplicationIsAssociative(int a, int b, int c)
6364
{
6465
// Using long to avoid overflow

0 commit comments

Comments
 (0)