#![cfg(any(target_os = "linux", target_os = "macos"))]
use std::os::unix::process::ExitStatusExt;
use std::path::Path;
use std::process::{Command, Stdio};
const BIN: &str = env!("CARGO_BIN_EXE_roteiro");
const SIGPIPE: i32 = 13;
fn git(dir: &Path, args: &[&str]) {
let status = Command::new("git")
.args([
"-c",
"user.name=Test",
"-c",
"user.email=test@example.com",
"-c",
"commit.gpgsign=false",
"-c",
"init.defaultBranch=main",
])
.args(args)
.current_dir(dir)
.status()
.expect("run git");
assert!(status.success(), "git {args:?} failed");
}
#[test]
fn query_exits_cleanly_when_stdout_pipe_closes_early() {
let dir = std::env::temp_dir().join(format!("roteiro-brokenpipe-cli-{}", std::process::id()));
std::fs::remove_dir_all(&dir).ok();
std::fs::create_dir_all(dir.join("src")).expect("mkdir");
std::fs::write(dir.join("src/lib.rs"), "pub fn a() {}\npub fn b() {}\n").expect("write");
std::fs::write(dir.join("README.md"), "# Readme\n").expect("write");
git(&dir, &["init", "-q"]);
git(&dir, &["add", "."]);
git(&dir, &["commit", "-q", "-m", "init"]);
let mut child = Command::new(BIN)
.args(["query", "--kind", "file"])
.current_dir(&dir)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("spawn roteiro");
drop(child.stdout.take());
let output = child.wait_with_output().expect("wait roteiro");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("panicked") && !stderr.contains("Broken pipe"),
"broken-pipe panic regressed: exit={:?} signal={:?}\nstderr:\n{stderr}",
output.status.code(),
output.status.signal(),
);
assert_ne!(
output.status.code(),
Some(101),
"process panicked (exit 101) instead of exiting on SIGPIPE\nstderr:\n{stderr}",
);
assert!(
output.status.signal() == Some(SIGPIPE) || output.status.success(),
"expected SIGPIPE termination or clean exit, got exit={:?} signal={:?}\nstderr:\n{stderr}",
output.status.code(),
output.status.signal(),
);
}