Skip to content

AppTestHelper.AssertAnsiSnapshot + make ToAnsi platform-independent#5343

Merged
tig merged 4 commits into
developfrom
feature/apptesthelper-ansi-snapshot
May 19, 2026
Merged

AppTestHelper.AssertAnsiSnapshot + make ToAnsi platform-independent#5343
tig merged 4 commits into
developfrom
feature/apptesthelper-ansi-snapshot

Conversation

@tig
Copy link
Copy Markdown
Member

@tig tig commented May 19, 2026

Summary

Two related changes:

1. AppTestHelper.AssertAnsiSnapshot (name) — golden-file ANSI snapshots

AppTestHelper could dump the screen (ScreenShot, AnsiScreenShot) but not assert it doesn't regress. AssertAnsiSnapshot captures the screen via IDriver.ToAnsi(), records __snapshots__/<name>.ans on first run (or UPDATE_SNAPSHOTS=1), and compares byte-for-byte after. On mismatch it writes a .ans.actual sibling and throws (framework-agnostic) with the plain-text render inline + cat commands — verify the look from a CI log or agent loop, no interactive run. The golden is the look: cat <name>.ans reproduces it.

2. Fix: ToAnsi was platform-dependent (root cause)

OutputBase.ToAnsi / BuildAnsiForRegion separated rows with StringBuilder.AppendLine() == Environment.NewLineCRLF on Windows, LF on Linux/macOS. ToAnsi is documented as a portable "recreate the screen" representation, so its bytes must not depend on the OS that produced them (this broke cross-platform golden snapshots — a real CI failure in gui-cs/Editor#142). Now emits a fixed '\n' for row breaks (both the ANSI and legacy-console paths). ToAnsi is not the live render path (real output goes through Write/WriteToConsole, untouched); terminals map LF→CRLF via ONLCR so cat/recreate fidelity is unchanged.
om/claude-code)

AppTestHelper already had AnsiScreenShot (dump ToAnsi() to a writer) but
no way to *assert* the look. AssertAnsiSnapshot records the screen as pure
ANSI (IDriver.ToAnsi() — truecolor/bold/reverse/blink/layout, excluding the
non-deterministic terminal cursor) into a __snapshots__/<name>.ans golden
on first run, then compares byte-for-byte. The .ans file IS the look:
`cat <name>.ans` reproduces the screen in any truecolor terminal.

On mismatch it writes a sibling .ans.actual and throws with the plain-text
render inline plus the `cat` commands, so a CI log or an agent can verify
the look without an interactive run. UPDATE_SNAPSHOTS=1 accepts an intended
change; SNAPSHOT_DIR overrides the golden root.

The exception type is framework-agnostic (no xunit dependency in
AppTestHelpers). *.ans is marked binary in .gitattributes — they are CRLF
escape blobs and core.autocrlf would corrupt the compare and `cat`.

Prototyped in gui-cs/Editor's integration suite (used there to verify
multi-caret/column-selection rendering); upstreaming the reusable core.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tig
Copy link
Copy Markdown
Member Author

tig commented May 19, 2026

@copilot fix ci/cd failures.

Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/d81858b1-5067-4b78-8173-6aeebfab7243

Co-authored-by: tig <585482+tig@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 19, 2026

@copilot fix ci/cd failures.

Fixed in 1483425 by making ANSI snapshots normalize row separators to LF before writing/comparing, which resolves the Linux/macOS integration-test mismatch. Local validation: build passed, IntegrationTests passed (256/256), UnitTestsParallelizable passed, UnitTests.NonParallelizable passed.

Copilot finished work on behalf of tig May 19, 2026 02:07
OutputBase.ToAnsi / BuildAnsiForRegion separated rows with
StringBuilder.AppendLine () == Environment.NewLine, so the "recreate the
screen" ANSI stream was CRLF on Windows and LF on Linux/macOS. That makes
ToAnsi output non-portable: golden snapshots or cross-platform diffs
recorded on one OS never match another (the failure that surfaced this).

ToAnsi is a portable representation, not the live render path (real output
goes through Write/WriteToConsole, untouched here). Emit a fixed '\n' for
row breaks in both the ANSI and legacy-console paths. Terminals map LF->CRLF
via the ONLCR tty discipline, so `cat`/recreate fidelity is unchanged.

Two OutputBaseTests assertions hard-coded "<g>" + Environment.NewLine —
they encoded the bug; updated to "<g>\n". Audited every other ToAnsi
consumer (ToAnsiTests splits on ['\r','\n']; OutputBase/Transparent/
Subview/Link/MenuBar tests use Contains on text/escapes) — none depended
on the platform newline; all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tig tig changed the title AppTestHelper: AssertAnsiSnapshot golden-file assertion AppTestHelper.AssertAnsiSnapshot + make ToAnsi platform-independent May 19, 2026
@tig tig marked this pull request as ready for review May 19, 2026 02:32
@tig tig requested review from BDisp and tznind May 19, 2026 02:32
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0d09dc286e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/AppTestHelpers/AppTestHelper.Snapshot.cs Outdated
@tig
Copy link
Copy Markdown
Member Author

tig commented May 19, 2026

@copilot fix this CR feedback: #5343 (comment)

Copy link
Copy Markdown
Contributor

Copilot AI commented May 19, 2026

@copilot fix this CR feedback: #5343 (comment)

Fixed in fc8e271 by stopping the helper before throwing the ANSI snapshot mismatch exception, with an integration test covering the mismatch path. Local validation: build passed, AnsiSnapshotTests passed, full IntegrationTests passed (257/257), and CodeQL skipped as test-only/trivial.

Copilot finished work on behalf of tig May 19, 2026 03:12
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.

3 participants