mod common;
use assert_cmd::Command;
#[cfg(unix)]
fn rat() -> Command {
common::rat_detached()
}
#[cfg(windows)]
fn rat() -> Command {
common::rat()
}
fn rat_bin() -> String {
assert_cmd::cargo::cargo_bin("rat").display().to_string()
}
#[test]
fn child_exit_code_is_propagated() {
rat()
.args(["spin", "--", &rat_bin(), "__exitcode", "3"])
.assert()
.code(3);
}
#[test]
fn silent_success_prints_nothing() {
rat()
.args(["spin", "--", &rat_bin(), "style", "hi"])
.assert()
.success()
.stdout("");
}
#[test]
fn show_output_passes_child_stdout_through() {
rat()
.env("NO_COLOR", "1")
.args(["spin", "--show-output", "--", &rat_bin(), "style", "hi"])
.assert()
.success()
.stdout("hi\n");
}
#[test]
fn show_error_prints_output_only_on_failure() {
rat()
.env("NO_COLOR", "1")
.args([
"spin",
"--show-error",
"--",
&rat_bin(),
"__exitcode",
"2",
"boom",
])
.assert()
.code(2)
.stderr(predicates::str::contains("boom"));
rat()
.env("NO_COLOR", "1")
.args(["spin", "--show-error", "--", &rat_bin(), "style", "fine"])
.assert()
.success()
.stdout("");
}
#[test]
fn missing_command_is_a_usage_error() {
rat().arg("spin").assert().code(2);
}
#[test]
fn a_child_that_outruns_the_bound_keeps_its_newest_lines() {
let assert = rat()
.args([
"spin",
"--show-output",
"--",
&rat_bin(),
"__lines",
"12000",
])
.assert()
.success();
let out = String::from_utf8(assert.get_output().stdout.clone()).expect("utf-8");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines.len(), 10_000, "the bound is a line count");
assert_eq!(lines.first().copied(), Some("2000"));
assert_eq!(lines.last().copied(), Some("11999"));
}
#[test]
fn spin_says_how_much_it_dropped_and_from_where() {
rat()
.args([
"spin",
"--show-output",
"--",
&rat_bin(),
"__lines",
"12000",
])
.assert()
.success()
.stderr(predicates::str::contains(
"2.0k lines dropped from stdout — kept the newest 10000",
));
}
#[test]
fn the_childs_stderr_is_bounded_on_its_own_route() {
let assert = rat()
.args([
"spin",
"--show-output",
"--",
&rat_bin(),
"__lines",
"--stderr",
"12000",
])
.assert()
.success();
let err = String::from_utf8(assert.get_output().stderr.clone()).expect("utf-8");
assert!(
err.contains("2.0k lines dropped from stderr — kept the newest 10000"),
"no notice for the stderr route: {}",
&err[..err.len().min(200)]
);
assert!(err.contains("\n11999\n"), "the newest line did not survive");
assert!(!err.contains("\n1999\n"), "a dropped line survived");
assert!(
assert.get_output().stdout.is_empty(),
"the child printed nothing on stdout"
);
}
#[test]
fn a_child_under_the_bound_is_replayed_whole_and_says_nothing() {
let assert = rat()
.args([
"spin",
"--show-output",
"--",
&rat_bin(),
"__lines",
"10000",
])
.assert()
.success();
let out = String::from_utf8(assert.get_output().stdout.clone()).expect("utf-8");
assert_eq!(
out.lines().count(),
10_000,
"exactly the bound is not over it"
);
assert_eq!(out.lines().next(), Some("0"), "nothing was evicted");
assert!(
assert.get_output().stderr.is_empty(),
"nothing was dropped, so there is nothing to say"
);
}
#[test]
fn a_flood_nobody_asked_to_see_is_not_reported() {
rat()
.args(["spin", "--", &rat_bin(), "__lines", "12000"])
.assert()
.success()
.stdout("")
.stderr("");
}
#[cfg(unix)]
#[test]
fn signal_death_becomes_exit_one() {
rat()
.args(["spin", "--", "sh", "-c", "kill -9 $$"])
.assert()
.code(1);
}
#[cfg(unix)]
#[test]
fn timeout_kills_the_child() {
rat()
.args(["spin", "--timeout", "200ms", "--", "sleep", "5"])
.assert()
.code(124)
.stderr(predicates::str::contains("timed out"));
}
#[test]
fn spawn_failure_is_a_plain_error() {
rat()
.args(["spin", "--", "no-such-binary-abcxyz"])
.assert()
.code(1)
.stderr(predicates::str::contains("no-such-binary-abcxyz"));
}