DevelopmentAll versions
On this page

Terminal Conformance Testing

KetraTerm verifies terminal behavior with complementary deterministic test strategies. No single external emulator is treated as a universal oracle: terminal implementations legitimately differ in policy areas such as width-changing resize and logical-line reflow.

Differential campaign

The xterm.js campaign replays generated protocol streams through KetraTerm and the version-pinned @xterm/headless oracle. Comparisons are restricted to state that both implementations expose. Intentional policy differences must declare their rationale and exact allowed mismatch paths.

./gradlew :ketraterm-testkit:xtermDifferentialSmokeTest
./gradlew :ketraterm-testkit:xtermDifferentialNightlyTest

Pull requests run 100 deterministic cases. The scheduled campaign runs 100,000 cases in four seed-range shards.

Resize and reflow campaign

The resize campaign constructs mixed-width Unicode state and repeatedly changes the viewport width and height. It verifies exact grapheme preservation, cursor bounds, dimensions, render-cell flags, and wide-cell adjacency. This is an invariant campaign focused on KetraTerm's own resize and reflow policy.

./gradlew :ketraterm-testkit:resizeReflowInvariantSmokeTest
./gradlew :ketraterm-testkit:resizeReflowInvariantNightlyTest

Independent grid-physics model

The grid-physics campaign executes each generated operation against the real parser-to-core pipeline and a deliberately small independent model. It covers:

  • ASCII, combining clusters, CJK characters, and width-two emoji;
  • deferred wrap, DECAWM, CR, LF, BS, CUP, CUF, and CUB;
  • DECSTBM, DECSLRM, DECLRMM, and DECOM;
  • RI, IL, DL, SU, and SD;
  • full-screen and partial-region scrolling, including scrollback admission;
  • wide occupants crossing horizontal line-mutation slice boundaries.

The comparison includes cell and cluster contents, wide spans, cursor position, mode state, soft-wrap markers, scrolling, and retained history.

./gradlew :ketraterm-testkit:cursorWrapModelSmokeTest
./gradlew :ketraterm-testkit:cursorWrapModelNightlyTest

Pull requests run 100 cases. Nightly CI runs 25,000 cases in four deterministic ranges of 6,250.

Reproducing failures

Every campaign uses a fixed base seed plus a global case index. Select an exact range with the corresponding StartIndex and Cases Gradle properties:

./gradlew :ketraterm-testkit:cursorWrapModelNightlyTest \
  -PcursorWrapStartIndex=12500 \
  -PcursorWrapCases=6250

Campaign manifests record the implementation or oracle version where applicable, base seed, case range, commit SHA, comparison scope, and status. Failures are automatically minimized and written beneath the relevant ketraterm-testkit/build/reports campaign directory. CI uploads manifests for all runs and retains minimized operation streams plus JUnit reports on failure.

Streaming placement

The streaming placement contract commits published grid effects. HostGraphemePolicyTest verifies that policy. Three retained HostGraphemeTest oracles test the stronger, unsupported requirement that every byte split produces identical placement:

  • Narrowing does not restore an overwritten neighbor.
  • Widening at a margin can differ from an initially wide write.
  • Late narrowing does not move an already wrapped cluster back.

The knownR06Failure helper reports only recorded assertion failures as skipped/aborted. Additional failures, changed messages, or unexpected passes fail the test and require review. A skip does not establish that later iterations of an oracle passed. Ordinary grapheme and byte-stream tests remain active.

./gradlew :ketraterm-host:test --tests '*HostGrapheme*' --tests '*KnownR06FailureTest' runs this focused verification.