//! 运行目录**碰撞**的 CLI 面:slug 同名 / 大小写不敏感不许让两个实例共用一个目录(复审 r1 的 R1)。 //! //! 从 `tests/adopt_test.rs` 拆出来只为守 400 行硬线;用例体未改。 use std::path::Path; use crate::support::{parse_json, run_cli, TempDir}; use crate::fixture::foreign_data_root; /// **slug 碰撞的两个展示名不能绑定同一个物理运行目录**(R1 的 CLI 面)。 /// /// 复审 r1 的实跑:`Better MC` 与 `Better-MC` 都成功、两个 UUID、却指向同一个目录, /// 随后 `launch --dry-run` 的 `--gameDir` 也是同一个。这条把它钉住。 /// /// 抓得住: /// - 登记侧不查已有实例占用的目录(两个 `run_dir` 相同,第一条断言红); /// - `launch` 的 `game_dir` 与登记的目录不一致(第三条断言红)。 /// /// 抓不住:`pack_dir` 的 slug 规则本身(既有行为,本 mission 不改)。 #[test] fn colliding_slug_names_get_separate_run_dirs() { let dir = TempDir::new("adopt-slug"); let root = dir.path(); foreign_data_root(root); let dir_arg = dir.arg(); let first = run_cli(&[ "instances", "adopt", "1.20.1", "--name", "Better MC", "--json", "--data-dir", dir_arg.as_str(), ]); assert_eq!( first.0, 0, "第一次登记应成功:stdout={} stderr={}", first.1, first.2 ); let first = parse_json(&first.1); let second = run_cli(&[ "instances", "adopt", "1.20.1", "--name", "Better-MC", "--json", "--data-dir", dir_arg.as_str(), ]); assert_eq!( second.0, 0, "第二次登记应成功:stdout={} stderr={}", second.1, second.2 ); let second = parse_json(&second.1); let first_dir = first["data"]["instance"]["run_dir"] .as_str() .expect("run_dir A") .to_string(); let second_dir = second["data"]["instance"]["run_dir"] .as_str() .expect("run_dir B") .to_string(); assert_ne!(first_dir, second_dir, "两个实例不许共用运行目录"); assert!( Path::new(&first_dir).is_dir() && Path::new(&second_dir).is_dir(), "两个运行目录都要真实存在" ); // 真启动计划(dry-run)也要分开:两条实例各自的 game_dir 不同。 for (value, expect) in [(&first, &first_dir), (&second, &second_dir)] { let id = value["data"]["instance"]["id"] .as_str() .expect("instance id"); let args = [ "launch", id, "--dry-run", "--json", "--data-dir", dir_arg.as_str(), ]; let (code, stdout, stderr) = run_cli(&args); assert_eq!( code, 0, "stdout={stdout} stderr={stderr}" ); assert_eq!( parse_json(&stdout)["data"]["game_dir"] .as_str() .expect("game_dir"), expect.as_str() ); } }