RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311) - #8461

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests
May 22, 2026
Merged

RFC 014 + impl: experimental TestRun.Current / PlannedTests API (#7311)#8461
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
dev/amauryleve/test-run-current-planned-tests

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented May 21, 2026

Copy link
Copy Markdown
Member

Adds an experimental ambient API for querying information about the current test run.

Closes#7311.

What

Three new [Experimental("MSTESTEXP")] types in Microsoft.VisualStudio.TestTools.UnitTesting (shipped via MSTest.TestFramework.Extensions):

  • static class TestRun with Current returning an ITestRunInfo (never null).
  • interface ITestRunInfo exposing IReadOnlyCollection<PlannedTest> PlannedTests.
  • sealed class PlannedTest — immutable DTO with the metadata needed to decide whether to run expensive setup: FullyQualifiedTestClassName, TestName, TestDisplayName, AssemblyPath, ManagedTypeName, ManagedMethodName, DeclaringFilePath, DeclaringLineNumber, TestCategories, TestProperties.

Adapter wiring: UnitTestRunner populates TestRun.SetCurrent(...) in its constructor, so the snapshot lives in the same AppDomain/process that runs [AssemblyInitialize] and the tests themselves (works for both the VSTest adapter path and the Microsoft.Testing.Platform path).

Why

The motivating use case from #7311: in [AssemblyInitialize], decide whether to perform expensive partial setup (e.g. build a compatibility solution, spin up a Docker container) based on whether any test matching a given criterion will actually run.

[AssemblyInitialize]publicstaticvoidInit(TestContext_){if(TestRun.Current.PlannedTests.Any(t =>t.TestCategories.Contains("Compatibility"))){BuildCompatibilitySolution();}}

Same call works from any helper / fixture / extension, not just lifecycle hooks.

Design notes

Full design rationale in docs/RFCs/014-TestRun-Current-PlannedTests.md (this PR). Highlights:

  • Separate static surface, not on TestContext.TestContext.Current is an AsyncLocal that is null outside test execution, so a static helper / fixture / extension cannot read it; per-run data on a per-test type was also called out as bloat in the issue thread. Matches the two-surface pattern of xUnit v3 and NUnit.
  • PlannedTest is a sealed class, not a struct (too many ref-typed fields) and not a record (structural equality across collections is surprising; positional records emit init accessors, which the repo guidelines explicitly forbid for new public APIs).
  • Naming mirrors existing MSTest surface: FullyQualifiedTestClassName / TestName / TestDisplayName from TestContext; DeclaringFilePath / DeclaringLineNumber from TestMethodAttribute; TestCategories from TestCategoryAttribute; TestProperties from [TestProperty(Name, Value)].
  • Collection types stay at the minimum that meets the use case: IReadOnlyCollection<string> (no IReadOnlySet on netstandard2.0 / net462), IReadOnlyCollection<KeyValuePair<string, string>> for the multi-valued [TestProperty].
  • TestRun.Current is never null — defaults to an empty implementation, so callers in any context can just dot through without null checks.

Tests

6 new unit tests in MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.cs covering: empty list, single element happy path, categories + multi-valued properties, non-null Current, reset semantics, and input-collection copy semantics. All adapter unit tests pass. Clean build across net9.0, net8.0, netstandard2.0, net462.

Compatibility

Additive only; not a breaking change. All API is [Experimental("MSTESTEXP")] for v1 so the shape can still evolve before locking based on user feedback.

Scope cleanup

The previously bundled --ansi <auto|on|off> CLI option has been split out into a separate PR: #8493.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental ambient MSTest API (TestRun.Current) for querying run-wide information (initially the filtered/discovered planned tests for the current assembly), and wires it up from the adapter so it’s available during [AssemblyInitialize] and test execution. In addition, the PR introduces a new --ansi terminal option in Microsoft.Testing.Platform to explicitly control ANSI escape emission and precedence over --no-ansi, including updated help text/resources and tests.

Changes:

  • Add [Experimental("MSTESTEXP")]TestRun, ITestRunInfo, and PlannedTest public APIs (plus PublicAPI entries) and adapter-side snapshot construction/wiring.
  • Add --ansi <auto|on|off> CLI option, argument validator helpers, updated help/info expectations, localized resources, and acceptance/unit tests.
  • Add adapter unit tests validating TestRunInfo snapshot creation and TestRun.Current reset semantics.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestRunInfoTests.csNew unit coverage for adapter TestRunInfo snapshot behavior and TestRun.Current reset semantics.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.csUnit tests for --ansi option validation and option metadata.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.csUnit tests for boolean/auto argument validation helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MSTest help expectations to include --ansi text.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.csUpdates MTP help/info expectations for --ansi option and info output.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.csUpdates “all extensions” help/info expectations for --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.csNew acceptance tests validating --ansi behavior (on/off/auto precedence & validation).
src/TestFramework/TestFramework.Extensions/TestRun.csNew ambient TestRun.Current API with internal setter and empty default.
src/TestFramework/TestFramework.Extensions/PublicAPI/PublicAPI.Unshipped.txtDeclares new public API surface for shipping validation.
src/TestFramework/TestFramework.Extensions/PlannedTest.csNew public DTO representing a planned test in the current run.
src/TestFramework/TestFramework.Extensions/ITestRunInfo.csNew public run-info interface surfaced via TestRun.Current.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds new localized resource entries for --ansi strings.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxAdds --ansi description and invalid-argument strings.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.csImplements precedence and mapping from --ansi/--no-ansi to terminal ANSI mode selection.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.csRegisters --ansi option and validates its argument.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.csAdds reusable validators for on/off/auto boolean-like option arguments.
src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.csWires TestRun.SetCurrent(...) to publish the planned test snapshot before execution.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.csBuilds ITestRunInfo snapshots from adapter UnitTestElement discovery/execution data.
docs/RFCs/014-TestRun-Current-PlannedTests.mdRFC documenting goals, design rationale, and initial surface for TestRun.Current.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
@Evangelink

Copy link
Copy Markdown
MemberAuthor

Copilot resolve the merge conflicts in this pull request

CopilotAI review requested due to automatic review settings May 22, 2026 09:09
@Evangelink
Amaury Levé (Evangelink) removed the request for review from CopilotMay 22, 2026 09:09

CopilotAI commented May 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved by merging origin/main into this branch and fixing the conflict in TerminalOutputDevice.cs in commit a0caa3163.

Adds a static ambient surface `TestRun.Current` exposing
`ITestRunInfo.PlannedTests` so user code (typically
[AssemblyInitialize] or fixtures) can decide whether expensive
setup is needed based on the filtered list of tests that will
actually run in the current assembly.
Surface (all `[Experimental(""MSTESTEXP"")]`):
- `static class TestRun` with `Current`
- `interface ITestRunInfo` with `PlannedTests`
- `sealed class PlannedTest` (sealed class, not record, to
avoid `init` accessors per repo guidelines and to keep
equality semantics off collection fields)
Adapter populates `TestRun.SetCurrent(...)` inside the
`UnitTestRunner` ctor so the snapshot lives in the same
AppDomain/process that runs [AssemblyInitialize] and the
tests themselves (works for both VSTest and MTP paths).
RFC: docs/RFCs/014-TestRun-Current-PlannedTests.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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: 8/8 changed files
  • Comments generated: 4

Comment threadsrc/TestFramework/TestFramework.Extensions/TestRun.cs
Comment threadsrc/TestFramework/TestFramework.Extensions/PlannedTest.cs
Comment threadsrc/Adapter/MSTestAdapter.PlatformServices/Execution/TestRunInfo.cs Outdated
- TestRun.Current setter changed from internal to private so SetCurrent(...) is the only mutation path, preserving the never-null invariant.
- TestRunInfo.ToPlannedTest now maps TestMethod.DisplayName to null when it equals TestMethod.Name (the default fallback), so consumers can distinguish 'no explicit display name' from 'display name set' as the docs already promise.
- Added internal PlannedTest.CreateFromOwnedArrays factory that skips the defensive copy when the adapter already owns freshly-built arrays, avoiding a double allocation for every test with traits.
- Added regression test covering the default-display-name-to-null mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit b625999 into mainMay 22, 2026
74 of 78 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/test-run-current-planned-tests branch May 22, 2026 15:49
Sign up for freeto 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.

Knowing which tests will run in AssemblyInitialize

3 participants

@Evangelink