-
-
Notifications
You must be signed in to change notification settings - Fork 108
Description
Info
- IDE: JetBrains Rider 2025.2.4
- TUnit version: 1.3.0 and also recreated on 1.2.11
Recreation of the problem
I have a compositional hierarchy equivalent to this the following classes:
public sealed class MyTestGeneratorAttribute<T> : DataSourceGeneratorAttribute<T> where T : MyType, new()
{
protected override IEnumerable<Func<T>> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata) => [() => new T()];
}
public class MyType;
public class ErrContext: IAsyncInitializer, IAsyncDisposable
{
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public Task InitializeAsync() => Task.CompletedTask;
}
public class ErrFixture<T> : IAsyncDisposable, IAsyncInitializer
{
public required ErrContext Fixture { get; set; }
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public Task InitializeAsync() => Task.CompletedTask;
}
public class ErrTest
{
[ClassDataSource<ErrFixture<MyType>>(Shared = SharedType.PerClass)]
public required ErrFixture<MyType> Fixture { get; init; }
public IEnumerable<Func<ErrContext>> TestExecutions => [() => Fixture.Fixture];
[MethodDataSource("TestExecutions")]
[Test]
public async Task MyTest(ErrContext context)
{
await Assert.That(context.GetType()).IsNotAssignableTo<MyType>();
}
[MyTestGeneratorAttribute<MyType>]
[Test]
public async Task MyTest2(MyType t)
{
await Assert.That(t.GetType()).IsAssignableTo<MyType>();
}
}This generates the following file that has compile time error:
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace TUnit.Generated;
internal sealed class MyNamespace_ErrTest_MyFailingTestIsHere__ErrContext_TestSource : global::TUnit.Core.Interfaces.SourceGenerator.ITestSource
{
#if NET8_0_OR_GREATER
[global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Field, Name = "<Fixture>k__BackingField")]
private static extern ref global::MyNamespace.ErrFixture<global::MyNamespace.MyType> GetFixtureBackingField(global::MyNamespace.ErrTest instance);
#endif
public async global::System.Collections.Generic.IAsyncEnumerable<global::TUnit.Core.TestMetadata> GetTestsAsync(string testSessionId, [global::System.Runtime.CompilerServices.EnumeratorCancellation] global::System.Threading.CancellationToken cancellationToken = default)
{
var metadata = new global::TUnit.Core.TestMetadata<global::MyNamespace.ErrTest>
{
TestName = "MyFailingTestIsHere",
TestClassType = typeof(global::MyNamespace.ErrTest),
TestMethodName = "MyFailingTestIsHere",
Dependencies = global::System.Array.Empty<global::TUnit.Core.TestDependency>(),
AttributeFactory = static () =>
[
new global::TUnit.Core.TestAttribute(),
new global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Design", "S3993")
{Justification = "TUnits' attributeusage must not and cannot be overwritten.",},
new global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Maintainability", "S4144")
{Justification = "This is a test class and method consuming code will not accidentally call wrong method due to similar signatures.",},
new global::TUnit.Core.ParallelLimiterAttribute<global::Hoeyer.OpcUa.EndToEndTest.Configuration.ParallelLimit>(),
new global::System.Reflection.AssemblyCompanyAttribute("Hoeyer.OpcUa.EndToEndTest"),
new global::System.Reflection.AssemblyConfigurationAttribute("Debug"),
new global::System.Reflection.AssemblyFileVersionAttribute("1.0.0.0"),
new global::System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+6ce90c5365417e7937319199a18c15ee9dcf63c7"),
new global::System.Reflection.AssemblyProductAttribute("Hoeyer.OpcUa.EndToEndTest"),
new global::System.Reflection.AssemblyTitleAttribute("Hoeyer.OpcUa.EndToEndTest"),
new global::System.Reflection.AssemblyVersionAttribute("1.0.0.0"),
new global::System.Reflection.AssemblyMetadataAttribute("Microsoft.Testing.Platform.Application", "true")
],
DataSources = new global::TUnit.Core.IDataSourceAttribute[]
{
new global::TUnit.Core.MethodDataSourceAttribute("TestExecutions")
{
Factory = (dataGeneratorMetadata) =>
{
async global::System.Collections.Generic.IAsyncEnumerable<global::System.Func<global::System.Threading.Tasks.Task<object?[]?>>> Factory()
{
object? instance;
if (dataGeneratorMetadata.TestClassInstance != null)
{
instance = dataGeneratorMetadata.TestClassInstance;
}
else
{
instance = new global::MyNamespace.ErrTest();
}
var result = ((global::MyNamespace.ErrTest)instance).TestExecutions;
if (result is global::System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
yield return () => global::System.Threading.Tasks.Task.FromResult(global::TUnit.Core.Helpers.DataSourceHelpers.ToObjectArray(item));
}
}
else
{
yield return () => global::System.Threading.Tasks.Task.FromResult(global::TUnit.Core.Helpers.DataSourceHelpers.ToObjectArray(result));
}
}
return Factory();
}
},
},
ClassDataSources = global::System.Array.Empty<global::TUnit.Core.IDataSourceAttribute>(),
PropertyDataSources = new global::TUnit.Core.PropertyDataSource[]
{
new global::TUnit.Core.PropertyDataSource
{
PropertyName = "Fixture",
PropertyType = typeof(global::MyNamespace.ErrFixture<global::MyNamespace.MyType>),
DataSource = new global::TUnit.Core.ClassDataSourceAttribute<global::MyNamespace.ErrFixture<global::MyNamespace.MyType>>()
{Shared = global::TUnit.Core.SharedType.PerClass,},
},
},
PropertyInjections = new global::TUnit.Core.PropertyInjectionData[]
{
new global::TUnit.Core.PropertyInjectionData
{
PropertyName = "Fixture",
PropertyType = typeof(global::MyNamespace.ErrFixture<global::MyNamespace.MyType>),
#if NET8_0_OR_GREATER
Setter = (instance, value) => GetFixtureBackingField((global::MyNamespace.ErrTest)instance) = (global::MyNamespace.ErrFixture<global::MyNamespace.MyType>)value,
#else
Setter = (instance, value) => throw new global::System.NotSupportedException("Setting init-only properties requires .NET 8 or later"),
#endif
ValueFactory = () => throw new global::System.InvalidOperationException("ValueFactory should be provided by TestDataCombination"),
NestedPropertyInjections = global::System.Array.Empty<global::TUnit.Core.PropertyInjectionData>(),
NestedPropertyValueFactory = obj =>
{
return new global::System.Collections.Generic.Dictionary<string, object?>();
}
},
},
InheritanceDepth = 0,
FilePath = @"C:\\Users\\rasmus\\RiderProjects\\Hoeyer.Opcua\\Hoeyer.OpcUa.EndToEndTest\\ClientTests\\ErrTest.cs",
LineNumber = 33,
MethodMetadata = new global::TUnit.Core.MethodMetadata
{
Type = typeof(global::MyNamespace.ErrTest),
TypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::MyNamespace.ErrTest)),
Name = "MyFailingTestIsHere",
GenericTypeCount = 0,
ReturnType = typeof(global::System.Threading.Tasks.Task),
ReturnTypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::System.Threading.Tasks.Task)),
Parameters = new global::TUnit.Core.ParameterMetadata[]
{
new global::TUnit.Core.ParameterMetadata(typeof(global::MyNamespace.ErrContext))
{
Name = "context",
TypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::MyNamespace.ErrContext)),
IsNullable = false,
ReflectionInfo = typeof(global::MyNamespace.ErrTest).GetMethod("MyFailingTestIsHere", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(global::MyNamespace.ErrContext) }, null)!.GetParameters()[0]
}
},
Class = global::TUnit.Core.ClassMetadata.GetOrAdd("Hoeyer.OpcUa.EndToEndTest:global::MyNamespace.ErrTest", static () =>
{
var classMetadata = new global::TUnit.Core.ClassMetadata
{
Type = typeof(global::MyNamespace.ErrTest),
TypeInfo = new global::TUnit.Core.ConcreteType(typeof(global::MyNamespace.ErrTest)),
Name = "ErrTest",
Namespace = "MyNamespace",
Assembly = global::TUnit.Core.AssemblyMetadata.GetOrAdd("Hoeyer.OpcUa.EndToEndTest", static () => new global::TUnit.Core.AssemblyMetadata { Name = "Hoeyer.OpcUa.EndToEndTest" }),
Parameters = global::System.Array.Empty<global::TUnit.Core.ParameterMetadata>(),
Properties = new global::TUnit.Core.PropertyMetadata[]
{
new global::TUnit.Core.PropertyMetadata
{
ReflectionInfo = typeof(global::MyNamespace.ErrTest).GetProperty("Fixture"),
Type = typeof(global::MyNamespace.ErrFixture<global::MyNamespace.MyType>),
Name = "Fixture",
IsStatic = false,
IsNullable = false,
Getter = o => ((global::MyNamespace.ErrTest)o).Fixture,
ClassMetadata = null!,
ContainingTypeMetadata = null!
},
new global::TUnit.Core.PropertyMetadata
{
ReflectionInfo = typeof(global::MyNamespace.ErrTest).GetProperty("TestExecutions"),
Type = typeof(global::System.Collections.Generic.IEnumerable<global::System.Func<global::MyNamespace.ErrContext>>),
Name = "TestExecutions",
IsStatic = false,
IsNullable = false,
Getter = o => ((global::MyNamespace.ErrTest)o).TestExecutions,
ClassMetadata = null!,
ContainingTypeMetadata = null!
}
},
Parent = null
};
foreach (var prop in classMetadata.Properties)
{
prop.ClassMetadata = classMetadata;
prop.ContainingTypeMetadata = classMetadata;
}
return classMetadata;
})
},
InstanceFactory = (typeArgs, args) => new global::MyNamespace.ErrTest()
{
Fixture = default!,
},
InvokeTypedTest = static (instance, args, cancellationToken) =>
{
try
{
switch (args.Length)
{
case 1:
return new global::System.Threading.Tasks.ValueTask(instance.MyFailingTestIsHere(TUnit.Core.Helpers.CastHelper.Cast<global::MyNamespace.ErrContext>(args[0])));
default:
throw new global::System.ArgumentException($"Expected exactly 1 argument, but got {args.Length}");
}
}
catch (global::System.Exception ex)
{
return new global::System.Threading.Tasks.ValueTask(global::System.Threading.Tasks.Task.FromException(ex));
}
},
};
metadata.UseRuntimeDataGeneration(testSessionId);
yield return metadata;
yield break;
}
}
internal static class MyNamespace_ErrTest_MyFailingTestIsHere__ErrContext_ModuleInitializer
{
[global::System.Runtime.CompilerServices.ModuleInitializer]
public static void Initialize()
{
global::TUnit.Core.SourceRegistrar.Register(typeof(global::MyNamespace.ErrTest), new MyNamespace_ErrTest_MyFailingTestIsHere__ErrContext_TestSource());
}
}What would solve my problem
Either an analyser error from TUnit informing about an easy fix or for it to work automagically
Metadata
Metadata
Assignees
Labels
No labels