Skip to content

Fix IAsyncEnumerable detection in MethodDataSource source generator - #2991

Merged
thomhurst merged 3 commits into
mainfrom
copilot/fix-2990
Aug 24, 2025
Merged

Fix IAsyncEnumerable detection in MethodDataSource source generator#2991
thomhurst merged 3 commits into
mainfrom
copilot/fix-2990

Conversation

CopilotAI commented Aug 23, 2025

Copy link
Copy Markdown
Contributor

The source generator was not correctly detecting when a method returns async IAsyncEnumerable<T>, causing MethodDataSource attributes with async enumerable data sources to throw InvalidCastException at runtime.

Problem

When using MethodDataSource with an IAsyncEnumerable, TUnit would attempt to cast the compiler-generated async iterator (e.g., <GetAsyncTestData>d__0) directly to the test data type instead of iterating through the async enumerable and yielding individual values.

// This would fail with InvalidCastExceptionpublicstaticasyncIAsyncEnumerable<(int,string)>GetSimpleAsyncData(){awaitTask.Delay(1);yieldreturn(1,"first");yieldreturn(2,"second");yieldreturn(3,"third");}[Test][MethodDataSource(nameof(GetSimpleAsyncData))]publicasyncTaskTestWithAsyncSimpleData(intid,stringname){ ...}

Root Cause

The IsAsyncEnumerable() method in TestMetadataGenerator.cs only checked type.AllInterfaces for IAsyncEnumerable<T> implementations, but didn't check if the type itself was an IAsyncEnumerable<T>. For methods returning async IAsyncEnumerable<T>, the return type is directly IAsyncEnumerable<T>, not a type that implements it.

Solution

Updated the detection logic to check both:

  1. If the type itself is IAsyncEnumerable<T> (for direct returns)
  2. If the type implements IAsyncEnumerable<T> (for inherited implementations)

This ensures the source generator correctly generates the async enumerable iteration code:

awaitforeach(variteminresult){yieldreturn()=>Task.FromResult(DataSourceHelpers.ToObjectArray(item));}

Instead of incorrectly treating the async iterator as a single value.

Testing

Added comprehensive test cases covering:

  • IAsyncEnumerable<Func<CustomType>> (matching documentation examples)
  • IAsyncEnumerable<(int, string)> (tuple returns)
  • IAsyncEnumerable<object[]> (existing patterns)

All async enumerable tests now pass, and existing functionality remains unaffected.

Fixes#2990.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

CopilotAIand others added 2 commits August 23, 2025 19:59
Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
CopilotAI changed the title [WIP] MethodDataSources with IAsyncEnumerable<T> throw invalid cast exceptionFix IAsyncEnumerable detection in MethodDataSource source generatorAug 23, 2025
CopilotAI requested a review from thomhurstAugust 23, 2025 20:08
@thomhurst
thomhurst marked this pull request as ready for review August 23, 2025 21:46
@thomhurst
thomhurst merged commit 76e027a into mainAug 24, 2025
11 of 15 checks passed
@thomhurst
thomhurst deleted the copilot/fix-2990 branch August 24, 2025 13:56
@claudeclaudeBot mentioned this pull request Aug 30, 2025
1 task
Sign up for freeto 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.

MethodDataSources with IAsyncEnumerable<T> throw invalid cast exception

2 participants

@thomhurst