test: cover the store and the exit codes before moving any of it
This commit is contained in:
99
tests/output_io.rs
Normal file
99
tests/output_io.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
// what a command reports and how it exits, including when the write fails.
|
||||
mod support;
|
||||
|
||||
use std::fs;
|
||||
use support::Case;
|
||||
|
||||
#[test]
|
||||
fn findings_are_reported_through_the_exit_code() {
|
||||
let case = Case::new("findings");
|
||||
case.write("loose.txt", b"x\n");
|
||||
|
||||
case.ahab(&["link", "check"]).ok();
|
||||
case.ahab(&["link", "check", "--exit-code"]).code_is(4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_argument_error_exits_two() {
|
||||
let case = Case::new("usage");
|
||||
|
||||
case.ahab(&["link", "restore"]).code_is(2);
|
||||
case.ahab(&["link", "restore", "--all", "some/path"])
|
||||
.code_is(2);
|
||||
case.ahab(&["postgres", "dump", "-F", "directory", "-z", "d"])
|
||||
.code_is(2);
|
||||
case.ahab(&["nonsense"]).code_is(2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_write_that_cannot_be_delivered_is_a_failure_rather_than_a_success() {
|
||||
let case = Case::new("devfull");
|
||||
for n in 0..200 {
|
||||
case.write(&format!("file-{n}.txt"), b"x\n");
|
||||
}
|
||||
|
||||
// /dev/full accepts the open and fails the write. exiting 0 there would
|
||||
// report a listing that was never delivered
|
||||
let Ok(full) = fs::File::create("/dev/full") else {
|
||||
eprintln!("skipped: this system has no /dev/full to fail a write against");
|
||||
return;
|
||||
};
|
||||
|
||||
let out = std::process::Command::new(env!("CARGO_BIN_EXE_ahab"))
|
||||
.current_dir(&case.repo)
|
||||
.env("XDG_DATA_HOME", case.repo.join("../xdg"))
|
||||
.args(["link", "check", "--exit-code", "--porcelain"])
|
||||
.stdout(full)
|
||||
.output()
|
||||
.expect("running ahab");
|
||||
|
||||
assert_eq!(out.status.code(), Some(1), "{:?}", out.status);
|
||||
assert!(
|
||||
String::from_utf8_lossy(&out.stderr).contains("writing to stdout failed"),
|
||||
"{}",
|
||||
String::from_utf8_lossy(&out.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_named_path_is_moved_even_when_the_reader_leaves() {
|
||||
let case = Case::new("partial");
|
||||
for name in ["a.env", "b.env", "c.env"] {
|
||||
case.write(name, b"x\n");
|
||||
}
|
||||
case.gitignore("a.env\nb.env\nc.env\n");
|
||||
|
||||
// a closed stdout must stop the writing, not the moving: the command had
|
||||
// planned to move all three and reported success for doing so
|
||||
let run = case.ahab(&["link", "add", "a.env", "b.env", "c.env"]);
|
||||
run.ok();
|
||||
|
||||
for name in ["a.env", "b.env", "c.env"] {
|
||||
assert!(case.is_symlink(name), "{name} was left behind");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quiet_keeps_the_reason_a_path_failed() {
|
||||
let case = Case::new("quiet");
|
||||
case.write("ok.env", b"x\n");
|
||||
case.gitignore("ok.env\n");
|
||||
|
||||
let run = case.ahab(&["-q", "link", "add", "ok.env", "missing.env"]);
|
||||
run.failed()
|
||||
.says("1 of 2 paths failed")
|
||||
// the line saying *which* and *why* is a result, not progress
|
||||
.says("missing.env");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_dry_run_changes_nothing_on_disk() {
|
||||
let case = Case::new("dryrun");
|
||||
case.write(".env", b"SECRET=1\n");
|
||||
case.gitignore(".env\n");
|
||||
|
||||
case.ahab(&["--dry-run", "link", "add", ".env"]).ok();
|
||||
|
||||
assert!(!case.is_symlink(".env"));
|
||||
assert!(!case.store.join(".env").exists());
|
||||
}
|
||||
Reference in New Issue
Block a user