Skip to content

Generic test method with a null and a non-null value for one type parameter infers object in source-gen but int in reflection (null becomes 0) #7155

Closed

Description

@thomhurst

Summary

Confirmed on main (04786b3). A generic test method whose type parameter gets one non-null value and one null infers a different type argument in each engine mode. Source-gen mode runs Run<object>(1, null). Reflection mode runs Run<int>(1, null) and silently turns the null into 0.

Repro

public class GenericNullRow
{
    [Test]
    [Arguments(1, null)]
    public void Run<T>(T a, T b)
    {
        Console.WriteLine($"T={typeof(T).Name} a={a} b={b ?? (object)"<null>"}");
    }
}

Run with --treenode-filter "/*/*/GenericNullRow/*", with and without --reflection.

Observed

Mode Test name typeof(T) b
Source-gen Run<object>(1, null) Object null
Reflection Run<int>(1, null) Int32 0

Both pass, but the two modes produce different test names (and so different test UIDs and filters). In reflection mode the test body also receives a value that the data row never supplied: null becomes default(int).

Expected

Both modes agree. Reflection mode should not change null into 0 without saying so. Either:

  • infer object (what source-gen does, and consistent with null-only rows inferring object), or
  • fail the row with a clear message that T was inferred as a value type and cannot accept null. Note that C# itself rejects Run(1, null) for this signature, because it infers T = int and null does not convert to int.

Where

  • src/TUnit.Engine/Services/TestGenericTypeResolver.cs:450-464: ResolveMethodGenericArguments skips null arguments, so the non-null 1 alone maps T to int.
  • The reflection invoker then passes null into an int parameter, which reflection invocation turns into 0.
  • The source generator infers object for the same row.

Related

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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