CI / fmt (rustfmt --check) (push) Waiting to run
CI / clippy (ubuntu-latest) (push) Waiting to run
CI / clippy (windows-latest) (push) Waiting to run
CI / test (ubuntu-latest) (push) Waiting to run
CI / test (windows-latest) (push) Waiting to run
CI / build release (ubuntu-latest) (push) Waiting to run
CI / build release (windows-latest) (push) Waiting to run
Guards / core 零 UI 守门 (push) Waiting to run
Guards / 文件行数 ≤400 守门 (push) Waiting to run
Guards / 依赖许可与来源(cargo-deny) (push) Waiting to run
单提交快照:main 只保留已发布版本的代码树,开发史在 dev。
130 lines
4.3 KiB
Rust
130 lines
4.3 KiB
Rust
//! `core::game::java::discover`:标准安装位置扫描与来源优先级。
|
||
//!
|
||
//! 真机上扫到什么取决于本机装了什么,所以断言只钉**不变量**:
|
||
//! 扫描结果形状、来源优先级(env 胜过扫盘)、去重保留高优先级、缺目录不报错。
|
||
|
||
use unlucky_core::game::java::discover;
|
||
use unlucky_core::game::java::mapping::{JavaRequirement, RequirementSource};
|
||
use unlucky_core::game::java::{pick, JavaOrigin, JavaRuntime};
|
||
|
||
fn runtime(path: &str, major: u32, origin: JavaOrigin) -> JavaRuntime {
|
||
JavaRuntime {
|
||
binary: std::path::PathBuf::from(path),
|
||
origin,
|
||
version: Some(format!("openjdk version \"{major}.0.1\"")),
|
||
major: Some(major),
|
||
bits: 64,
|
||
vendor: None,
|
||
}
|
||
}
|
||
|
||
fn at_least(minimum: u32) -> JavaRequirement {
|
||
JavaRequirement::new(minimum, None, RequirementSource::Table)
|
||
}
|
||
|
||
#[test]
|
||
fn scanned_paths_always_point_at_a_java_binary() {
|
||
// 本机可能一个都没有(裸机/容器)——那也算通过,只是列表为空。
|
||
for binary in discover::scan_java_binaries() {
|
||
assert!(
|
||
binary.is_file(),
|
||
"扫描结果必须是真实存在的文件:{}",
|
||
binary.display()
|
||
);
|
||
assert_eq!(
|
||
binary
|
||
.file_name()
|
||
.map(|name| name.to_string_lossy().into_owned()),
|
||
Some(unlucky_core::game::java::java_binary_name().to_string()),
|
||
"扫描结果必须是 bin/java[.exe]:{}",
|
||
binary.display()
|
||
);
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn standard_roots_are_absolute_and_unique() {
|
||
let roots = discover::standard_roots();
|
||
for root in &roots {
|
||
assert!(
|
||
root.is_absolute(),
|
||
"候选根必须是绝对路径:{}",
|
||
root.display()
|
||
);
|
||
}
|
||
let mut keys: Vec<String> = roots.iter().map(|root| discover::path_key(root)).collect();
|
||
let total = keys.len();
|
||
keys.sort();
|
||
keys.dedup();
|
||
assert_eq!(keys.len(), total, "候选根不该重复");
|
||
}
|
||
|
||
#[test]
|
||
fn environment_java_beats_scanned_java_when_both_satisfy() {
|
||
// D13 的「优先级链不变」:环境变量是用户意图,扫盘只是候选。
|
||
let candidates = [
|
||
runtime(
|
||
"C:/Program Files/Eclipse Adoptium/jdk-21/bin/java.exe",
|
||
21,
|
||
JavaOrigin::System,
|
||
),
|
||
runtime(
|
||
"C:/Program Files/Microsoft/jdk-21/bin/java.exe",
|
||
21,
|
||
JavaOrigin::JavaHome,
|
||
),
|
||
];
|
||
let picked = pick(&candidates, &at_least(17)).expect("应有候选");
|
||
assert_eq!(picked.origin, JavaOrigin::JavaHome);
|
||
}
|
||
|
||
#[test]
|
||
fn scanned_java_is_still_used_when_nothing_else_matches() {
|
||
// MSI 装了 Temurin 21、没设环境变量、PATH 上是 Java 8:1.20.5 只认扫盘那个。
|
||
let candidates = [
|
||
runtime("java", 8, JavaOrigin::Path),
|
||
runtime(
|
||
"C:/Program Files/Java/jdk-21/bin/java.exe",
|
||
21,
|
||
JavaOrigin::System,
|
||
),
|
||
];
|
||
let picked = pick(&candidates, &at_least(21)).expect("应有候选");
|
||
assert_eq!(picked.origin, JavaOrigin::System);
|
||
}
|
||
|
||
#[test]
|
||
fn dedupe_collapses_one_install_found_twice() {
|
||
// `JAVA_HOME` 指向 Program Files 里的 JDK → 同一个 java 不应列两次。
|
||
// 第二条的「另一种写法」随平台给:Windows 上大小写和分隔符都可能不一致(NTFS 不区分
|
||
// 大小写),POSIX 上大小写是有效区别,只能靠分隔符拼出同一路径的第二种写法。
|
||
let duplicate = if cfg!(windows) {
|
||
"c:/program files/java/jdk-21/bin/java.exe"
|
||
} else {
|
||
"C:\\Program Files\\Java\\jdk-21/bin/java.exe"
|
||
};
|
||
let candidates = discover::dedupe(vec![
|
||
runtime(
|
||
"C:/Program Files/Java/jdk-21/bin/java.exe",
|
||
21,
|
||
JavaOrigin::JavaHome,
|
||
),
|
||
runtime(duplicate, 21, JavaOrigin::System),
|
||
]);
|
||
assert_eq!(candidates.len(), 1);
|
||
assert_eq!(candidates[0].origin, JavaOrigin::JavaHome);
|
||
}
|
||
|
||
#[test]
|
||
fn registry_absence_is_tolerated() {
|
||
// 非 Windows 必然为空;Windows 上没装老 Oracle JDK 也是空。
|
||
let homes = discover::registry_homes();
|
||
for home in &homes {
|
||
assert!(
|
||
home.is_absolute(),
|
||
"注册表里的 JavaHome 应是绝对路径:{}",
|
||
home.display()
|
||
);
|
||
}
|
||
}
|