Unlucky Launcher v0.2.0
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
CI / runtime smoke (ubuntu x64, xvfb) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s

首个 iced + Material 3 Expressive 版本的源码快照。
完整历史与日常提交在 dev 分支;main 只放阶段性快照。
This commit is contained in:
AskaEth committed 2026-11-05 14:22:11 +08:00
commit 8a8e5ca0c0
1079 files changed
+208035

No files matched your search

+172
View File
@@ -0,0 +1,172 @@
//! `cli::Options` 的解析断言(M100 从 `cli.rs` 内联的 `mod tests` 搬出来:那边 394 行,
//! 加一个 `ForcedState::Rest` 就必然破 400)。
//!
//! 搬移**不改一行断言**:只去掉了 `mod tests { }` 那一层缩进,外加 M100 新增的
//! `screenshots_default_to_the_rest_state`(见文件末尾)。
//!
//! 站位:本文件是 `crate::cli::tests`,`use super::*;` 就够(`Options` / `ForcedState` /
//! `Backend` / `Screen` 都在 `cli` 里)。
use super::*;
fn parse(args: &[&str]) -> Result<Options, String> {
Options::parse(args.iter().map(|arg| (*arg).to_owned()))
}
#[test]
fn defaults_are_auto_system_theme_and_shell() {
let options = parse(&[]).expect("空参数要能解析");
assert_eq!(options.backend, Backend::Auto);
assert_eq!((options.theme, options.screenshot), (None, None));
assert_eq!(options.screen, Screen::Shell);
}
#[test]
fn software_renderer_is_an_alias_of_cpu() {
assert_eq!(
parse(&["--software-renderer"]).unwrap().backend,
Backend::Cpu
);
assert_eq!(parse(&["--renderer=cpu"]).unwrap().backend, Backend::Cpu);
assert_eq!(parse(&["--renderer", "gpu"]).unwrap().backend, Backend::Gpu);
}
#[test]
fn both_argv_forms_are_accepted() {
let spaced = parse(&["--screenshot", "out.png"]).unwrap();
let inline = parse(&["--screenshot=out.png"]).unwrap();
assert_eq!(spaced.screenshot, Some(PathBuf::from("out.png")));
assert_eq!(spaced.screenshot, inline.screenshot);
assert_eq!(
parse(&["--diff", "a.png", "b.png"]).unwrap().diff,
Some((PathBuf::from("a.png"), PathBuf::from("b.png")))
);
assert_eq!(
parse(&["--screen", "gallery"]).unwrap().screen,
Screen::Gallery
);
assert_eq!(parse(&["--diff-scan=2"]).unwrap().diff_scan, 2);
assert_eq!(
parse(&["--force-state", "hover"]).unwrap().force_state,
Some(ForcedState::Hover)
);
}
#[test]
fn screenshot_theme_wins_over_theme() {
let o = parse(&["--theme=dark", "--screenshot-theme=light"]).unwrap();
assert_eq!(
(o.theme, o.shot_flavor()),
(Some(SchemeFlavor::Dark), Some(SchemeFlavor::Light))
);
}
#[test]
fn bad_values_are_reported_not_panicked() {
for args in [
&["--renderer=metal"][..],
&["--theme=blue"],
&["--scale-factor=0"],
&["--scale-factor=abc"],
&["--screenshot"],
&["--diff", "only-one.png"],
&["--screen=settings"],
&["--force-state=focus"],
&["--diff-scan=-1"],
&["--nope"],
] {
assert!(parse(args).is_err(), "{args:?} 应该报错");
}
}
#[test]
fn data_dir_is_accepted_and_ignored_for_the_flip() {
// 现役 CI 冒烟:--software-renderer --screenshot <png> --data-dir <dir>
let options = parse(&[
"--software-renderer",
"--screenshot",
"shot.png",
"--data-dir",
"/d/tmp/x",
])
.expect("翻牌前必须兼容 --data-dir");
assert_eq!(options.backend, Backend::Cpu);
assert_eq!(options.screenshot, Some(PathBuf::from("shot.png")));
assert_eq!(options.data_dir, Some(PathBuf::from("/d/tmp/x")));
}
/// **取证不变量(M100)**:截图通道默认 Rest,交互模式保持 `None`,显式要态仍然优先。
///
/// 抓得住:① 谁把截图默认值改回 `None`(系统指针 hover 会重新漏进图,M99 复审实测翻盘过一次);
/// ② 谁顺手在交互模式也钉死状态(那会让真窗口永远看不到 hover)。
/// 抓不住:**产品页**上是否还有不消费 forced 的控件——那要出图比对,测试管不了。
#[test]
fn screenshots_default_to_the_rest_state() {
assert_eq!(
parse(&["--force-state=rest"]).unwrap().force_state,
Some(ForcedState::Rest),
"rest 是显式的合法取值"
);
assert_eq!(
parse(&["--screenshot", "out.png"]).unwrap().force_state,
Some(ForcedState::Rest),
"截图通道必须默认 Rest"
);
assert_eq!(
parse(&["--screenshot", "o.png", "--force-state=hover"])
.unwrap()
.force_state,
Some(ForcedState::Hover),
"显式要态时按用户给的画(状态矩阵图靠它)"
);
assert_eq!(
parse(&["--screenshot", "o.png", "--force-state=pressed"])
.unwrap()
.force_state,
Some(ForcedState::Pressed)
);
assert_eq!(
parse(&[]).unwrap().force_state,
None,
"交互模式不许替用户钉死状态"
);
assert_eq!(parse(&["--theme=dark"]).unwrap().force_state, None);
}
/// **门禁依赖**:CI 的 runtime-smoke 不带主题,截图模式必须有确定主题。
/// 退化成 `None` 的话,xvfb 里的 runner 会挂到超时(不是红,更难查)。
#[test]
fn screenshot_without_theme_defaults_to_light() {
let options = parse(&["--screenshot", "out.png"]).unwrap();
assert_eq!(options.shot_flavor(), None, "用户没给主题");
assert_eq!(
options.capture_flavor(),
Some(SchemeFlavor::Light),
"截图模式必须给确定主题(CI 冒烟依赖这条)"
);
assert!(!options.wants_system_theme(), "截图模式不许等系统主题");
}
#[test]
fn explicit_themes_still_win_in_screenshot_mode() {
let dark = parse(&["--screenshot", "a.png", "--theme=dark"]).unwrap();
assert_eq!(dark.capture_flavor(), Some(SchemeFlavor::Dark));
let both = parse(&[
"--screenshot",
"a.png",
"--theme=dark",
"--screenshot-theme=light",
]);
assert_eq!(both.unwrap().capture_flavor(), Some(SchemeFlavor::Light));
}
#[test]
fn interactive_mode_still_follows_the_system_theme() {
let interactive = parse(&[]).unwrap();
assert_eq!(interactive.capture_flavor(), None);
assert!(interactive.wants_system_theme(), "交互模式等系统主题");
let pinned = parse(&["--theme=dark"]).unwrap();
assert_eq!(pinned.capture_flavor(), Some(SchemeFlavor::Dark));
assert!(!pinned.wants_system_theme());
}