test(app-iced): M102 r5 行距护栏追绑定(M4 假绿做死)+ 等价重构不再假红(M3/M6)
r4 复审的结论是「产品代码没问题,两条 p1 都在护栏的『抓得住』与实测不符」:
- **M4(真正的假绿,做死)**:`rows = rows.spacing(ui.space(Space::X1));` 只要另起一条语句
就能绕过「只锁构建链」的旧护栏。现在 `list_column_spaces_rows_only_from_the_shared_constant`
用 `function_region` 取整段函数,再用 `source::call_arguments` 拿每一处 `rows.spacing(…)`
的实参,并用新增的 `source::derived_from` 顺 `let` / `Some(x) =` 绑定往回追(最多三跳):
实参必须追回 `ROW_SPACING`。于是
· 直接 `ui.space(spacing)`(来自 `if let Some(spacing) = ROW_SPACING`)→ 绿;
· `let spacing = ROW_SPACING;` 再中转(H3)→ 绿;
· 先把令牌挪进 `let extra = Space::X1;` 再 `rows.spacing(ui.space(extra))`(M4)→ 红。
- **M3(假红)**:日志接线护栏改用 `function_region`,于是 `wrap::breakable` 外面套一层同义
包装(`fn soft(…) { mono_owned(ui, wrap::breakable(…)) }`)不再假红;整条链路都没碰
`wrap::breakable` 照样红。
- **M6(假红)**:新增 `source::region_across`(多文件转调跟踪,`frame.rs` + `layout/block.rs`),
把盒子原样搬进 `block::body_box` 再转调不再假红;`align_x` 改判**实参**(`Alignment::Start`
与 `iced::Alignment::Start` 同等放行),于是搬进别的模块后路径写全也不假红。
- **M1/M2 按塔的裁定不加断言**:与 `frame::body` 逐像素等价的另写就是等价重构;docstring 写明
「抓得住:语义变化;抓不住:逐像素等价的另写」。
最终变异矩阵(本轮自跑、每条跑完 `git checkout --` 回滚、白名单已核):
基线 429 passed / 0 failed;M4 红(只红 list_column_spaces_rows_only_from_the_shared_constant);
M3 绿;M6 绿;G 红(只红 single_column_pages_call_the_body_box_not_the_centred_one);
I 红(只红 the_page_wires_the_soft_breaks_into_both_rendering_paths);
旧 p1 复跑 A 红、D 红,等价重构 J 绿。
This commit is contained in:
1 parent
f499961e5b
commit
4b26a0a9dc
5 files changed
+299
-39
No files matched your search
@@ -57,36 +57,81 @@ fn list_viewport_fits_whole_rows_and_still_overflow() {
|
||||
);
|
||||
}
|
||||
|
||||
/// **源码结构**:列表**行容器**的构建链上不许叠页级间距,行距只能来自 [`ROW_SPACING`]。
|
||||
/// **源码结构**:`list_column()` 里对行容器的间距**只能**来自 [`ROW_SPACING`]。
|
||||
///
|
||||
/// 为什么读源码:变异实测(M102 r1)把 `.spacing(ui.space(Space::X1))` 直接加回 `list_column()`
|
||||
/// 的行容器上,上面那条几何断言照样绿——它算的是常量,看不见页面又叠了一层。iced 的 Element
|
||||
/// 又没有内省接口,所以只能断言这段代码的形状。
|
||||
/// 为什么读源码:变异实测(M102 r1)把 `.spacing(ui.space(Space::X1))` 加回行容器后,
|
||||
/// 几何断言照样绿——它算的是常量,看不见页面又叠了一层。iced 的 Element 又没有内省接口,
|
||||
/// 所以只能断言这段代码的形状。
|
||||
///
|
||||
/// **禁词范围只到「`let mut rows = column(…);` 这一条语句链」**(r2 复审 P2-2 的订正):
|
||||
/// 早先扫整个 `list_column()` 并禁一切 `.spacing(ui.space(Space::`,那样将来在
|
||||
/// `column![head, scroller]` 上加一条合法间距会**假红**。现在只钉行容器那条链。
|
||||
/// ## 两层判据(r4 复审的 M4 订正)
|
||||
///
|
||||
/// **抓得住**:行容器上又写字面量 `.spacing(…)`(视觉复审 ② 的页级附加量,含「先存局部变量
|
||||
/// 再 `.spacing(gap)`」的写法);`ROW_SPACING` / `LIST_BOTTOM_INSET` 两个真源被摘掉;
|
||||
/// **抓不住**:行距被算进别处再传进 `list_row()`(那要改组件几何,代码评审能看出来)。
|
||||
/// | 层 | 判据 | 抓的是 |
|
||||
/// |---|---|---|
|
||||
/// | ① 构建链 | `let mut rows = column(…);` 这条语句链上不许有 `.spacing(` | 直接写在链上的间距(变异 D) |
|
||||
/// | ② 语句序列 | `list_column()` 里**每一处** `rows.spacing(…)` 的实参都要**顺绑定追回 `ROW_SPACING`** | **另起一条语句**再叠间距(变异 M4,含「先把令牌挪进一条 `let`」的写法) |
|
||||
///
|
||||
/// 为什么②要追绑定而不是比字面:合法写法有几种形状——`rows = rows.spacing(ui.space(spacing))`
|
||||
/// 直接取自 `if let Some(spacing) = ROW_SPACING`,或先 `let spacing = ROW_SPACING;` 再中转
|
||||
/// (变异 H3)。`layout/source.rs::derived_from` 顺 `let` / `Some(…) =` 两种绑定往回追最多三跳,
|
||||
/// 于是「真源」放行、「中转了一层 `Space::X1`」判否。
|
||||
///
|
||||
/// **抓得住**:构建链上的字面量间距(D)、另起语句的行距(M4)、`ROW_SPACING` / `LIST_BOTTOM_INSET`
|
||||
/// 两个真源被摘掉;`column![head, scroller]` 上的合法间距不受影响(变异 J,绿);
|
||||
/// **抓不住**:把间距算进别处再以非令牌形式传进 `list_row()`(那要改组件几何,代码评审能看出来)、
|
||||
/// 以及绕过 `rows.spacing(…)` 这个调用形状的写法。
|
||||
#[test]
|
||||
fn list_column_spaces_rows_only_from_the_shared_constant() {
|
||||
let body = source::function_body(include_str!("../instances.rs"), "fn list_column");
|
||||
let rows_chain = source::statement(include_str!("../instances.rs"), "let mut rows = column(");
|
||||
let file = include_str!("../instances.rs");
|
||||
let body = source::function_region(file, "fn list_column");
|
||||
let rows_chain = source::statement(file, "let mut rows = column(");
|
||||
|
||||
assert!(
|
||||
body.contains("ROW_SPACING"),
|
||||
"列表行距必须从 ROW_SPACING 取,不许另写:\n{body}"
|
||||
);
|
||||
assert!(
|
||||
!rows_chain.contains(".spacing("),
|
||||
"行容器的构建链上又出现了间距(M102 ② 的页级附加量):\n{rows_chain}"
|
||||
);
|
||||
assert!(
|
||||
body.contains("LIST_BOTTOM_INSET"),
|
||||
"底部内缩必须从 LIST_BOTTOM_INSET 取:\n{body}"
|
||||
);
|
||||
|
||||
// ① 行容器的构建链上不许叠间距(`column![head, scroller]` 上的合法间距不在这条链里)
|
||||
assert!(
|
||||
!rows_chain.contains(".spacing("),
|
||||
"行容器的构建链上又出现了间距(M102 ② 的页级附加量):\n{rows_chain}"
|
||||
);
|
||||
|
||||
// ② 语句序列:每一处 `rows.spacing(…)` 的实参都必须**顺绑定追回 `ROW_SPACING`**
|
||||
// (直接用它、或 `let spacing = ROW_SPACING` 再中转都算;先 `let extra = Space::X1;`
|
||||
// 再 `rows.spacing(ui.space(extra))` 则红——r4 复审的变异 M4)
|
||||
let applied = source::call_arguments(&body, "rows.spacing(");
|
||||
assert!(
|
||||
!applied.is_empty(),
|
||||
"`list_column()` 里没有把 ROW_SPACING 应用到行容器的调用:\n{body}"
|
||||
);
|
||||
for argument in &applied {
|
||||
let ident = argument
|
||||
.split_once("ui.space(")
|
||||
.map(|(_, rest)| rest)
|
||||
.unwrap_or(argument);
|
||||
let ident: String = ident
|
||||
.chars()
|
||||
.take_while(|ch| ch.is_alphanumeric() || *ch == '_')
|
||||
.collect();
|
||||
|
||||
assert!(
|
||||
argument.contains("ui.space("),
|
||||
"行容器的间距实参必须走令牌栅格(`ui.space(…)`),收到 {argument:?}"
|
||||
);
|
||||
assert!(
|
||||
!argument.contains("Space::"),
|
||||
"行容器的间距实参里直接写了令牌档位:{argument:?}\n{body}"
|
||||
);
|
||||
assert!(
|
||||
source::derived_from(&body, &ident, "ROW_SPACING"),
|
||||
"行容器的间距不是从 ROW_SPACING 来的(`{ident}` 追不到 ROW_SPACING)——\
|
||||
M102 ② 的页级附加量不许另起一条语句塞回来:{argument:?}\n{body}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// **散文接线**:详情页的正文段必须进 `frame::prose`(424),不许直接塞进 `frame::body`(1044)。
|
||||
|
||||
Reference in new issue
Block a user