test(core): add headless end-to-end tests and fix bugs they found
Adds crates/ghostty-core/tests/e2e_*.rs: 81 tests that drive the real core Surface, termio, pty and child processes through a fake runtime (recording apprt actions, in-memory clipboard) with a headless renderer (ghostty-renderer/src/headless.rs). They cover keys (legacy, DECCKM, kitty, modifyOtherKeys), keybinding actions and sequences, mouse selection/reporting/scrolling/links, clipboard incl. OSC 52 and paste safety, resize, focus, titles/pwd/bell/notifications/progress, child exit, and IME preedit. Fixes for issues found by the tests and by the Codex audit (docs/rewrite/notes/review-core-codex.md, all 9 items): - replacing a selection with copy-on-select panicked (stale tracked handles); global new_window no longer inherits a parent; the child environment uses the runtime's env wholesale so GTK's removals stick; Flatpak host resources path; locale recovery (ensureLocale) in apprt-gtk before GTK init and for CLI actions; failed screen-file opens propagate errors; OSC 52 base64 rules, CSI/ESC binding length limits and GHOSTTY_LOG parsing match Zig. - Also includes V2's termio cleanups (tmux viewer wiring in the stream handler, Pty slave semantics docs, shared cgroup wait loop). apprt-gtk gains a debug input replay hook (GHOSTTY_DEBUG_INPUT_SCRIPT) exercising the real GTK key path. With it, the real app was verified on Wayland: typing and output, new tab, splits, select-all/copy/paste and font size all work (docs/rewrite/notes/verification-V1.md). Not yet exercised at GTK level: mouse, real IM-context IME, clipboard dialogs. Test Plan: - cargo test --workspace (2983 passed) - cargo test -p ghostty-core --tests (81 e2e tests)
This commit is contained in:
1 parent
d650e5171b
commit
be6d706ba5
33 files changed
+3016
-222
No files matched your search
@@ -35,7 +35,7 @@ Legend: ⬜ todo · 🟨 in progress · ✅ done (gate passed, committed) · ⚠
|
||||
| RV1 | Codex read-only audit core Surface vs Zig | codex astra | ✅ | 9 findings (notes/review-core-codex.md) → handed to V1 |
|
||||
| P1 | ghostty-bench port, Zig baseline, perf tuning | sonnet | ✅ | stream at Zig parity; screen-clone 2.6x |
|
||||
| V1b | finish V1: clippy, audit fixes, GTK replay check | sonnet | 🟨 | |
|
||||
| P2 | perf: screen-clone, osc-parser | sonnet | 🟨 | |
|
||||
| P2 | perf: screen-clone, osc-parser | sonnet | ✅ | clone at parity; render 2.4x |
|
||||
|
||||
## Log
|
||||
- 2026-10-11: Phase 0 complete; Phase 1 launched.
|
||||
|
||||
@@ -40,7 +40,7 @@ Wiring details: renderer->app via `Host` (scrollbar/health/redraw as app mailbox
|
||||
apprt-gtk got `RtSurface::gl_proc_address` (libepoxy `epoxy_*` pointer variables) and `create_scope_fn` (cgroup scope over D-Bus from the IO thread).
|
||||
Deviations/stubs: inspector no-op; locale only via GTK's setlocale (no unsafe in core/root); crash reporting (sentry) not ported; `Rust version` row of `+version` empty;
|
||||
default DPI 96 (Zig linux).
|
||||
How to run: `GSETTINGS_BACKEND=memory GHOSTTY_RESOURCES_DIR=/usr/share/ghostty cargo run -- -e sh -c '...'` (debug builds only find resources via the env var here).
|
||||
How to run (resources are found automatically via `<workspace>/resources`, see notes/cleanup-V2.md): `GSETTINGS_BACKEND=memory cargo run -- -e sh -c '...'`.
|
||||
Dev screenshot: `GHOSTTY_DEBUG_SCREENSHOT=/abs/out.png [GHOSTTY_DEBUG_SCREENSHOT_MS=2500]` dumps the renderer's last frame (compositor screenshots under niri come out black / are blocked).
|
||||
Verified manually: window opens on Wayland and X11, shell prompt and SGR colored output render (target/screenshots/frame.png, shell.png), child exit closes window, clean shutdown.
|
||||
NOT verified: keyboard input end-to-end (no way to inject keys into the window here; xdotool/niri did not deliver), mouse, clipboard, IME, splits/tabs.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Verification V1 / V1b (core end-to-end + GTK runtime)
|
||||
|
||||
## E2E tests (`crates/ghostty-core/tests/`, 81 tests, all headless; real core Surface + termio + pty + headless EGL renderer, fake apprt)
|
||||
- `common/mod.rs`: harness (FakeRt recording actions/clipboard, recorder child `cat`-like process, pump/wait/settle helpers).
|
||||
- `e2e_bindings.rs` (23): default and configured binding actions, select-all/copy/paste, csi/esc/text, screen-file open, child env.
|
||||
- `e2e_ime.rs` (4): preedit state/rendering, commit, composing key events.
|
||||
- `e2e_keys.rs` (15): key events -> encoder -> pty bytes (legacy, kitty, modifiers, sequences).
|
||||
- `e2e_mouse.rs` (19): selection, copy-on-select, multi-click, mouse reporting (x10/normal/sgr), wheel, alternate scroll.
|
||||
- `e2e_term.rs` (20): resize/TIOCSWINSZ, focus, title, pwd, bell, OSC 52 read/write, notifications, progress, child exit.
|
||||
- Gate: workspace build, `cargo test --workspace` (~480 tests), `cargo clippy --workspace --all-targets -D warnings`, `cargo fmt --all` all pass.
|
||||
|
||||
## Bugs found and fixed
|
||||
- core `surface/mod.rs`: set_selection compared against the previous selection after replacing it (tracked-pin panic, e.g. select-all twice with copy-on-select).
|
||||
- core `surface/mod.rs`: child env overlaid runtime env on the process env; now the runtime env wholesale (fallback only if empty).
|
||||
- core `surface/keyboard.rs`: global/all `new_window` targeted the surface (parent inheritance); now `Target::App`.
|
||||
- core `global.rs` + apprt-gtk `flatpak.rs`: runtime-specific resources-dir hook (host_path), wired from `src/main.rs`.
|
||||
- core `surface/binding.rs`: failed screen-file open returned success; now an error (performable bindings fall through). CSI/ESC > 128 bytes rejected.
|
||||
- core `surface/clipboard.rs`: OSC 52 base64 acceptance matches Zig (size check, ignore trailing-bit errors).
|
||||
- core `global.rs`: `GHOSTTY_LOG` boolean aliases/empty value/invalid-field behaviour.
|
||||
- apprt-gtk `class/application.rs` + `src/main.rs`: `init_locale` (ensureLocale) before GTK init and for CLI actions.
|
||||
- renderer `headless.rs`, termio, apprt `runtime_api.rs`: fixes needed by the headless harness; apprt-gtk `debug_input.rs`: new input replay hook.
|
||||
- tests: wheel e2e test raced under load (one discrete tick = 3 reports); fixed to wait for all 6.
|
||||
- `dist/` (desktop file, metainfo, dbus/systemd units, icons) is legitimate install data; kept.
|
||||
|
||||
## Codex audit (review-core-codex.md), 9 items
|
||||
1. selection-replacement panic: FIXED, test `select_all_twice_with_copy_on_select_does_not_panic`.
|
||||
2. child env filtering: FIXED, test `child_environment_comes_from_the_runtime`.
|
||||
3. new_window parent: FIXED for global/all (keyboard.rs). Surface-local `new_window` binding (binding.rs) still passes `Target::Surface` deliberately: Zig Surface.zig:5122 calls `app.newWindow` with the surface as parent there.
|
||||
4. flatpak host path: FIXED (hook, no unit test: needs /.flatpak-info).
|
||||
5. screen-file open failure: FIXED, test `write_screen_file_open_failure_is_an_error`.
|
||||
6. ensureLocale: FIXED (unsafe setlocale/setenv in apprt-gtk, SAFETY comments); not unit-testable (process-global locale).
|
||||
7. OSC 52 base64: FIXED, test `osc52_write_base64_acceptance_matches_zig`.
|
||||
8. CSI/ESC length limit: FIXED, test `csi_binding_longer_than_the_zig_buffer_is_rejected`.
|
||||
9. GHOSTTY_LOG parsing: FIXED, unit test `logging_parse`.
|
||||
|
||||
## GTK runtime check (real app, Wayland, `GHOSTTY_DEBUG_INPUT_SCRIPT` + screenshots)
|
||||
- `echo hi` + Enter: output `hi` shown. PASS.
|
||||
- ctrl+shift+t: new tab, typing works in it. PASS.
|
||||
- ctrl+shift+o / ctrl+shift+e: right and down splits, each pane renders and quits cleanly. PASS.
|
||||
- ctrl+shift+a, ctrl+shift+c, ctrl+shift+v: select all highlighted, copied text pasted back. PASS.
|
||||
- ctrl+= x4: font size 12 -> 16, glyphs visibly larger. PASS.
|
||||
- The "panic after the first screenshot" did not reproduce; the likely cause was the selection panic (item 1), now fixed. Observed instead: a screenshot taken <~1.6 s after opening a new tab/split can fail with "no frame has been presented yet" (new surface's first frame is slow in a debug build); use longer `wait`s.
|
||||
- A `quit` with a child shell lacking shell integration (`sh`) shows the close-confirmation dialog, so the process stays alive (expected behaviour).
|
||||
|
||||
## Still open
|
||||
- Not exercised in the GTK check: mouse, IME via real IM, clipboard confirmation dialogs.
|
||||
- Runtime warnings unchanged: `unimplemented action=CellSize`, cgroup scope creation failing in this sandbox.
|
||||
Reference in new issue
Block a user