use super::*;
fn run_version(args: &[&str]) -> String {
let assertion = cabin().args(args).assert().success();
let out = assertion.get_output();
let stderr = String::from_utf8_lossy(&out.stderr).to_string();
assert!(
stderr.is_empty(),
"cabin {args:?} stderr should be empty: {stderr}"
);
String::from_utf8(out.stdout.clone()).expect("stdout should be utf-8")
}
#[test]
fn version_subcommand_prints_concise_release_name() {
let stdout = run_version(&["version"]);
assert_eq!(stdout, format!("cabin {CABIN_VERSION}\n"));
}
#[test]
fn top_level_dash_dash_version_still_works() {
let stdout = run_version(&["--version"]);
assert_eq!(stdout, format!("cabin {CABIN_VERSION}\n"));
}
#[test]
fn top_level_dash_v_short_still_works() {
let stdout = run_version(&["-V"]);
assert_eq!(stdout, format!("cabin {CABIN_VERSION}\n"));
}
#[test]
fn version_verbose_omits_build_metadata() {
let stdout = run_version(&["version", "-v"]);
let first_line = stdout.lines().next().expect("at least one line");
assert_eq!(first_line, format!("cabin {CABIN_VERSION}"));
assert!(
stdout.contains(format!("release: {CABIN_VERSION}").as_str()),
"verbose version missing `release:` line: {stdout}"
);
for removed in ["commit-hash:", "commit-date:", "host:"] {
assert!(
!stdout.contains(removed),
"verbose version unexpectedly contains removed build metadata `{removed}`: {stdout}"
);
}
}
#[test]
fn version_verbose_long_form_matches_short_form() {
let short = run_version(&["version", "-v"]);
let long = run_version(&["version", "--verbose"]);
assert_eq!(
short, long,
"`-v` and `--verbose` should produce identical output"
);
}
#[test]
fn global_verbose_before_subcommand_also_triggers_verbose() {
let trailing = run_version(&["version", "-v"]);
let leading = run_version(&["-v", "version"]);
assert_eq!(
trailing, leading,
"`cabin -v version` and `cabin version -v` should agree"
);
}
#[test]
fn verbose_emits_fields_in_deterministic_order() {
let first = run_version(&["version", "-v"]);
let second = run_version(&["version", "-v"]);
assert_eq!(first, second);
let canonical_order = ["release", "os"];
let observed: Vec<&str> = first
.lines()
.skip(1) .filter_map(|line| line.split(':').next())
.collect();
let mut next = 0;
for label in &observed {
let position = canonical_order
.iter()
.position(|known| known == label)
.unwrap_or_else(|| panic!("unexpected label `{label}` in {first}"));
assert!(
position >= next,
"labels appeared out of order: `{label}` before expected slot ({first})"
);
next = position;
}
assert!(observed.contains(&"release"));
}
#[test]
fn version_quiet_does_not_suppress_output() {
let stdout = run_version(&["version", "-q"]);
assert_eq!(stdout, format!("cabin {CABIN_VERSION}\n"));
let stdout_leading = run_version(&["-q", "version"]);
assert_eq!(stdout_leading, format!("cabin {CABIN_VERSION}\n"));
}
#[test]
fn version_verbose_never_leaks_local_filesystem_paths() {
let stdout = run_version(&["version", "-v"]);
for needle in ["/Users/", "/home/", "/private/", "/opt/", "/tmp/", "/root/"] {
assert!(
!stdout.contains(needle),
"verbose version unexpectedly contains `{needle}`: {stdout}"
);
}
}
#[test]
fn version_verbose_never_leaks_username_or_hostname() {
let stdout = run_version(&["version", "-v"]);
if let Ok(user) = std::env::var("USER")
&& !user.is_empty()
&& user.len() >= 3
&& user != "user"
{
assert!(
!stdout.contains(&user),
"verbose version unexpectedly contains $USER ({user}): {stdout}"
);
}
if let Ok(home) = std::env::var("HOME") {
if let Some(name) = std::path::Path::new(&home)
.file_name()
.and_then(|s| s.to_str())
&& !name.is_empty()
&& name.len() >= 3
{
assert!(
!stdout.contains(name),
"verbose version unexpectedly contains $HOME basename ({name}): {stdout}"
);
}
}
}
#[test]
fn version_verbose_never_leaks_internal_planning_or_prompt_text() {
let stdout = run_version(&["version", "-v"]);
for forbidden in ["TODO", "FIXME", "roadmap"] {
assert!(
!stdout.contains(forbidden),
"verbose version unexpectedly contains `{forbidden}`: {stdout}"
);
}
}
#[test]
fn top_level_help_lists_version_subcommand() {
let assertion = cabin().arg("--help").assert().success();
let stdout = String::from_utf8_lossy(&assertion.get_output().stdout).to_string();
assert!(
stdout.contains("version"),
"top-level help should list the `version` subcommand: {stdout}"
);
}
#[test]
fn version_help_documents_inheriting_global_verbosity() {
let assertion = cabin().args(["version", "--help"]).assert().success();
let stdout = String::from_utf8_lossy(&assertion.get_output().stdout).to_string();
assert!(
stdout.contains("--verbose"),
"`cabin version --help` should mention --verbose: {stdout}"
);
assert!(
stdout.contains("--quiet"),
"`cabin version --help` should mention --quiet: {stdout}"
);
}
#[test]
fn version_works_outside_workspace() {
let dir = TempDir::new().unwrap();
let assertion = cabin()
.current_dir(dir.path())
.arg("version")
.assert()
.success();
let stdout =
String::from_utf8(assertion.get_output().stdout.clone()).expect("stdout should be utf-8");
assert_eq!(stdout, format!("cabin {CABIN_VERSION}\n"));
}
#[test]
fn version_verbose_works_outside_workspace() {
let dir = TempDir::new().unwrap();
let assertion = cabin()
.current_dir(dir.path())
.args(["version", "-v"])
.assert()
.success();
let stdout =
String::from_utf8(assertion.get_output().stdout.clone()).expect("stdout should be utf-8");
assert!(stdout.starts_with(format!("cabin {CABIN_VERSION}\n").as_str()));
assert!(stdout.contains(format!("\nrelease: {CABIN_VERSION}\n").as_str()));
}
#[test]
fn other_cargo_interface_commands_still_appear_in_help() {
let assertion = cabin().arg("--help").assert().success();
let stdout = String::from_utf8_lossy(&assertion.get_output().stdout).to_string();
for cmd in visible_subcommand_names() {
assert!(
stdout.contains(&cmd),
"top-level help should still list `{cmd}`: {stdout}"
);
}
}