test(m126 r2): 加一支枚举不更新对外契约现在必然红(集合断言 + help 守卫)
r2 复审指出「加一家加载器会被逼着表态」只做到一半:编译期只拦「漏 match」,三处消费方 用最省事的 `=> Vanilla` 糊过去既编得过、测试也全绿——新加载器会静默显示成原版,正是本 mission 要消灭的形态(r1 里「Rift 会红」是负样本名字撞上的巧合,不是守卫)。 - presenter 的 `loader_kind_ids_are_the_released_contract` 增加**第 ② 段**:把 core 的 `LoaderKind::ALL.map(as_str)` 与独立手写的七个 id 做**集合相等**比较。加一支而不更新 契约 → 红;改词表 → 红。(r1 删掉 `assert!(ALL.len()==7)` 后缺的正是这一环:数组宽度 只保证「表里那一行写成 7 个」,不保证枚举没多一支。) - 新增 `cli::commands::instances::help_vocabulary_tests::help_lists_every_stable_id`: 按 `LoaderKind::ALL` 遍历 `ull help instances` 的词表行,漏写一个新 id 必红(此前 `help.rs:67` 那段词表没有任何测试,而旧的 `help_documents_the_loader_field_contract` 只查关键词,加一家新加载器时它照样绿)。 - `addon::loader::tests::vocabulary` 补 `installable_list_matches_the_from_core_mapping`: 把唯一还手写的 `LoaderKind::all()` 与 `from_core` 认可的集合对齐(不重抄字面量)。 - 模块文档第 ③ 步改成真话:契约测试会拦「改词表」与「加新种类」;但 `=> Vanilla` 这种 糊法**编得过**,拦住它的是那条集合断言,不是编译器(改名同理,只有契约测试会红)。 - 一并修掉 presenter 那条测试 doc 里指向已被删除的 `MARKERS` / `markers_cover_every_kind_that_has_one` 的引用,改指向现在真实存在的守卫。 - loader.rs 从 398 压到 395(≤400,留 5 行余量;拆测试到子模块需要 scope 放宽到 `crates/core/src/game/loader/**`,超出本任务文件清单,已按规矩记账)。 验收实测(临时加 `Abyss` + 三处 `=> Vanilla` 糊过去,已还原):presenter 契约测试红 (left 8 项 / right 7 项),CLI help 测试红(漏了 `abyss`);core 往返测试与安装侧清单 守卫、CLI 的 `json_rows_*` 仍绿(它们本就管别的事)。
This commit is contained in:
1 parent
a322cfcbfe
commit
14ac0dc248
4 files changed
+101
-35
No files matched your search
@@ -61,3 +61,24 @@ fn modrinth_alias_is_input_only() {
|
||||
assert_eq!(LoaderKind::parse(raw), None, "`{raw}` 不该被安装侧接受");
|
||||
}
|
||||
}
|
||||
|
||||
/// [`LoaderKind::all`] 是安装侧唯一还手写的清单(CF id 前缀匹配、CLI `--loader` 提示用),
|
||||
/// 它与 [`LoaderKind::from_core`] 认可的集合必须一致——不重抄字面量,直接对映射本身。
|
||||
///
|
||||
/// 抓得住:往 core 加一家**能装**的加载器,`from_core` 补了却忘了 `all()`(CLI 提示会漏一家、
|
||||
/// CF id 不认识它的前缀);反过来 `all()` 里多一家而 `from_core` 说装不了。
|
||||
/// 抓不住:`all()` 的顺序(那是 CLI 提示的展示序,没有对外契约意义)。
|
||||
#[test]
|
||||
fn installable_list_matches_the_from_core_mapping() {
|
||||
let mut derived: Vec<LoaderKind> = Wide::ALL
|
||||
.into_iter()
|
||||
.filter_map(LoaderKind::from_core)
|
||||
.collect();
|
||||
derived.sort_unstable();
|
||||
let mut listed = LoaderKind::all().to_vec();
|
||||
listed.sort_unstable();
|
||||
assert_eq!(
|
||||
listed, derived,
|
||||
"`LoaderKind::all()` 必须正好是 `from_core` 认可的那几家"
|
||||
);
|
||||
}
|
||||
@@ -17,29 +17,29 @@
|
||||
//!
|
||||
//! 契约(0.2.0 已发布形状,**不许改名**):`vanilla` / `fabric` / `quilt` / `forge` /
|
||||
//! `neoforge` / `optifine` / `liteloader`。生产代码里这七个串只有**一处**:下面那次
|
||||
//! `loader_kind_vocab!` 展开——枚举、`ALL`、`as_str`、`has_marker` 全从同一张表长出来,
|
||||
//! 所以「加了一支却漏进清单」**物理上做不到**(手写枚举 + 手写清单时它既不报错也不会被测试
|
||||
//! 抓住:测试同样从 `ALL` 出发,新加载器被**静默**当成「认不出」)。安装侧与 presenter 的
|
||||
//! `as_str` / `parse` 都是**委派**,CLI 直接调;唯一不在词表里的字面量是安装侧收的输入别名
|
||||
//! `neo-forge`(Modrinth 拼法,只进不出)。
|
||||
//! `loader_kind_vocab!` 展开——枚举、`ALL`、`as_str`、`has_marker` 全从同一张表长出来,所以
|
||||
//! 「加了一支却漏进清单」物理上做不到(理由见宏的注释)。安装侧与 presenter 的 `as_str` /
|
||||
//! `parse` 都是**委派**,CLI 直接调;唯一不在词表里的字面量是安装侧收的输入别名 `neo-forge`
|
||||
//! (Modrinth 拼法,只进不出)。
|
||||
//!
|
||||
//! 加一家加载器要动:① `loader_kind_vocab!` 表里加一行(id + 认不认标记)→ 枚举 / `ALL` /
|
||||
//! `as_str` / `has_marker` / 解析顺序一起长出来,漏不了;② presenter 的 `to_core`·`from_core`
|
||||
//! **编不过**(逼你决定 DTO 怎么显示它),能装的话安装侧 `as_str`·`from_core` 也各差一支;
|
||||
//! ③ 契约测试(presenter 的 `loader_kind_ids_are_the_released_contract`、CLI 的
|
||||
//! `json_rows_expose_loader_kind_and_version`、`ull help instances` 的词表行)**会红**——那
|
||||
//! 是逼你确认「对外词表真的要多一个 id」,因为 0.2.0 已经发出去过。
|
||||
//! ③ 契约测试**会红**:presenter 的 `loader_kind_ids_are_the_released_contract` 把 core 的
|
||||
//! `ALL` 与独立手写的七个 id 做**集合比较**,CLI 的 `help_lists_every_stable_id` 按 `ALL`
|
||||
//! 遍历 help 词表,`json_rows_*` 钉真二进制输出面——三处都逼你确认「对外词表真的要多一个
|
||||
//! id」,因为 0.2.0 已经发出去过。
|
||||
//!
|
||||
//! 分工:**改名**(`neoforge` → `neo_forge`)不会被往返测试抓住(词表与解析同源、改名自洽),
|
||||
//! 只有第 ③ 步的契约测试会红——那里**故意**再抄一遍七个串,那是唯一抓得住改名的东西;往返
|
||||
//! 测试抓的是「规则把 id 认错」。
|
||||
//! ⚠️ 分工要看准:**编译器只拦「漏 match」**。新种类在三处消费方用最省事的 `=> Vanilla` 糊
|
||||
//! 过去是**编得过**的(那时它会被静默当成原版);真正拦住这件事的是 ③ 里那条集合断言,不是
|
||||
//! 编译器。**改名**(`neoforge` → `neo_forge`)同理:往返测试是绿的(词表与解析同源、改名自
|
||||
//! 洽),只有 ③ 会红——那里**故意**再抄一遍七个串。
|
||||
//!
|
||||
//! # 解析规则(按整段前缀匹配,大小写不敏感,**最靠左的标记胜**)
|
||||
//!
|
||||
//! 1. 把 id 按 `-` 切段,从左往右找第一段,它的**前缀**是某个加载器标记
|
||||
//! (`neoforge` / `fabric` / `quilt` / `forge` / `optifine` / `liteloader`);
|
||||
//! 标记后面紧跟的 `loader` 段(`fabric-loader-…`)、或同一段里的 `_loader` 尾巴,
|
||||
//! 都算标记的一部分而不是版本段;
|
||||
//! (`neoforge` / `fabric` / `quilt` / `forge` / `optifine` / `liteloader`);紧跟的 `loader`
|
||||
//! 段(`fabric-loader-…`)或同段里的 `_loader` 尾巴算标记的一部分,不是版本段;
|
||||
//! 2. 该段里标记之后剩下的部分,加上它右边的所有段,按 `-` 拼回版本段
|
||||
//! (`_` 之类的原样保留,所以 `1.13.2-OptiFine_HD_U_E6` 的版本是 `HD_U_E6`);
|
||||
//! 3. 例外:版本段有 **≥2 段** 且**最后一段**长得像 MC 版本(`1.20.1` 这种纯数字点号)时
|
||||
@@ -50,11 +50,10 @@
|
||||
|
||||
/// 一张表生成整份词表:枚举、[`LoaderKind::ALL`]、`as_str`、`has_marker` 一起长出来。
|
||||
///
|
||||
/// 为什么非要用宏:Rust 没有「枚举有哪几支」的编译期反射,手写枚举 + 手写清单时「加了一支
|
||||
/// 却忘了进清单」既不报错也不会被测试抓住(测试同样从清单出发),新加载器被**静默**当成
|
||||
/// 「认不出」。让两者从同一张表展开,这件事在物理上不可能发生。
|
||||
///
|
||||
/// 表里的顺序就是标记的匹配优先级;带 `marker` 的条目参与 id 识别,不带的(原版)不参与。
|
||||
/// 为什么非要用宏:Rust 没有「枚举有哪几支」的编译期反射,手写枚举 + 手写清单时「加了一支却
|
||||
/// 忘了进清单」既不报错也不会被测试抓住(测试同样从清单出发),新加载器被**静默**当成「认不
|
||||
/// 出」;让两者从同一张表展开,这件事在物理上不可能发生。表里的顺序就是标记的匹配优先级;
|
||||
/// 带 `marker` 的条目参与 id 识别,不带的(原版)不参与。
|
||||
macro_rules! loader_kind_vocab {
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
@@ -231,8 +230,8 @@ fn join_version(parts: &[&str]) -> String {
|
||||
kept.join("-")
|
||||
}
|
||||
|
||||
/// 这一段长得像不像 MC 版本(`1.20.1` 这种全数字 + 点号)。只用于「砍 HMCL 尾巴」,那一条
|
||||
/// 要求前面还有内容(`≥2` 段),所以单独的 `0.16.5` 不会被砍,`0.20.0-beta.9` 也不会。
|
||||
/// 这一段长得像不像 MC 版本(`1.20.1` 这种全数字 + 点号);只用于「砍 HMCL 尾巴」(要求前面
|
||||
/// 还有内容,所以 `0.16.5` 与 `0.20.0-beta.9` 都不受影响)。
|
||||
fn looks_like_mc_version(text: &str) -> bool {
|
||||
text.contains('.')
|
||||
&& text
|
||||
@@ -375,11 +374,9 @@ mod tests {
|
||||
|
||||
/// 往返锚:**每个对外 id 喂回解析都要认成它自己**,标记顺序也得留优先级。
|
||||
///
|
||||
/// 抓得住:标记匹配退化(段前缀变整段全等、`loader` 后缀/MC 尾巴规则被改坏);标记串与
|
||||
/// 词表脱节;`neoforge` 被排到 `forge` 后面。
|
||||
/// 抓不住:**改名**(`neoforge` → `neo_forge`)——词表与解析同源、改名自洽,本条是绿的;
|
||||
/// 抓改名是对外契约测试的职责(`cli::commands::instances::tests::
|
||||
/// json_rows_expose_loader_kind_and_version`)。
|
||||
/// 抓得住:标记匹配退化(段前缀变整段全等、`loader` 后缀/MC 尾巴规则被改坏)、标记串与词表
|
||||
/// 脱节、`neoforge` 被排到 `forge` 后面。抓不住:**改名**——词表与解析同源、改名自洽,本条
|
||||
/// 是绿的;抓改名是 presenter 的 `loader_kind_ids_are_the_released_contract`。
|
||||
#[test]
|
||||
fn every_stable_id_parses_back_to_its_kind() {
|
||||
for kind in LoaderKind::ALL {
|
||||
|
||||
Reference in new issue
Block a user