Skip to content

Commit 76e027a

Browse files
Copilotthomhurst
andauthored
Fix IAsyncEnumerable detection in MethodDataSource source generator (#2991)
* Initial plan * Initial investigation of IAsyncEnumerable issue Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Fix IAsyncEnumerable detection in source generator Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
1 parent 9c7a25b commit 76e027a

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,14 @@ private static void GenerateMethodDataSourceFactory(CodeWriter writer, IMethodSy
978978

979979
private static bool IsAsyncEnumerable(ITypeSymbol type)
980980
{
981+
// Check if the type itself is an IAsyncEnumerable<T>
982+
if (type is INamedTypeSymbol namedType && namedType.IsGenericType &&
983+
namedType.OriginalDefinition.ToDisplayString() == "System.Collections.Generic.IAsyncEnumerable<T>")
984+
{
985+
return true;
986+
}
987+
988+
// Check if the type implements IAsyncEnumerable<T>
981989
return type.AllInterfaces.Any(i =>
982990
i.IsGenericType &&
983991
i.OriginalDefinition.ToDisplayString() == "System.Collections.Generic.IAsyncEnumerable<T>");

TUnit.UnitTests/AsyncDataSourceTests.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ public async Task TestWithAsyncValueTaskDataSource(int value, string text)
7474
await Assert.That(text).Contains("hundred");
7575
}
7676

77+
[Test]
78+
[MethodDataSource(nameof(AsyncEnumerableDataSource))]
79+
public async Task TestWithAsyncEnumerableDataSource(int value, string text)
80+
{
81+
await Assert.That(value).IsGreaterThan(0);
82+
await Assert.That(text).IsNotNull();
83+
await Assert.That(text).IsNotEmpty();
84+
}
85+
7786

7887
}
7988

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System.Collections.Generic;
2+
using System.Runtime.CompilerServices;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using TUnit.Core;
6+
7+
namespace TUnit.UnitTests;
8+
9+
public record AsyncTestData(int Id, string Name, DateTime CreatedAt);
10+
11+
public static class AsyncTestDataSources
12+
{
13+
// AOT-compatible async data source with cancellation support - matching documentation
14+
public static async IAsyncEnumerable<Func<AsyncTestData>> GetAsyncTestData(
15+
[EnumeratorCancellation] CancellationToken ct = default)
16+
{
17+
for (int i = 1; i <= 3; i++)
18+
{
19+
ct.ThrowIfCancellationRequested();
20+
21+
// Simulate async data loading (database, API, etc.)
22+
await Task.Delay(10, ct);
23+
24+
yield return () => new AsyncTestData(
25+
Id: i,
26+
Name: $"Item_{i}",
27+
CreatedAt: DateTime.UtcNow.AddDays(-i)
28+
);
29+
}
30+
}
31+
32+
// Simple async enumerable returning tuples - matching documentation
33+
public static async IAsyncEnumerable<(int, string)> GetSimpleAsyncData(
34+
[EnumeratorCancellation] CancellationToken ct = default)
35+
{
36+
await Task.Delay(1, ct); // Simulate async work
37+
yield return (1, "first");
38+
yield return (2, "second");
39+
yield return (3, "third");
40+
}
41+
}
42+
43+
public class IAsyncEnumerableDocumentationExample
44+
{
45+
[Test]
46+
[MethodDataSource(typeof(AsyncTestDataSources), nameof(AsyncTestDataSources.GetAsyncTestData))]
47+
public async Task TestWithAsyncComplexData(AsyncTestData testData)
48+
{
49+
await Assert.That(testData.Id).IsGreaterThan(0);
50+
await Assert.That(testData.Name).StartsWith("Item_");
51+
await Assert.That(testData.CreatedAt).IsLessThan(DateTime.UtcNow);
52+
}
53+
54+
[Test]
55+
[MethodDataSource(typeof(AsyncTestDataSources), nameof(AsyncTestDataSources.GetSimpleAsyncData))]
56+
public async Task TestWithAsyncSimpleData(int id, string name)
57+
{
58+
await Assert.That(id).IsGreaterThan(0).And.IsLessThanOrEqualTo(3);
59+
await Assert.That(name).IsNotEmpty();
60+
}
61+
}

0 commit comments

Comments
 (0)