Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions Common.Test.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.14.2" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="1.6.3" />
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.5.2" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="2.1.0" />

<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion Common.props
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@

<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.201" PrivateAssets="all" />
</ItemGroup>
</Project>
4 changes: 2 additions & 2 deletions build/_build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Nuke.Common" Version="9.0.4" />
<PackageReference Include="ReportGenerator" Version="5.1.19" />
<PackageReference Include="Nuke.Common" Version="10.1.0" />
<PackageReference Include="ReportGenerator" Version="5.5.4" />
<PackageDownload Include="GitVersion.Tool" Version="[5.10.3]" />
</ItemGroup>

Expand Down
5 changes: 4 additions & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"sdk": {
"version": "8.0.0",
"version": "10.0.0",
"rollForward": "latestMinor"
},
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
5 changes: 2 additions & 3 deletions src/AutoFixture.TUnit/AutoArgumentsAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,9 @@ protected AutoArgumentsAttribute(Func<IFixture> fixtureFactory, params object?[]
public object?[] Values { get; }

/// <inheritdoc />
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
return new AutoDataSource(this.FixtureFactory, new InlineDataSource(this.Values))
.GenerateDataSources(dataGeneratorMetadata)
.Select(x => x());
.GetDataRowsAsync(dataGeneratorMetadata);
}
}
4 changes: 2 additions & 2 deletions src/AutoFixture.TUnit/AutoClassDataSourceAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ protected AutoClassDataSourceAttribute(Func<IFixture> fixtureFactory, Type sourc
public object?[] Parameters { get; }

/// <inheritdoc />
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
var source = new AutoDataSource(this.FixtureFactory,
new ClassDataSource(this.SourceType, this.Parameters));

return source.GenerateDataSources(dataGeneratorMetadata).Select(x => x());
return source.GetDataRowsAsync(dataGeneratorMetadata);
}
}
4 changes: 2 additions & 2 deletions src/AutoFixture.TUnit/AutoDataSourceAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ protected AutoDataSourceAttribute(Func<IFixture> fixtureFactory)
public Func<IFixture> FixtureFactory { get; }

/// <inheritdoc />
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
var source = new AutoDataSource(this.FixtureFactory);

return source.GenerateDataSources(dataGeneratorMetadata).Select(x => x());
return source.GetDataRowsAsync(dataGeneratorMetadata);
}
}
8 changes: 6 additions & 2 deletions src/AutoFixture.TUnit/AutoFixture.TUnit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<Import Project="..\..\Common.props" />

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net8.0;net10.0</TargetFrameworks>

<!-- NuGet options -->
<PackageId>AutoFixture.TUnit</PackageId>
Expand All @@ -12,7 +12,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="TUnit.Core" Version="0.16.56" />
<PackageReference Include="PolySharp" Version="1.15.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="TUnit.Core" Version="1.21.6" />
<PackageReference Include="AutoFixture" Version="4.18.1" />
</ItemGroup>

Expand Down
4 changes: 2 additions & 2 deletions src/AutoFixture.TUnit/AutoMemberDataSourceAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ protected AutoMemberDataSourceAttribute(Func<IFixture> fixtureFactory, Type? mem
public object?[] Parameters { get; }

/// <inheritdoc />
public override IEnumerable<object?[]?> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
var testMethod = dataGeneratorMetadata.GetMethod();

Expand All @@ -100,6 +100,6 @@ protected AutoMemberDataSourceAttribute(Func<IFixture> fixtureFactory, Type? mem
createFixture: this.FixtureFactory,
source: new MemberDataSource(sourceType, this.MemberName, this.Parameters));

return source.GenerateDataSources(dataGeneratorMetadata).Select(x => x());
return source.GetDataRowsAsync(dataGeneratorMetadata);
}
}
44 changes: 21 additions & 23 deletions src/AutoFixture.TUnit/BaseDataSourceAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ namespace AutoFixture.TUnit;
/// <summary>
/// Base class for data sources that provide AutoFixture test data for TUnit data driven tests.
/// </summary>
public abstract class BaseDataSourceAttribute : NonTypedDataSourceGeneratorAttribute, IDataSource
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public abstract class BaseDataSourceAttribute : Attribute, IDataSourceAttribute, IDataSource
{
/// <summary>
/// Returns the test data provided by the source.
Expand All @@ -17,35 +18,32 @@ public abstract class BaseDataSourceAttribute : NonTypedDataSourceGeneratorAttri
/// Returns a sequence of argument collections, where each collection
/// is an array of objects representing the arguments for a test method.
/// </returns>
public abstract IEnumerable<object?[]?> GetData(DataGeneratorMetadata dataGeneratorMetadata);
public abstract IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata);

/// <inheritdoc />
public override IEnumerable<Func<object?[]>> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata)
public bool SkipIfEmpty { get; set; }

