Skip to content

fix(sourcegen): pair each GenerateGenericTest type only with its typed ClassDataSource<T> - #7188

Merged
thomhurst merged 1 commit into
mainfrom
fix/issue-7158-generic-typed-classdatasource
Oct 20, 2026
Merged

thomhurst merged 1 commit into
mainfrom
fix/issue-7158-generic-typed-classdatasource

Conversation

@thomhurst

Copy link
Copy Markdown
Owner

Summary

A generic test method with several [GenerateGenericTest] types and one typed ClassDataSource<T> per type now produces the same tests in both modes.

[Test]
[GenerateGenericTest(typeof(GenA))]
[GenerateGenericTest(typeof(GenB))]
[ClassDataSource<GenA>(Shared = SharedType.None)]
[ClassDataSource<GenB>(Shared = SharedType.None)]
public void Run<T>(T d) { }
  • Before: source-gen mode built 4 tests. The 2 mismatched pairs (Run<GenA> with a GenB, and Run<GenB> with a GenA) failed with InvalidCastException. Reflection mode built 2 passing tests.
  • After: both modes build 2 passing tests. Run<GenA> runs only ClassDataSource<GenA>, and Run<GenB> runs only ClassDataSource<GenB>.

Cause

Both modes already scope a typed data source to the instantiation it infers. CollectConcreteInstantiations creates the GenA and GenB instantiations from the two typed sources, and each stores its source as SpecificArgumentsAttribute. The [GenerateGenericTest] types are duplicates and are dropped.

The emitted data sources are then filtered with IsSpecificMethodDataSource, which calls AreSameAttribute. That method compared only AttributeClass.Name and the constructor arguments. ClassDataSource<GenA> and ClassDataSource<GenB> have the same name and no constructor arguments, so each instantiation's filter accepted both sources.

Fix

AreSameAttribute now compares the constructed attribute class with SymbolEqualityComparer.Default instead of comparing names. This is a single change in TestMetadataGenerator.cs. Reflection mode was already correct and is unchanged. No other generator snapshot changed.

Tests

  • New tests/TUnit.TestProject/Bugs/_7158/GenerateGenericTestTypedClassDataSourceTests.cs (the issue's repro).
  • New generator snapshot test Tests7158: each entry's testDataSources holds only its own type's source. Before the fix both entries held both sources.
  • New Issue7158Tests engine test (reflection, plus AOT/source-gen in CI): 2 total, 2 passed.
  • TUnit.Core.SourceGenerator.Tests on net10.0: 193 passed, 1 skipped, no snapshot changes. Tests7158 also passes on net472.
  • TestProject with the _7158 filter: source-gen 2/2 passed, --reflection 2/2 passed.

Fixes #7158

…d ClassDataSource<T>

AreSameAttribute compared attribute classes by name, so ClassDataSource<A> and
ClassDataSource<B> (same name, no constructor arguments) matched each other and
every instantiation ran every typed data source. Compare the constructed
attribute class instead.

Fixes #7158
@coderabbitai

coderabbitai Bot commented Oct 20, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 34 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 8 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8a6f0a34-e3b5-4a1d-b703-d3d6448757d1
📥 Commits

Reviewing files that changed from the base of the PR and between c4b9977 and cff5540.

📒 Files selected for processing: 5
  • src/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs
  • tests/TUnit.Core.SourceGenerator.Tests/Bugs/7158/Tests7158.cs
  • tests/TUnit.Core.SourceGenerator.Tests/Tests7158.Test.verified.txt
  • tests/TUnit.Engine.Tests/Issue7158Tests.cs
  • tests/TUnit.TestProject/Bugs/_7158/GenerateGenericTestTypedClassDataSourceTests.cs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T05:30:17.589181Z cff5540 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@greptile-apps

greptile-apps Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] This PR appears safe to merge.

Summary

AreSameAttribute now compares constructed attribute types instead of names. This keeps ClassDataSource<Gen7158A> separate from ClassDataSource<Gen7158B>.

  • Each generated generic test uses only its matching typed data source.

Reviews (1) · Last reviewed commit: "fix(sourcegen): pair each GenerateGeneri..." · Reviewed by Greptile

@github-actions

Copy link
Copy Markdown
Contributor

Review: PR 7188 (typed ClassDataSource scoping)

Verdict: looks good. I found no blocking issues.

  • Root cause: AreSameAttribute compared only AttributeClass.Name. ClassDataSource<A> and ClassDataSource<B> share that name and have no constructor arguments, so they compared as equal. Comparing the constructed class with SymbolEqualityComparer.Default fixes this, and it is the correct way to compare symbols.
  • Other callers: AreSameAttribute is also used at lines ~731, 736, 766, 7073, 7112, 7121 and 7126, all to match an attribute against SpecificArgumentsAttribute. Both sides come from the same compilation, so symbol equality is safe and only makes matching stricter where names collided. Non-generic attributes behave as before, and the PR reports no other snapshot changes.
  • Tests:
    • The generator snapshot (Tests7158) and its explicit per-entry Contains / DoesNotContain assertions guard the regression directly.
    • The engine test runs in both modes.
    • The TestProject repro matches the issue.
  • Optional: the Tests7158 assertions locate each entry with Substring and IndexOf. They would throw an unhelpful error if the emitted format changed. The verified snapshot already covers this, so you could drop the manual slicing and rely on the snapshot alone.

Reflection mode is untouched and was already correct, so both modes now agree. Approving.

@thomhurst
thomhurst merged commit 03622b5 into main Oct 20, 2026
23 checks passed
@thomhurst
thomhurst deleted the fix/issue-7158-generic-typed-classdatasource branch October 20, 2026 09:04
This was referenced Oct 20, 2026
This was referenced Oct 29, 2026

This branch was previously deployed

1 inactive deployment
Pull Requests — cff55402 Deployed Oct 20, 2026 by thomhurst via modularpipeline (ubuntu-latest) #20290
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Source-gen pairs every GenerateGenericTest instantiation with every typed ClassDataSource<T>; reflection filters (2 extra failing tests)

1 participant