#![allow(
clippy::expect_used,
reason = "clippy.toml exempts test modules, and an integration test is a separate crate it cannot reach"
)]
use assert_cmd::Command;
use predicates::prelude::*;
fn reserve() -> Command {
let mut command = Command::cargo_bin("reserve").expect("the binary is built for the test run");
command.env_remove("RESERVE_CONCURRENCY");
command.env_remove("RESERVE_TIMEOUT");
command.env_remove("RESERVE_WIDTH");
command.env_remove("RESERVE_NO_INPUT");
command.env_remove("COLUMNS");
command.env_remove("LINES");
command.env("TERM", "xterm-256color");
command.env("NO_COLOR", "1");
command
}
#[test]
fn help_goes_to_stdout_and_exits_zero() {
reserve()
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Check one or more names"))
.stdout(predicate::str::contains("EXAMPLES:"));
}
#[test]
fn version_goes_to_stdout_and_exits_zero() {
reserve()
.arg("--version")
.assert()
.success()
.stdout(predicate::str::contains(env!("CARGO_PKG_VERSION")));
}
#[test]
fn every_subcommand_answers_its_own_help() {
for command in ["groups", "extensions", "config", "doctor", "completions"] {
reserve().args([command, "--help"]).assert().success();
}
}
#[test]
fn an_unknown_flag_is_a_usage_error() {
reserve()
.arg("--not-a-real-flag")
.assert()
.code(2)
.stderr(predicate::str::contains("--not-a-real-flag"));
}
#[test]
fn a_missing_name_is_refused_before_any_lookup_starts() {
reserve()
.assert()
.code(2)
.stderr(predicate::str::contains("name.list_empty"));
}
#[test]
fn an_unattended_run_never_waits_for_an_answer() {
for extra in [vec!["--no-input"], vec!["--json"], vec![]] {
let mut command = reserve();
command.args(&extra);
command
.timeout(std::time::Duration::from_secs(20))
.assert()
.code(2)
.stderr(predicate::str::contains("name.list_empty"));
}
reserve()
.env("CI", "true")
.timeout(std::time::Duration::from_secs(20))
.assert()
.code(2)
.stderr(predicate::str::contains("name.list_empty"));
}
#[test]
fn conflicting_flags_are_refused_by_the_parser() {
reserve()
.args(["--no-input", "--interactive", "example"])
.assert()
.code(2);
}
#[test]
fn an_unknown_group_names_the_value_and_carries_its_error_id() {
reserve()
.args(["extensions", "--group", "definitely-not-a-group"])
.assert()
.code(2)
.stderr(predicate::str::contains("group.unknown"));
}
#[test]
fn the_machine_readable_mode_emits_one_json_document_on_stdout() {
let output = reserve()
.args(["groups", "--json"])
.assert()
.success()
.get_output()
.stdout
.clone();
let parsed: serde_json::Value =
serde_json::from_slice(&output).expect("the json mode emits one complete document");
assert!(
parsed.as_array().is_some_and(|rows| !rows.is_empty()),
"the group listing is a non-empty array"
);
}
#[test]
fn a_piped_run_carries_no_escape_codes_and_no_progress_line() {
let output = reserve()
.args(["extensions", "--group", "popular"])
.assert()
.success()
.get_output()
.clone();
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!stdout.contains('\u{1b}'),
"piped output must stay parseable, with no styling"
);
assert!(
!output.stderr.contains(&b'\r'),
"the progress line must never render when stderr is not a terminal"
);
}
#[test]
fn the_boolean_environment_fallback_accepts_how_a_script_spells_true() {
for spelling in ["1", "true", "yes", "on"] {
reserve()
.env("RESERVE_NO_INPUT", spelling)
.args(["groups"])
.assert()
.success();
}
}
#[test]
fn the_completion_script_is_written_for_every_shell_offered() {
for shell in ["bash", "elvish", "fish", "powershell", "zsh"] {
reserve()
.args(["completions", shell])
.assert()
.success()
.stdout(predicate::str::contains("reserve"));
}
}
#[test]
fn the_diagnostic_command_reports_in_both_forms() {
reserve().arg("doctor").assert().success();
let output = reserve()
.args(["doctor", "--json"])
.assert()
.success()
.get_output()
.stdout
.clone();
let parsed: serde_json::Value =
serde_json::from_slice(&output).expect("the diagnostic json mode parses");
assert!(parsed.get("version").is_some(), "the build is identified");
}
#[test]
fn the_resolved_settings_are_reported_with_where_each_came_from() {
reserve()
.args(["config", "show"])
.assert()
.success()
.stdout(predicate::str::contains("timeout"))
.stdout(predicate::str::contains("built-in default"));
reserve()
.env("RESERVE_TIMEOUT", "60")
.args(["config", "show"])
.assert()
.success()
.stdout(predicate::str::contains("60"))
.stdout(predicate::str::contains("environment"));
reserve()
.args(["config", "show", "--width", "100"])
.assert()
.success()
.stdout(predicate::str::contains("100"))
.stdout(predicate::str::contains("flag"));
reserve().args(["config", "path"]).assert().success();
}
#[test]
fn the_diagnostic_names_where_the_registry_list_comes_from() {
reserve()
.arg("doctor")
.assert()
.success()
.stdout(predicate::str::contains("Network"))
.stdout(predicate::str::contains("data.iana.org"));
let output = reserve()
.args(["doctor", "--json"])
.assert()
.success()
.get_output()
.stdout
.clone();
let parsed: serde_json::Value =
serde_json::from_slice(&output).expect("the diagnostic json mode parses");
assert!(
parsed.get("network").is_some(),
"the json form carries the network block the help promises"
);
assert!(
parsed.get("paths").is_some(),
"the json form carries the paths the text form prints"
);
}
#[test]
fn append_cannot_start_a_write_on_its_own() {
reserve()
.args(["--append", "example", "--tld", "com"])
.assert()
.code(2)
.stderr(predicate::str::contains("append"));
}
#[test]
fn cautious_composes_with_a_pacing_flag_instead_of_refusing_it() {
reserve()
.args(["extensions", "--group", "popular"])
.env("RESERVE_CONCURRENCY", "8")
.assert()
.success();
}