Unlucky Launcher v0.2.2
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
Release / 选槽位(默认两个 Windows) (push) Canceled after 0s
Release / build (${{ matrix.slot }}) (push) Canceled after 0s
Release / GitHub Release (push) Canceled after 0s
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
Release / 选槽位(默认两个 Windows) (push) Canceled after 0s
Release / build (${{ matrix.slot }}) (push) Canceled after 0s
Release / GitHub Release (push) Canceled after 0s
This commit is contained in:
commit
1105a86448
1128 files changed
+217164
No files matched your search
@@ -0,0 +1,213 @@
|
||||
//! host/install_processors.rs 的单测(拆文件守 400 行上限)。
|
||||
//!
|
||||
//! 夹具在 [`super::fixture`]:这里只断言「计划怎么组」「找不到 Java 怎么说」
|
||||
//! 「哪一步挂了怎么报」「进度文案长什么样」。
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use unlucky_core::addon::loader::forge::InstallProfile;
|
||||
use unlucky_core::addon::loader::processors::{ProcessorError, StepStatus};
|
||||
use unlucky_core::addon::loader::LoaderKind as CoreLoaderKind;
|
||||
use unlucky_core::download::DownloadErrorKind;
|
||||
use unlucky_core::game::install::{FileFailure, FileOutcome, FileRole, FileStatus, InstallReport};
|
||||
use unlucky_core::game::java::JavaRequirement;
|
||||
|
||||
use super::fixture::{input, installer, outcome, profile, Fake, Harness};
|
||||
use super::{diagnostic, java_missing, libraries_failed, stage, step_line, StageInput};
|
||||
|
||||
#[test]
|
||||
fn step_line_names_the_step_and_marks_the_outcome() {
|
||||
let executed = step_line(&outcome(StepStatus::Executed), 9);
|
||||
assert_eq!(
|
||||
executed,
|
||||
"installer 处理器 3/9:net.minecraftforge:installertools:1.3.0(1234 ms)"
|
||||
);
|
||||
let skipped = step_line(&outcome(StepStatus::Skipped), 9);
|
||||
assert!(skipped.contains("产物已就绪"), "{skipped}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diagnostic_keeps_the_stable_code_and_the_hint() {
|
||||
let failed = ProcessorError::failed("net.minecraftforge:installertools:1.3.0", "1", "boom")
|
||||
.with_hint("确认 Java 版本与磁盘权限");
|
||||
let text = diagnostic(&failed);
|
||||
assert!(text.contains("processor_failed"), "{text}");
|
||||
assert!(text.contains("退出码 1"), "{text}");
|
||||
assert!(text.contains("boom"), "stderr 尾部要留:{text}");
|
||||
assert!(text.contains("建议:确认 Java 版本"), "{text}");
|
||||
|
||||
let plan = diagnostic(&ProcessorError::plan("install profile 缺 `jar`"));
|
||||
assert!(plan.contains("processor_plan"), "{plan}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn java_missing_points_at_the_java_page() {
|
||||
let managed = PathBuf::from("/tmp/.ULL/java");
|
||||
let text = java_missing(&JavaRequirement::table(21, None), &managed);
|
||||
assert!(text.contains("Java 21+"), "{text}");
|
||||
assert!(text.contains("Java」页"), "{text}");
|
||||
assert!(text.contains("JAVA_HOME"), "{text}");
|
||||
assert!(text.contains(&managed.display().to_string()), "{text}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn libraries_failed_lists_at_most_three() {
|
||||
let files: Vec<FileOutcome> = (0..4)
|
||||
.map(|index| FileOutcome {
|
||||
role: FileRole::Library,
|
||||
name: format!("lib{index}.jar"),
|
||||
dest: PathBuf::from(format!("lib{index}.jar")),
|
||||
status: FileStatus::Failed,
|
||||
bytes: 0,
|
||||
source: None,
|
||||
failure: Some(FileFailure {
|
||||
kind: DownloadErrorKind::Network,
|
||||
message: "连接超时".to_string(),
|
||||
}),
|
||||
})
|
||||
.collect();
|
||||
let report = InstallReport {
|
||||
files,
|
||||
version_json: None,
|
||||
warnings: Vec::new(),
|
||||
};
|
||||
let text = libraries_failed(&report);
|
||||
assert!(text.contains("4 个失败,共 4 个"), "{text}");
|
||||
assert!(text.contains("lib0.jar"), "{text}");
|
||||
assert!(!text.contains("lib3.jar"), "最多列三条:{text}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_skips_when_the_version_json_is_already_there() {
|
||||
let h = Harness::new();
|
||||
let installer = installer();
|
||||
let profile = profile();
|
||||
let mut input = input(&profile, &installer);
|
||||
input.installed = true;
|
||||
let fake = Fake::new();
|
||||
let result = stage(&h.env, &h.engine, &input, &fake, &h.reporter(), &h.cancel);
|
||||
assert!(matches!(result, Ok(None)));
|
||||
assert!(fake.calls().is_empty(), "已装完就不该再动网络/Java");
|
||||
assert!(h.log().contains("跳过 installer processors"), "{}", h.log());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_skips_an_empty_processor_list() {
|
||||
let h = Harness::new();
|
||||
let installer = installer();
|
||||
let profile = InstallProfile::default();
|
||||
let input = input(&profile, &installer);
|
||||
let fake = Fake::new();
|
||||
let result = stage(&h.env, &h.engine, &input, &fake, &h.reporter(), &h.cancel);
|
||||
assert!(matches!(result, Ok(None)), "没有 processor 就没这段");
|
||||
assert!(fake.calls().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_reports_missing_installer_metadata() {
|
||||
let h = Harness::new();
|
||||
let input = StageInput {
|
||||
kind: CoreLoaderKind::Forge,
|
||||
mc_version: "1.20.1",
|
||||
version_id: "1.20.1-forge-47.2.0",
|
||||
profile: None,
|
||||
installer: None,
|
||||
installed: false,
|
||||
};
|
||||
let fake = Fake::new();
|
||||
let err = stage(&h.env, &h.engine, &input, &fake, &h.reporter(), &h.cancel).unwrap_err();
|
||||
assert!(err.contains("install profile"), "{err}");
|
||||
assert!(h.log().contains("失败:"), "{}", h.log());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_builds_the_command_line_from_the_install_profile() {
|
||||
let h = Harness::new();
|
||||
let installer = installer();
|
||||
let profile = profile();
|
||||
let input = input(&profile, &installer);
|
||||
let fake = Fake::new();
|
||||
let run = stage(&h.env, &h.engine, &input, &fake, &h.reporter(), &h.cancel)
|
||||
.expect("stage 成功")
|
||||
.expect("应当真的跑了 processors");
|
||||
assert_eq!(run.executed(), 1);
|
||||
let steps = fake.steps();
|
||||
assert_eq!(steps.len(), 1);
|
||||
let (index, label, args, classpath) = &steps[0];
|
||||
assert_eq!(*index, 1);
|
||||
assert_eq!(label, "net.minecraftforge:installertools:1.3.0");
|
||||
assert_eq!(args, &vec!["--task".to_string(), "MCP_DATA".to_string()]);
|
||||
assert_eq!(*classpath, 1, "jar 自己不在 -cp 里(拼命令行时才补)");
|
||||
assert_eq!(fake.calls(), vec!["libraries", "java", "run"]);
|
||||
let messages = h.messages();
|
||||
assert!(
|
||||
messages.iter().any(|m| m.contains("installer 处理器 1/1")),
|
||||
"面板要看到当前处理器:{messages:?}"
|
||||
);
|
||||
assert!(
|
||||
messages
|
||||
.last()
|
||||
.is_some_and(|m| m.contains("正在写入版本清单")),
|
||||
"{messages:?}"
|
||||
);
|
||||
assert!(
|
||||
h.log().contains("processors 完成:执行 1 步"),
|
||||
"{}",
|
||||
h.log()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_fails_loudly_without_a_usable_java() {
|
||||
let h = Harness::new();
|
||||
let installer = installer();
|
||||
let profile = profile();
|
||||
let input = input(&profile, &installer);
|
||||
let mut fake = Fake::new();
|
||||
fake.java = None;
|
||||
let err = stage(&h.env, &h.engine, &input, &fake, &h.reporter(), &h.cancel).unwrap_err();
|
||||
assert!(err.contains("Java"), "{err}");
|
||||
assert!(err.contains("托管目录"), "{err}");
|
||||
assert_eq!(
|
||||
fake.calls(),
|
||||
vec!["libraries", "java"],
|
||||
"没 Java 就不该起进程"
|
||||
);
|
||||
assert!(h.log().contains("失败:"), "{}", h.log());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_fails_loudly_when_a_processor_exits_nonzero() {
|
||||
let h = Harness::new();
|
||||
let installer = installer();
|
||||
let profile = profile();
|
||||
let input = input(&profile, &installer);
|
||||
let mut fake = Fake::new();
|
||||
fake.run_error = Some(ProcessorError::failed(
|
||||
"net.minecraftforge:installertools:1.3.0",
|
||||
"1",
|
||||
"java.lang.NoSuchMethodError",
|
||||
));
|
||||
let err = stage(&h.env, &h.engine, &input, &fake, &h.reporter(), &h.cancel).unwrap_err();
|
||||
assert!(err.contains("processor_failed"), "{err}");
|
||||
assert!(err.contains("NoSuchMethodError"), "{err}");
|
||||
let log = h.log();
|
||||
assert!(log.contains("失败:"), "{log}");
|
||||
assert!(log.contains("NoSuchMethodError"), "日志要能回溯:{log}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_reports_incomplete_library_downloads() {
|
||||
let h = Harness::new();
|
||||
let installer = installer();
|
||||
let profile = profile();
|
||||
let input = input(&profile, &installer);
|
||||
let mut fake = Fake::new();
|
||||
fake.libraries_ok = false;
|
||||
let err = stage(&h.env, &h.engine, &input, &fake, &h.reporter(), &h.cancel).unwrap_err();
|
||||
assert!(err.contains("依赖库没下全"), "{err}");
|
||||
assert!(err.contains("连接超时"), "{err}");
|
||||
assert_eq!(fake.calls(), vec!["libraries"], "库没下全就别去选 Java");
|
||||
let progress = h.meter.lock().expect("进度锁").progress.clone();
|
||||
assert!(progress.files_total >= 2, "依赖库要计入文件总数");
|
||||
}
|
||||
Reference in new issue
Block a user