Skip to content

Add --ansi option for explicit ANSI control#7107

Closed
Evangelink with Copilot wants to merge 5 commits into
mainfrom
copilot/add-ansi-option-to-force-output
Closed

Add --ansi option for explicit ANSI control#7107
Evangelink with Copilot wants to merge 5 commits into
mainfrom
copilot/add-ansi-option-to-force-output

Conversation

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Contributor

Summary

Adds a new --ansi <auto|on|off> CLI option to give users explicit control over ANSI escape sequence output. Fixes #5081.

Behavior

  • --ansi auto (default): Auto-detect terminal capabilities (existing behavior when no option is passed).
  • --ansi on|true|enable|1: Force ANSI output (including cursor movement) even when stdout is redirected, e.g. mytest.exe | Out-Host.
  • --ansi off|false|disable|0: Disable ANSI output.
  • --no-ansi: continues to work unchanged.
  • When both --ansi and --no-ansi are specified, --ansi wins (documented in the help text).

Implementation notes

  • New internal CommandLineOptionArgumentValidator helper exposes IsValidBooleanArgument / IsValidBooleanAutoArgument / IsOnValue / IsOffValue / IsAutoValue so future boolean and boolean+auto options (e.g. --no-progress) can reuse it.
  • The --ansi value parsing in TerminalOutputDevice uses a private AnsiOverride enum scoped to that file. We considered promoting a generic ActivationMode (Auto/On/Off) enum into the CommandLine namespace but kept it local for now to avoid widening the public/internal surface for a single consumer; a follow-up can introduce a shared type once a second option (e.g. --no-progress) actually needs it.
  • --no-ansi is intentionally left without deprecation/obsolescence metadata. The earlier prototype added obsolescence plumbing to CommandLineOption but it was reverted because the matching infrastructure was removed from main by Delete dead code #7734 as dead code, and reintroducing it for a single option felt out of scope. The help text for --ansi instead notes that --ansi wins over --no-ansi so users have a clear migration path.

Tests

  • Unit tests for CommandLineOptionArgumentValidator and the updated TerminalTestReporterCommandLineOptionsProvider.
  • New AnsiOptionTests acceptance tests covering on/off/auto behavior, the alias values, precedence vs --no-ansi, and invalid argument rejection.
  • Updated MTP and MSTest --help / --info acceptance expectations to include the new option.

Copilot AI changed the title [WIP] Add --ansi option to force Ansi output Add --ansi option for explicit ANSI control Dec 11, 2025
Copilot AI requested a review from Evangelink December 11, 2025 14:20
Comment thread src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOption.cs Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs Outdated
Copilot AI requested a review from Evangelink December 12, 2025 16:53
@Evangelink Evangelink marked this pull request as ready for review December 15, 2025 11:28
@Evangelink Evangelink enabled auto-merge (squash) December 15, 2025 15:08

@nohwnd nohwnd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I need to go through the logic around use ansi and force ansi on the internal options. I am not clear on why we needed / need both options. so please wait for me.

Comment thread src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/CommandLine/OptionMode.cs Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/CommandLine/TriStateMode.cs Outdated

@nohwnd nohwnd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

just comments that you don't have to address.

Comment thread src/Platform/Microsoft.Testing.Platform/CommandLine/ActivationMode.cs Outdated
@nohwnd nohwnd disabled auto-merge December 18, 2025 13:45

@nohwnd nohwnd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

^^^

@Evangelink Evangelink enabled auto-merge (squash) December 18, 2025 15:18
@Evangelink Evangelink closed this Dec 19, 2025
auto-merge was automatically disabled December 19, 2025 12:38

Pull request was closed

@Evangelink Evangelink reopened this May 20, 2026
Evangelink and others added 4 commits May 20, 2026 17:20
Implements the user-facing --ansi option with auto/on/off values (plus
true|enable|1 / false|disable|0 aliases). The new option fulfils issue
#5081 by mapping --ansi on to the existing internal AnsiMode.ForceAnsi,
which emits ANSI escape codes (including cursor movement) even when
stdout is redirected (for example, in 'mytest.exe | Out-Host' pipelines).

- New internal CommandLineOptionArgumentValidator helper exposes
  IsValidBooleanArgument / IsValidBooleanAutoArgument / IsOnValue /
  IsOffValue / IsAutoValue for reuse by future on|off|auto options.
- --no-ansi continues to work unchanged. When both --ansi and --no-ansi
  are specified, --ansi wins (documented in the help text).
- Updated MTP and MSTest acceptance test --help and --info expectations
  to include the new option.
- Added unit tests for the validator and the provider plus integration
  tests verifying the on/off/auto behavior, alias handling, and invalid
  argument rejection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Introduce AnsiOverride.Auto so the switch can distinguish 'user typed
  --ansi auto' from 'no --ansi at all'. With this, any explicit --ansi
  value (auto, on, off) now overrides the legacy --no-ansi flag, which
  makes the help text accurate.
- Drop the dead-defensive null check on TryGetOptionArgumentList output:
  ArgumentArity.ExactlyOne guarantees a single-element array when the
  call returns true.
- Clarify the AnsiOption_Auto integration test comment to explain it now
  exercises the real AnsiIfPossible-plus-redirection path, and add a
  companion test asserting --no-ansi --ansi auto runs successfully (i.e.
  precedence is honored).

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

- AnsiOption_Auto_DoesNotProduceAnsiOutputWhenRedirected was passing
  trivially under GITHUB_ACTIONS=true because the CI branch picked
  SimpleAnsi (which emits color codes). Now explicitly clears
  GITHUB_ACTIONS / TF_BUILD so the assertion is deterministic.
