Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,19 @@
},
async generatedFiles =>
{
});
// Verify that inherited test methods have their categories properly included
var generatedCode = string.Join(Environment.NewLine, generatedFiles);

// Check that the BaseTest method has the BaseCategory attribute
await Assert.That(generatedCode).Contains("new global::TUnit.Core.CategoryAttribute(\"BaseCategory\")");

// Check that the BaseTestWithMultipleCategories method has both category attributes
await Assert.That(generatedCode).Contains("new global::TUnit.Core.CategoryAttribute(\"AnotherBaseCategory\")");
await Assert.That(generatedCode).Contains("new global::TUnit.Core.CategoryAttribute(\"MultipleCategories\")");

// Verify that the generated code includes the inherited test methods
await Assert.That(generatedCode).Contains("BaseTest");
await Assert.That(generatedCode).Contains("BaseTestWithMultipleCategories");
});
}
}

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

Type or namespace definition, or end-of-file expected

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

Type or namespace definition, or end-of-file expected

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

Type or namespace definition, or end-of-file expected

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

Type or namespace definition, or end-of-file expected

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

Type or namespace definition, or end-of-file expected

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

Type or namespace definition, or end-of-file expected

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

Type or namespace definition, or end-of-file expected

Check failure on line 44 in TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

Type or namespace definition, or end-of-file expected
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,26 @@ public class AttributeWriter
public static void WriteAttributes(ICodeWriter sourceCodeWriter, Compilation compilation,
ImmutableArray<AttributeData> attributeDatas)
{
for (var index = 0; index < attributeDatas.Length; index++)
var attributesToWrite = new List<AttributeData>();

// Filter out attributes that we can write
foreach (var attributeData in attributeDatas)
{
var attributeData = attributeDatas[index];

if (attributeData.ApplicationSyntaxReference is null)
// Include attributes with syntax reference (from current compilation)
// Include attributes without syntax reference (from other assemblies) as long as they have an AttributeClass
if (attributeData.ApplicationSyntaxReference is not null || attributeData.AttributeClass is not null)
{
continue;
attributesToWrite.Add(attributeData);
}
}

for (var index = 0; index < attributesToWrite.Count; index++)
{
var attributeData = attributesToWrite[index];

WriteAttribute(sourceCodeWriter, compilation, attributeData);

if (index != attributeDatas.Length - 1)
if (index != attributesToWrite.Count - 1)
{
sourceCodeWriter.AppendLine(",");
}
Expand All @@ -32,7 +40,17 @@ public static void WriteAttributes(ICodeWriter sourceCodeWriter, Compilation com
public static void WriteAttribute(ICodeWriter sourceCodeWriter, Compilation compilation,
AttributeData attributeData)
{
sourceCodeWriter.Append(GetAttributeObjectInitializer(compilation, attributeData));
if (attributeData.ApplicationSyntaxReference is null)
{
// For attributes from other assemblies (like inherited methods),
// use the WriteAttributeWithoutSyntax approach
WriteAttributeWithoutSyntax(sourceCodeWriter, attributeData);
}
else
{
// For attributes from the current compilation, use the syntax-based approach
sourceCodeWriter.Append(GetAttributeObjectInitializer(compilation, attributeData));
}
}

public static void WriteAttributeMetadata(ICodeWriter sourceCodeWriter, Compilation compilation,
Expand Down Expand Up @@ -212,14 +230,68 @@ public static void WriteAttributeWithoutSyntax(ICodeWriter sourceCodeWriter, Att

sourceCodeWriter.Append($"new {attributeName}({formattedConstructorArgs})");

if (string.IsNullOrEmpty(formattedNamedArgs))
// Check if we need to add properties (named arguments or data generator properties)
var hasNamedArgs = !string.IsNullOrEmpty(formattedNamedArgs);
var hasDataGeneratorProperties = HasNestedDataGeneratorProperties(attributeData);

if (!hasNamedArgs && !hasDataGeneratorProperties)
{
return;
}

sourceCodeWriter.AppendLine();
sourceCodeWriter.Append("{");
sourceCodeWriter.Append($"{formattedNamedArgs}");

if (hasNamedArgs)
{
sourceCodeWriter.Append($"{formattedNamedArgs}");
if (hasDataGeneratorProperties)
{
sourceCodeWriter.Append(",");
}
}

if (hasDataGeneratorProperties)
{
// For attributes without syntax, we still need to handle data generator properties
// but we can't rely on syntax analysis, so we'll use a simpler approach
WriteDataSourceGeneratorPropertiesWithoutSyntax(sourceCodeWriter, attributeData);
}

sourceCodeWriter.Append("}");
}

private static void WriteDataSourceGeneratorPropertiesWithoutSyntax(ICodeWriter sourceCodeWriter, AttributeData attributeData)
{
foreach (var propertySymbol in attributeData.AttributeClass?.GetMembers().OfType<IPropertySymbol>() ?? [])
{
if (propertySymbol.DeclaredAccessibility != Accessibility.Public)
{
continue;
}

if (propertySymbol.GetAttributes().FirstOrDefault(x => x.IsDataSourceAttribute()) is not { } dataSourceAttribute)
{
continue;
}

sourceCodeWriter.Append($"{propertySymbol.Name} = ");

var propertyType = propertySymbol.Type.GloballyQualified();
var isNullable = propertySymbol.Type.NullableAnnotation == NullableAnnotation.Annotated;

if (propertySymbol.Type.IsReferenceType && !isNullable)
{
sourceCodeWriter.Append("null!,");
}
else if (propertySymbol.Type.IsValueType && !isNullable)
{
sourceCodeWriter.Append($"default({propertyType}),");
}
else
{
sourceCodeWriter.Append("null,");
}
}
}
}
8 changes: 8 additions & 0 deletions TUnit.TestProject.Library/BaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@
public abstract class BaseTests
{
[Test]
[Category("BaseCategory")]
public void BaseTest()
{
}

[Test]
[Category("AnotherBaseCategory")]
[Category("MultipleCategories")]
public void BaseTestWithMultipleCategories()
{
}
}
24 changes: 24 additions & 0 deletions TUnit.TestProject/InheritedCategoryTestValidation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using TUnit.TestProject.Attributes;

namespace TUnit.TestProject;

[EngineTest(ExpectedResult.Pass)]
[InheritsTests]
public class InheritedCategoryTestValidation : Library.BaseTests
{
[Test]
public async Task TestInheritedBaseTestHasBaseCategory()
{
// This test verifies that when we call the inherited BaseTest method,
// it retains its BaseCategory attribute
await Assert.That(TestContext.Current!.TestDetails.Categories.Contains("BaseCategory"));

Check failure on line 14 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 14 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 14 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 14 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 14 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 14 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await Assert.That(TestContext.Current!.TestDetails.Categories.Contains("BaseCategory"));
await Assert.That(TestContext.Current!.TestDetails.Categories).Contains("BaseCategory");

}

[Test]
public async Task TestInheritedMultipleCategoriesMethod()
{
// This test verifies that inherited methods with multiple categories retain all of them
await Assert.That(TestContext.Current!.TestDetails.Categories.Contains("AnotherBaseCategory"));

Check failure on line 21 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 21 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 21 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 21 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 21 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 21 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)
await Assert.That(TestContext.Current!.TestDetails.Categories.Contains("MultipleCategories"));

Check failure on line 22 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 22 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 22 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 22 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 22 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 22 in TUnit.TestProject/InheritedCategoryTestValidation.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

'ValueAssertionBuilder<bool>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'ValueAssertionBuilder<bool>' could be found (are you missing a using directive or an assembly reference?)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await Assert.That(TestContext.Current!.TestDetails.Categories.Contains("AnotherBaseCategory"));
await Assert.That(TestContext.Current!.TestDetails.Categories.Contains("MultipleCategories"));
await Assert.That(TestContext.Current!.TestDetails.Categories).Contains("AnotherBaseCategory");
await Assert.That(TestContext.Current!.TestDetails.Categories).Contains("MultipleCategories");

}
}
14 changes: 14 additions & 0 deletions TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,18 @@
public void NonGenericMethodDataSource(string value)
{
}

[Test]
public void VerifyInheritedCategoriesAreAvailable()
{
// This test validates that categories from inherited methods are properly available at runtime
// The BaseTest method should have the "BaseCategory" category
// This will only pass if the source generator correctly includes the category attributes
var currentTest = TestContext.Current?.TestDetails;
Assert.That(currentTest).IsNotNull();

Check failure on line 33 in TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

Assert statements must be awaited - all TUnit assertions return Task

Check failure on line 33 in TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

Assert statements must be awaited - all TUnit assertions return Task

Check failure on line 33 in TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

Assert statements must be awaited - all TUnit assertions return Task

Check failure on line 33 in TUnit.TestProject/InheritedTestsFromDifferentProjectTests.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

Assert statements must be awaited - all TUnit assertions return Task
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Assert.That(currentTest).IsNotNull();
await Assert.That(currentTest).IsNotNull();
await Assert.That(currentTest!.Categories).Contains("BaseCategory");


// Note: This specific test won't have categories itself, but we're testing that
// the framework can properly access categories from inherited tests in the same class
// The real validation is in the generated code assertions in the source generator test
}
}
Loading