Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions crates/termlens-cli/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,20 @@ fn with_stdin(args: &[&str], input: &str) -> std::process::Output {
.stderr(Stdio::piped())
.spawn()
.expect("spawn termlens");
child
.stdin
.take()
.expect("a stdin pipe")
.write_all(input.as_bytes())
.expect("write to the child's stdin");
// A broken pipe here is a *result*, not a failure. `diff - -` refuses its
// arguments before reading anything, so the child can exit and close the
// pipe before this write lands — the faster the refusal, the likelier it
// is. The stress workflow found it on both Linux shards while it never
// reproduced locally, because on an idle machine the bytes reach the
// pipe buffer first. The child's exit code and stderr are what the
// callers assert; whether it read the input is the child's business.
let mut pipe = child.stdin.take().expect("a stdin pipe");
match pipe.write_all(input.as_bytes()) {
Ok(()) => {}
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => {}
Err(e) => panic!("write to the child's stdin: {e}"),
}
drop(pipe);
child.wait_with_output().expect("the child's output")
}

Expand Down
21 changes: 16 additions & 5 deletions crates/termlens/tests/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ fn a_panicking_child_puts_its_message_on_the_screen() -> termlens::Result<()> {
// Wide enough that the message is one row: the runtime's own
// `panicked at <file>:<line>` line wraps on a narrow grid, and a
// wrapped needle is a test about the width, not about the panic.
//
// And every wait below names the *message*, never the word "panicked".
// The runtime writes the location line and the message as separate
// writes, so `contains("panicked")` is true one line before the message
// exists — which went red on CI with the grid holding `panicked at
// …:281:37:` and nothing under it. Waiting for the message is rule 3 of
// the wait-semantics contract (docs/DESIGN.md §2): name the last thing
// the application paints, so that its truth implies the rest arrived.
// "panicked" is then asserted rather than waited on — it cannot be
// absent once the line after it is there.
let wide = || {
Terminal::builder()
.size(100, 10)
Expand All @@ -174,8 +184,9 @@ fn a_panicking_child_puts_its_message_on_the_screen() -> termlens::Result<()> {

// 1. A plain child, which is what the README's table is about.
let mut t = common::spawn_emit(wide(), &["drew this ", "--panic", "plain panic here"])?;
t.wait_until(|s| s.contains("panicked"))?;
t.wait_until(|s| s.contains("plain panic here"))?;
let s = t.screen();
assert!(s.contains("panicked"), "the word the README promises: {s}");
assert!(
s.contains("plain panic here"),
"the message reaches the grid: {s}"
Expand All @@ -201,10 +212,10 @@ fn a_panicking_child_puts_its_message_on_the_screen() -> termlens::Result<()> {
"boom in the alt screen",
],
)?;
t.wait_until(|s| s.contains("panicked"))?;
t.wait_until(|s| s.contains("boom in the alt screen"))?;
let s = t.screen();
assert!(s.contains("panicked"), "{s}");
assert!(s.alternate_screen(), "nothing tore it down: {s}");
assert!(s.contains("boom in the alt screen"), "{s}");
assert!(
s.contains("TUI drawing here"),
"the message joins the frame it died on: {s}"
Expand All @@ -225,10 +236,10 @@ fn a_panicking_child_puts_its_message_on_the_screen() -> termlens::Result<()> {
"boom after teardown",
],
)?;
t.wait_until(|s| s.contains("panicked"))?;
t.wait_until(|s| s.contains("boom after teardown"))?;
let s = t.screen();
assert!(s.contains("panicked"), "{s}");
assert!(!s.alternate_screen(), "the child left it: {s}");
assert!(s.contains("boom after teardown"), "{s}");
assert!(
!s.contains("TUI drawing here"),
"what the alternate screen held went with it: {s}"
Expand Down