fix(m198): JAVAGUARD——首屏自动扫 / 子进程回收 / 参数长度三条守卫 + 设置页正文结构断言
- 首屏自动扫:删掉 `cfg!(test)` 分叉,生产入口在测试里真跑;新增 `the_first_hydrate_starts_a_real_scan_by_itself`(删掉那一行、或把实参翻成 `true` 都红)。顺手删掉恒为假的 `seeded && !live`:截图种子档在上方就 return 了,编译器也 报 "assigned but never used"。 - proc:`kill()` + `wait()` 收进 `terminate()`(三个分支共用);用例先用同一条命令 真跑一次证明子进程起得来(`spawn().ok()?` 的空跑假绿),并新增 Linux/Android 的 僵尸回收用例(只 kill 不 wait ⇒ `/proc/<pid>` 留成僵尸)。 - java.extra_args:`MAX_JVM_ARGS = 1024` 镜像 schema,`Refusal::JvmTooLong` + 中英 文案 + JVM 输入框变红;App 级用例断言回执是具名的「太长」而不是通用的「写不进去」。 - 设置页正文:判据①从「数 `stack = stack.push(` 的出现次数」升级成按角色断言 (唯一来源 section_columns、`push(` 恰一次且实参是循环变量、尾表达式、禁 extend/chain/once/concat/append),单行折叠变异体现在会红。
This commit is contained in:
1 parent
7f697f5762
commit
aae9a233ff
9 files changed
+385
-81
No files matched your search
@@ -230,8 +230,8 @@ fn setting_row<'a>(ui: &'a Ui, label: &'a str, value: &'a str) -> Element<'a, Me
|
||||
/// 正文由两半拼成:`mod.rs` 的 [`section_columns`](super::section_columns) **生产**「每组一件」的列,
|
||||
/// `form` 只把它们堆起来再滚出去。于是:
|
||||
///
|
||||
/// - [`the_form_stops_at_its_last_group`] 守**收尾**:`form()` 里 `stack = stack.push(` 恰好一处、
|
||||
/// 且以 `frame::scroll(ui, stack)` 收尾 —— 尾部多一件、或整段换成别的拼装(push 数变 0)都红;
|
||||
/// - [`the_form_stacks_nothing_but_its_sections`] 守**收尾**:正文的唯一来源是 `section_columns`
|
||||
/// (`push(` 恰好一次、实参必须是循环变量、尾表达式是 `frame::scroll`)—— 多一件就红;
|
||||
/// - [`the_form_holds_exactly_one_column_per_group`] 守**生产**:真调 `section_columns` 数它交出的
|
||||
/// 列数(窄窗 == `GROUPS.len()`,单选各组 == 1)—— 多塞一件就红,**不管那件叫什么名字**。
|
||||
///
|
||||
@@ -244,9 +244,11 @@ fn setting_row<'a>(ui: &'a Ui, label: &'a str, value: &'a str) -> Element<'a, Me
|
||||
///
|
||||
/// ## 抓得住 / 抓不住(据实写)
|
||||
///
|
||||
/// 抓得住(三种变异都实测过):①按原样把卡加回循环之后(`stack = stack.push(...)`)⇒ 收尾那条红;
|
||||
/// ②改成「塞进列清单」(`section_columns` 里多 push 一件)⇒ 列数那条红,换任何名字都躲不掉;
|
||||
/// ③把拼装整段重写成别的形状(不再用上面那个惯用法)⇒ 收尾那条数的 1 变成 0,同样红。
|
||||
/// 抓得住(四种变异都实测过):①把卡折叠回循环
|
||||
/// (`stack = stack.push(section).push(frame::demo_card(…))`)⇒ 收尾那条数到 2 处 `push(`,红
|
||||
/// (与 `cargo fmt` 是否拆行无关);②换成别的来源(`stack = stack.push(frame::text_role(…))`)⇒
|
||||
/// 实参不是 `section`,红;③塞进列清单(`section_columns` 里多 push 一件)⇒ 列数那条红;
|
||||
/// ④整段改写成 `extend` / `chain` / 尾表达式再包一层 ⇒ 收尾那条红。
|
||||
/// 抓不住:**某一组自己的列里**换内容(比如某个分组真的需要自己的空态)。那不是本缺陷——本页允许
|
||||
/// 组内有空态,前提是它长在该组的列里、用本页语义的文案。`DevDocs/artifacts/m196/` 那组图是**当时**
|
||||
/// 的证据,不是将来的防线(静态图只能证明「现在没有」)。
|
||||
@@ -287,6 +289,15 @@ mod no_stray_empty_state {
|
||||
Ui::with_platform(SchemeFlavor::Light, Platform::Windows, FAMILIES)
|
||||
}
|
||||
|
||||
/// `form()` 的函数体,**剥掉每行 `//` 之后的部分**:判据数的是代码,注释里的 `push(` 不算。
|
||||
fn form_code() -> String {
|
||||
form_body()
|
||||
.lines()
|
||||
.map(|line| line.split("//").next().unwrap_or_default())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
/// 演示 / harness 路径那份只读状态(与 `pages::page` 同源,不伪造第二份)。
|
||||
fn states() -> States<'static> {
|
||||
States {
|
||||
@@ -295,24 +306,55 @@ mod no_stray_empty_state {
|
||||
}
|
||||
}
|
||||
|
||||
/// 判据 ①(**收尾**):循环之后没有任何额外的 `push`,且函数以滚出去收尾。
|
||||
/// 判据 ①(**收尾**):正文的柱子只有一个来源——`section_columns` 交出的那一列。
|
||||
///
|
||||
/// 循环体里只有一件(一组一列),所以「`stack = stack.push(` 恰好一次」等于「尾部空着」;
|
||||
/// 拼装被整段重写成别的形状时计数变 0,同样红。
|
||||
/// M195 r2 复审实测的盲区:原来数的是 `stack = stack.push(` 的出现**次数**,于是
|
||||
/// `stack = stack.push(section).push(frame::demo_card(ui, &[]));` 一句折叠里塞第二件时计数仍是 1
|
||||
/// (第二个 `.push(` 前面没有 `stack = `)⇒ 判据 ① 与 ② 同时绿。那是在数**写法**。现在按**角色**
|
||||
/// 断言:循环头直接迭代 `section_columns`、`push(` 恰好一次且实参是那个循环变量、尾表达式恰好是
|
||||
/// `frame::scroll(ui, stack)`、没有 `extend`/`chain`/`once`/`concat`/`append`。`push(` 按**次数**
|
||||
/// 数(拆行不影响),注释里的不算(先剥掉每行 `//`)。变异证明见模块文档的「抓得住」。
|
||||
#[test]
|
||||
fn the_form_stops_at_its_last_group() {
|
||||
let body = form_body();
|
||||
let pushes = body.matches("stack = stack.push(").count();
|
||||
fn the_form_stacks_nothing_but_its_sections() {
|
||||
let body = form_code();
|
||||
|
||||
assert!(
|
||||
body.contains("for section in section_columns("),
|
||||
"`form()` 的循环头必须直接迭代 `section_columns(...)`:正文节点的唯一来源就是它"
|
||||
);
|
||||
|
||||
let pushes = body.matches("push(").count();
|
||||
assert_eq!(
|
||||
pushes, 1,
|
||||
"`form()` 里出现了 {pushes} 处 `stack = stack.push(`:分组循环里只该有一处。\
|
||||
尾部又被叠了一件东西的话,设置页每一组下面都会多出同一件(M196 那张\
|
||||
「没有逐实例覆盖」的卡就是这么来的)"
|
||||
"`form()` 里出现了 {pushes} 处 `push(`:分组循环里只该有一处。多出来的那一处就是\
|
||||
「每组下面多一件」(M196 那张卡)——同一句里折叠成 `.push(a).push(b)` 也算两处"
|
||||
);
|
||||
assert!(
|
||||
body.contains(" frame::scroll(ui, stack)\n}"),
|
||||
|
||||
let at = body.find("push(").expect("上面刚数过一次") + "push(".len();
|
||||
let argument = body[at..].split(')').next().unwrap_or_default().trim();
|
||||
assert_eq!(
|
||||
argument, "section",
|
||||
"被压进正文的必须是 `section_columns` 交出的那一列(循环变量 `section`),实际是 \
|
||||
`{argument}`:别的来源(演示卡 / 空态 / 任何控件)都不许进正文"
|
||||
);
|
||||
|
||||
for append in ["extend(", "chain(", "once(", "concat(", "append("] {
|
||||
assert!(
|
||||
!body.contains(append),
|
||||
"`form()` 用了 `{append}`:正文只许从 `section_columns` 逐列 push 进来"
|
||||
);
|
||||
}
|
||||
|
||||
let tail: Vec<&str> = body
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty())
|
||||
.collect();
|
||||
assert_eq!(
|
||||
tail.iter().rev().take(2).copied().collect::<Vec<_>>(),
|
||||
vec!["}", "frame::scroll(ui, stack)"],
|
||||
"`form()` 必须以 `frame::scroll(ui, stack)` 收尾(后面紧跟函数右花括号):\
|
||||
正文到最后一组就结束,别再往后叠东西"
|
||||
正文到最后一组就结束,别再包一层或往后叠东西"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user