Skip to content

Add Microsoft.Testing.Extensions.CtrfReport extension (CTRF reporter)#8903

Open
Evangelink wants to merge 11 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/ctrf-report-extension
Open

Add Microsoft.Testing.Extensions.CtrfReport extension (CTRF reporter)#8903
Evangelink wants to merge 11 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/ctrf-report-extension

Conversation

@Evangelink
Copy link
Copy Markdown
Member

@Evangelink Evangelink commented Jun 7, 2026

What

Adds a new MTP extension Microsoft.Testing.Extensions.CtrfReport that emits a CTRF (Common Test Report Format) JSON file at the end of a test session. This is the discussion outcome of #8858 — opening a draft so we can iterate.

CTRF is a vendor-neutral JSON schema for test results (spec v0.0.0) that is gaining adoption (xUnit, Jest, Mocha, Cypress, Playwright, Pytest, RSpec, JUnit, and others all have CTRF reporters). Supporting it natively in MTP lets users plug their results into the same dashboards/integrations regardless of the test framework.

CLI surface

  • --report-ctrf — enables generation.
  • --report-ctrf-filename <name.json> — optional file name (defaults to {user}_{machine}_{module}_{tfm}_{timestamp}.ctrf.json).

Validation mirrors the existing HtmlReport/TrxReport extensions:

  • file extension must be .json
  • relative paths must stay under the results directory
  • requires --report-ctrf when filename is set
  • not allowed together with --list-tests

How it maps to CTRF

Top-level: reportFormat: "CTRF", specVersion: "0.0.0", random reportId, ISO 8601 timestamp, generatedBy: "Microsoft.Testing.Extensions.CtrfReport@<ver>".

results:

  • tool: { name, version } from ITestFramework
  • summary: tests/passed/failed/skipped/pending/other/flaky/start/stop/duration (counts unique UIDs)
  • tests[]: one entry per unique test UID. Re-runs of the same UID collapse into a single entry with retries: N, retryAttempts[], and flaky: true when the final attempt passes after earlier failures.
  • environment: osPlatform, osVersion, and extra.{user,machine,exitCode,testApplication}

Status mapping (CTRF enum: passed/failed/skipped/pending/other):

  • Passed → passed
  • Skipped → skipped
  • Failed / Error / Timeout → failed (rawStatus top-level field preserves the original where it differs)
  • Cancelled → other

