Skip to content

Commit

Permalink
NonTypedDataSourceGeneratorAttribute
Browse files Browse the repository at this point in the history
  • Loading branch information
thomhurst committed Jan 13, 2025
1 parent 6b5fce8 commit 0a2d397
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 11 deletions.
21 changes: 20 additions & 1 deletion TUnit.Core.SourceGenerator.Tests/DataSourceGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
using TUnit.Core.SourceGenerator.CodeGenerators;
using TUnit.Core.SourceGenerator.Tests.Options;

namespace TUnit.Core.SourceGenerator.Tests;

internal class DataSourceGeneratorTests : TestsBase<TestsGenerator>
{
[Test]
public Task Test() => RunTest(Path.Combine(Git.RootDirectory.FullName,
public Task Typed() => RunTest(Path.Combine(Git.RootDirectory.FullName,
"TUnit.TestProject",
"DataSourceGeneratorTests.cs"),
async generatedFiles =>
{
await Assert.That(generatedFiles.Length).IsEqualTo(3);
});

[Test]
public Task NonTyped() => RunTest(Path.Combine(Git.RootDirectory.FullName,
"TUnit.TestProject",
"AutoDataTests.cs"),
new RunTestOptions()
{
AdditionalFiles = [
Path.Combine(Git.RootDirectory.FullName,
"TUnit.TestProject",
"Attributes",
"AutoDataAttribute.cs")
]
},
async generatedFiles =>
{
await Assert.That(generatedFiles.Length).IsEqualTo(1);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,14 @@ public static IEnumerable<BaseContainer> GetArguments(GeneratorAttributeSyntaxCo
if (dataAttribute.AttributeClass?.IsOrInherits(WellKnownFullyQualifiedClassNames
.DataSourceGeneratorAttribute.WithGlobalPrefix) == true)
{
yield return DataSourceGeneratorRetriever.Parse(context, namedTypeSymbol, dataAttribute, argumentsType,
yield return DataSourceGeneratorRetriever.Parse(context, namedTypeSymbol, parameterOrPropertyTypes, dataAttribute, argumentsType,
index, propertyName);
}

if (dataAttribute.AttributeClass?.IsOrInherits(WellKnownFullyQualifiedClassNames
.NonTypedDataSourceGeneratorAttribute.WithGlobalPrefix) == true)
{
yield return DataSourceGeneratorRetriever.Parse(context, namedTypeSymbol, parameterOrPropertyTypes, dataAttribute, argumentsType,
index, propertyName);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using TUnit.Core.SourceGenerator.Enums;
using TUnit.Core.SourceGenerator.Extensions;
using TUnit.Core.SourceGenerator.Models.Arguments;
Expand All @@ -7,7 +8,9 @@ namespace TUnit.Core.SourceGenerator.CodeGenerators.Helpers;

public static class DataSourceGeneratorRetriever
{
public static ArgumentsContainer Parse(GeneratorAttributeSyntaxContext context, INamedTypeSymbol namedTypeSymbol,
public static ArgumentsContainer Parse(GeneratorAttributeSyntaxContext context,
INamedTypeSymbol namedTypeSymbol,
ImmutableArray<ITypeSymbol> parameterOrPropertyTypes,
AttributeData attributeData,
ArgumentsType argumentsType,
int index,
Expand All @@ -18,11 +21,12 @@ public static ArgumentsContainer Parse(GeneratorAttributeSyntaxContext context,
context,
attributeData: attributeData,
ArgumentsType: argumentsType,
parameterOrPropertyTypes: parameterOrPropertyTypes,
TestClassTypeName: namedTypeSymbol.ToDisplayString(DisplayFormats.FullyQualifiedGenericWithGlobalPrefix),
AttributeDataGeneratorType: attributeData.AttributeClass!.ToDisplayString(DisplayFormats
.FullyQualifiedGenericWithGlobalPrefix),
GenericArguments: GetDataGeneratorAttributeBaseClass(attributeData.AttributeClass).TypeArguments
.Select(x => x.ToDisplayString(DisplayFormats.FullyQualifiedGenericWithGlobalPrefix)).ToArray(),
GenericArguments: GetDataGeneratorAttributeBaseClass(attributeData.AttributeClass)?.TypeArguments
.Select(x => x.ToDisplayString(DisplayFormats.FullyQualifiedGenericWithGlobalPrefix)).ToArray() ?? [],
AttributeIndex: index
)
{
Expand All @@ -36,11 +40,16 @@ .Value.Value as bool? ??
};
}

private static INamedTypeSymbol GetDataGeneratorAttributeBaseClass(ITypeSymbol attributeClass)
private static INamedTypeSymbol? GetDataGeneratorAttributeBaseClass(ITypeSymbol attributeClass)
{
var selfAndBaseTypes = attributeClass.GetSelfAndBaseTypes();

return (INamedTypeSymbol) selfAndBaseTypes.First(HasGeneratorInterface);
if (selfAndBaseTypes.FirstOrDefault(HasGeneratorInterface) is INamedTypeSymbol generatorInterface)
{
return generatorInterface;
}

return null;
}

private static bool HasGeneratorInterface(ITypeSymbol t)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using TUnit.Core.SourceGenerator.CodeGenerators.Writers;
using TUnit.Core.SourceGenerator.Enums;
using TUnit.Core.SourceGenerator.Extensions;

namespace TUnit.Core.SourceGenerator.Models.Arguments;

public record GeneratedArgumentsContainer : ArgumentsContainer
{
public GeneratedArgumentsContainer(GeneratorAttributeSyntaxContext context, AttributeData attributeData,
ArgumentsType ArgumentsType, int AttributeIndex, string TestClassTypeName, string[] GenericArguments,
ArgumentsType ArgumentsType, ImmutableArray<ITypeSymbol> parameterOrPropertyTypes, int AttributeIndex,
string TestClassTypeName, string[] GenericArguments,
string AttributeDataGeneratorType) : base(ArgumentsType)
{
this.AttributeIndex = AttributeIndex;
Context = context;
AttributeData = attributeData;
ParameterOrPropertyTypes = parameterOrPropertyTypes;
this.TestClassTypeName = TestClassTypeName;
this.GenericArguments = GenericArguments;
this.AttributeDataGeneratorType = AttributeDataGeneratorType;
Expand Down Expand Up @@ -137,8 +141,17 @@ public override void WriteVariableAssignments(SourceCodeWriter sourceCodeWriter,
var generatedDataVariableName = $"{VariableNamePrefix}GeneratedData";

sourceCodeWriter.WriteLine($"var {generatedDataVariableName} = {generatedDataVariableName}Accessor();");

if (GenericArguments.Length > 1)

if (GenericArguments.Length == 0)
{
for (var i = 0; i < ParameterOrPropertyTypes.Length; i++)
{
var refIndex = i;

sourceCodeWriter.WriteLine(GenerateVariable(ParameterOrPropertyTypes[i].GloballyQualified(), $"({ParameterOrPropertyTypes[i].GloballyQualified()}){generatedDataVariableName}[{i}]", ref refIndex).ToString());
}
}
else if (GenericArguments.Length > 1)
{
for (var i = 0; i < GenericArguments.Length; i++)
{
Expand Down Expand Up @@ -176,6 +189,7 @@ public override string[] GetArgumentTypes()

public GeneratorAttributeSyntaxContext Context { get; }
public AttributeData AttributeData { get; }
public ImmutableArray<ITypeSymbol> ParameterOrPropertyTypes { get; }
public string TestClassTypeName { get; }

public string[] GenericArguments { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public static class WellKnownFullyQualifiedClassNames
public static readonly FullyQualifiedTypeName MatrixAttribute = "TUnit.Core.MatrixAttribute";
public static readonly FullyQualifiedTypeName ClassConstructorAttribute = "TUnit.Core.ClassConstructorAttribute";
public static readonly FullyQualifiedTypeName DataSourceGeneratorAttribute = "TUnit.Core.DataSourceGeneratorAttribute";
public static readonly FullyQualifiedTypeName NonTypedDataSourceGeneratorAttribute = "TUnit.Core.NonTypedDataSourceGeneratorAttribute";


// Metadata
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace TUnit.Core;

internal interface INonTypedDataSource : IDataAttribute;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TUnit.Core;

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)]
public abstract class NonTypedDataSourceGeneratorAttribute : TestDataAttribute, INonTypedDataSource
{
public abstract IEnumerable<Func<object?[]?>> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata);
}
26 changes: 26 additions & 0 deletions TUnit.TestProject/Attributes/AutoDataAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using AutoFixture.Kernel;

namespace TUnit.TestProject.Attributes;

public class AutoDataAttribute : NonTypedDataSourceGeneratorAttribute
{
private static AutoFixture.Fixture _fixture = new();

public override IEnumerable<Func<object?[]?>> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata)
{
yield return () => GenerateRow(dataGeneratorMetadata);
}

private object?[] GenerateRow(DataGeneratorMetadata dataGeneratorMetadata)
{
return GenerateRowEnumerable(dataGeneratorMetadata).ToArray();
}

private static IEnumerable<object> GenerateRowEnumerable(DataGeneratorMetadata dataGeneratorMetadata)
{
foreach (var parameterInfo in dataGeneratorMetadata.ParameterInfos ?? [])
{
yield return _fixture.Create(parameterInfo.ParameterType, new SpecimenContext(_fixture));
}
}
}
13 changes: 13 additions & 0 deletions TUnit.TestProject/AutoDataTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using TUnit.TestProject.Attributes;

namespace TUnit.TestProject;

public class AutoDataTests
{
[AutoData]
[Test]
public Task Test1(string value1, int value2, double value3, bool value4)
{
return Task.CompletedTask;
}
}
1 change: 1 addition & 0 deletions TUnit.TestProject/TUnit.TestProject.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" />
<PackageReference Include="coverlet.collector" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Humanizer" />
Expand Down

0 comments on commit 0a2d397

Please sign in to comment.