Skip to content
Merged
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
9 changes: 8 additions & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,11 @@ jobs:
run: dotnet build -p:ContinuousIntegrationBuild=True --no-restore --configuration Release

- name: Test
run: dotnet test --no-build --configuration Release --verbosity normal
run: dotnet test --no-build --configuration Release --verbosity normal

- name: AOT Publish Validation
run: |
$rid = if ($env:RUNNER_OS -eq 'Windows') { 'win-x64' } else { 'linux-x64' }
dotnet publish TrxLib.AotSample/TrxLib.AotSample.csproj -r $rid -c Release --self-contained
$ext = if ($env:RUNNER_OS -eq 'Windows') { '.exe' } else { '' }
& "TrxLib.AotSample/bin/Release/net10.0/$rid/publish/TrxLib.AotSample$ext"
20 changes: 20 additions & 0 deletions TrxLib.AotSample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using TrxLib;

var sampleRoot = Path.Combine(AppContext.BaseDirectory, "SampleTrxFiles");
if (!Directory.Exists(sampleRoot))
throw new DirectoryNotFoundException($"Sample TRX directory not found: {sampleRoot}");

var sampleFiles = Directory
.EnumerateFiles(sampleRoot, "*.trx", SearchOption.AllDirectories)
.OrderBy(path => path, StringComparer.Ordinal)
.ToArray();

if (sampleFiles.Length == 0)
throw new InvalidOperationException($"No TRX sample files found under: {sampleRoot}");

foreach (var file in sampleFiles)
{
_ = TrxParser.Parse(new FileInfo(file));
}

Console.WriteLine($"TrxLib AOT validation passed. Parsed {sampleFiles.Length} sample files.");
22 changes: 22 additions & 0 deletions TrxLib.AotSample/TrxLib.AotSample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<PublishAot>true</PublishAot>
<IsPublishable>true</IsPublishable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\TrxLib\TrxLib.csproj" />
</ItemGroup>

<ItemGroup>
<Content Include="..\TrxLib.Tests\SampleTrxFiles\**\*.trx"
Link="SampleTrxFiles\%(RecursiveDir)%(Filename)%(Extension)"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>

