Skip to content

[Bug]: [AssertionExtension] on generic class with concrete receiver emits two angle-bracket lists #5918

@JohnVerheij

Description

@JohnVerheij

Description

When an [AssertionExtension]-decorated class introduces its own generic type parameter and derives from Assertion<TConcrete> for a non-sealed concrete receiver, AssertionExtensionGenerator emits the receiver's covariant type parameter and the class's own generic parameter as two adjacent angle-bracket lists in the generated extension method signature.

Expected Behavior

The generator should emit a single merged generic-parameter list (for example <TActual, T>) so the generated extension compiles.

Actual Behavior

The generator emits something shaped like <TActual><T>, with two separate generic-parameter blocks back-to-back. This is invalid C# syntax; the file fails to parse.

Steps to Reproduce

  1. Declare an [AssertionExtension] class that introduces a generic parameter and derives from Assertion<NonSealedConcreteType>:
[AssertionExtension("Matches")]
public class MatchesAssertion<T> : Assertion<System.Exception>
{
    private readonly System.Func<T, bool> _predicate;

    public MatchesAssertion(AssertionContext<System.Exception> context, System.Func<T, bool> predicate)
        : base(context) { _predicate = predicate; }

    protected override System.Threading.Tasks.Task<AssertionResult> CheckAsync(
        EvaluationMetadata<System.Exception> metadata)
        => System.Threading.Tasks.Task.FromResult(AssertionResult.Passed);

    protected override string GetExpectation() => "to match";
}
  1. Build the project. The generated extension method has two adjacent <...> blocks in its signature and the build fails.

TUnit Version

1.44.0

.NET Version

.NET 10.0

Operating System

Windows

IDE / Test Runner

dotnet CLI (dotnet test / dotnet run)

Error Output / Stack Trace

error CS1003: Syntax error, ',' expected

Additional Context

The bug surfaces when both conditions hold:

  1. The assertion class declares its own generic type parameter (class MyAssertion<T> : ...).
  2. The base assertion type is Assertion<TConcrete> where TConcrete is a non-sealed class (i.e. a covariance candidate per the generator's existing covariance logic).

A class that derives from Assertion<TConcrete> for a sealed type, or a class without its own generic parameter, is not affected.

IDE-Specific Issue?

  • I've confirmed this issue occurs when running via dotnet test or dotnet run, not just in my IDE

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions