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:?}");
}
|