Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TUnit.Engine.Tests/HtmlReporterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,4 +462,5 @@ public void FilterEngineNotices_PassesThroughWhenNoTUnitPrefix()
EndTime = startTime,
RetryAttempt = 0,
};

}
35 changes: 35 additions & 0 deletions TUnit.Engine.Tests/TestNodeLocationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.Testing.Platform.Extensions.Messages;
using Shouldly;
using TUnit.Core;
using TUnit.Engine.Discovery;
using TUnit.Engine.Extensions;

namespace TUnit.Engine.Tests;
Expand Down Expand Up @@ -60,6 +61,25 @@ public void ToTestNode_Falls_Back_To_Start_Line_When_End_Line_Is_Unavailable()
location.LineSpan.End.Column.ShouldBe(0);
}

[Test]
public void SourceLocationResolver_Finds_EndLine_For_Block_Bodied_Reflection_Tests()
{
var method = typeof(TestNodeLocationTests).GetMethod(
nameof(SourceLocationResolver_Finds_EndLine_For_Block_Bodied_Reflection_Tests))!;

var location = SourceLocationResolver.Resolve(method);
var lines = File.ReadAllLines(location.FilePath);
var snippet = string.Join('\n', lines.Skip(location.LineNumber - 1).Take(location.EndLineNumber - location.LineNumber + 1));

lines[location.LineNumber - 1].Trim().ShouldBe("[Test]");
location.EndLineNumber.ShouldBeGreaterThan(location.LineNumber);
snippet.ShouldContain("SourceLocationResolver.Resolve(method);");
}

[Test]
public Task SourceLocationResolver_Finds_EndLine_For_Expression_Bodied_Reflection_Tests()
=> AssertExpressionBodySourceLocationAsync();

