From a69a200139fbf402835dd1d114c27ecd39890d2a Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sun, 16 Aug 2026 14:02:40 +0800 Subject: [PATCH] test(daemon): hold the promise that closing a pane drops its screen Deleting `scrollback::forget(pane_id)` from `kill_pane` left the whole suite green. The invariant is written down twice -- the privacy page says the file goes "at once", and `kill_pane`'s own comment says why, that a screen left behind is one that can turn up in some later restore -- and nothing held it. What looked like coverage tested `forget` itself, which keeps working while nobody calls it. The test drops a screen for a pane id that is not registered, because that is the case the call has to survive: `kill_pane` must forget the screen whether or not it found a pane to stop. Found by mutation-testing the invariants that would be worst to break, rather than by reading. The neighbours came out well and are worth recording: removing `:(literal)` from a pathspec fails eight tests including one named for it, and making `checksums::verify` accept anything fails four, one of them at integration level. --- crates/tty7-core/src/daemon/server.rs | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/tty7-core/src/daemon/server.rs b/crates/tty7-core/src/daemon/server.rs index 055eab3c..96db5fd6 100644 --- a/crates/tty7-core/src/daemon/server.rs +++ b/crates/tty7-core/src/daemon/server.rs @@ -1256,6 +1256,47 @@ fn spawn_writer( #[cfg(test)] mod tests { + + /// Closing a pane takes its stored screen with it. + /// + /// The privacy page promises the file goes "at once", and [`kill_pane`]'s + /// own comment says why: a screen left behind is a screen that can turn up + /// in some later restore. Both were true and neither was held — deleting + /// the `forget` call from `kill_pane` left the whole suite green, because + /// what covered it tested `forget` rather than anyone calling it. + #[test] + fn closing_a_pane_drops_its_stored_screen() { + let dir = std::env::temp_dir().join(format!("tty7-killpane-{}", std::process::id())); + std::fs::create_dir_all(&dir).ok(); + crate::core::config::set_config_dir(dir); + + let pane_id = 91_337; + crate::daemon::scrollback::save( + pane_id, + &[crate::daemon::scrollback::Segment { + size: crate::daemon::protocol::WinSize { + cols: 80, + rows: 24, + cell_w: 8, + cell_h: 16, + }, + bytes: b"what the pane had on it".to_vec(), + }], + ); + assert!( + crate::daemon::scrollback::load(pane_id).is_some(), + "the screen is on disk to begin with" + ); + + // No pane of that id is registered, which is the point: `kill_pane` + // must drop the screen whether or not it found something to stop. + kill_pane(&Registry::new(), pane_id); + + assert!( + crate::daemon::scrollback::load(pane_id).is_none(), + "a pane the user closed left its screen on disk" + ); + } use super::*; #[test]