</Project>
46 changes: 46 additions & 0 deletions TrxLib.Tests/SampleTrxFiles/theory-tests.trx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<TestRun id="e70a511e-0bfb-420b-8259-d0a72fdba1a0" name="benja@BAM-Z690 2026-05-16 21:39:55" runUser="BAM-Z690\benja" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Times creation="2026-05-16T21:39:55.3918046-07:00" queuing="2026-05-16T21:39:55.3918050-07:00" start="2026-05-16T21:39:54.5463544-07:00" finish="2026-05-16T21:39:55.3962459-07:00" />
<TestSettings name="default" id="e738a127-b106-49cf-8a3d-f73e3c609f43">
<Deployment runDeploymentRoot="benja_BAM-Z690_2026-05-16_21_39_55" />
</TestSettings>
<Results>
<UnitTestResult executionId="d29a42b5-85e5-4de5-8485-488b36990291" testId="69bf1a74-6bd3-1b8d-520d-c9801d194c51" testName="Acme.Tests.MathTests.AddNumbers(left: 1, right: 2)" computerName="BAM-Z690" duration="00:00:00.0002264" startTime="2026-05-16T21:39:55.2985338-07:00" endTime="2026-05-16T21:39:55.2989500-07:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="d29a42b5-85e5-4de5-8485-488b36990291" />
<UnitTestResult executionId="a1fa9069-44cf-41cb-96c9-11f88e879548" testId="718be9ec-e1ee-2f03-4dd6-5b464b52a593" testName="Acme.Tests.MathTests.AddNumbers(left: 0, right: 0)" computerName="BAM-Z690" duration="00:00:00.0175485" startTime="2026-05-16T21:39:55.2666361-07:00" endTime="2026-05-16T21:39:55.2903128-07:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="a1fa9069-44cf-41cb-96c9-11f88e879548" />
<UnitTestResult executionId="003fc356-5ae3-4120-a0e8-8ca8ff6d9caa" testId="2f0a2807-568e-bacb-3945-4a25878eaf48" testName="Acme.Tests.MathTests.PlainTest" computerName="BAM-Z690" duration="00:00:00.0010569" startTime="2026-05-16T21:39:55.2999872-07:00" endTime="2026-05-16T21:39:55.3000209-07:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="003fc356-5ae3-4120-a0e8-8ca8ff6d9caa" />
</Results>
<TestDefinitions>
<UnitTest name="Acme.Tests.MathTests.AddNumbers(left: 0, right: 0)" storage="d:\trxlib\trxlib.tests\bin\debug\net10.0\trxlib.tests.dll" id="718be9ec-e1ee-2f03-4dd6-5b464b52a593">
<Execution id="a1fa9069-44cf-41cb-96c9-11f88e879548" />
<TestMethod codeBase="D:\TrxLib\TrxLib.Tests\bin\Debug\net10.0\TrxLib.Tests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="Acme.Tests.MathTests" name="AddNumbers" />
</UnitTest>
<UnitTest name="Acme.Tests.MathTests.PlainTest" storage="d:\trxlib\trxlib.tests\bin\debug\net10.0\trxlib.tests.dll" id="2f0a2807-568e-bacb-3945-4a25878eaf48">
<Execution id="003fc356-5ae3-4120-a0e8-8ca8ff6d9caa" />
<TestMethod codeBase="D:\TrxLib\TrxLib.Tests\bin\Debug\net10.0\TrxLib.Tests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="Acme.Tests.MathTests" name="PlainTest" />
</UnitTest>
<UnitTest name="Acme.Tests.MathTests.AddNumbers(left: 1, right: 2)" storage="d:\trxlib\trxlib.tests\bin\debug\net10.0\trxlib.tests.dll" id="69bf1a74-6bd3-1b8d-520d-c9801d194c51">
<Execution id="d29a42b5-85e5-4de5-8485-488b36990291" />
<TestMethod codeBase="D:\TrxLib\TrxLib.Tests\bin\Debug\net10.0\TrxLib.Tests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="Acme.Tests.MathTests" name="AddNumbers" />
</UnitTest>
</TestDefinitions>
<TestEntries>
<TestEntry testId="69bf1a74-6bd3-1b8d-520d-c9801d194c51" executionId="d29a42b5-85e5-4de5-8485-488b36990291" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="718be9ec-e1ee-2f03-4dd6-5b464b52a593" executionId="a1fa9069-44cf-41cb-96c9-11f88e879548" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="2f0a2807-568e-bacb-3945-4a25878eaf48" executionId="003fc356-5ae3-4120-a0e8-8ca8ff6d9caa" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
</TestEntries>
<TestLists>
<TestList name="Results Not in a List" id="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestList name="All Loaded Results" id="19431567-8539-422a-85d7-44ee4e166bda" />
</TestLists>
<ResultSummary outcome="Completed">
<Counters total="3" executed="3" passed="3" failed="0" error="0" timeout="0" aborted="0" inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" disconnected="0" warning="0" completed="0" inProgress="0" pending="0" />
<Output>
<StdOut>[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.8)&#xD;
[xUnit.net 00:00:00.08] Discovering: TrxLib.Tests&#xD;
[xUnit.net 00:00:00.13] Discovered: TrxLib.Tests&#xD;
[xUnit.net 00:00:00.15] Starting: TrxLib.Tests&#xD;
[xUnit.net 00:00:00.20] Finished: TrxLib.Tests&#xD;
</StdOut>
</Output>
</ResultSummary>
</TestRun>
30 changes: 29 additions & 1 deletion TrxLib.Tests/TrxParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,34 @@ private static bool NotWindows()
return !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
}

[Fact]
public void Parse_TheoryTestsTrx_AppendsSuffixToFqtnForParameterizedTests()
{
var results = TrxParser.Parse(new FileInfo(GetSampleFilePath("theory-tests.trx")));
results.Select(r => r.FullyQualifiedTestName)
.Should()
.Contain("Acme.Tests.MathTests.AddNumbers(left: 1, right: 2)");
results.Select(r => r.FullyQualifiedTestName)
.Should()
.Contain("Acme.Tests.MathTests.AddNumbers(left: 0, right: 0)");
}

[Fact]
public void Parse_TheoryTestsTrx_DoesNotAppendSuffixForNonParameterizedTest()
{
var results = TrxParser.Parse(new FileInfo(GetSampleFilePath("theory-tests.trx")));
results.Single(r => r.FullyQualifiedTestName == "Acme.Tests.MathTests.PlainTest")
.Should().NotBeNull();
}

