diff --git a/src/TUnit.Analyzers/TestDataAnalyzer.cs b/src/TUnit.Analyzers/TestDataAnalyzer.cs index 8471129cb4..33c0b069f2 100644 --- a/src/TUnit.Analyzers/TestDataAnalyzer.cs +++ b/src/TUnit.Analyzers/TestDataAnalyzer.cs @@ -12,6 +12,14 @@ namespace TUnit.Analyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class TestDataAnalyzer : ConcurrentDiagnosticAnalyzer { + private static readonly SymbolDisplayFormat TestDataTypeDisplayFormat = + new( + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, + genericsOptions: SymbolDisplayFormat.MinimallyQualifiedFormat.GenericsOptions, + memberOptions: SymbolDisplayFormat.MinimallyQualifiedFormat.MemberOptions, + parameterOptions: SymbolDisplayFormat.MinimallyQualifiedFormat.ParameterOptions, + miscellaneousOptions: SymbolDisplayFormat.MinimallyQualifiedFormat.MiscellaneousOptions); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create( Rules.WrongArgumentTypeTestData, @@ -622,8 +630,8 @@ private void CheckMethodDataSource(SymbolAnalysisContext context, context.ReportDiagnostic(Diagnostic.Create( Rules.WrongArgumentTypeTestData, attribute.GetLocation(), - string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null")), - string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null"))) + string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null")), + string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null"))) ); return; } @@ -666,8 +674,8 @@ private void CheckMethodDataSource(SymbolAnalysisContext context, Diagnostic.Create( Rules.WrongArgumentTypeTestData, attribute.GetLocation(), - string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null")), - string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null"))) + string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null")), + string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null"))) ); return; } @@ -708,8 +716,8 @@ private void CheckMethodDataSource(SymbolAnalysisContext context, context.ReportDiagnostic(Diagnostic.Create( Rules.WrongArgumentTypeTestData, attribute.GetLocation(), - string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null")), - string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null"))) + string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null")), + string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null"))) ); return; } @@ -744,8 +752,8 @@ private void CheckMethodDataSource(SymbolAnalysisContext context, Diagnostic.Create( Rules.WrongArgumentTypeTestData, attribute.GetLocation(), - string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null")), - string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) ?? "null"))) + string.Join(", ", unwrappedTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null")), + string.Join(", ", testParameterTypes.Select(t => t?.ToDisplayString(TestDataTypeDisplayFormat) ?? "null"))) ); } } diff --git a/tests/TUnit.Analyzers.Tests/GenericTupleArrayMethodDataSourceTests.cs b/tests/TUnit.Analyzers.Tests/GenericTupleArrayMethodDataSourceTests.cs index fa33a11770..98c3e8f4be 100644 --- a/tests/TUnit.Analyzers.Tests/GenericTupleArrayMethodDataSourceTests.cs +++ b/tests/TUnit.Analyzers.Tests/GenericTupleArrayMethodDataSourceTests.cs @@ -97,7 +97,7 @@ public struct Fixture : IAsyncInitializer { await Verifier.VerifyAnalyzerAsync(source, Verifier.Diagnostic(Rules.WrongArgumentTypeTestData).WithLocation(0) - .WithArguments($"Fixture, CancellationToken, {sourceElement}", $"(Fixture, CancellationToken, {targetElement})")); + .WithArguments($"C.Fixture, CancellationToken, {sourceElement}", $"(C.Fixture, CancellationToken, {targetElement})")); } else { diff --git a/tests/TUnit.Analyzers.Tests/NestedTypeDiagnosticDisplayTests.cs b/tests/TUnit.Analyzers.Tests/NestedTypeDiagnosticDisplayTests.cs new file mode 100644 index 0000000000..43af3afdd9 --- /dev/null +++ b/tests/TUnit.Analyzers.Tests/NestedTypeDiagnosticDisplayTests.cs @@ -0,0 +1,43 @@ +using Verifier = TUnit.Analyzers.Tests.Verifiers.CSharpAnalyzerVerifier; + +namespace TUnit.Analyzers.Tests; + +public class NestedTypeDiagnosticDisplayTests : BaseAnalyzerTests +{ + [Test] + [Arguments("Outer.D", "Outer.D")] + [Arguments("Outer.Nested", "Outer.Nested")] + [Arguments("Outer.Middle.D", "Outer.Middle.D")] + [Arguments("Outer.Middle.Nested", "Outer.Middle.Nested")] + [Arguments("IConsumer.D, Outer.D>[]", "IConsumer.D, Outer.D>[]")] + [Arguments("IConsumer.Nested, Outer.Nested>[]", "IConsumer.Nested, Outer.Nested>[]")] + [Arguments("Outer.Middle.D[]", "Outer.Middle.D[]")] + public async Task MethodDataSourcePreservesContainingTypes(string sourceType, string targetType) + { + var source = $$""" + #pragma warning disable TUnit0046 + using TUnit.Core; + public class Outer + { + public delegate void D(); + public class Nested { } + public class Middle + { + public delegate void D(); + public class Nested { } + } + } + public interface IConsumer { } + public class Tests + { + public static (int, {{sourceType}}) Row() => default; + [Test, {|#0:MethodDataSource(nameof(Row))|}] + public void Test((int, {{targetType}}) row) { } + } + """; + + await Verifier.VerifyAnalyzerAsync(source, + Verifier.Diagnostic(Rules.WrongArgumentTypeTestData).WithLocation(0) + .WithArguments($"int, {sourceType}", $"(int, {targetType})")); + } +}