fix(core): M110 r2 —— duplicate_override_paths 两种冲突同时报,补 mrpack 同侧分支用例

- p2-2:`duplicate_override_paths` 改成「先按 path 分组,再在组内报 (侧集合, 条目份数)」,
  判据 `侧数 > 1 || 份数 > 侧数`。r1 修好了跨侧(Both×Client)但按侧去重把「同侧两个组
  撞同一路径」这条旧能力换掉了(实测返回 []);现在两种冲突同时报得出来,返回值升为
  `Vec<(String, Vec<PackSide>, usize)>`(M111 注意:这是最后一次改形状的窗口)。
- p3-a:mrpack `check_overrides` 的「每侧只能有一个覆盖目录」分支补用例(此前零测试,
  删掉它 54 条全绿;现在删掉即红)。
- p3-b:把 ReadBudget 的「每次调用一份额度,不是整包一份」写进 `override_files` /
  `ReadBudget` 文档(mrpack 连调三次 ⇒ 理论上限 3×;要整包共用额度就走
  `override_files_with`;`open` 阶段的声明总量仍是整包一次)。
- 顺带(复审点名、各一行):mrpack 非表达目录的 hint 里 21 个连续空格;
  curseforge 文档里 `.minecraft/.minecraft/…` 的说法按 CF 语义订正(overrides 是 zip 内前缀,
  内容铺开不丢;要不要多拷一层取决于导入器)。
This commit is contained in:
AskaEth committed 2026-11-04 00:20:25 +08:00
1 parent 6dd652aced
commit 34f3db359a
7 files changed
+111 -22

No files matched your search

@@ -127,3 +127,30 @@ fn same_format_export_is_still_allowed() {
.check_overrides(&manifest)
.expect("mrpack 自己读出来的模型必须能被 mrpack 表达");
}
#[test]
fn mrpack_refuses_two_override_groups_for_the_same_side() {
// r2 p3-a:mrpack 的「每侧只能有一个覆盖目录」分支此前零测试(删掉它 59 条全绿)。
// 目录名检查管不到这里:两个组的 `dir` 都合法,区别只在于同一侧出现了两次。
let mut manifest = PackManifest::new("同侧两个覆盖目录");
manifest.version = Some("1.0.0".to_string());
manifest.minecraft = Some("1.20.1".to_string());
manifest
.overrides
.push(PackOverrides::new("overrides", PackSide::Both));
manifest
.overrides
.push(PackOverrides::new("overrides", PackSide::Both));
let target = temp_root("export-mr-same-side").join("out.mrpack");
let error = MODRINTH
.write(&manifest, PackPayload::metadata_only(), &target)
.expect_err("同一侧两个覆盖目录必须拒");
assert_eq!(error.kind(), PackErrorKind::Unsupported, "{error}");
assert!(
error.message().contains("每个侧只能有一个覆盖目录"),
"错误要指出是「同侧重复」而不是「目录名不对」:{}",
error.message()
);
assert!(!target.exists(), "被拒时不许留下目标文件");
}
+38 -2
View File
@@ -33,9 +33,45 @@ fn duplicate_override_paths_counts_across_sides_not_per_side() {
manifest.duplicate_override_paths(),
vec![(
"config/x.toml".to_string(),
vec![PackSide::Both, PackSide::Client]
vec![PackSide::Both, PackSide::Client],
2
)],
"只报真正撞车的路径,并给出涉及的侧"
"只报真正撞车的路径,并给出涉及的侧与条目份数"
);
}
#[test]
fn duplicate_override_paths_still_reports_two_groups_on_the_same_side() {
// r2 p2-2:上一版按侧去重,把这半能力换掉了 —— 两个 Both 组撞同一路径实测返回 `[]`。
// 现在判据是「侧数 > 1 || 条份数 > 侧数」,两种冲突同时报得出来。
let mut first = PackOverrides::new("overrides", PackSide::Both);
first.files.push(file("config/x.toml", "a", 1));
let mut second = PackOverrides::new("extra-overrides", PackSide::Both);
second.files.push(file("config/x.toml", "b", 2));
let manifest = PackManifest {
overrides: vec![first, second],
..PackManifest::default()
};
assert_eq!(
manifest.duplicate_override_paths(),
vec![("config/x.toml".to_string(), vec![PackSide::Both], 2)],
"同侧两个组撞同一路径必须报(侧集合只有一个,份数是 2)"
);
}
#[test]
fn duplicate_override_paths_reports_the_same_path_twice_inside_one_group() {
// 同侧撞车的另一种形态:一个组里同一路径列了两次(模型被合并出来时会出现)。
let mut group = PackOverrides::new("overrides", PackSide::Both);
group.files.push(file("config/x.toml", "a", 1));
group.files.push(file("config/x.toml", "b", 2));
let manifest = PackManifest {
overrides: vec![group],
..PackManifest::default()
};
assert_eq!(
manifest.duplicate_override_paths(),
vec![("config/x.toml".to_string(), vec![PackSide::Both], 2)]
);
}