private static TestContext CreateTestContext(
string testId,
string filePath,
Expand Down Expand Up @@ -138,6 +158,21 @@ private static TestContext CreateTestContext(
return context;
}

private static Task AssertExpressionBodySourceLocationAsync()
{
var method = typeof(TestNodeLocationTests).GetMethod(
nameof(SourceLocationResolver_Finds_EndLine_For_Expression_Bodied_Reflection_Tests))!;

var location = SourceLocationResolver.Resolve(method);
var lines = File.ReadAllLines(location.FilePath);

lines[location.LineNumber - 1].Trim().ShouldBe("[Test]");
location.EndLineNumber.ShouldBeGreaterThan(location.LineNumber);
lines[location.EndLineNumber - 1].ShouldContain("AssertExpressionBodySourceLocationAsync();");

return Task.CompletedTask;
}

private sealed class EmptyServiceProvider : IServiceProvider
{
public static EmptyServiceProvider Instance { get; } = new();
Expand Down
53 changes: 29 additions & 24 deletions TUnit.Engine/Discovery/ReflectionTestDataCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,8 @@ private static TestMetadata BuildTestMetadata(

try
{
var sourceLocation = SourceLocationResolver.Resolve(testMethod);

return new ReflectionTestMetadata(testClass, testMethod)
{
TestName = testName,
Expand All @@ -1054,8 +1056,11 @@ private static TestMetadata BuildTestMetadata(
PropertyDataSources = ReflectionAttributeExtractor.ExtractPropertyDataSources(testClass),
InstanceFactory = CreateInstanceFactory(testClass)!,
TestInvoker = CreateTestInvoker(testClass, testMethod),
FilePath = ExtractFilePath(testMethod) ?? "Unknown",
LineNumber = ExtractLineNumber(testMethod) ?? 0,
FilePath = sourceLocation.FilePath,
LineNumber = sourceLocation.LineNumber,
StartColumnNumber = sourceLocation.StartColumnNumber,
EndLineNumber = sourceLocation.EndLineNumber,
EndColumnNumber = sourceLocation.EndColumnNumber,
MethodMetadata = ReflectionMetadataBuilder.CreateMethodMetadata(testClass, testMethod),
GenericTypeInfo = ReflectionGenericTypeResolver.ExtractGenericTypeInfo(typeForGenericResolution),
GenericMethodInfo = ReflectionGenericTypeResolver.ExtractGenericMethodInfo(testMethod),
Expand Down Expand Up @@ -1314,14 +1319,18 @@ private static TestMetadata CreateFailedMethodGenericMetadata(
var testName = $"[GENERIC METHOD RESOLUTION FAILED] {type.FullName}.{method.Name}";
var displayName = $"{testName} - {errorMessage}";
var exception = new InvalidOperationException(errorMessage);
var sourceLocation = SourceLocationResolver.Resolve(method);

return new FailedTestMetadata(exception, displayName)
{
TestName = testName,
TestClassType = type,
TestMethodName = method.Name,
FilePath = ExtractFilePath(method) ?? "Unknown",
LineNumber = ExtractLineNumber(method) ?? 0,
FilePath = sourceLocation.FilePath,
LineNumber = sourceLocation.LineNumber,
StartColumnNumber = sourceLocation.StartColumnNumber,
EndLineNumber = sourceLocation.EndLineNumber,
EndColumnNumber = sourceLocation.EndColumnNumber,
MethodMetadata = ReflectionMetadataBuilder.CreateMethodMetadata(type, method),
AttributeFactory = () => method.GetCustomAttributes().ToArray(),
DataSources = [],
Expand All @@ -1330,16 +1339,6 @@ private static TestMetadata CreateFailedMethodGenericMetadata(
};
}

private static string? ExtractFilePath(MethodInfo method)
{
return method.GetCustomAttribute<TestAttribute>()?.File;
}

private static int? ExtractLineNumber(MethodInfo method)
{
return method.GetCustomAttribute<TestAttribute>()?.Line;
}

private static TestMetadata CreateFailedTestMetadataForAssembly(Assembly assembly, Exception ex)
{
var testName = $"[ASSEMBLY SCAN FAILED] {assembly.GetName().Name}";
Expand Down Expand Up @@ -1379,15 +1378,19 @@ private static TestMetadata CreateFailedTestMetadata(
{
var testName = $"[DISCOVERY FAILED] {type.FullName}.{method.Name}";
var displayName = $"{testName} - {ex.Message}";
var sourceLocation = SourceLocationResolver.Resolve(method);

// Create a special metadata that will yield a failed data combination
return new FailedTestMetadata(ex, displayName)
{
TestName = testName,
TestClassType = type,
TestMethodName = method.Name,
FilePath = ExtractFilePath(method) ?? "Unknown",
LineNumber = ExtractLineNumber(method) ?? 0,
FilePath = sourceLocation.FilePath,
LineNumber = sourceLocation.LineNumber,
StartColumnNumber = sourceLocation.StartColumnNumber,
EndLineNumber = sourceLocation.EndLineNumber,
EndColumnNumber = sourceLocation.EndColumnNumber,
MethodMetadata = ReflectionMetadataBuilder.CreateMethodMetadata(type, method),
AttributeFactory = () => method.GetCustomAttributes()
.ToArray(),
Expand Down Expand Up @@ -2071,11 +2074,10 @@ private async Task<List<TestMetadata>> ExecuteDynamicTestBuilder(Type testClass,
var dynamicTests = new List<TestMetadata>(50);

// Extract file path and line number from the DynamicTestBuilderAttribute if possible
var filePath = ExtractFilePath(builderMethod) ?? "Unknown";
var lineNumber = ExtractLineNumber(builderMethod) ?? 0;
var sourceLocation = SourceLocationResolver.Resolve(builderMethod);

// Create context
var context = new DynamicTestBuilderContext(filePath, lineNumber);
var context = new DynamicTestBuilderContext(sourceLocation.FilePath, sourceLocation.LineNumber);

// Create instance if needed
object? instance = null;
Expand Down Expand Up @@ -2123,11 +2125,10 @@ private async IAsyncEnumerable<TestMetadata> ExecuteDynamicTestBuilderStreamingA
try
{
// Extract file path and line number from the DynamicTestBuilderAttribute if possible
var filePath = ExtractFilePath(builderMethod) ?? "Unknown";
var lineNumber = ExtractLineNumber(builderMethod) ?? 0;
var sourceLocation = SourceLocationResolver.Resolve(builderMethod);

// Create context
var context = new DynamicTestBuilderContext(filePath, lineNumber);
var context = new DynamicTestBuilderContext(sourceLocation.FilePath, sourceLocation.LineNumber);

// Create instance if needed
object? instance = null;
Expand Down Expand Up @@ -2330,14 +2331,18 @@ private static TestMetadata CreateFailedTestMetadataForDynamicBuilder(
{
var testName = $"[DYNAMIC BUILDER FAILED] {type.FullName}.{method.Name}";
var displayName = $"{testName} - {ex.Message}";
var sourceLocation = SourceLocationResolver.Resolve(method);

return new FailedTestMetadata(ex, displayName)
{
TestName = testName,
TestClassType = type,
TestMethodName = method.Name,
FilePath = ExtractFilePath(method) ?? "Unknown",
LineNumber = ExtractLineNumber(method) ?? 0,
FilePath = sourceLocation.FilePath,
LineNumber = sourceLocation.LineNumber,
StartColumnNumber = sourceLocation.StartColumnNumber,
EndLineNumber = sourceLocation.EndLineNumber,
EndColumnNumber = sourceLocation.EndColumnNumber,
MethodMetadata = ReflectionMetadataBuilder.CreateMethodMetadata(type, method),
AttributeFactory = () => method.GetCustomAttributes().ToArray(),
DataSources = [],
Expand Down
Loading
Loading