JSON is written via Utf8JsonWriter with the default safe encoder (escapes <, >, &, ', ") so the report is safe to embed in HTML/JS dashboards.

Tests

  • Unit tests (test/UnitTests/Microsoft.Testing.Extensions.UnitTests): 35 tests covering CLI option validation, JSON shape, retry collapsing, empty-results handling, name fallback, status mapping, and XSS-safe escaping.
  • Acceptance tests (test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/CtrfReportTests.cs): end-to-end (file generated, valid JSON, CLI options).
  • Help/info expectations (HelpInfoAllExtensionsTests.cs) and MSBuild known-extension registration (MSBuild.KnownExtensionRegistration.cs) updated.

Validation against the CTRF schema

The generated reports validate against ctrf.schema.json. I also ran a side-by-side comparison against the most popular xUnit CTRF reporter (DotnetCtrfJsonReporter, ~650k NuGet downloads) on matching test suites — full notes in the session artifacts. TL;DR:

MTP (this PR) xUnit (DotnetCtrfJsonReporter)
Schema-valid ❌ (emits suite as string; spec requires array)
skipped correctly reported ❌ (rounds to status: "other", summary.skipped: 0)
summary.duration
summary.flaky aggregate
environment block
Retry collapsing / retryAttempts[]
Theory cases Name (1,1,2) Name(a: 1, b: 1, expected: 2)

Closes (or follows up on) #8858.

cc @bradwilson (xUnit, CTRF contributor) for visibility per the discussion thread.

Evangelink and others added 2 commits June 7, 2026 10:31
Adds a new MTP extension that emits a CTRF (Common Test Report Format, https://ctrf.io) JSON file at the end of a test session, mirroring the layout of Microsoft.Testing.Extensions.HtmlReport.

CLI options:

- --report-ctrf: enables generation

- --report-ctrf-filename <name.json>: optional file name (default: {user}_{machine}_{module}_{tfm}_{timestamp}.ctrf.json)

Refs microsoft#8858.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… fallback

Apply spec/expert-review fixes to the CTRF report extension:

* Collapse same-UID captures into a single tests[] entry with
  retryAttempts[]; set retries=N-1 and flaky=true when the final
  attempt passed after earlier failures (CTRF retry idiom).
* Update summary.tests to count unique UIDs (and add summary.flaky)
  so CTRF aggregators no longer double-count retries.
* Drop UnsafeRelaxedJsonEscaping: HTML/JS metachars in test names
  could become XSS vectors in downstream CTRF dashboards.
* Cap WriteWithRetryAsync attempts at 1000 in addition to the
  existing 5s wall-clock bound.
* Fall back to UID when DisplayName is empty so tests[].name keeps
  the schema-required minLength: 1.
* Add unit tests for the collapsed retry shape, empty result set,
  HTML-escaping behavior, and DisplayName -> UID fallback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 7, 2026 08:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Microsoft.Testing.Platform (MTP) report extension, Microsoft.Testing.Extensions.CtrfReport, to emit test results in CTRF (Common Test Report Format) JSON at the end of a test session, including CLI integration and end-to-end coverage in unit + acceptance tests.

Changes:

  • Introduces the new Microsoft.Testing.Extensions.CtrfReport extension project (engine, command line provider, generator, MSBuild hook, packaging metadata, localization resources).
  • Adds unit tests validating CLI validation, CTRF JSON structure/aggregation, retry collapsing/flaky detection, and HTML/JS-safe JSON escaping.
  • Updates acceptance tests + help/info expectations + MSBuild known-extension registration to include the new CTRF extension and CLI options.
Show a summary per file
File Description
TestFx.slnx Adds the CTRF report extension project to the main solution.
NonWindowsTests.slnf Includes the CTRF report extension in the non-Windows solution filter.
Microsoft.Testing.Platform.slnf Includes the CTRF report extension in the platform solution filter.
src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj Grants InternalsVisibleTo access for the new CTRF extension.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Microsoft.Testing.Extensions.CtrfReport.csproj New extension project definition and packaging layout.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/PACKAGE.md NuGet package documentation for CTRF report extension.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/BannedSymbols.txt Enforces platform conventions (IClock/RoslynString/etc.) for the new project.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/PublicAPI/PublicAPI.Shipped.txt Initializes shipped API surface tracking for the new package.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/PublicAPI/PublicAPI.Unshipped.txt Declares newly introduced public APIs for the CTRF extension package.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/TestingPlatformBuilderHook.cs MSBuild hook entry point to register the CTRF extension into the builder.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/CtrfReportExtensions.cs Public extension method (AddCtrfReportProvider) for registering CTRF reporting.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/CtrfReportGeneratorCommandLine.cs Implements --report-ctrf and --report-ctrf-filename options + validation.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/CtrfReportGenerator.cs Captures test node updates and publishes CTRF JSON report as a session artifact.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs Projects terminal test node updates into bounded DTOs for reporting.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/CapturedTestResult.cs Defines the captured test result DTO used by the CTRF engine.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/CtrfReportEngine.cs Generates CTRF JSON (summary, environment, collapsed retries/flaky) and writes report file.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/buildMultiTargeting/Microsoft.Testing.Extensions.CtrfReport.props Declares the well-known MSBuild extension hook metadata.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/buildTransitive/Microsoft.Testing.Extensions.CtrfReport.props Adds transitive build import for the extension hook.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/build/Microsoft.Testing.Extensions.CtrfReport.props Adds build-time import for the extension hook.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/ExtensionResources.resx Adds localizable strings for CLI validation and artifact metadata.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.cs.xlf Adds localization XLF for cs.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.de.xlf Adds localization XLF for de.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.es.xlf Adds localization XLF for es.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.fr.xlf Adds localization XLF for fr.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.it.xlf Adds localization XLF for it.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.ja.xlf Adds localization XLF for ja.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.ko.xlf Adds localization XLF for ko.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.pl.xlf Adds localization XLF for pl.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.pt-BR.xlf Adds localization XLF for pt-BR.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.ru.xlf Adds localization XLF for ru.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.tr.xlf Adds localization XLF for tr.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.zh-Hans.xlf Adds localization XLF for zh-Hans.
src/Platform/Microsoft.Testing.Extensions.CtrfReport/Resources/xlf/ExtensionResources.zh-Hant.xlf Adds localization XLF for zh-Hant.
test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Microsoft.Testing.Extensions.UnitTests.csproj References the new CTRF extension project for unit testing.
test/UnitTests/Microsoft.Testing.Extensions.UnitTests/CtrfReportGeneratorCommandLineTests.cs Adds unit tests for CTRF CLI option validation behavior.
test/UnitTests/Microsoft.Testing.Extensions.UnitTests/CtrfReportEngineTests.cs Adds unit tests for CTRF JSON generation, collapsing retries, and environment/test shape.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/CtrfReportTests.cs Adds end-to-end acceptance tests for CTRF file generation and JSON shape.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.cs Updates help/info expectations to document CTRF CLI options and provider info.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/MSBuild.KnownExtensionRegistration.cs Ensures the CTRF extension is registered/visible via MSBuild known-extension wiring.

Copilot's findings

  • Files reviewed: 39/39 changed files
  • Comments generated: 1

@bradwilson
Copy link
Copy Markdown

Would it be useful to use this with an xUnit.net test project and compare the results against our built-in report as well? I'd be curious to know if/where we diverge.

@bradwilson
Copy link
Copy Markdown

One of the things that makes me wonder about this is, for example, how our TRX reports diverge. I'm thinking less about the current display bug in VS, and more about the fact that we have more information than MTP has (like, knowing about explicit tests), so knowing if (a) our commonalities all end up the same in CTRF, and (b) how the metadata differences manifest.

@Evangelink
Copy link
Copy Markdown
Member Author

Makes total sense to me, I'll post project and diffs for us to analyze. I still need to work out what to do with explicit case (I know this is long overdue).

@bradwilson
Copy link
Copy Markdown

bradwilson commented Jun 7, 2026

Some diffs I can see comparing against xUnit.net's built-in CTRF:

  1. We write computer name to /results/extra/computer, you write to /results/extra/machine
  2. We write the OS version to /results/environment/osRelease, you write to /results/environment/osVersion
  3. As expected, we count un-run explicit tests in /results/summary/pending, you count them in /results/summary/skipped
  4. You are (illegally) placing traits inside /results/tests/[]/labels, which does not appear to be part of the spec for Test Object; we are placing them inside /results/tests/[]/extra/traits. Additionally, we are also placing any trait named Category into /results/tests/[]/tags. Would be curious to know where this lands on your side, since "trait" is a pretty xUnit.net-centric name.
  5. For all tests, we write the CLR test class name to /results/tests/[]/extra/type, you only appear to write this into the array at /results/tests/[]/suite/[] (and it appears that you're writing Name rather than FullName, which would presumably group tests together which are in the types with the same Name but different Namespace). Our suite value seems incorrect, since the spec says this should be a string array, not a string. (I don't know if this changed in the spec or I just output the wrong thing...)
  6. For all tests, you write start and stop timestamps to /results/tests/[], we do not
  7. For failed tests, we write the CLR exception type to /results/tests/[]/extra/exception, you write to /results/tests/[]/extra/exceptionType
  8. For unrun (explicit) tests, as expected we mark this in /results/tests/[]/status as pending, you mark it as skipped
  9. You place test output into /results/tests/[]/stdout/[], we place it in /results/tests/[]/extra/output. Interestingly, you don't appear to be splitting on newlines, so you always end up with a single string in the array; the spec is not 100% clear on what "lines of output" means, but it probably means splitting on newlines.
  10. We write warnings to /results/tests/[]/extra/warnings/[]. There is no mechanism today to report warnings to MTP.
  11. We write attachments to /results/tests/[]/attachments, you do not appear to log attachments.

On the whole, this looks very good to me. We seem be in 99% agreement where possible (we can't realistically expect you to identify explicit tests, for example). I think I exercised every feature of xUnit.net that should've caused something to show in CTRF, but I may have missed something.

From this, I see these changes I will make for xUnit.net 4.0:

  • Duplicate OS version into /results/environment/osVersion
  • Writing /results/tests/[]/suite/[] incorrectly
  • Writing /results/tests/[]/start and /results/tests/[]/stop
  • Writing /results/tests/[]/message for explicit tests to align with the output from MTP (helpful to the user)
  • Move /results/tests/[]/extra/output to /results/tests/[]/stdout/[] (using split lines)

I'll leave it for you to decide if the reconciliation of our extra property names is important.

@bradwilson
Copy link
Copy Markdown

All of the xUnit.net-side fixes are now available in v3 4.0.0-pre.139 https://xunit.net/docs/using-ci-builds

…omparison

Provides two MTP test apps that generate CTRF reports for the same set of
tests (pass / fail / skip / theory / throw) using two different generators:

- samples/CtrfPlayground/Mtp: MSTest + Microsoft.Testing.Extensions.CtrfReport
  (the experimental extension shipped by this repository)
- samples/CtrfPlayground/XunitMtp: xunit.v3 with its built-in '-ctrf <file>'
  reporter

This allows reviewers to diff the CTRF JSON produced by both stacks against
the same test fixtures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Copy link
Copy Markdown
Member Author

Follow-ups in 288620d (and the rawStatus thread reply):

  • Experimental marker: the public surface is already gated on TPEXP:

    • [Experimental(""TPEXP"", UrlFormat = ""https://aka.ms/testingplatform/diagnostics#{0}"")] on CtrfReportExtensions
    • [TPEXP] prefix in PublicAPI/PublicAPI.Unshipped.txt
    • > **⚠️ Experimental:** callout in PACKAGE.md

    This mirrors Microsoft.Testing.Extensions.HtmlReport exactly. The TestingPlatformBuilderHook class is intentionally not marked (same as HtmlReport).

  • Side-by-side comparison sample added under samples/CtrfPlayground/: two MTP test apps that exercise the same fixtures (pass / fail / skip / theory / throw) and produce a CTRF JSON each — one via this extension (MSTest), one via xunit.v3's built-in -ctrf reporter — so the two outputs can be diffed directly.

  • rawStatus: clarified on the open thread that rawStatus is a top-level test property in the CTRF schema, so the implementation is schema-correct. Updated the PR description wording (was incorrectly written as extra.rawStatus).

Match the versioning scheme used by other experimental Microsoft.Testing.Platform extensions (Logging, OpenTelemetry, AI). Packages will now ship as 1.0.0-alpha.* instead of the repo-default *-preview.*.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 8, 2026 08:45
@Evangelink
Copy link
Copy Markdown
Member Author

Also switched to the experimental alpha versioning scheme (with true), so the package now ships as 1.0.0-alpha.* like the other experimental MTP extensions (Logging, OpenTelemetry, AI) rather than the repo-default -preview.* label. Commit: f7aeac3

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 45/45 changed files
  • Comments generated: 1

Comment thread samples/CtrfPlayground/XunitMtp/XunitMtp.csproj Outdated
Copilot AI added 2 commits June 8, 2026 11:43
Replace structural contains-style assertions with a verbatim snapshot of the entire JSON document. Runtime-variable fields (GUID report id, ISO timestamp, epoch-ms times, extension version, OS info, user/machine, absolute test app path) are normalized via field-scoped regexes to deterministic tokens, while everything else (key order, indentation, conditional emission, dummy framework values) must match byte-for-byte.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After the CtrfReport package was moved to the experimental versioning scheme (1.0.0-alpha) it no longer matches the platform version requested by the acceptance test asset csproj. Introduce a dedicated MicrosoftTestingExtensionsCtrfReportVersion property on AcceptanceTestBase and a \\\$\ placeholder so the dummy app references the package at the version actually produced by the local pack. Also fix two pre-existing MSTEST0068 analyzer errors in CtrfReportEngineTests.cs that block packing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Copy link
Copy Markdown
Member Author

Follow-up commits on this branch:

  • 7aeac3ec — Apply the experimental versioning scheme (VersionPrefix=1.0.0, PreReleaseVersionLabel=alpha, SuppressFinalPackageVersion=true) to Microsoft.Testing.Extensions.CtrfReport.csproj.
  • 2a0fd39de — Convert the CTRF acceptance test from structural contains-style assertions to a verbatim full-content snapshot of the generated JSON. Runtime-variable fields (GUID report id, ISO timestamp, epoch-ms times, extension version, OS info, user/machine, absolute test app path) are folded into stable tokens via field-scoped regexes; everything else (key order, indentation, conditional emission, dummy framework values) must match byte-for-byte.
  • 4704b5421 — Plumb a dedicated MicrosoftTestingExtensionsCtrfReportVersion property/placeholder through AcceptanceTestBase so the asset csproj can reference the (now-experimental) CTRF package at the version actually produced by the local pack. Also fixes two pre-existing MSTEST0068 analyzer errors in CtrfReportEngineTests.cs that were blocking -pack.

All 15 CtrfReportTests pass locally against the new snapshot. Bumping for visibility cc @microsoft/testfx-maintainers.

- Correct the misleading comment in samples/CtrfPlayground/XunitMtp/XunitMtp.csproj: xunit.v3 exposes its built-in CTRF reporter via the `-ctrf <file>` switch, not a generic `report-ctrf` option.

- Switch the HelpInfoAllExtensionsTests asset csproj to the dedicated \\$ placeholder (the CTRF extension now follows the experimental versioning scheme and no longer matches \\$).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 8, 2026 11:45
@Evangelink
Copy link
Copy Markdown
Member Author

Follow-up commit on this branch:

  • 22d2f1d — Correct the misleading XunitMtp.csproj comment to mention xunit.v3's -ctrf <file> switch, and switch HelpInfoAllExtensionsTests to the dedicated \\$ placeholder so the test no longer requests the platform version.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 46/46 changed files
  • Comments generated: 1

Comment thread src/Platform/Microsoft.Testing.Extensions.CtrfReport/CtrfReportEngine.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 8, 2026 12:37
@Evangelink Evangelink marked this pull request as ready for review June 8, 2026 12:37
Comment thread samples/CtrfPlayground/XunitMtp/XunitMtp.csproj Outdated
Comment thread samples/CtrfPlayground/XunitMtp/XunitMtp.csproj Outdated
Co-authored-by: Amaury Levé <amauryleve@microsoft.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 46/46 changed files
  • Comments generated: 2

Comment on lines 103 to 106
<PackageReference Include="Microsoft.Testing.Extensions.AzureDevOpsReport" Version="$MicrosoftTestingPlatformVersion$" />
<PackageReference Include="Microsoft.Testing.Extensions.CrashDump" Version="$MicrosoftTestingPlatformVersion$" />
<PackageReference Include="Microsoft.Testing.Extensions.CtrfReport" Version="$MicrosoftTestingPlatformVersion$" />
<PackageReference Include="Microsoft.Testing.Extensions.HangDump" Version="$MicrosoftTestingPlatformVersion$" />
Copy link
Copy Markdown
Member Author

@Evangelink Evangelink Jun 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - both MSBuild.KnownExtensionRegistration.cs test methods (lines 22 and 106) were updated in a2bd24f to use $MicrosoftTestingExtensionsCtrfReportVersion$ (resolved via AcceptanceTestBase.MicrosoftTestingExtensionsCtrfReportVersion).

Comment on lines +31 to 33
testHostResult.AssertOutputContains("--report-ctrf");
testHostResult.AssertOutputContains("--report-html");
testHostResult.AssertOutputContains("--report-trx");
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - same fix landed in a2bd24f.

…acceptance test, expand snapshot, fix markdown lint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 8, 2026 13:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 47/47 changed files
  • Comments generated: 1

Comment on lines +99 to +102
// for the whole session. We never deduplicate on TestNode.Uid: some
// frameworks emit several distinct results sharing the same UID
// (parameterized rows, theory data, in-process retries). The engine
// surfaces all of them so no data is dropped.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - reworded the comment in 32fbbb4 to remove the misleading "never deduplicate" wording and explicitly point at CtrfReportEngine.CollapseAttempts, which collapses same-UID captures into retryAttempts[] (and sets flaky when an earlier attempt failed).

…und in CI

* Skip samples/CtrfPlayground/{Mtp,XunitMtp} under 'dotnet test -p:UsingDotNetTest=true' (the playground intentionally contains failing/throwing/skipped tests for diffing against xunit.v3 CTRF output). Mirrors the WasiPlayground pattern. Fixes the Windows/MacOS Debug Test CI failures.

* Split CTRF stdout/stderr into per-line array entries. The CTRF schema types these as 'lines of output'; we now split on LF (normalizing CRLF) and omit the trailing empty entry when input ends with a newline. Brad Wilson's xunit.v3 CTRF comparison item microsoft#9.

* Replace the misleading 'we never deduplicate on TestNode.Uid' wording in CtrfReportGenerator with a comment pointing at CtrfReportEngine.CollapseAttempts (which DOES collapse same-UID captures into retryAttempts[]).

Adds two unit tests for the new line-splitting behavior (CRLF normalization, trailing-newline handling, single-line output).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Copy link
Copy Markdown
Member Author

Thanks @bradwilson - really appreciate the detailed side-by-side, this was super helpful. Going through each item:

1. environment.extra.machine vs environment.extra.computer - Both are inside the freeform extra object (the spec marks environment as additionalProperties: false, so anything non-canonical has to live there), so they're both spec-compliant; the difference is purely naming. I'd rather not chase parity with the only other current MTP CTRF producer if it means churning consumers that already keyed off our shape. Happy to align if the CTRF folks bless a canonical name - I'll open an issue on ctrf-io for items 1/4/7 below.

2. osVersion vs osRelease - These are two different first-class fields in the spec (osRelease = release version, osVersion = version string). We emit osVersion. If your reader adds it too on the xunit side we'll both be good.

3. unrun-explicit-tests = pending - MTP doesn't surface an "explicit/pending" concept (a Skip attribute always lands as MTP's skipped state). Nothing to do here on our side without a platform change. If we want runtime-explicit semantics, that's a TestFramework concern.

4. labels vs extra.traits - I read the spec slightly differently here: labels is defined as "Structured key-value metadata for the test case (e.g. priority, severity, external identifiers)" typed as an object - which is exactly what MTP TestMetadataProperty traits are (key=value pairs). The "e.g." reads to me as non-exhaustive examples, not a restriction. I'd rather use the first-class spec slot than push them into extra. That said, this is one of the items I'll ask the CTRF maintainers about.

5. suite (array vs string) - We already emit it as an array of strings ([Namespace, ClassName]), so we should be schema-conformant. Whether to use Name or FullName is your decision on the xunit.v3 side.

6. start / stop per test - We already emit both. Glad you'll add them too - it'll make our outputs easier to diff.

7. extra.exception vs extra.exceptionType - Same situation as #1: both in extra, purely a naming choice. Our field is the .NET type name (e.g. System.InvalidOperationException); exceptionType felt more accurate than exception (which sounds like it should be the rendered exception object). Will include in the ctrf-io issue.

8. Same as #3 - no action.

9. stdout / stderr split into lines - You're right, the spec says "lines of output" and we were emitting a single multi-line string. Fixed in 32fbbb4: we now split on LF (normalizing CRLF, omitting the trailing empty entry from a trailing newline), with unit-test coverage for the boundary cases.

10. warnings - MTP doesn't expose a first-class "warnings" channel today. Not actionable from the extension; would need a platform-level addition.

11. attachments - MTP has FileArtifactProperty, so this is achievable - just out of scope for this initial PR. Will track as a follow-up.

So to summarize what I'm doing here vs deferring:

@Evangelink
Copy link
Copy Markdown
Member Author

Filed ctrf-io/ctrf#53 covering the naming and labels clarification questions (items 1, 4, 7) plus a follow-up on whether absent stdout/stderr should be [] or omitted.

@bradwilson
Copy link
Copy Markdown

I don't see labels in the spec: https://ctrf.io/docs/specification/test

In addition, your current implementation generates illegal JSON when a trait name has more than one value, because it emits the same name twice, like:

{
    "Name": "Value1",
    "Name": "Value2"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants