Skip to content

Commit

Permalink
Fix default arguments in attribute constructors (#1543)
Browse files Browse the repository at this point in the history
* Fix default arguments in attribute constructors

* Verify

* Redundant variable

* Verify

* Verify

* Verify
  • Loading branch information
thomhurst authored Jan 12, 2025
1 parent 60ee7d9 commit cf8fa2f
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace TUnit.Core.SourceGenerator.Tests.Bugs._1538;

internal class Tests : TestsBase<TestsGenerator>
internal class Tests1538 : TestsBase<TestsGenerator>
{
[Test]
public Task Test() => RunTest(Path.Combine(Git.RootDirectory.FullName,
Expand Down
17 changes: 17 additions & 0 deletions TUnit.Core.SourceGenerator.Tests/Bugs/1539/Tests1539.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using TUnit.Core.SourceGenerator.CodeGenerators;

namespace TUnit.Core.SourceGenerator.Tests.Bugs._1539;

internal class Tests1539 : TestsBase<TestsGenerator>
{
[Test]
public Task Test() => RunTest(Path.Combine(Git.RootDirectory.FullName,
"TUnit.TestProject",
"Bugs",
"1539",
"Tests.cs"),
async generatedFiles =>
{
await Assert.That(generatedFiles.Length).IsEqualTo(1);
});
}
215 changes: 215 additions & 0 deletions TUnit.Core.SourceGenerator.Tests/Tests1538.Test.verified.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
[
// <auto-generated/>
#pragma warning disable
using global::System.Linq;
using global::System.Reflection;
using global::TUnit.Core;
using global::TUnit.Core.Extensions;

namespace TUnit.SourceGenerated;

[global::System.Diagnostics.StackTraceHidden]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
file partial class Tests : TUnit.Core.Interfaces.SourceGenerator.ITestSource
{
[global::System.Runtime.CompilerServices.ModuleInitializer]
public static void Initialise()
{
SourceRegistrar.Register(new Tests());
}
public global::System.Collections.Generic.IReadOnlyList<SourceGeneratedTestNode> CollectTests(string sessionId)
{
return Tests0(sessionId);
}
private global::System.Collections.Generic.List<SourceGeneratedTestNode> Tests0(string sessionId)
{
global::System.Collections.Generic.List<SourceGeneratedTestNode> nodes = [];
var classDataIndex = 0;
var testMethodDataIndex = 0;
try
{
var testClassType = typeof(global::TUnit.TestProject.Bugs._1538.Tests);
var methodInfo = global::TUnit.Core.Helpers.MethodInfoRetriever.GetMethodInfo(typeof(global::TUnit.TestProject.Bugs._1538.Tests), "Eight_Args", 0, [typeof(global::System.Boolean), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String)]);

var testBuilderContext = new global::TUnit.Core.TestBuilderContext();
var testBuilderContextAccessor = new global::TUnit.Core.TestBuilderContextAccessor(testBuilderContext);
foreach (var methodDataAccessor in global::TUnit.TestProject.Bugs._1538.Tests.EightItems())
{
testMethodDataIndex++;

var methodData = methodDataAccessor;
var methodArgTuples = global::System.TupleExtensions.ToTuple<global::System.Boolean, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String>(methodData);
global::System.Boolean methodArg = methodArgTuples.Item1;
global::System.String methodArg1 = methodArgTuples.Item2;
global::System.String methodArg2 = methodArgTuples.Item3;
global::System.String methodArg3 = methodArgTuples.Item4;
global::System.String methodArg4 = methodArgTuples.Item5;
global::System.String methodArg5 = methodArgTuples.Item6;
global::System.String methodArg6 = methodArgTuples.Item7;
global::System.String methodArg7 = methodArgTuples.Rest.Item1;
var resettableClassFactoryDelegate = () => new ResettableLazy<global::TUnit.TestProject.Bugs._1538.Tests>(() =>
new global::TUnit.TestProject.Bugs._1538.Tests()
, sessionId, testBuilderContext);

var resettableClassFactory = resettableClassFactoryDelegate();

nodes.Add(new TestMetadata<global::TUnit.TestProject.Bugs._1538.Tests>
{
TestId = $"global::TUnit.Core.MethodDataSourceAttribute:{testMethodDataIndex}:TL-EMDS0:{testMethodDataIndex}:TUnit.TestProject.Bugs._1538.Tests.Eight_Args(System.Boolean,System.String,System.String,System.String,System.String,System.String,System.String,System.String):0",
TestClassArguments = [],
TestMethodArguments = [methodArg, methodArg1, methodArg2, methodArg3, methodArg4, methodArg5, methodArg6, methodArg7],
TestClassProperties = [],
CurrentRepeatAttempt = 0,
RepeatLimit = 0,
MethodInfo = methodInfo,
ResettableClassFactory = resettableClassFactory,
TestMethodFactory = (classInstance, cancellationToken) => AsyncConvert.Convert(() => classInstance.Eight_Args(methodArg, methodArg1, methodArg2, methodArg3, methodArg4, methodArg5, methodArg6, methodArg7)),
TestFilePath = @"",
TestLineNumber = 5,
TestAttributes = [ new global::TUnit.Core.TestAttribute()
{

}, new global::TUnit.Core.MethodDataSourceAttribute("EightItems")
{

} ],
ClassAttributes = [ ],
AssemblyAttributes = [ ],
DataAttributes = [ ],
TestBuilderContext = testBuilderContext,
});
resettableClassFactory = resettableClassFactoryDelegate();
testBuilderContext = new();
testBuilderContextAccessor.Current = testBuilderContext;
}
}
catch (global::System.Exception exception)
{
nodes.Add(new FailedInitializationTest
{
TestId = $"global::TUnit.Core.MethodDataSourceAttribute:{testMethodDataIndex}:TL-EMDS0:{testMethodDataIndex}:TUnit.TestProject.Bugs._1538.Tests.Eight_Args(System.Boolean,System.String,System.String,System.String,System.String,System.String,System.String,System.String):0",
TestClass = typeof(global::TUnit.TestProject.Bugs._1538.Tests),
ReturnType = global::TUnit.Core.Helpers.MethodInfoRetriever.GetMethodInfo(typeof(global::TUnit.TestProject.Bugs._1538.Tests), "Eight_Args", 0, [typeof(global::System.Boolean), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String)]).ReturnType,
ParameterTypeFullNames = [typeof(global::System.Boolean), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String)],
TestName = "Eight_Args",
TestFilePath = @"",
TestLineNumber = 5,
Exception = exception,
});
}
return nodes;
}
}


// <auto-generated/>
#pragma warning disable
using global::System.Linq;
using global::System.Reflection;
using global::TUnit.Core;
using global::TUnit.Core.Extensions;

namespace TUnit.SourceGenerated;

[global::System.Diagnostics.StackTraceHidden]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
file partial class Tests : TUnit.Core.Interfaces.SourceGenerator.ITestSource
{
[global::System.Runtime.CompilerServices.ModuleInitializer]
public static void Initialise()
{
SourceRegistrar.Register(new Tests());
}
public global::System.Collections.Generic.IReadOnlyList<SourceGeneratedTestNode> CollectTests(string sessionId)
{
return Tests0(sessionId);
}
private global::System.Collections.Generic.List<SourceGeneratedTestNode> Tests0(string sessionId)
{
global::System.Collections.Generic.List<SourceGeneratedTestNode> nodes = [];
var classDataIndex = 0;
var testMethodDataIndex = 0;
try
{
var testClassType = typeof(global::TUnit.TestProject.Bugs._1538.Tests);
var methodInfo = global::TUnit.Core.Helpers.MethodInfoRetriever.GetMethodInfo(typeof(global::TUnit.TestProject.Bugs._1538.Tests), "SixteenArgs", 0, [typeof(global::System.Boolean), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String)]);

var testBuilderContext = new global::TUnit.Core.TestBuilderContext();
var testBuilderContextAccessor = new global::TUnit.Core.TestBuilderContextAccessor(testBuilderContext);
foreach (var methodDataAccessor in global::TUnit.TestProject.Bugs._1538.Tests.SixteenItems())
{
testMethodDataIndex++;

var methodData = methodDataAccessor;
var methodArgTuples = global::System.TupleExtensions.ToTuple<global::System.Boolean, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String, global::System.String>(methodData);
global::System.Boolean methodArg = methodArgTuples.Item1;
global::System.String methodArg1 = methodArgTuples.Item2;
global::System.String methodArg2 = methodArgTuples.Item3;
global::System.String methodArg3 = methodArgTuples.Item4;
global::System.String methodArg4 = methodArgTuples.Item5;
global::System.String methodArg5 = methodArgTuples.Item6;
global::System.String methodArg6 = methodArgTuples.Item7;
global::System.String methodArg7 = methodArgTuples.Rest.Item1;
global::System.String methodArg8 = methodArgTuples.Rest.Item2;
global::System.String methodArg9 = methodArgTuples.Rest.Item3;
global::System.String methodArg10 = methodArgTuples.Rest.Item4;
global::System.String methodArg11 = methodArgTuples.Rest.Item5;
global::System.String methodArg12 = methodArgTuples.Rest.Item6;
global::System.String methodArg13 = methodArgTuples.Rest.Item7;
global::System.String methodArg14 = methodArgTuples.Rest.Rest.Item1;
global::System.String methodArg15 = methodArgTuples.Rest.Rest.Item2;
var resettableClassFactoryDelegate = () => new ResettableLazy<global::TUnit.TestProject.Bugs._1538.Tests>(() =>
new global::TUnit.TestProject.Bugs._1538.Tests()
, sessionId, testBuilderContext);

var resettableClassFactory = resettableClassFactoryDelegate();

nodes.Add(new TestMetadata<global::TUnit.TestProject.Bugs._1538.Tests>
{
TestId = $"global::TUnit.Core.MethodDataSourceAttribute:{testMethodDataIndex}:TL-EMDS0:{testMethodDataIndex}:TUnit.TestProject.Bugs._1538.Tests.SixteenArgs(System.Boolean,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String):0",
TestClassArguments = [],
TestMethodArguments = [methodArg, methodArg1, methodArg2, methodArg3, methodArg4, methodArg5, methodArg6, methodArg7, methodArg8, methodArg9, methodArg10, methodArg11, methodArg12, methodArg13, methodArg14, methodArg15],
TestClassProperties = [],
CurrentRepeatAttempt = 0,
RepeatLimit = 0,
MethodInfo = methodInfo,
ResettableClassFactory = resettableClassFactory,
TestMethodFactory = (classInstance, cancellationToken) => AsyncConvert.Convert(() => classInstance.SixteenArgs(methodArg, methodArg1, methodArg2, methodArg3, methodArg4, methodArg5, methodArg6, methodArg7, methodArg8, methodArg9, methodArg10, methodArg11, methodArg12, methodArg13, methodArg14, methodArg15)),
TestFilePath = @"",
TestLineNumber = 13,
TestAttributes = [ new global::TUnit.Core.TestAttribute()
{

}, new global::TUnit.Core.MethodDataSourceAttribute("SixteenItems")
{

} ],
ClassAttributes = [ ],
AssemblyAttributes = [ ],
DataAttributes = [ ],
TestBuilderContext = testBuilderContext,
});
resettableClassFactory = resettableClassFactoryDelegate();
testBuilderContext = new();
testBuilderContextAccessor.Current = testBuilderContext;
}
}
catch (global::System.Exception exception)
{
nodes.Add(new FailedInitializationTest
{
TestId = $"global::TUnit.Core.MethodDataSourceAttribute:{testMethodDataIndex}:TL-EMDS0:{testMethodDataIndex}:TUnit.TestProject.Bugs._1538.Tests.SixteenArgs(System.Boolean,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String):0",
TestClass = typeof(global::TUnit.TestProject.Bugs._1538.Tests),
ReturnType = global::TUnit.Core.Helpers.MethodInfoRetriever.GetMethodInfo(typeof(global::TUnit.TestProject.Bugs._1538.Tests), "SixteenArgs", 0, [typeof(global::System.Boolean), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String)]).ReturnType,
ParameterTypeFullNames = [typeof(global::System.Boolean), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String), typeof(global::System.String)],
TestName = "SixteenArgs",
TestFilePath = @"",
TestLineNumber = 13,
Exception = exception,
});
}
return nodes;
}
}

]
99 changes: 99 additions & 0 deletions TUnit.Core.SourceGenerator.Tests/Tests1539.Test.verified.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
[
// <auto-generated/>
#pragma warning disable
using global::System.Linq;
using global::System.Reflection;
using global::TUnit.Core;
using global::TUnit.Core.Extensions;

namespace TUnit.SourceGenerated;

[global::System.Diagnostics.StackTraceHidden]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
file partial class Tests : TUnit.Core.Interfaces.SourceGenerator.ITestSource
{
[global::System.Runtime.CompilerServices.ModuleInitializer]
public static void Initialise()
{
SourceRegistrar.Register(new Tests());
}
public global::System.Collections.Generic.IReadOnlyList<SourceGeneratedTestNode> CollectTests(string sessionId)
{
return Tests0(sessionId);
}
private global::System.Collections.Generic.List<SourceGeneratedTestNode> Tests0(string sessionId)
{
global::System.Collections.Generic.List<SourceGeneratedTestNode> nodes = [];
var classDataIndex = 0;
var testMethodDataIndex = 0;
try
{
var testClassType = typeof(global::TUnit.TestProject.Bugs._1539.Tests);
var methodInfo = global::TUnit.Core.Helpers.MethodInfoRetriever.GetMethodInfo(typeof(global::TUnit.TestProject.Bugs._1539.Tests), "Test", 0, []);

var testBuilderContext = new global::TUnit.Core.TestBuilderContext();
var testBuilderContextAccessor = new global::TUnit.Core.TestBuilderContextAccessor(testBuilderContext);

var resettableClassFactoryDelegate = () => new ResettableLazy<global::TUnit.TestProject.Bugs._1539.Tests>(() =>
new global::TUnit.TestProject.Bugs._1539.Tests()
, sessionId, testBuilderContext);

var resettableClassFactory = resettableClassFactoryDelegate();

nodes.Add(new TestMetadata<global::TUnit.TestProject.Bugs._1539.Tests>
{
TestId = $"TUnit.TestProject.Bugs._1539.Tests.Test:0",
TestClassArguments = [],
TestMethodArguments = [],
TestClassProperties = [],
CurrentRepeatAttempt = 0,
RepeatLimit = 0,
MethodInfo = methodInfo,
ResettableClassFactory = resettableClassFactory,
TestMethodFactory = (classInstance, cancellationToken) => AsyncConvert.Convert(() => classInstance.Test()),
TestFilePath = @"",
TestLineNumber = 5,
TestAttributes = [ new global::TUnit.Core.TestAttribute()
{

}, new global::TUnit.TestProject.Bugs._1539.Tests.AttributeWithPositionalArgs()
{

}, new global::TUnit.TestProject.Bugs._1539.Tests.AttributeWithPositionalArgs(11)
{

}, new global::TUnit.TestProject.Bugs._1539.Tests.AttributeWithPositionalArgs(two:"two")
{

}, new global::TUnit.TestProject.Bugs._1539.Tests.AttributeWithPositionalArgs(three:false)
{

} ],
ClassAttributes = [ ],
AssemblyAttributes = [ ],
DataAttributes = [ ],
TestBuilderContext = testBuilderContext,
});
resettableClassFactory = resettableClassFactoryDelegate();
testBuilderContext = new();
testBuilderContextAccessor.Current = testBuilderContext;
}
catch (global::System.Exception exception)
{
nodes.Add(new FailedInitializationTest
{
TestId = $"TUnit.TestProject.Bugs._1539.Tests.Test:0",
TestClass = typeof(global::TUnit.TestProject.Bugs._1539.Tests),
ReturnType = global::TUnit.Core.Helpers.MethodInfoRetriever.GetMethodInfo(typeof(global::TUnit.TestProject.Bugs._1539.Tests), "Test", 0, []).ReturnType,
ParameterTypeFullNames = [],
TestName = "Test",
TestFilePath = @"",
TestLineNumber = 5,
Exception = exception,
});
}
return nodes;
}
}

]
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using TUnit.Core.SourceGenerator.CodeGenerators.Helpers;
using TUnit.Core.SourceGenerator.Extensions;
Expand Down Expand Up @@ -30,12 +31,21 @@ public static string WriteAttribute(GeneratorAttributeSyntaxContext context, Att
var constructorArgumentSyntaxes = attributeSyntax.DescendantNodes()
.OfType<AttributeArgumentSyntax>()
.Where(x => x.NameEquals is null);

var typedConstantsToExpression =
constructorArgumentSyntaxes.Zip(attributeData.ConstructorArguments, (syntax, constant) => (syntax, constant));

var constructorArguments = typedConstantsToExpression.Select(x =>
TypedConstantParser.GetTypedConstantValue(context.SemanticModel, x.syntax.Expression, x.constant.Type));
var constructorArguments = attributeData.ConstructorArguments
.Select((constant, index) =>
{
var elementAtOrDefault = constructorArgumentSyntaxes.ElementAtOrDefault(index);
return new
{
Syntax = elementAtOrDefault,
Constant = constant,
Name = elementAtOrDefault?.NameColon?.ToString()
};
})
.Where(x => x.Syntax != null)
.Select(x =>
$"{x.Name}{TypedConstantParser.GetTypedConstantValue(context.SemanticModel, x.Syntax!.Expression, x.Constant.Type)}");

var namedArgSyntaxes = attributeSyntax.DescendantNodes()
.OfType<AttributeArgumentSyntax>()
Expand Down
Loading

0 comments on commit cf8fa2f

Please sign in to comment.