[Fact]
public void Parse_TheoryTestsTrx_ParsesAllThreeTestResults()
{
var results = TrxParser.Parse(new FileInfo(GetSampleFilePath("theory-tests.trx")));
results.Should().HaveCount(3);
results.Count(r => r.Outcome == TestOutcome.Passed).Should().Be(3);
}

[ConditionalFact(nameof(NotWindows))]
public void Parse_Example1OSXTrx_ParsesCodebaseCorrectly()
{
Expand Down Expand Up @@ -355,4 +383,4 @@ public void Parse_Example1OSXTrx_ParsesFinishTimeCorrectly()
var results = TrxParser.Parse(new FileInfo(GetSampleFilePath(Path.Combine("1", "example1_OSX.trx"))));
results.CompletedTime.Should().Be(DateTimeOffset.Parse("2017-01-17T10:39:57.1294340-08:00"));
}
}
}
1 change: 1 addition & 0 deletions TrxLib.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<File Path="NuGet.config" />
<File Path="README.md" />
</Folder>
<Project Path="TrxLib.AotSample/TrxLib.AotSample.csproj" />
<Project Path="TrxLib.Tests/TrxLib.Tests.csproj" />
<Project Path="TrxLib/TrxLib.csproj" />
</Solution>
33 changes: 7 additions & 26 deletions TrxLib/Counters.cs
Original file line number Diff line number Diff line change
@@ -1,74 +1,55 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
/// Represents the test result counters from the ResultSummary element of a TRX file.
/// Contains the authoritative vstest-computed counts for each outcome category.
/// Represents the vstest-authoritative test run counters from the ResultSummary element.
/// </summary>
public class Counters
{
/// <summary>Gets or sets the total number of tests.</summary>
[XmlAttribute("total")]
public int Total { get; set; }

/// <summary>Gets or sets the number of tests that were executed.</summary>
[XmlAttribute("executed")]
public int Executed { get; set; }

/// <summary>Gets or sets the number of tests that passed.</summary>
[XmlAttribute("passed")]
public int Passed { get; set; }

/// <summary>Gets or sets the number of tests that failed.</summary>
[XmlAttribute("failed")]
public int Failed { get; set; }

/// <summary>Gets or sets the number of tests that encountered a system error.</summary>
[XmlAttribute("error")]
/// <summary>Gets or sets the number of tests that produced an error.</summary>
public int Error { get; set; }

/// <summary>Gets or sets the number of tests that timed out.</summary>
[XmlAttribute("timeout")]
public int Timeout { get; set; }

/// <summary>Gets or sets the number of tests that were aborted.</summary>
[XmlAttribute("aborted")]
public int Aborted { get; set; }

/// <summary>Gets or sets the number of tests with inconclusive results.</summary>
[XmlAttribute("inconclusive")]
/// <summary>Gets or sets the number of tests that were inconclusive.</summary>
public int Inconclusive { get; set; }

/// <summary>Gets or sets the number of tests that passed but the run was aborted.</summary>
[XmlAttribute("passedButRunAborted")]
public int PassedButRunAborted { get; set; }

/// <summary>Gets or sets the number of tests that were not runnable.</summary>
[XmlAttribute("notRunnable")]
public int NotRunnable { get; set; }

/// <summary>Gets or sets the number of tests that were not executed.</summary>
[XmlAttribute("notExecuted")]
public int NotExecuted { get; set; }

/// <summary>Gets or sets the number of tests that were disconnected.</summary>
[XmlAttribute("disconnected")]
/// <summary>Gets or sets the number of disconnected tests.</summary>
public int Disconnected { get; set; }

/// <summary>Gets or sets the number of tests with a warning outcome.</summary>
[XmlAttribute("warning")]
/// <summary>Gets or sets the number of tests that produced warnings.</summary>
public int Warning { get; set; }

/// <summary>Gets or sets the number of completed tests.</summary>
[XmlAttribute("completed")]
public int Completed { get; set; }

/// <summary>Gets or sets the number of tests currently in progress.</summary>
[XmlAttribute("inProgress")]
/// <summary>Gets or sets the number of tests in progress.</summary>
public int InProgress { get; set; }

/// <summary>Gets or sets the number of tests that are pending.</summary>
[XmlAttribute("pending")]
/// <summary>Gets or sets the number of pending tests.</summary>
public int Pending { get; set; }
}
3 changes: 0 additions & 3 deletions TrxLib/Deployment.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
Expand All @@ -11,6 +9,5 @@ public class Deployment
/// <summary>
/// Gets or sets the root directory path where test run files are deployed.
/// </summary>
[XmlAttribute("runDeploymentRoot")]
public string? RunDeploymentRoot { get; set; }
}
4 changes: 0 additions & 4 deletions TrxLib/ErrorInfo.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
Expand All @@ -11,13 +9,11 @@ public class ErrorInfo
/// <summary>
/// Gets or sets the error message describing why the test failed.
/// </summary>
[XmlElement("Message")]
public string? Message { get; set; }