- AnsiOption_AutoExplicit_OverridesNoAnsiFlag used to only assert
  ExitCode.Success which gave the same value for both fixed and
  regressed code paths. It now sets GITHUB_ACTIONS=true so the
  precedence story discriminates: when --ansi auto correctly wins over
  --no-ansi the CI branch selects SimpleAnsi -> ANSI escape codes
  appear; when --no-ansi wins (regression) no codes appear. The new
  assertion catches that regression.

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

Replace AnsiOption_AutoExplicit_OverridesNoAnsiFlag with
AnsiOption_OnExplicit_AfterNoAnsi_StillForcesAnsiOutput. The new test
uses '--no-ansi --ansi on' instead of '--no-ansi --ansi auto'. Because
AnsiOverride.ForceOn short-circuits both the inCI and the
LLMEnvironmentDetector checks in TerminalOutputDevice, the assertion no
longer flakes on contributors running the suite from inside an LLM
agent (Claude Code, Cursor, Copilot CLI, Codex CLI, etc.) whose
environment variables would leak into the test child process via
TestHost.ExecuteAsync.

This still proves the same precedence invariant ('any explicit --ansi
value overrides --no-ansi', order-independent), and the assertion is a
direct function of the precedence fix alone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 20, 2026 16:28
@Evangelink Evangelink force-pushed the copilot/add-ansi-option-to-force-output branch from 6a4bcd6 to 337033a Compare May 20, 2026 16:28
@Evangelink

Copy link
Copy Markdown
Member

Rebased onto current main from scratch (the prior branch was stale and had non-trivial conflicts). I dropped the AutoOnOff enum and the obsolescence-marker plumbing for --no-ansi so the change stays small (the obsolescence infrastructure was removed from main by #7734 as dead code, and reintroducing it for one consumer felt out of scope). Instead, --ansi maps straight to the existing internal AnsiMode enum:

  • --ansi on|true|enable|1AnsiMode.ForceAnsi (fulfils Add --ansi option to force Ansi output #5081 — emits ANSI even when stdout is redirected)
  • --ansi off|false|disable|0AnsiMode.NoAnsi
  • --ansi auto (default) → current detection logic (LLM → NoAnsi, CI → SimpleAnsi, else → AnsiIfPossible)
  • --no-ansi stays working as-is; any explicit --ansi <value> wins over it

Help text calls out that --ansi on includes cursor movement and recommends pairing with --no-progress for clean redirected output.

The branch went through 3 rounds with the expert reviewer; iterations addressed: (1) --ansi auto + --no-ansi precedence, (2) CI-deterministic auto test, (3) a precedence test that's also immune to LLM env-var leakage. Final regression guard uses --no-ansi --ansi on because ForceOn short-circuits both inCI and LLMEnvironmentDetector checks.

Acceptance tests need build.cmd -pack to run locally; I built Microsoft.Testing.Platform, the unit-tests project (864/864 pass) and the integration tests project (compiles cleanly).

Copilot AI 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

This PR adds an explicit --ansi <auto|on|off> command-line option to control whether ANSI escape sequences are emitted by the terminal reporter, while keeping --no-ansi for backward compatibility. It also updates localization resources and acceptance tests so --help/--info output reflects the new option.

Changes:

  • Add --ansi option (with auto|on/off aliases) and wire it into TerminalOutputDevice ANSI mode selection/precedence over --no-ansi.
  • Introduce a reusable CommandLineOptionArgumentValidator helper and add unit tests for the validator and the terminal option provider.
  • Update help/info acceptance-test expectations and add an integration test validating redirected-output behavior for --ansi.
Show a summary per file
File Description
test/UnitTests/Microsoft.Testing.Platform.UnitTests/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProviderTests.cs Adds unit tests for --ansi option validation and presence.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineOptionArgumentValidatorTests.cs Adds unit tests for the new boolean/auto argument validator helpers.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/HelpInfoTests.cs Updates MSTest runner --help expectations to include --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoTests.cs Updates MTP --help and --info expectations to include --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.cs Updates “all extensions” help/info expectations to include --ansi.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/AnsiOptionTests.cs Adds integration tests validating --ansi behavior (esp. when stdout is redirected).
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf Adds localized entries for --ansi description + invalid-argument message.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx Adds TerminalAnsiOptionDescription and TerminalAnsiOptionInvalidArgument resources.
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs Parses --ansi and applies precedence over --no-ansi to select AnsiMode.
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporterCommandLineOptionsProvider.cs Declares --ansi and validates its argument via the new validator.
src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineOptionArgumentValidator.cs Adds reusable helpers for auto/on/off argument validation.

Copilot's findings

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

…options

- Guard against empty argument list when validating --ansi (e.g. `--ansi on --ansi` would have invoked the validator twice, once with an empty arguments array).
- Move --ansi from the platform 'Options:' section to the 'Extension options:' section in HelpInfoAllExtensionsTests because TerminalTestReporterCommandLineOptionsProvider registers the option as a non built-in extension option.

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

Copy link
Copy Markdown
Member

Closing in favor of #8493, which is a refreshed version of this PR (cleaner validator code using LINQ, refactored TerminalOutputDevice branch using CIEnvironmentDetector, and an additional acceptance test for the missing-argument case).

@Evangelink Evangelink closed this May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add --ansi option to force Ansi output

4 participants