quick_search/crates/quicksearch-gui/tests/cli_stderr.rs

61 lines
2.2 KiB
Rust
Raw Normal View History

//! Terminal search with its stderr in a pipe nobody reads, as under
//! `2>&1 | head -n1` once `head` has its line: a note that cannot be written
//! is lost, never a panic that turns a finished search into exit 101.
use std::process::{Command, Stdio};
use quicksearch_core::testutil::{seed_index, Scratch, SeedSpec, NEEDLE};
#[test]
fn a_closed_stderr_loses_the_truncation_note_not_the_exit_code() {
let (dir, db) = Scratch::db("cli-stderr");
// More files named for the needle than the limit below, so the search is
// cut short and has its note to write.
seed_index(
&db,
&SeedSpec {
files: 40,
dirs: 4,
needle_names: 4,
needle_docs: 0,
body_term_docs: 0,
..SeedSpec::default()
},
);
// The per-user config the CLI finds, on either platform.
let config_home = dir.join("config");
std::fs::create_dir_all(config_home.join("quicksearch")).unwrap();
std::fs::write(
config_home.join("quicksearch").join("config.toml"),
format!("[paths]\ndatabase_path = '{}'\n", db.display()),
)
.unwrap();
let search = || {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_quicksearch-cli"));
cmd.args(["--limit", "1", NEEDLE])
.env("XDG_CONFIG_HOME", &config_home)
.env("APPDATA", &config_home)
.stdin(Stdio::null());
cmd
};
// Read, stderr has the note: the path under test is taken.
let out = search().output().unwrap();
let stderr = String::from_utf8_lossy(&out.stderr);
assert_eq!(out.status.code(), Some(0), "stderr: {stderr}");
assert!(
stderr.contains("truncated at 1 results"),
"stderr: {stderr}"
);
// The read end is gone before the child starts, so every stderr write
// fails as a broken pipe; stdout is read as usual.
let (reader, writer) = std::io::pipe().unwrap();
drop(reader);
let out = search().stderr(writer).output().unwrap();
let stdout = String::from_utf8_lossy(&out.stdout);
assert_eq!(out.status.code(), Some(0), "stdout: {stdout}");
assert_eq!(stdout.lines().count(), 1, "one hit, as limited: {stdout}");
}