Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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