aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/cli.rs
blob: 09b974605b815ab4beeac868425e6527e35ef0eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::sync::{Mutex, Once};

const COMMANDS: &[&str] = &[
    "about",
    "archive",
    "audit",
    "browse",
    "bump",
    "check-platform-reqs",
    "clear-cache",
    "config",
    "create-project",
    "depends",
    "diagnose",
    "dump-autoload",
    "exec",
    "fund",
    "global",
    "init",
    "install",
    "licenses",
    "outdated",
    "prohibits",
    "reinstall",
    "remove",
    "repository",
    "require",
    "run-script",
    "search",
    "self-update",
    "show",
    "status",
    "suggests",
    "update",
    "validate",
];

static QUIET_PANIC: Once = Once::new();

/// `shirabe::run` reads/writes process-global env, so concurrent invocations race;
/// serialize them since the default test harness runs tests on many threads.
static SERIAL: Mutex<()> = Mutex::new(());

/// Runs the CLI with `args`. Returns true on clean exit, false on any panic / error / non-zero
/// exit.
fn run(args: &[&str]) -> bool {
    QUIET_PANIC.call_once(|| std::panic::set_hook(Box::new(|_| {})));
    let _guard = SERIAL.lock().unwrap_or_else(|e| e.into_inner());

    // Each invocation must look like a fresh process.
    //
    // SAFETY: all environment access in these tests happens through `shirabe::run` while holding
    // `SERIAL`, so no other thread reads or writes the environment concurrently with these calls.
    unsafe {
        std::env::remove_var("COLUMNS");
        std::env::remove_var("LINES");
    }

    let mut argv = vec!["composer".to_string()];
    argv.extend(args.iter().map(|s| s.to_string()));
    matches!(
        catch_unwind(AssertUnwindSafe(|| shirabe::run(argv))),
        Ok(Ok(0))
    )
}

#[test]
fn version_flag() {
    assert!(run(&["--version"]));
}

#[test]
fn help_flag() {
    assert!(run(&["--help"]));
}

#[test]
fn each_command_help() {
    let failed: Vec<&&str> = COMMANDS.iter().filter(|c| !run(&[c, "--help"])).collect();
    assert!(failed.is_empty(), "`<cmd> --help` failed for: {failed:?}");
}