release: v0.2.4 里程碑快照(孤儿提交,无父;树 = dev 68362e5)
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
CI / runtime smoke (ubuntu x64, xvfb) (push) Waiting to run
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / update-e2e (windows x64) (push) Waiting to run
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Waiting to run
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Waiting to run
Guards / core 零 UI 守门 (push) Waiting to run
Guards / presenter 零 UI 守门 (push) Waiting to run
Guards / design 零第三方依赖守门 (push) Waiting to run
Guards / unsafe 落点守门(集合必须恰好等于期望) (push) Waiting to run
Guards / 文件行数 ≤400 守门 (push) Waiting to run
Guards / 依赖许可与来源(cargo-deny) (push) Waiting to run
Release guard / 发布标记语义守门(push tag → 稳定版) (push) Waiting to run
Signing status(播报,不是门禁) / 判据自测(三行/退出码/变异重放/接线) (push) Waiting to run
Signing status(播报,不是门禁) / 签名就绪度(播报) (push) Waiting to run
Release / 选槽位(默认四个:Windows 两档 + Linux 两档) (push) Waiting to run
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
CI / runtime smoke (ubuntu x64, xvfb) (push) Waiting to run
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / update-e2e (windows x64) (push) Waiting to run
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Waiting to run
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Waiting to run
Guards / core 零 UI 守门 (push) Waiting to run
Guards / presenter 零 UI 守门 (push) Waiting to run
Guards / design 零第三方依赖守门 (push) Waiting to run
Guards / unsafe 落点守门(集合必须恰好等于期望) (push) Waiting to run
Guards / 文件行数 ≤400 守门 (push) Waiting to run
Guards / 依赖许可与来源(cargo-deny) (push) Waiting to run
Release guard / 发布标记语义守门(push tag → 稳定版) (push) Waiting to run
Signing status(播报,不是门禁) / 判据自测(三行/退出码/变异重放/接线) (push) Waiting to run
Signing status(播报,不是门禁) / 签名就绪度(播报) (push) Waiting to run
Release / 选槽位(默认四个:Windows 两档 + Linux 两档) (push) Waiting to run
本批内容见 CHANGELOG.md 的 0.2.4 段。按 D41 用孤儿快照推 main,保留「公开史只有里程碑」的模型。
This commit is contained in:
commit
a5d1dec495
1580 files changed
+320938
No files matched your search
@@ -0,0 +1,200 @@
|
||||
//! 边界与失败面:父版本缺失、组合不支持、数据源形状坏、取消。
|
||||
//!
|
||||
//! 网络层的失败映射(`DownloadError` → `loader_network`)由 `core::download` 的引擎测试
|
||||
//! 与既有加载器测试覆盖,这里**不联网**:外部源的真实可用性在 mission 报告里单独列
|
||||
//! (含探测结果),不混进单元测试冒充。
|
||||
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
use unlucky_core::addon::loader::liteloader::parse_versions;
|
||||
use unlucky_core::addon::loader::{
|
||||
LoaderErrorKind, LoaderInstallPlan, LoaderKind, LoaderPlanInput, LoaderSource,
|
||||
};
|
||||
use unlucky_core::download::blocking::block_on;
|
||||
use unlucky_core::game::arguments::Environment;
|
||||
use unlucky_core::game::install::{execute_with_cancel, InstallErrorKind};
|
||||
use unlucky_core::game::layout::GameLayout;
|
||||
|
||||
use crate::support::{engine, liteloader_release, prefill, put_version, TempDir, VANILLA_1122};
|
||||
|
||||
/// 父版本不是原版、又没装在盘上 → **具名报错**,绝不默默改成叠原版。
|
||||
#[test]
|
||||
fn missing_loader_parent_is_a_named_error() {
|
||||
let temp = TempDir::new("missing-parent");
|
||||
let layout = GameLayout::new(temp.path());
|
||||
put_version(&layout, "1.12.2", VANILLA_1122);
|
||||
let release = liteloader_release("1.12.2-forge-14.23.5.2860");
|
||||
|
||||
let error = LoaderInstallPlan::build(LoaderPlanInput {
|
||||
layout: &layout,
|
||||
release: &release,
|
||||
environment: &Environment::host(),
|
||||
parent_installed: false,
|
||||
})
|
||||
.expect_err("父版本缺失必须报错");
|
||||
assert_eq!(error.kind(), LoaderErrorKind::NotFound);
|
||||
assert!(
|
||||
error.message().contains("1.12.2-forge-14.23.5.2860"),
|
||||
"错误里要点名缺的是哪个父版本:{}",
|
||||
error.message()
|
||||
);
|
||||
assert!(error.hint().is_some(), "要给出下一步怎么办");
|
||||
}
|
||||
|
||||
/// 父版本链:读盘定位原版版本 id(合成 loader id / 定位 jar 都用它)。
|
||||
#[test]
|
||||
fn parent_chain_walks_to_the_vanilla_root() {
|
||||
let temp = TempDir::new("parent-chain");
|
||||
let layout = GameLayout::new(temp.path());
|
||||
put_version(&layout, "1.12.2", VANILLA_1122);
|
||||
put_version(
|
||||
&layout,
|
||||
"1.12.2-forge-14.23.5.2860",
|
||||
crate::support::FORGE_1122,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
unlucky_core::addon::loader::parent::root_version_id(&layout, "1.12.2-forge-14.23.5.2860")
|
||||
.expect("两层链应走得到根"),
|
||||
"1.12.2"
|
||||
);
|
||||
assert_eq!(
|
||||
unlucky_core::addon::loader::parent::root_version_id(&layout, "1.12.2").expect("根是自己"),
|
||||
"1.12.2"
|
||||
);
|
||||
|
||||
// 没装的父版本 → not_found(而不是猜一个原版版本号)。
|
||||
let error = unlucky_core::addon::loader::parent::root_version_id(&layout, "9.9.9-forge-1.0.0")
|
||||
.expect_err("缺父版本必须报错");
|
||||
assert_eq!(error.kind(), LoaderErrorKind::NotFound);
|
||||
}
|
||||
|
||||
/// 只有 LiteLoader 接受「父版本不是原版」;别家**具名拒绝**,不去发请求。
|
||||
#[test]
|
||||
fn only_liteloader_accepts_a_non_vanilla_parent() {
|
||||
let temp = TempDir::new("combo-guard");
|
||||
let engine = engine(temp.path());
|
||||
let source = LoaderSource::new(&engine, temp.path());
|
||||
let error = block_on(async {
|
||||
source
|
||||
.resolve_on(
|
||||
LoaderKind::Forge,
|
||||
"1.12.2",
|
||||
Some("14.23.5.2860"),
|
||||
Some("1.12.2-liteloader-1.12.2-SNAPSHOT"),
|
||||
)
|
||||
.await
|
||||
})
|
||||
.expect_err("Forge 叠在 LiteLoader 上必须被拒");
|
||||
assert_eq!(error.kind(), LoaderErrorKind::Unsupported);
|
||||
assert!(
|
||||
error
|
||||
.message()
|
||||
.contains("1.12.2-liteloader-1.12.2-SNAPSHOT"),
|
||||
"要说清是哪个组合:{}",
|
||||
error.message()
|
||||
);
|
||||
}
|
||||
|
||||
/// 版本表形状坏 / 空表:各自给具名大类,不当成「没有版本」糊过去。
|
||||
#[test]
|
||||
fn broken_version_table_is_reported_distinctly() {
|
||||
let shape = parse_versions(r#"{"versions": []}"#).expect_err("形状不符");
|
||||
assert_eq!(shape.kind(), LoaderErrorKind::Metadata);
|
||||
let empty = parse_versions(r#"{"meta": {}, "versions": {}}"#).expect_err("空表");
|
||||
assert_eq!(empty.kind(), LoaderErrorKind::NotFound);
|
||||
|
||||
// 版本段缺失(记录没有 version):只剩 latest 别名 → 仍当空表处理。
|
||||
let only_latest = r#"{"versions": {"1.7.10": {"artefacts": {"com.mumfrey:liteloader":
|
||||
{"latest": {"tweakClass": "x", "version": "", "file": "liteloader.jar"}}}}}}"#;
|
||||
let error = parse_versions(only_latest).expect_err("只有 http 别名时没有可用版本");
|
||||
assert_eq!(error.kind(), LoaderErrorKind::NotFound);
|
||||
}
|
||||
|
||||
/// 取消:执行段看标志就返回 `Cancelled`,**版本 JSON 不落盘**(不留半成品)。
|
||||
#[test]
|
||||
fn cancel_leaves_no_manifest() {
|
||||
let temp = TempDir::new("cancel");
|
||||
let layout = GameLayout::new(temp.path());
|
||||
put_version(&layout, "1.12.2", VANILLA_1122);
|
||||
let release = liteloader_release("1.12.2");
|
||||
let plan = LoaderInstallPlan::build(LoaderPlanInput {
|
||||
layout: &layout,
|
||||
release: &release,
|
||||
environment: &Environment::host(),
|
||||
parent_installed: true,
|
||||
})
|
||||
.expect("计划应可组");
|
||||
|
||||
let engine = engine(temp.path());
|
||||
prefill(&plan.install);
|
||||
let cancel = AtomicBool::new(true);
|
||||
let error = block_on(execute_with_cancel(
|
||||
&engine,
|
||||
&plan.install,
|
||||
4,
|
||||
None,
|
||||
Some(&cancel),
|
||||
))
|
||||
.expect_err("取消必须返回错误");
|
||||
assert_eq!(error.kind(), InstallErrorKind::Cancelled);
|
||||
assert!(
|
||||
!layout.version_json(&release.version_id).exists(),
|
||||
"取消之后不许留下版本清单"
|
||||
);
|
||||
}
|
||||
|
||||
/// 同一个 loader 版本 id 被两条父链请求:**具名报错**,且盘上那份清单一个字节都不动。
|
||||
///
|
||||
/// 为什么必须有这道门:`<原版>-liteloader-<ver>` 对「叠原版」与「叠 Forge」是同一个目录名,
|
||||
/// 直接覆盖会让已经登记、指向这个版本 id 的旧实例**静默换父链**(启动行为跟着变)。
|
||||
#[test]
|
||||
fn parent_collision_is_refused_instead_of_overwriting() {
|
||||
let temp = TempDir::new("parent-collision");
|
||||
let layout = GameLayout::new(temp.path());
|
||||
put_version(&layout, "1.12.2", VANILLA_1122);
|
||||
put_version(
|
||||
&layout,
|
||||
"1.12.2-forge-14.23.5.2860",
|
||||
crate::support::FORGE_1122,
|
||||
);
|
||||
|
||||
let vanilla_release = liteloader_release("1.12.2");
|
||||
let existing = serde_json::json!({
|
||||
"id": vanilla_release.version_id,
|
||||
"inheritsFrom": "1.12.2",
|
||||
"mainClass": "net.minecraft.launchwrapper.Launch",
|
||||
"arguments": {"game": ["--tweakClass", "com.mumfrey.liteloader.launch.LiteLoaderTweaker"]},
|
||||
"libraries": []
|
||||
});
|
||||
put_version(
|
||||
&layout,
|
||||
&vanilla_release.version_id,
|
||||
&serde_json::to_string_pretty(&existing).expect("序列化"),
|
||||
);
|
||||
let before = std::fs::read_to_string(layout.version_json(&vanilla_release.version_id))
|
||||
.expect("读旧清单");
|
||||
|
||||
let forge_release = liteloader_release("1.12.2-forge-14.23.5.2860");
|
||||
assert_eq!(
|
||||
forge_release.version_id, vanilla_release.version_id,
|
||||
"两条父链撞同一个 id"
|
||||
);
|
||||
let error = LoaderInstallPlan::build(LoaderPlanInput {
|
||||
layout: &layout,
|
||||
release: &forge_release,
|
||||
environment: &Environment::host(),
|
||||
parent_installed: true,
|
||||
})
|
||||
.expect_err("撞父链必须报错");
|
||||
assert_eq!(error.kind(), LoaderErrorKind::Unsupported);
|
||||
assert!(
|
||||
error.message().contains("1.12.2-forge-14.23.5.2860") && error.message().contains("1.12.2"),
|
||||
"要说清两条父链各是什么:{}",
|
||||
error.message()
|
||||
);
|
||||
|
||||
let after = std::fs::read_to_string(layout.version_json(&vanilla_release.version_id))
|
||||
.expect("读旧清单");
|
||||
assert_eq!(before, after, "报错之后盘上那份清单不许被改动");
|
||||
}
|
||||
Reference in new issue
Block a user