DrawingSelf-test
Sheet7 / 11
Rev0.3.66
Date08-2026
Scale1:1
MaterialC99

A terminal emulator that tests itself

A terminal emulator is only as good as the thousand escape sequences it renders correctly. rbterm proves it: ~240 checks drive a real rbterm through its own scripting API, read the screen back, and pixel-verify the result — fully automated, headless, and ruthless.

~240 checks 19 categories Headless by default MIT
SEC 01

Self-hosted by design

The terminal is both the thing under test and the test harness.

~240
Checks

The full suite, run by make stress.

19
Categories

Areas of terminal behaviour, from the VT parser to process control.

px
Verified shots

PNGs decoded by a dependency-free reader, then asserted on.

0
Windows shown

Nothing appears, nothing takes focus, nothing steals a key.

There are no mocks and no stubs. Every check spins up the actual terminal binary, feeds bytes into a pane exactly as a shell would, and asserts on what the VT parser, grid, and renderer actually produced. If a colour is off by a shade or the cursor lands one column wrong, the suite fails — loudly.

rbterm ships a scripting API that can drive a running instance and read it back. The test framework is built directly on it: send-text to feed escape sequences into a pane, get-text / get-text --ansi to read the rendered screen (with full colour and attributes), ls and get-colors to inspect structure and palette, and screenshot to capture pixels. One real pipeline, asserted end to end.

def test_truecolor(rc):
    rc.run_cmd("clear")
    rc.emit(r"\033[38;2;10;200;30mTRUE\033[0m\n")   # 24-bit green
    ansi = rc.get_text(ansi=True)                  # read the screen, with SGR
    i = ansi.rfind("TRUE")
    assert "38;2;10;200;30" in ansi[i-28:i]    # confirm the colour rendered
    # ok test_truecolor
SEC 02

What it exercises

The hard parts of a terminal — not just “hello world”.

VT parser

Cursor addressing (CUP/HVP, relative moves, save & restore), erase (ED/EL/ECH), delete/insert, scroll regions & reverse index, auto-wrap on/off, carriage-return overwrite.

Colour & attributes

Bold, italic, underline, reverse, strike; 16-colour, 256-colour, and 24-bit truecolour; default reset — verified by reading back the actual SGR stream.

Unicode

Accented text, Greek, symbols, and double-width CJK round-tripped byte-for-byte through input and output.

Palette

OSC 4 palette updates and live recolouring, confirmed against a colour query.

Modes & graphics

Alternate screen buffer isolation, DEC special-graphics box drawing, window-title sequences.

Layout

Opening and closing tabs, nested splits, stable pane identity, font size and spacing.

Targeting

The boolean match engine — and/or/not over id, title, cwd, pid, and user variables.

Input & process

Synthesised key chords, signal delivery to pane processes, and captured command output.

SEC 03

Pixel-verified screenshots

“It looks right” isn't good enough — we read the pixels.

The framework captures PNGs of rendered panes and decodes them with a dependency-free PNG reader, then asserts on actual pixel values: a background fill matches the colour that was set, white text produces bright pixels where glyphs land, colour bars contain the expected distinct hues. Both of the frames listed below were produced by the framework itself — captured headless, with no window ever shown.

Frame 01
Attributes, truecolour, box drawing and Unicode in one rendered frame: bold, italic, underline, reverse and strike; 16-colour dots; a 24-bit truecolour gradient; DEC box drawing; and café, 世界, Ω≠∞.
Frame 02
The full 256-colour cube, rendered as background blocks and screenshotted headlessly, then checked hue by hue.

The capture path is nothing special to the tests: it is the scripting API's own screenshot command, which any script can call to render a pane offscreen.

SEC 04

Headless by default

Tests never steal your screen, focus, or keystrokes.

rbterm can run with a hidden window. The GPU context and offscreen render targets still work, so remote control and screenshot render in full — but nothing appears on your desktop, nothing takes focus, and a stray keypress can never land in a test session.

That makes the suite safe to run any time, including in continuous integration — on Linux it runs under a virtual display.

SEC 05

It catches real bugs

Already earning its keep.

This isn't a checkbox suite. On its very first full run it surfaced — and drove fixes for — two genuine rendering bugs:

Double-encoding
Non-ASCII text was being double-encoded across the control channel. Fixed, with regression coverage.
X11 colour spec
An X11 rgb: colour specification was scaled wrong, so every channel came out a quarter of its intended brightness. Fixed, with regression coverage.
Running the suitemake
# run it
make test      # fast sanity subset
make stress    # the full suite + pixel-verified screenshots

238 passed, 0 failed, 2 xfail (known bugs), of 240