diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:39:59 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:43:18 +0900 |
| commit | 894764ecb04f9c456b9ebda77d155bf6128e2175 (patch) | |
| tree | 5bd69c0e127bc257513c02a13541d876d722a931 | |
| parent | 3b783e97a9aac366a7d6e26059961ba53d5e8b20 (diff) | |
| download | php-shirabe-894764ecb04f9c456b9ebda77d155bf6128e2175.tar.gz php-shirabe-894764ecb04f9c456b9ebda77d155bf6128e2175.tar.zst php-shirabe-894764ecb04f9c456b9ebda77d155bf6128e2175.zip | |
test(cli): serialize cli_tests via serial_test
Replace the hand-rolled `SERIAL` mutex guarding process-global env access
with serial_test's `#[serial]` attribute on each test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| -rw-r--r-- | Cargo.lock | 37 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/shirabe/Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/shirabe/src/lib.rs | 21 |
4 files changed, 49 insertions, 11 deletions
@@ -457,6 +457,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] name = "futures-sink" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1574,6 +1585,31 @@ dependencies = [ ] [[package]] +name = "serial_test" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "sha1" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1619,6 +1655,7 @@ dependencies = [ "regex", "serde", "serde_json", + "serial_test", "sha1", "shirabe-class-map-generator", "shirabe-external-packages", @@ -24,6 +24,7 @@ reqwest = "0.13.4" serde = { version = "1.0.228", features = ["derive"] } serde_json = { version = "1.0.149", features = ["preserve_order"] } serde_urlencoded = "0.7.1" +serial_test = "3.5.0" sha1 = "0.11.0" sha2 = "0.11.0" tempfile = "3.27.0" diff --git a/crates/shirabe/Cargo.toml b/crates/shirabe/Cargo.toml index 7b95ae5..1176165 100644 --- a/crates/shirabe/Cargo.toml +++ b/crates/shirabe/Cargo.toml @@ -22,6 +22,7 @@ tokio.workspace = true url.workspace = true [dev-dependencies] +serial_test.workspace = true tempfile.workspace = true [lints] diff --git a/crates/shirabe/src/lib.rs b/crates/shirabe/src/lib.rs index ec63ee1..9182cbe 100644 --- a/crates/shirabe/src/lib.rs +++ b/crates/shirabe/src/lib.rs @@ -47,8 +47,9 @@ pub fn run(argv: Vec<String>) -> anyhow::Result<i32> { #[cfg(test)] mod cli_tests { + use serial_test::serial; use std::panic::{AssertUnwindSafe, catch_unwind}; - use std::sync::{Mutex, Once}; + use std::sync::Once; const COMMANDS: &[&str] = &[ "about", @@ -87,20 +88,15 @@ mod cli_tests { static QUIET_PANIC: Once = Once::new(); - /// `crate::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 `crate::run` while holding - // `SERIAL`, so no other thread reads or writes the environment concurrently with these calls. + // SAFETY: every test reaching this code is marked `#[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"); @@ -115,16 +111,19 @@ mod cli_tests { } #[test] + #[serial] fn version_flag() { assert!(run(&["--version"])); } #[test] + #[serial] fn help_flag() { assert!(run(&["--help"])); } #[test] + #[serial] 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:?}"); @@ -134,14 +133,13 @@ mod cli_tests { /// not panic (any exit code, including non-zero or an `Err` return, counts as success). fn run_no_panic(args: &[&str]) -> bool { QUIET_PANIC.call_once(|| std::panic::set_hook(Box::new(|_| {}))); - let _guard = SERIAL.lock().unwrap_or_else(|e| e.into_inner()); let original = std::env::current_dir().ok(); let dir = tempfile::tempdir().expect("create temp dir"); std::env::set_current_dir(dir.path()).expect("chdir to temp dir"); - // SAFETY: all environment access here happens while holding `SERIAL`, so no other thread - // touches the environment or working directory concurrently. + // SAFETY: every test reaching this code is marked `#[serial]`, so no other thread touches + // the environment or working directory concurrently. unsafe { std::env::remove_var("COLUMNS"); std::env::remove_var("LINES"); @@ -163,6 +161,7 @@ mod cli_tests { $( $(#[$attr])* #[test] + #[serial] fn $name() { assert!(run_no_panic(&[$cmd]), "`{}` panicked", $cmd); } |