/// <summary>
/// Gets or sets the stack trace information from the test failure.
/// Contains the call stack at the point of the exception that caused the test to fail.
/// </summary>
[XmlElement("StackTrace")]
public string? StackTrace { get; set; }
}
10 changes: 3 additions & 7 deletions TrxLib/Execution.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
/// Represents the execution element of a unit test definition in a TRX file.
/// Contains the execution ID that links a test definition to its result.
/// Represents the Execution element inside a UnitTest definition.
/// Links the test definition to its execution record and result.
/// </summary>
public class Execution
{
/// <summary>
/// Gets or sets the execution identifier. Links this test definition to the
/// corresponding UnitTestResult via its executionId attribute.
/// Gets or sets the execution identifier.
/// </summary>
[XmlAttribute("id")]
public string? Id { get; set; }
}
4 changes: 0 additions & 4 deletions TrxLib/Output.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
Expand All @@ -12,12 +10,10 @@ public class Output
/// Gets or sets the error information if the test failed.
/// Contains the error message and stack trace details.
/// </summary>
[XmlElement("ErrorInfo")]
public ErrorInfo? ErrorInfo { get; set; }

/// <summary>
/// Gets or sets the standard output text captured during test execution.
/// </summary>
[XmlElement("StdOut")]
public string? StdOut { get; set; }
}
15 changes: 5 additions & 10 deletions TrxLib/ResultSummary.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
/// Represents the ResultSummary element of a TRX file.
/// Contains the overall run outcome, authoritative vstest-computed counters, and run-level output.
/// Represents the ResultSummary element of a TRX file, containing the overall
/// outcome and vstest-authoritative test counters for the run.
/// </summary>
public class ResultSummary
{
/// <summary>
/// Gets or sets the overall outcome of the test run (e.g. "Passed", "Failed", "Completed").
/// Gets or sets the overall outcome of the test run (e.g., "Passed", "Failed").
/// </summary>
[XmlAttribute("outcome")]
public string? Outcome { get; set; }

/// <summary>
/// Gets or sets the test result counters for the run.
/// Gets or sets the authoritative test counters computed by vstest.
/// </summary>
[XmlElement("Counters")]
public Counters? Counters { get; set; }

/// <summary>
/// Gets or sets the run-level output (e.g. run-level stdout written by the test host).
/// Gets or sets the run-level output (e.g., stdout from the test host).
/// </summary>
[XmlElement("Output")]
public Output? Output { get; set; }
}
3 changes: 0 additions & 3 deletions TrxLib/Results.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
Expand All @@ -11,6 +9,5 @@ public class Results
/// <summary>
/// Gets or sets the list of unit test results from the test run.
/// </summary>
[XmlElement("UnitTestResult")]
public List<UnitTestResult>? UnitTestResults { get; set; }
}
3 changes: 0 additions & 3 deletions TrxLib/TestDefinitions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
Expand All @@ -11,6 +9,5 @@ public class TestDefinitions
/// <summary>
/// Gets or sets the list of unit test definitions.
/// </summary>
[XmlElement("UnitTest")]
public List<UnitTest>? UnitTests { get; set; }
}
8 changes: 2 additions & 6 deletions TrxLib/TestEntries.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
using System.Xml.Serialization;

namespace TrxLib;

/// <summary>
/// Represents the TestEntries element of a TRX file.
/// Contains the execution index linking test IDs to execution IDs and test list categories.
/// Represents the TestEntries element, which indexes test definitions to their execution records.
/// </summary>
public class TestEntries
{
/// <summary>Gets or sets the individual test entry records.</summary>
[XmlElement("TestEntry")]
/// <summary>Gets or sets the collection of test entry records.</summary>
public List<TestEntry>? Items { get; set; }
}
Loading
Loading