/// <inheritdoc />
public async IAsyncEnumerable<Func<Task<object?[]?>>> GetDataRowsAsync(DataGeneratorMetadata dataGeneratorMetadata)
{
if (dataGeneratorMetadata is null) throw new ArgumentNullException(nameof(dataGeneratorMetadata));

return GetTestDataEnumerable();
var parameters = dataGeneratorMetadata.MembersToGenerate;
if (parameters.Length == 0)
{
// If the method has no parameters, a single test run is enough.
yield return () => Task.FromResult<object?[]?>(Array.Empty<object?>());
yield break;
}

var enumerable = this.GetData(dataGeneratorMetadata)
?? throw new InvalidOperationException("The source member yielded no test data.");

IEnumerable<Func<object?[]>> GetTestDataEnumerable()
await foreach (var testDataFunc in enumerable)
{
var parameters = dataGeneratorMetadata.MembersToGenerate;
if (parameters.Length == 0)
{
// If the method has no parameters, a single test run is enough.
yield return () => [];
yield break;
}

var enumerable = this.GetData(dataGeneratorMetadata)
?? throw new InvalidOperationException("The source member yielded no test data.");

foreach (var testData in enumerable)
{
if (testData is null) throw new InvalidOperationException("The source member yielded a null test data.");
if (testData.Length > parameters.Length) throw new InvalidOperationException("The number of arguments provided exceeds the number of parameters.");

yield return () => testData;
}
if (testDataFunc is null) throw new InvalidOperationException("The source member yielded a null test data.");

yield return testDataFunc;
}
}
}
27 changes: 19 additions & 8 deletions src/AutoFixture.TUnit/CompositeDataSourceAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,33 @@ public CompositeDataSourceAttribute(params BaseDataSourceAttribute[] attributes)
public IReadOnlyList<BaseDataSourceAttribute> Attributes => Array.AsReadOnly(this.attributes);

/// <inheritdoc />
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override async IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
if (dataGeneratorMetadata is null)
{
throw new ArgumentNullException(nameof(dataGeneratorMetadata));
}

var results = this.attributes
.Select(attr => attr.GenerateDataSources(dataGeneratorMetadata))
.ToArray();
var results = await Task.WhenAll(this.attributes
.Select(async attr =>
{
var rows = new List<object?[]>();
await foreach (var rowFunc in attr.GetDataRowsAsync(dataGeneratorMetadata))
{
var row = await rowFunc()
?? throw new InvalidOperationException("The source member yielded a null test data.");
rows.Add(row);
}

return (IEnumerable<object?[]>)rows;
}));

var theoryRows = results
.Select(x => x.Select(y => y()))
.Zip(dataSets => dataSets.Collapse().ToArray())
.ToArray();
.Zip(dataSets => dataSets.Collapse().ToArray());

return theoryRows;
foreach (var row in theoryRows)
{
yield return () => Task.FromResult<object?[]?>(row);
}
}
}
15 changes: 9 additions & 6 deletions src/AutoFixture.TUnit/Internal/AutoDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,30 @@ public AutoDataSource(Func<IFixture> createFixture, IDataSource? source = null)
/// </summary>
/// <param name="dataGeneratorMetadata">The target method for which to provide the arguments.</param>
/// <returns>Returns a sequence of argument collections.</returns>
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
return this.Source is null
? this.GenerateValues(dataGeneratorMetadata)
: this.CombineValues(dataGeneratorMetadata, this.Source);
}

private IEnumerable<object?[]> GenerateValues(DataGeneratorMetadata metadata)
private IAsyncEnumerable<Func<Task<object?[]?>>> GenerateValues(DataGeneratorMetadata metadata)
{
var parameters = Array.ConvertAll(metadata.GetMethod().GetParameters(), TestParameter.From);
var fixture = this.CreateFixture();
yield return Array.ConvertAll(parameters, parameter => GenerateAutoValue(parameter, fixture));
return new[] { Array.ConvertAll(parameters, parameter => (object?)GenerateAutoValue(parameter, fixture)) }.ToAsyncDataSource();
}

