diff --git a/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete1.verified.txt b/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete1.verified.txt index d4bda4466f..16cf573c7b 100644 --- a/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete1.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete1.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -50,7 +50,7 @@ internal static class TUnit_TestProject_AbstractTests_ConcreteClass1_AssertClass MethodName = "AssertClassName", FullyQualifiedName = "TUnit.TestProject.AbstractTests.ConcreteClass1.AssertClassName", FilePath = @"", - LineNumber = 3, + LineNumber = 6, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, diff --git a/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete2.verified.txt b/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete2.verified.txt index 85d3699447..47b36aa0d7 100644 --- a/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete2.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/AbstractTests.Concrete2.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -144,7 +144,7 @@ internal static class TUnit_TestProject_AbstractTests_ConcreteClass2_AssertClass MethodName = "AssertClassName", FullyQualifiedName = "TUnit.TestProject.AbstractTests.ConcreteClass2.AssertClassName", FilePath = @"", - LineNumber = 3, + LineNumber = 6, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, @@ -219,7 +219,7 @@ internal static class TUnit_TestProject_AbstractTests_ConcreteClass1_AssertClass MethodName = "AssertClassName", FullyQualifiedName = "TUnit.TestProject.AbstractTests.ConcreteClass1.AssertClassName", FilePath = @"", - LineNumber = 3, + LineNumber = 6, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, diff --git a/TUnit.Core.SourceGenerator.Tests/BasicTests.cs b/TUnit.Core.SourceGenerator.Tests/BasicTests.cs index 8166bea3da..5480a6bd76 100644 --- a/TUnit.Core.SourceGenerator.Tests/BasicTests.cs +++ b/TUnit.Core.SourceGenerator.Tests/BasicTests.cs @@ -1,18 +1,34 @@ +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using TUnit.Core.SourceGenerator.Tests.Options; namespace TUnit.Core.SourceGenerator.Tests; internal class BasicTests : TestsBase { + private static readonly string InputFile = Path.Combine(Git.RootDirectory.FullName, "TUnit.TestProject", "BasicTests.cs"); + [Test] - public Task Test() => RunTest(Path.Combine(Git.RootDirectory.FullName, - "TUnit.TestProject", - "BasicTests.cs"), + public Task Test() => RunTest(InputFile, new RunTestOptions { VerifyConfigurator = verify => verify.UniqueForTargetFrameworkAndVersion() }, async generatedFiles => { - }); + var source = await File.ReadAllTextAsync(InputFile); + var syntaxTree = CSharpSyntaxTree.ParseText(source); + var firstMethod = syntaxTree.GetRoot() + .DescendantNodes() + .OfType() + .First(x => x.Identifier.ValueText == "SynchronousTest"); + + var lineSpan = firstMethod.GetLocation().GetLineSpan(); + var generatedCode = string.Join(Environment.NewLine, generatedFiles); + + await Assert.That(generatedCode).Contains($"LineNumber = {lineSpan.StartLinePosition.Line + 1},"); + await Assert.That(generatedCode).Contains($"StartColumnNumber = {lineSpan.StartLinePosition.Character + 1},"); + await Assert.That(generatedCode).Contains($"EndLineNumber = {lineSpan.EndLinePosition.Line + 1},"); + await Assert.That(generatedCode).Contains($"EndColumnNumber = {lineSpan.EndLinePosition.Character + 1},"); + }); } diff --git a/TUnit.Core.SourceGenerator.Tests/Bugs2971NullableTypeTest.cs b/TUnit.Core.SourceGenerator.Tests/Bugs2971NullableTypeTest.cs index b2c91106fc..97187bcef8 100644 --- a/TUnit.Core.SourceGenerator.Tests/Bugs2971NullableTypeTest.cs +++ b/TUnit.Core.SourceGenerator.Tests/Bugs2971NullableTypeTest.cs @@ -23,7 +23,11 @@ public Task Test() => RunTest(Path.Combine(Git.RootDirectory.FullName, { // Scrub GUIDs from generated files before verification (same as TestsBase) var scrubbedFiles = generatedFiles.Select(file => ScrubGuids(file)).ToArray(); - await Verify(scrubbedFiles).UniqueForTargetFrameworkAndVersion(); + await Verify(scrubbedFiles) + .ScrubLinesContaining("StartColumnNumber = ") + .ScrubLinesContaining("EndLineNumber = ") + .ScrubLinesContaining("EndColumnNumber = ") + .UniqueForTargetFrameworkAndVersion(); }); private string ScrubGuids(string text) @@ -50,4 +54,4 @@ private string ScrubGuids(string text) return scrubbedText; } -} \ No newline at end of file +} diff --git a/TUnit.Core.SourceGenerator.Tests/ConcreteClassTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/ConcreteClassTests.Test.verified.txt index 85d3699447..47b36aa0d7 100644 --- a/TUnit.Core.SourceGenerator.Tests/ConcreteClassTests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/ConcreteClassTests.Test.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -144,7 +144,7 @@ internal static class TUnit_TestProject_AbstractTests_ConcreteClass2_AssertClass MethodName = "AssertClassName", FullyQualifiedName = "TUnit.TestProject.AbstractTests.ConcreteClass2.AssertClassName", FilePath = @"", - LineNumber = 3, + LineNumber = 6, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, @@ -219,7 +219,7 @@ internal static class TUnit_TestProject_AbstractTests_ConcreteClass1_AssertClass MethodName = "AssertClassName", FullyQualifiedName = "TUnit.TestProject.AbstractTests.ConcreteClass1.AssertClassName", FilePath = @"", - LineNumber = 3, + LineNumber = 6, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, diff --git a/TUnit.Core.SourceGenerator.Tests/InheritedPropertySetterTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/InheritedPropertySetterTests.Test.verified.txt index 9d930b2712..1f9a7f369a 100644 --- a/TUnit.Core.SourceGenerator.Tests/InheritedPropertySetterTests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/InheritedPropertySetterTests.Test.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -266,7 +266,7 @@ internal static class TUnit_TestProject_InheritedPropertySetterTests_Test_TestSo MethodName = "Test", FullyQualifiedName = "TUnit.TestProject.InheritedPropertySetterTests.Test", FilePath = @"", - LineNumber = 3, + LineNumber = 70, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, diff --git a/TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.Test.verified.txt index 1679c6d689..62bb573445 100644 --- a/TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/InheritedTestsFromDifferentProjectTests.Test.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -292,7 +292,7 @@ internal static class TUnit_TestProject_InheritedTestsFromDifferentProjectTests_ MethodName = "BaseTest", FullyQualifiedName = "TUnit.TestProject.InheritedTestsFromDifferentProjectTests.BaseTest", FilePath = @"", - LineNumber = 5, + LineNumber = 8, Categories = new string[] { "BaseCategory" }, Properties = global::System.Array.Empty(), HasDataSource = false, @@ -372,7 +372,7 @@ internal static class TUnit_TestProject_InheritedTestsFromDifferentProjectTests_ MethodName = "BaseTestWithMultipleCategories", FullyQualifiedName = "TUnit.TestProject.InheritedTestsFromDifferentProjectTests.BaseTestWithMultipleCategories", FilePath = @"", - LineNumber = 5, + LineNumber = 15, Categories = new string[] { "AnotherBaseCategory", "MultipleCategories" }, Properties = global::System.Array.Empty(), HasDataSource = false, diff --git a/TUnit.Core.SourceGenerator.Tests/InheritsTestsAbstractTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/InheritsTestsAbstractTests.Test.verified.txt index 85d3699447..47b36aa0d7 100644 --- a/TUnit.Core.SourceGenerator.Tests/InheritsTestsAbstractTests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/InheritsTestsAbstractTests.Test.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -144,7 +144,7 @@ internal static class TUnit_TestProject_AbstractTests_ConcreteClass2_AssertClass MethodName = "AssertClassName", FullyQualifiedName = "TUnit.TestProject.AbstractTests.ConcreteClass2.AssertClassName", FilePath = @"", - LineNumber = 3, + LineNumber = 6, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, @@ -219,7 +219,7 @@ internal static class TUnit_TestProject_AbstractTests_ConcreteClass1_AssertClass MethodName = "AssertClassName", FullyQualifiedName = "TUnit.TestProject.AbstractTests.ConcreteClass1.AssertClassName", FilePath = @"", - LineNumber = 3, + LineNumber = 6, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, diff --git a/TUnit.Core.SourceGenerator.Tests/InheritsTestsTests.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/InheritsTestsTests.Test.verified.txt index bc92075324..ce09d93dc1 100644 --- a/TUnit.Core.SourceGenerator.Tests/InheritsTestsTests.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/InheritsTestsTests.Test.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -198,7 +198,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(int), "value", new glo MethodName = "Test", FullyQualifiedName = "TUnit.TestProject.Bugs._1924.None.Tests.Test", FilePath = @"", - LineNumber = 23, + LineNumber = 16, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, @@ -298,7 +298,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(int), "value", new glo MethodName = "Test", FullyQualifiedName = "TUnit.TestProject.Bugs._1924.None.Tests2.Test", FilePath = @"", - LineNumber = 26, + LineNumber = 16, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, @@ -398,7 +398,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(int), "value", new glo MethodName = "Test", FullyQualifiedName = "TUnit.TestProject.Bugs._1924.None.Tests3.Test", FilePath = @"", - LineNumber = 29, + LineNumber = 16, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, diff --git a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet10_0.verified.txt b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet10_0.verified.txt index e12b6432db..8d771b7d9c 100644 --- a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet10_0.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet10_0.verified.txt @@ -141,7 +141,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test2", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test2", FilePath = @"", - LineNumber = 6, + LineNumber = 12, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, @@ -235,7 +235,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test3", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test3", FilePath = @"", - LineNumber = 6, + LineNumber = 19, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, diff --git a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet8_0.verified.txt b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet8_0.verified.txt index e12b6432db..8d771b7d9c 100644 --- a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet8_0.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet8_0.verified.txt @@ -141,7 +141,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test2", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test2", FilePath = @"", - LineNumber = 6, + LineNumber = 12, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, @@ -235,7 +235,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test3", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test3", FilePath = @"", - LineNumber = 6, + LineNumber = 19, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, diff --git a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet9_0.verified.txt b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet9_0.verified.txt index e12b6432db..8d771b7d9c 100644 --- a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet9_0.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.DotNet9_0.verified.txt @@ -141,7 +141,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test2", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test2", FilePath = @"", - LineNumber = 6, + LineNumber = 12, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, @@ -235,7 +235,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test3", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test3", FilePath = @"", - LineNumber = 6, + LineNumber = 19, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, diff --git a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.Net4_7.verified.txt b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.Net4_7.verified.txt index 862d9edb8b..33c81a7ab6 100644 --- a/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.Net4_7.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/Tests1889.Test.Net4_7.verified.txt @@ -141,7 +141,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test2", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test2", FilePath = @"", - LineNumber = 6, + LineNumber = 12, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, @@ -235,7 +235,7 @@ global::TUnit.Core.ParameterMetadataFactory.Create(typeof(bool), "condition", ne MethodName = "Test3", FullyQualifiedName = "TUnit.TestProject.Bugs._1889.DerivedTest.Test3", FilePath = @"", - LineNumber = 6, + LineNumber = 19, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = true, diff --git a/TUnit.Core.SourceGenerator.Tests/Tests1899.Test.verified.txt b/TUnit.Core.SourceGenerator.Tests/Tests1899.Test.verified.txt index 43d87b6af9..cfcaa07987 100644 --- a/TUnit.Core.SourceGenerator.Tests/Tests1899.Test.verified.txt +++ b/TUnit.Core.SourceGenerator.Tests/Tests1899.Test.verified.txt @@ -1,4 +1,4 @@ -// +// #pragma warning disable #nullable enable @@ -52,7 +52,7 @@ internal static class TUnit_TestProject_Bugs__1899_DerivedTest_Test1_TestSource MethodName = "Test1", FullyQualifiedName = "TUnit.TestProject.Bugs._1899.DerivedTest.Test1", FilePath = @"", - LineNumber = 6, + LineNumber = 14, Categories = global::System.Array.Empty(), Properties = global::System.Array.Empty(), HasDataSource = false, diff --git a/TUnit.Core.SourceGenerator.Tests/TestsBase.cs b/TUnit.Core.SourceGenerator.Tests/TestsBase.cs index 91ff554b83..3fbf1c12ec 100644 --- a/TUnit.Core.SourceGenerator.Tests/TestsBase.cs +++ b/TUnit.Core.SourceGenerator.Tests/TestsBase.cs @@ -161,7 +161,10 @@ Have you added required references and additional files? // Scrub GUIDs from generated files before verification var scrubbedFiles = generatedFiles.Select(file => Scrub(file)).ToArray(); var verifyTask = Verify(scrubbedFiles) - .ScrubFilePaths(); + .ScrubFilePaths() + .ScrubLinesContaining("StartColumnNumber = ") + .ScrubLinesContaining("EndLineNumber = ") + .ScrubLinesContaining("EndColumnNumber = "); if (runTestOptions.VerifyConfigurator != null) { diff --git a/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs b/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs index 226f8a6119..92f353e4f2 100644 --- a/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs +++ b/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs @@ -160,14 +160,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var isGenericType = containingType is { IsGenericType: true, TypeParameters.Length: > 0 }; var isGenericMethod = methodSymbol is { IsGenericMethod: true }; - var (filePath, lineNumber) = GetTestMethodSourceLocation(methodSyntax, testAttribute); + var location = GetTestMethodSourceLocation(methodSyntax, testAttribute); return new TestMethodMetadata { MethodSymbol = methodSymbol ?? throw new InvalidOperationException("Symbol is not a method"), TypeSymbol = containingType, - FilePath = filePath, - LineNumber = lineNumber, + FilePath = location.FilePath, + LineNumber = location.LineNumber, + StartColumnNumber = location.StartColumnNumber, + EndLineNumber = location.EndLineNumber, + EndColumnNumber = location.EndColumnNumber, TestAttribute = context.Attributes.First(), Context = context, CompilationContext = compilationContext, @@ -222,7 +225,7 @@ private static void GenerateInheritedTestSources(SourceProductionContext context { continue; } - var (filePath, lineNumber) = GetTestMethodSourceLocation(method, testAttribute, classInfo); + var location = GetTestMethodSourceLocation(method, testAttribute, classInfo); // If the method is from a generic base class, use the constructed version from the inheritance hierarchy var typeForMetadata = classInfo.TypeSymbol; @@ -246,8 +249,11 @@ private static void GenerateInheritedTestSources(SourceProductionContext context { MethodSymbol = concreteMethod ?? method, // Use concrete method if found, otherwise base method TypeSymbol = typeForMetadata, // Use constructed generic base if applicable - FilePath = filePath, - LineNumber = lineNumber, + FilePath = location.FilePath, + LineNumber = location.LineNumber, + StartColumnNumber = location.StartColumnNumber, + EndLineNumber = location.EndLineNumber, + EndColumnNumber = location.EndColumnNumber, TestAttribute = testAttribute, Context = classInfo.Context, // Use class context to access Compilation CompilationContext = classInfo.CompilationContext, @@ -1050,8 +1056,7 @@ private static void EmitTestEntryFields(CodeWriter writer, TestMethodMetadata te writer.AppendLine($"MethodName = \"{EscapeString(entry.TestName)}\","); writer.AppendLine($"FullyQualifiedName = \"{EscapeString(fullyQualifiedName)}\","); - writer.AppendLine($"FilePath = @\"{(testMethod.FilePath ?? "").Replace("\\", "\\\\")}\","); - writer.AppendLine($"LineNumber = {testMethod.LineNumber},"); + WriteSourceLocationMetadata(writer, testMethod); writer.AppendLine($"Categories = {categoriesArray},"); writer.AppendLine($"Properties = {propertiesArray},"); writer.AppendLine($"HasDataSource = {(hasDataSource ? "true" : "false")},"); @@ -1195,15 +1200,22 @@ private static void GenerateMetadata(CodeWriter writer, TestMethodMetadata testM // Inheritance depth writer.AppendLine($"InheritanceDepth = {testMethod.InheritanceDepth},"); - // File location metadata - writer.AppendLine($"FilePath = @\"{(testMethod.FilePath ?? "").Replace("\\", "\\\\")}\","); - writer.AppendLine($"LineNumber = {testMethod.LineNumber},"); + WriteSourceLocationMetadata(writer, testMethod); // Method metadata writer.Append("MethodMetadata = "); SourceInformationWriter.GenerateMethodInformation(writer, compilation, testMethod.TypeSymbol, testMethod.MethodSymbol, null, ','); } + private static void WriteSourceLocationMetadata(CodeWriter writer, TestMethodMetadata testMethod) + { + writer.AppendLine($"FilePath = @\"{(testMethod.FilePath ?? "").Replace("\\", "\\\\")}\","); + writer.AppendLine($"LineNumber = {testMethod.LineNumber},"); + writer.AppendLine($"StartColumnNumber = {testMethod.StartColumnNumber},"); + writer.AppendLine($"EndLineNumber = {testMethod.EndLineNumber},"); + writer.AppendLine($"EndColumnNumber = {testMethod.EndColumnNumber},"); + } + private static void GenerateMetadataForConcreteInstantiation(CodeWriter writer, TestMethodMetadata testMethod) { var compilation = testMethod.Context!.Value.SemanticModel.Compilation; @@ -1243,9 +1255,7 @@ private static void GenerateMetadataForConcreteInstantiation(CodeWriter writer, // Inheritance depth writer.AppendLine($"InheritanceDepth = {testMethod.InheritanceDepth},"); - // File location metadata - writer.AppendLine($"FilePath = @\"{(testMethod.FilePath ?? "").Replace("\\", "\\\\")}\","); - writer.AppendLine($"LineNumber = {testMethod.LineNumber},"); + WriteSourceLocationMetadata(writer, testMethod); // Method metadata writer.Append("MethodMetadata = "); @@ -3068,8 +3078,7 @@ private static string PreGenerateTestEntryDataFields(TestMethodMetadata testMeth writer.AppendLine($"MethodName = \"{EscapeString(methodName)}\","); writer.AppendLine($"FullyQualifiedName = \"{EscapeString(fullyQualifiedName)}\","); - writer.AppendLine($"FilePath = @\"{(testMethod.FilePath ?? "").Replace("\\", "\\\\")}\","); - writer.AppendLine($"LineNumber = {testMethod.LineNumber},"); + WriteSourceLocationMetadata(writer, testMethod); writer.AppendLine($"Categories = {categoriesArray},"); writer.AppendLine($"Properties = {propertiesArray},"); writer.AppendLine($"HasDataSource = {(hasDataSource ? "true" : "false")},"); @@ -3981,71 +3990,87 @@ private static bool TypesMatchForInheritance(ITypeSymbol derivedType, ITypeSymbo return false; } - private static (string filePath, int lineNumber) GetTestMethodSourceLocation( + private static TestSourceLocation GetTestMethodSourceLocation( MethodDeclarationSyntax methodSyntax, AttributeData testAttribute) { - // Prioritize TestAttribute's File/Line from [CallerFilePath]/[CallerLineNumber] first var attrFilePath = testAttribute.ConstructorArguments.ElementAtOrDefault(0).Value?.ToString(); - if (!string.IsNullOrEmpty(attrFilePath)) - { - var attrLineNumber = (int?)testAttribute.ConstructorArguments.ElementAtOrDefault(1).Value ?? 0; - if (attrLineNumber > 0) - { - return (attrFilePath!, attrLineNumber); - } - } + var attrLineNumber = (int?)testAttribute.ConstructorArguments.ElementAtOrDefault(1).Value ?? 0; - // Fall back to method syntax location var methodLocation = methodSyntax.GetLocation(); - var filePath = methodLocation.SourceTree?.FilePath; - if (!string.IsNullOrEmpty(filePath)) + if (methodLocation.IsInSource) { - var lineNumber = methodLocation.GetLineSpan().StartLinePosition.Line + 1; - return (filePath!, lineNumber); + return CreateSourceLocation( + methodLocation.GetLineSpan(), + !string.IsNullOrEmpty(attrFilePath) ? attrFilePath! : methodLocation.SourceTree?.FilePath ?? methodSyntax.SyntaxTree.FilePath ?? ""); } - // Final fallback - filePath = methodSyntax.SyntaxTree.FilePath ?? ""; - var fallbackLineNumber = methodLocation.GetLineSpan().StartLinePosition.Line + 1; - return (filePath, fallbackLineNumber); + return CreateFallbackSourceLocation( + !string.IsNullOrEmpty(attrFilePath) ? attrFilePath! : methodSyntax.SyntaxTree.FilePath ?? "", + attrLineNumber); } - private static (string filePath, int lineNumber) GetTestMethodSourceLocation( + private static TestSourceLocation GetTestMethodSourceLocation( IMethodSymbol method, AttributeData testAttribute, InheritsTestsClassMetadata classInfo) { - // Prioritize TestAttribute's File/Line from [CallerFilePath]/[CallerLineNumber] first var attrFilePath = testAttribute.ConstructorArguments.ElementAtOrDefault(0).Value?.ToString(); - if (!string.IsNullOrEmpty(attrFilePath)) - { - var attrLineNumber = (int?)testAttribute.ConstructorArguments.ElementAtOrDefault(1).Value ?? 0; - if (attrLineNumber > 0) - { - return (attrFilePath!, attrLineNumber); - } - } + var attrLineNumber = (int?)testAttribute.ConstructorArguments.ElementAtOrDefault(1).Value ?? 0; - // Fall back to method symbol location var methodLocation = method.Locations.FirstOrDefault(); if (methodLocation != null && methodLocation.IsInSource) { - var filePath = methodLocation.SourceTree?.FilePath; - if (!string.IsNullOrEmpty(filePath)) - { - var lineNumber = methodLocation.GetLineSpan().StartLinePosition.Line + 1; - return (filePath!, lineNumber); - } + return CreateSourceLocation( + methodLocation.GetLineSpan(), + !string.IsNullOrEmpty(attrFilePath) ? attrFilePath! : methodLocation.SourceTree?.FilePath ?? ""); } - // Final fallback to class location var classLocation = classInfo.ClassSyntax.GetLocation(); - var derivedFilePath = classLocation.SourceTree?.FilePath ?? classInfo.ClassSyntax.SyntaxTree.FilePath ?? ""; - var derivedLineNumber = classLocation.GetLineSpan().StartLinePosition.Line + 1; - return (derivedFilePath, derivedLineNumber); + if (classLocation.IsInSource) + { + return CreateSourceLocation( + classLocation.GetLineSpan(), + !string.IsNullOrEmpty(attrFilePath) ? attrFilePath! : classLocation.SourceTree?.FilePath ?? classInfo.ClassSyntax.SyntaxTree.FilePath ?? ""); + } + + return CreateFallbackSourceLocation( + !string.IsNullOrEmpty(attrFilePath) ? attrFilePath! : classInfo.ClassSyntax.SyntaxTree.FilePath ?? "", + attrLineNumber); } + private static TestSourceLocation CreateSourceLocation(FileLinePositionSpan lineSpan, string filePath) + { + // Roslyn reports zero-based line/character positions; TUnit stores user-facing source + // coordinates as one-based values alongside the existing LineNumber convention. + return new TestSourceLocation( + filePath, + lineSpan.StartLinePosition.Line + 1, + lineSpan.StartLinePosition.Character + 1, + lineSpan.EndLinePosition.Line + 1, + lineSpan.EndLinePosition.Character + 1); + } + + private static TestSourceLocation CreateFallbackSourceLocation(string filePath, int lineNumber) + { + // Exact Roslyn span data was unavailable. Preserve any caller-supplied start line, and + // use zero-valued columns to indicate that the precise character range could not be determined. + var resolvedLineNumber = lineNumber > 0 ? lineNumber : 0; + return new TestSourceLocation(filePath, resolvedLineNumber, 0, resolvedLineNumber, 0); + } + + /// + /// Source coordinates for a discovered test. + /// Line and column values use one-based numbering; zero-valued columns indicate that the + /// precise character span could not be determined for the fallback location. + /// + private readonly record struct TestSourceLocation( + string FilePath, + int LineNumber, + int StartColumnNumber, + int EndLineNumber, + int EndColumnNumber); + private static void GenerateReflectionFieldAccessors(CodeWriter writer, INamedTypeSymbol typeSymbol) { // Find all init-only properties with data source attributes @@ -6114,8 +6139,7 @@ private static void GenerateConcreteMetadataWithFilteredDataSources( GeneratePropertyInjections(writer, concreteTypeSymbol, concreteTypeSymbol.GloballyQualified()); // Other metadata - writer.AppendLine($"FilePath = @\"{(testMethod.FilePath ?? "").Replace("\\", "\\\\")}\","); - writer.AppendLine($"LineNumber = {testMethod.LineNumber},"); + WriteSourceLocationMetadata(writer, testMethod); writer.AppendLine($"InheritanceDepth = {testMethod.InheritanceDepth},"); writer.AppendLine("TestSessionId = testSessionId,"); @@ -6462,8 +6486,7 @@ private static void GenerateConcreteTestMetadataForNonGeneric( // Generate typed invoker GenerateTypedInvokers(writer, testMethod, className); - writer.AppendLine($"FilePath = @\"{(testMethod.FilePath ?? "").Replace("\\", "\\\\")}\","); - writer.AppendLine($"LineNumber = {testMethod.LineNumber},"); + WriteSourceLocationMetadata(writer, testMethod); writer.Unindent(); writer.AppendLine("};"); diff --git a/TUnit.Core.SourceGenerator/Models/TestMethodMetadata.cs b/TUnit.Core.SourceGenerator/Models/TestMethodMetadata.cs index 33616e1e7d..0d3713a44a 100644 --- a/TUnit.Core.SourceGenerator/Models/TestMethodMetadata.cs +++ b/TUnit.Core.SourceGenerator/Models/TestMethodMetadata.cs @@ -18,6 +18,9 @@ public class TestMethodMetadata : IEquatable public required INamedTypeSymbol TypeSymbol { get; init; } public required string FilePath { get; init; } public required int LineNumber { get; init; } + public required int StartColumnNumber { get; init; } + public required int EndLineNumber { get; init; } + public required int EndColumnNumber { get; init; } public required AttributeData TestAttribute { get; init; } public GeneratorAttributeSyntaxContext? Context { get; init; } public required CompilationContext CompilationContext { get; init; } @@ -49,6 +52,9 @@ public bool Equals(TestMethodMetadata? other) SymbolEqualityComparer.Default.Equals(TypeSymbol, other.TypeSymbol) && FilePath == other.FilePath && LineNumber == other.LineNumber && + StartColumnNumber == other.StartColumnNumber && + EndLineNumber == other.EndLineNumber && + EndColumnNumber == other.EndColumnNumber && IsGenericType == other.IsGenericType && IsGenericMethod == other.IsGenericMethod && InheritanceDepth == other.InheritanceDepth; @@ -68,6 +74,9 @@ public override int GetHashCode() hashCode = (hashCode * 397) ^ SymbolEqualityComparer.Default.GetHashCode(TypeSymbol); hashCode = (hashCode * 397) ^ FilePath.GetHashCode(); hashCode = (hashCode * 397) ^ LineNumber; + hashCode = (hashCode * 397) ^ StartColumnNumber; + hashCode = (hashCode * 397) ^ EndLineNumber; + hashCode = (hashCode * 397) ^ EndColumnNumber; hashCode = (hashCode * 397) ^ IsGenericType.GetHashCode(); hashCode = (hashCode * 397) ^ IsGenericMethod.GetHashCode(); hashCode = (hashCode * 397) ^ InheritanceDepth; diff --git a/TUnit.Core/TestDetails.cs b/TUnit.Core/TestDetails.cs index 8c25a03311..119f493605 100644 --- a/TUnit.Core/TestDetails.cs +++ b/TUnit.Core/TestDetails.cs @@ -49,6 +49,9 @@ public partial class TestDetails : ITestIdentity, ITestClass, ITestMethod, ITest public required MethodMetadata MethodMetadata { get; set; } public string TestFilePath { get; set; } = ""; public int TestLineNumber { get; set; } + internal int TestStartColumnNumber { get; set; } + internal int TestEndLineNumber { get; set; } + internal int TestEndColumnNumber { get; set; } public required Type ReturnType { get; set; } // Lazy — the vast majority of tests use zero injected properties, so we skip the // per-test ConcurrentDictionary allocation (~200+ bytes) until there's actually diff --git a/TUnit.Core/TestEntry.cs b/TUnit.Core/TestEntry.cs index a16d5a2fdc..a7505c05b9 100644 --- a/TUnit.Core/TestEntry.cs +++ b/TUnit.Core/TestEntry.cs @@ -36,9 +36,18 @@ public sealed class TestEntry< /// Source file path. public required string FilePath { get; init; } - /// Source line number. + /// Source start line number. This preserves the existing LineNumber semantics for backwards compatibility. public required int LineNumber { get; init; } + /// Source start column number. Uses a one-based column index; zero indicates the exact column is unavailable for fallback/no-span locations. + public int StartColumnNumber { get; init; } + + /// Source end line number. + public int EndLineNumber { get; init; } + + /// Source end column number. Uses a one-based column index; zero indicates the exact column is unavailable for fallback/no-span locations. + public int EndColumnNumber { get; init; } + /// Pre-extracted categories for fast filtering. public string[] Categories { get; init; } = []; @@ -127,6 +136,9 @@ internal TestMetadata ToTestMetadata(string testSessionId) AttributeGroupIndex = AttributeGroupIndex, FilePath = FilePath, LineNumber = LineNumber, + StartColumnNumber = StartColumnNumber, + EndLineNumber = EndLineNumber, + EndColumnNumber = EndColumnNumber, MethodMetadata = MethodMetadata, RepeatCount = RepeatCount > 0 ? RepeatCount : null, TestSessionId = testSessionId, diff --git a/TUnit.Core/TestMetadata.cs b/TUnit.Core/TestMetadata.cs index c87581862e..894a0b857e 100644 --- a/TUnit.Core/TestMetadata.cs +++ b/TUnit.Core/TestMetadata.cs @@ -39,6 +39,12 @@ public abstract class TestMetadata public required int LineNumber { get; init; } + internal int StartColumnNumber { get; init; } + + internal int EndLineNumber { get; init; } + + internal int EndColumnNumber { get; init; } + public required MethodMetadata MethodMetadata { get; init; } public GenericTypeInfo? GenericTypeInfo { get; init; } diff --git a/TUnit.Engine.Tests/TestNodeLocationTests.cs b/TUnit.Engine.Tests/TestNodeLocationTests.cs new file mode 100644 index 0000000000..c1d218e323 --- /dev/null +++ b/TUnit.Engine.Tests/TestNodeLocationTests.cs @@ -0,0 +1,147 @@ +#pragma warning disable TPEXP + +using Microsoft.Testing.Platform.Extensions.Messages; +using Shouldly; +using TUnit.Core; +using TUnit.Engine.Extensions; + +namespace TUnit.Engine.Tests; + +public class TestNodeLocationTests +{ + [Test] + public void ToTestNode_Uses_Source_Span_For_Mtp_File_Location() + { + TestExtensions.ClearCaches(); + + var context = CreateTestContext( + testId: Guid.NewGuid().ToString("N"), + filePath: @"C:\tests\SampleTests.cs", + lineNumber: 12, + startColumnNumber: 5, + endLineNumber: 16, + endColumnNumber: 6); + + var node = context.ToTestNode(DiscoveredTestNodeStateProperty.CachedInstance); + + var location = node.Properties.AsEnumerable() + .OfType() + .Single(); + + location.FilePath.ShouldBe(@"C:\tests\SampleTests.cs"); + location.LineSpan.Start.Line.ShouldBe(12); + location.LineSpan.Start.Column.ShouldBe(5); + location.LineSpan.End.Line.ShouldBe(16); + location.LineSpan.End.Column.ShouldBe(6); + } + + [Test] + public void ToTestNode_Falls_Back_To_Start_Line_When_End_Line_Is_Unavailable() + { + TestExtensions.ClearCaches(); + + var context = CreateTestContext( + testId: Guid.NewGuid().ToString("N"), + filePath: @"C:\tests\SampleTests.cs", + lineNumber: 12, + startColumnNumber: 0, + endLineNumber: 0, + endColumnNumber: 0); + + var node = context.ToTestNode(DiscoveredTestNodeStateProperty.CachedInstance); + + var location = node.Properties.AsEnumerable() + .OfType() + .Single(); + + location.LineSpan.Start.Line.ShouldBe(12); + location.LineSpan.Start.Column.ShouldBe(0); + location.LineSpan.End.Line.ShouldBe(12); + location.LineSpan.End.Column.ShouldBe(0); + } + + private static TestContext CreateTestContext( + string testId, + string filePath, + int lineNumber, + int startColumnNumber, + int endLineNumber, + int endColumnNumber) + { + var classMetadata = new ClassMetadata + { + Type = typeof(TestNodeLocationTests), + TypeInfo = new ConcreteType(typeof(TestNodeLocationTests)), + Name = nameof(TestNodeLocationTests), + Namespace = typeof(TestNodeLocationTests).Namespace, + Assembly = new AssemblyMetadata + { + Name = typeof(TestNodeLocationTests).Assembly.GetName().Name ?? string.Empty + }, + Parent = null, + Parameters = [], + Properties = [] + }; + + var methodMetadata = new MethodMetadata + { + Type = typeof(TestNodeLocationTests), + TypeInfo = new ConcreteType(typeof(TestNodeLocationTests)), + Name = nameof(ToTestNode_Uses_Source_Span_For_Mtp_File_Location), + GenericTypeCount = 0, + ReturnType = typeof(void), + ReturnTypeInfo = new ConcreteType(typeof(void)), + Parameters = [], + Class = classMetadata + }; + + var beforeDiscoveryContext = new BeforeTestDiscoveryContext { TestFilter = null }; + var discoveryContext = new TestDiscoveryContext(beforeDiscoveryContext) { TestFilter = null }; + var sessionContext = new TestSessionContext(discoveryContext) + { + Id = Guid.NewGuid().ToString("N"), + TestFilter = null + }; + var assemblyContext = new AssemblyHookContext(sessionContext) + { + Assembly = typeof(TestNodeLocationTests).Assembly + }; + var classContext = new ClassHookContext(assemblyContext) + { + ClassType = typeof(TestNodeLocationTests) + }; + var builderContext = new TestBuilderContext + { + TestMetadata = methodMetadata + }; + + var context = new TestContext(testId, EmptyServiceProvider.Instance, classContext, builderContext, CancellationToken.None); + context.TestDetails = new TestDetails([]) + { + TestId = testId, + TestName = methodMetadata.Name, + ClassType = typeof(TestNodeLocationTests), + MethodName = methodMetadata.Name, + ClassInstance = new TestNodeLocationTests(), + TestMethodArguments = [], + TestClassArguments = [], + MethodMetadata = methodMetadata, + TestFilePath = filePath, + TestLineNumber = lineNumber, + TestStartColumnNumber = startColumnNumber, + TestEndLineNumber = endLineNumber, + TestEndColumnNumber = endColumnNumber, + ReturnType = typeof(void), + AttributesByType = new Dictionary>() + }; + + return context; + } + + private sealed class EmptyServiceProvider : IServiceProvider + { + public static EmptyServiceProvider Instance { get; } = new(); + + public object? GetService(Type serviceType) => null; + } +} diff --git a/TUnit.Engine/Building/TestBuilder.cs b/TUnit.Engine/Building/TestBuilder.cs index c366936314..3b64c01ffe 100644 --- a/TUnit.Engine/Building/TestBuilder.cs +++ b/TUnit.Engine/Building/TestBuilder.cs @@ -1081,6 +1081,9 @@ private async ValueTask CreateTestContextAsync(string testId, TestM TestClassArguments = testData.ClassData, TestFilePath = metadata.FilePath, TestLineNumber = metadata.LineNumber, + TestStartColumnNumber = metadata.StartColumnNumber, + TestEndLineNumber = metadata.EndLineNumber, + TestEndColumnNumber = metadata.EndColumnNumber, ReturnType = metadata.MethodMetadata.ReturnType ?? typeof(void), MethodMetadata = metadata.MethodMetadata, AttributesByType = attributes.ToAttributeDictionary(), @@ -1175,6 +1178,9 @@ private TestDetails CreateFailedTestDetails(TestMetadata metadata, string testId TestClassArguments = [], TestFilePath = metadata.FilePath ?? "Unknown", TestLineNumber = metadata.LineNumber, + TestStartColumnNumber = metadata.StartColumnNumber, + TestEndLineNumber = metadata.EndLineNumber, + TestEndColumnNumber = metadata.EndColumnNumber, ReturnType = typeof(Task), MethodMetadata = metadata.MethodMetadata, AttributesByType = AttributeDictionaryHelper.Empty diff --git a/TUnit.Engine/Building/TestBuilderPipeline.cs b/TUnit.Engine/Building/TestBuilderPipeline.cs index de56c157e6..493aec53b5 100644 --- a/TUnit.Engine/Building/TestBuilderPipeline.cs +++ b/TUnit.Engine/Building/TestBuilderPipeline.cs @@ -254,6 +254,9 @@ private async Task GenerateDynamicTests(TestMetadata m TestClassArguments = [], TestFilePath = metadata.FilePath ?? "Unknown", TestLineNumber = metadata.LineNumber, + TestStartColumnNumber = metadata.StartColumnNumber, + TestEndLineNumber = metadata.EndLineNumber, + TestEndColumnNumber = metadata.EndColumnNumber, ReturnType = typeof(Task), MethodMetadata = metadata.MethodMetadata, AttributesByType = attributes.ToAttributeDictionary() @@ -380,6 +383,9 @@ private async IAsyncEnumerable BuildTestsFromSingleMetad TestClassArguments = [], TestFilePath = resolvedMetadata.FilePath ?? "Unknown", TestLineNumber = resolvedMetadata.LineNumber, + TestStartColumnNumber = resolvedMetadata.StartColumnNumber, + TestEndLineNumber = resolvedMetadata.EndLineNumber, + TestEndColumnNumber = resolvedMetadata.EndColumnNumber, ReturnType = typeof(Task), MethodMetadata = resolvedMetadata.MethodMetadata, AttributesByType = attributes.ToAttributeDictionary() @@ -458,6 +464,9 @@ private AbstractExecutableTest CreateFailedTestForDataGenerationError(TestMetada TestClassArguments = [], TestFilePath = metadata.FilePath ?? "Unknown", TestLineNumber = metadata.LineNumber, + TestStartColumnNumber = metadata.StartColumnNumber, + TestEndLineNumber = metadata.EndLineNumber, + TestEndColumnNumber = metadata.EndColumnNumber, ReturnType = typeof(Task), MethodMetadata = metadata.MethodMetadata, AttributesByType = AttributeDictionaryHelper.Empty @@ -510,6 +519,9 @@ private AbstractExecutableTest CreateFailedTestForGenericResolutionError(TestMet TestClassArguments = [], TestFilePath = metadata.FilePath ?? "Unknown", TestLineNumber = metadata.LineNumber, + TestStartColumnNumber = metadata.StartColumnNumber, + TestEndLineNumber = metadata.EndLineNumber, + TestEndColumnNumber = metadata.EndColumnNumber, ReturnType = typeof(Task), MethodMetadata = metadata.MethodMetadata, AttributesByType = AttributeDictionaryHelper.Empty diff --git a/TUnit.Engine/Extensions/TestExtensions.cs b/TUnit.Engine/Extensions/TestExtensions.cs index 841e8cc70d..875fe97e5f 100644 --- a/TUnit.Engine/Extensions/TestExtensions.cs +++ b/TUnit.Engine/Extensions/TestExtensions.cs @@ -48,8 +48,10 @@ private static CachedTestNodeProperties GetOrCreateCachedProperties(TestContext var testDetails = testContext.Metadata.TestDetails; var fileLocation = new TestFileLocationProperty(testDetails.TestFilePath, new LinePositionSpan( - new LinePosition(testDetails.TestLineNumber, 0), - new LinePosition(testDetails.TestLineNumber, 0) + new LinePosition(testDetails.TestLineNumber, testDetails.TestStartColumnNumber), + new LinePosition( + testDetails.TestEndLineNumber > 0 ? testDetails.TestEndLineNumber : testDetails.TestLineNumber, + testDetails.TestEndColumnNumber) )); var methodIdentifier = new TestMethodIdentifierProperty( diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt index 5ab83ff645..409ded9318 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet10_0.verified.txt @@ -1578,6 +1578,8 @@ namespace public required <[], object?[], T> CreateInstance { get; init; } public .TestDependency[] Dependencies { get; init; } public string[] DependsOn { get; init; } + public int EndColumnNumber { get; init; } + public int EndLineNumber { get; init; } public required string FilePath { get; init; } public required string FullyQualifiedName { get; init; } public bool HasDataSource { get; init; } @@ -1589,6 +1591,7 @@ namespace public required string MethodName { get; init; } public string[] Properties { get; init; } public int RepeatCount { get; init; } + public int StartColumnNumber { get; init; } public .IDataSourceAttribute[] TestDataSources { get; init; } } public class TestInstantiationException : .TestBuilderException diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt index 2c27794cfb..67bf6e0e85 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -1578,6 +1578,8 @@ namespace public required <[], object?[], T> CreateInstance { get; init; } public .TestDependency[] Dependencies { get; init; } public string[] DependsOn { get; init; } + public int EndColumnNumber { get; init; } + public int EndLineNumber { get; init; } public required string FilePath { get; init; } public required string FullyQualifiedName { get; init; } public bool HasDataSource { get; init; } @@ -1589,6 +1591,7 @@ namespace public required string MethodName { get; init; } public string[] Properties { get; init; } public int RepeatCount { get; init; } + public int StartColumnNumber { get; init; } public .IDataSourceAttribute[] TestDataSources { get; init; } } public class TestInstantiationException : .TestBuilderException diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt index 24562acdb3..a53b2b7905 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -1578,6 +1578,8 @@ namespace public required <[], object?[], T> CreateInstance { get; init; } public .TestDependency[] Dependencies { get; init; } public string[] DependsOn { get; init; } + public int EndColumnNumber { get; init; } + public int EndLineNumber { get; init; } public required string FilePath { get; init; } public required string FullyQualifiedName { get; init; } public bool HasDataSource { get; init; } @@ -1589,6 +1591,7 @@ namespace public required string MethodName { get; init; } public string[] Properties { get; init; } public int RepeatCount { get; init; } + public int StartColumnNumber { get; init; } public .IDataSourceAttribute[] TestDataSources { get; init; } } public class TestInstantiationException : .TestBuilderException diff --git a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt index 64ca32b5e5..7b10e10041 100644 --- a/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt +++ b/TUnit.PublicAPI/Tests.Core_Library_Has_No_API_Changes.Net4_7.verified.txt @@ -1519,6 +1519,8 @@ namespace public required <[], object?[], T> CreateInstance { get; init; } public .TestDependency[] Dependencies { get; init; } public string[] DependsOn { get; init; } + public int EndColumnNumber { get; init; } + public int EndLineNumber { get; init; } public required string FilePath { get; init; } public required string FullyQualifiedName { get; init; } public bool HasDataSource { get; init; } @@ -1530,6 +1532,7 @@ namespace public required string MethodName { get; init; } public string[] Properties { get; init; } public int RepeatCount { get; init; } + public int StartColumnNumber { get; init; } public .IDataSourceAttribute[] TestDataSources { get; init; } } public class TestInstantiationException : .TestBuilderException