按 M218 SURVEY-p1 §4.1 的清单接上 LiteLoader 的安装路线,不动 OptiFine。
- core: 新增 addon::loader::liteloader(官方 versions.json 解析 + 合成清单)与
addon::loader::parent(父版本链读盘定位原版版本);LoaderKind 加 LiteLoader;
LoaderRelease 加 parent_version_id、LoaderPlanInput::vanilla_installed → parent_installed;
LoaderInstallPlan::build 改返回 Result(父版本缺失具名报错);LoaderSource::resolve_on
支持指定父版本(仅 LiteLoader,其它组合具名 unsupported)。
- 继承边界(本 mission 第一步核实):arguments.game 父在前子在后追加,minecraftArguments
子覆盖父,启动顺序 legacy(24) → arguments.game(25)。所以 tweakClass 只写 arguments.game,
绝不写 minecraftArguments(会顶掉 Forge 1.12.2 的 FMLTweaker)。
- maven/fabric 的 `_ =>` 通配改成穷尽分支:非 maven 族不再静默回落 Forge 的仓库;
maven::{metadata_url,installer_url} 改返回 Option<String>。
- presenter: supported() 收 LiteLoader、wizard_choices 六选、dto::instances 按关注点拆成
instances/{loader,runtime,create,tests}.rs(原文件 395 行,动手前先拆)。
- cli: --loader 区分「认不出」(loader_unknown) 与「认得但装不了」(loader_unsupported);
<version> 位写加载器版本 id 时按父版本处理(只有 liteloader 接受);help 只改 install 段。
- app-iced: 下载页加载器 chip 加 LiteLoader(1.5.2~1.12.2,两头按官方没有构建拒),
chip 清单改为委派 Loader::ALL。
- 测试: 真实响应的裁剪夹具(dl.liteloader.com 与 repo.mumfrey.com 的 maven-metadata)
驱动「解析→计划→落盘→继承→启动参数顺序」全链;Forge 父链有回归(FMLTweaker 必须还在
且排在 LiteLoader 之前);父版本缺失/组合不支持/取消/坏表各自具名错误。
141 lines
4.4 KiB
Rust
141 lines
4.4 KiB
Rust
//! `ull install --loader liteloader` 的**离线**可验面:词表分流、父版本缺失、help 文案。
|
||
//!
|
||
//! 这里刻意不联网:LiteLoader 的版本表在 `dl.liteloader.com`,把「拉到表之后」的链路放在
|
||
//! `crates/core/tests/liteloader/**`(真实响应夹具 + 合成 + 计划 + 落盘 + 启动参数)。
|
||
//! 本文件守的是「进门那一步」:`optifine` 与随机拼法的错误码必须分开、父版本没装必须具名报错、
|
||
//! 非 LiteLoader 不许叠在别的加载器层上。
|
||
|
||
#[path = "support/mod.rs"]
|
||
mod support;
|
||
|
||
use support::{parse_json, run_cli, TempDir};
|
||
|
||
#[test]
|
||
fn optifine_is_recognized_but_not_supported() {
|
||
let dir = TempDir::new("liteloader-optifine");
|
||
let (code, stdout, _) = run_cli(&[
|
||
"install",
|
||
"1.20.1",
|
||
"--loader",
|
||
"optifine",
|
||
"--json",
|
||
"--data-dir",
|
||
&dir.arg(),
|
||
]);
|
||
assert_eq!(code, 1);
|
||
let value = parse_json(&stdout);
|
||
assert_eq!(
|
||
value["error"]["code"], "loader_unsupported",
|
||
"optifine 是「认得但装不了」,不是未知加载器:{stdout}"
|
||
);
|
||
assert!(
|
||
value["error"]["message"]
|
||
.as_str()
|
||
.unwrap_or_default()
|
||
.contains("optifine"),
|
||
"{stdout}"
|
||
);
|
||
}
|
||
|
||
/// `optifine` 之外,真正不认识的拼法仍是 `loader_unknown`(样本用**明显无效**的名字,
|
||
/// 不拿任何真实加载器名当「未知」前提)。
|
||
#[test]
|
||
fn genuinely_unknown_loader_stays_unknown() {
|
||
let dir = TempDir::new("liteloader-unknown");
|
||
let (code, stdout, _) = run_cli(&[
|
||
"install",
|
||
"1.20.1",
|
||
"--loader",
|
||
"ull-invalid-loader-test",
|
||
"--json",
|
||
"--data-dir",
|
||
&dir.arg(),
|
||
]);
|
||
assert_eq!(code, 1);
|
||
let value = parse_json(&stdout);
|
||
assert_eq!(value["error"]["code"], "loader_unknown", "{stdout}");
|
||
let hint = value["error"]["hint"].as_str().unwrap_or_default();
|
||
assert!(hint.contains("liteloader"), "提示要列全六家:{hint}");
|
||
}
|
||
|
||
/// 父版本(`1.12.2-forge-…`)没装时:具名报缺哪个父版本,且**不发网络请求**。
|
||
#[test]
|
||
fn liteloader_on_a_missing_forge_parent_names_the_parent() {
|
||
let dir = TempDir::new("liteloader-missing-parent");
|
||
let (code, stdout, _) = run_cli(&[
|
||
"install",
|
||
"1.12.2-forge-14.23.5.2860",
|
||
"--loader",
|
||
"liteloader",
|
||
"--json",
|
||
"--data-dir",
|
||
&dir.arg(),
|
||
]);
|
||
assert_eq!(code, 1);
|
||
let value = parse_json(&stdout);
|
||
assert_eq!(value["error"]["code"], "loader_not_found", "{stdout}");
|
||
let message = value["error"]["message"].as_str().unwrap_or_default();
|
||
assert!(
|
||
message.contains("1.12.2-forge-14.23.5.2860"),
|
||
"要点名缺哪个父版本:{message}"
|
||
);
|
||
}
|
||
|
||
/// 只有 LiteLoader 接受「叠在别的加载器层上」;别家在进门处就说清(不静默改成叠原版)。
|
||
#[test]
|
||
fn only_liteloader_accepts_stacking_on_another_loader_layer() {
|
||
let dir = TempDir::new("liteloader-stack-guard");
|
||
let (code, stdout, _) = run_cli(&[
|
||
"install",
|
||
"1.12.2-forge-14.23.5.2860",
|
||
"--loader",
|
||
"fabric",
|
||
"--json",
|
||
"--data-dir",
|
||
&dir.arg(),
|
||
]);
|
||
assert_eq!(code, 1);
|
||
let value = parse_json(&stdout);
|
||
assert_eq!(value["error"]["code"], "usage", "{stdout}");
|
||
let message = value["error"]["message"].as_str().unwrap_or_default();
|
||
assert!(
|
||
message.contains("LiteLoader") && message.contains("Fabric"),
|
||
"{message}"
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn install_help_names_the_liteloader_route() {
|
||
let (code, stdout, _) = run_cli(&["help", "install"]);
|
||
assert_eq!(code, 0);
|
||
for needle in [
|
||
"liteloader",
|
||
"optifine",
|
||
"launchwrapper",
|
||
"tweakClass",
|
||
"loader_unsupported",
|
||
"loader_unknown",
|
||
] {
|
||
assert!(
|
||
stdout.contains(needle),
|
||
"`ull help install` 少了 `{needle}`:\n{stdout}"
|
||
);
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn general_help_lists_liteloader_under_install() {
|
||
let (code, stdout, _) = run_cli(&["--help"]);
|
||
assert_eq!(code, 0);
|
||
let install_block = stdout
|
||
.lines()
|
||
.skip_while(|line| !line.trim_start().starts_with("install <version>"))
|
||
.take(3)
|
||
.collect::<Vec<_>>()
|
||
.join("\n");
|
||
assert!(
|
||
install_block.contains("liteloader"),
|
||
"总帮助的 install 段要提到 liteloader:\n{install_block}"
|
||
);
|
||
}
|