private IEnumerable<object?[]> CombineValues(DataGeneratorMetadata metadata, IDataSource source)
private async IAsyncEnumerable<Func<Task<object?[]?>>> CombineValues(DataGeneratorMetadata metadata, IDataSource source)
{
var method = metadata.GetMethod();

var parameters = Array.ConvertAll(method.GetParameters(), TestParameter.From);

foreach (var testData in source.GetData(metadata))
await foreach (var testDataFunc in source.GetData(metadata))
{
var testData = await testDataFunc();

var customizations = parameters.Take(testData!.Length)
.Zip(testData, (parameter, value) => new Argument(parameter, value))
.Select(argument => argument.GetCustomization())
Expand All @@ -72,7 +74,8 @@ public AutoDataSource(Func<IFixture> createFixture, IDataSource? source = null)
.Select(parameter => GenerateAutoValue(parameter, fixture))
.ToArray();

yield return testData.Concat(missingValues).ToArray();
var combined = testData.Concat(missingValues).ToArray();
yield return () => Task.FromResult<object?[]?>(combined);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/AutoFixture.TUnit/Internal/ClassDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public ClassDataSource(Type type, params object?[] parameters)
public IReadOnlyList<object?> Parameters => Array.AsReadOnly(this.parameters);

/// <inheritdoc/>
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
var instance = Activator.CreateInstance(type: this.Type, args: this.parameters);

Expand All @@ -43,6 +43,6 @@ public ClassDataSource(Type type, params object?[] parameters)
throw new InvalidOperationException($"Data source type \"{this.Type}\" should implement the \"{typeof(IEnumerable<object>)}\" interface.");
}

return enumerable;
return enumerable.ToAsyncDataSource();
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
using System.Reflection;
using TUnit.Core.Enums;
using TUnit.Core.Extensions;

namespace AutoFixture.TUnit.Internal;

internal static class DataGeneratorMetadataExtensions
{
public static MethodBase GetMethod(this DataGeneratorMetadata dataGeneratorMetadata)
{
if (dataGeneratorMetadata.TestInformation == null)
{
throw new InvalidOperationException("Not a test method");
}

if (dataGeneratorMetadata.Type == DataGeneratorType.ClassParameters)
{
return dataGeneratorMetadata.TestClassType.GetConstructors().First();
return dataGeneratorMetadata.TestInformation.Class.Type.GetConstructors().First();
}

return dataGeneratorMetadata.TestInformation.ReflectionInformation;
return dataGeneratorMetadata.TestInformation.GetReflectionInfo();
}
}
2 changes: 1 addition & 1 deletion src/AutoFixture.TUnit/Internal/DataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ namespace AutoFixture.TUnit.Internal;
Justification = "The type is not a collection.")]
[SuppressMessage("Naming", "CA1710:Identifiers should have correct suffix",
Justification = "The type is not a collection.")]
public abstract class DataSource : BaseDataSourceAttribute, IDataSource;
public abstract class DataSource : BaseDataSourceAttribute;
11 changes: 11 additions & 0 deletions src/AutoFixture.TUnit/Internal/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,15 @@ internal static IEnumerable<T> Collapse<T>(this IEnumerable<IEnumerable<T>> sequ
}
}
}

#pragma warning disable CS1998 // Async method lacks 'await' - required for IAsyncEnumerable yield
internal static async IAsyncEnumerable<Func<Task<object?[]?>>> ToAsyncDataSource(
#pragma warning restore CS1998
this IEnumerable<object?[]> source)
{
foreach (var item in source)
{
yield return () => Task.FromResult<object?[]?>(item);
}
}
}
5 changes: 3 additions & 2 deletions src/AutoFixture.TUnit/Internal/FieldDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ public FieldDataSource(FieldInfo fieldInfo)
/// <exception cref="InvalidCastException">
/// Thrown when the field does not return an enumerable value.
/// </exception>
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
public override IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
{
var value = this.FieldInfo.GetValue(null);

if (value is not IEnumerable<object?[]> enumerable)
{
throw new InvalidCastException("Member does not return an enumerable value.");
}

return enumerable;
return enumerable.ToAsyncDataSource();
}
}
2 changes: 1 addition & 1 deletion src/AutoFixture.TUnit/Internal/IDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ public interface IDataSource
/// </summary>
/// <param name="dataGeneratorMetadata">The target method for which to provide the arguments.</param>
/// <returns>Returns a sequence of argument collections.</returns>
IEnumerable<object?[]?> GetData(DataGeneratorMetadata dataGeneratorMetadata);
IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata);
}
6 changes: 4 additions & 2 deletions src/AutoFixture.TUnit/Internal/InlineDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public InlineDataSource(object?[] values)
public IReadOnlyList<object?> Values => Array.AsReadOnly(this.values);

/// <inheritdoc />
public override IEnumerable<object?[]> GetData(DataGeneratorMetadata dataGeneratorMetadata)
#pragma warning disable CS1998 // Async method lacks 'await' - required for IAsyncEnumerable yield
public override async IAsyncEnumerable<Func<Task<object?[]?>>> GetData(DataGeneratorMetadata dataGeneratorMetadata)
#pragma warning restore CS1998
{
if (dataGeneratorMetadata is null)
{
Expand All @@ -43,6 +45,6 @@ public InlineDataSource(object?[] values)
"The number of arguments provided exceeds the number of parameters.");
}

yield return this.values;
yield return () => Task.FromResult<object?[]?>(this.values);
}
}
Loading