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:
AskaEth committed 2026-11-04 19:53:45 +08:00
1 parent f499961e5b
commit 4b26a0a9dc
5 files changed
+299 -39

No files matched your search

+21 -9
View File
@@ -141,14 +141,19 @@ fn body_block_starts_at_the_header_title_and_fills_the_page() {
/// `body_offset(metrics)`、`align_x` 只许是 `Start`(不写 = container 默认 Start,等价),
/// 且不出现居中/散文列宽。
///
/// 扫的是 [`layout::source::function_region`](函数体 + 本文件内被它转调的函数),
/// 所以「拆成 `body` → `body_impl` 两层再转调」这种**等价重构不假红**(r2 复审的变异 H1)。
/// 扫的是 [`layout::source::region_across`]:`frame.rs` **加上** `layout/block.rs`,
/// 于是「拆成 `body` → `body_impl`」(变异 H1)与「把盒子原样搬进 `block::body_box`」(变异 M6)
/// 这两种**等价重构都不假红**,而「换成居中 424 盒子」照样红(变异 A)。
///
/// **抓得住**:`body()` 被换回居中(变异 A)、宽度改回 `metrics.column`、`align_x` 改成 `Center`;
/// **抓不住**:跨文件转调、或先赋局部变量再建盒的写法(见 `layout/source.rs` 的边界说明)。
/// **抓得住**:盒子的**语义**变了(居中 / 用散文列宽 / 用 `centered`);
/// **抓不住**:`frame::centered(metrics.column, …)` 这种**与 `frame::body` 逐像素等价**的另写
/// (r4 复审的 M1/M2 —— 按塔的裁定那是等价重构,护栏不该为此红),也不抓「先赋局部变量再建盒」。
#[test]
fn frame_body_is_built_from_the_block_quantities() {
let body = layout::source::function_region(include_str!("frame.rs"), "pub fn body<'a>(");
let body = layout::source::region_across(
&[include_str!("frame.rs"), include_str!("layout/block.rs")],
"pub fn body<'a>(",
);
for needle in ["body_width(metrics)", "body_offset(metrics)"] {
assert!(
@@ -159,10 +164,12 @@ fn frame_body_is_built_from_the_block_quantities() {
// `align_x` 出现就必须是 Start:`.align_y(Alignment::Start)` 单独存在不算数(r2 复审 P2-3),
// 而「干脆不写 align_x」(container 默认 Start)视为等价重构,放行。
if let Some(at) = body.find(".align_x(") {
// 判的是**实参**而不是整段文本,所以 `Alignment::Start` 与 `iced::Alignment::Start` 同等放行
// (把盒子搬进别的模块后路径要写全,那是等价重构,不该假红 —— r4 复审的变异 M6)。
for argument in layout::source::call_arguments(&body, ".align_x(") {
assert!(
body[at..].starts_with(".align_x(Alignment::Start)"),
"`frame::body` 的 align_x 只许是 Start:\n{body}"
argument.trim().ends_with("Alignment::Start"),
"`frame::body` 的 align_x 只许是 Start,收到 {argument:?}:\n{body}"
);
}
@@ -182,9 +189,14 @@ fn frame_body_is_built_from_the_block_quantities() {
/// **源码结构**:`frame::prose` 的宽度必须来自 `prose_width`(= `metrics.column`),不来自块宽。
///
/// M102 把两个量拆开后,「把散文塞进 1044 的块」不会红任何数值断言;这条盯接线。
/// 与 `frame::body` 那条一样用 [`layout::source::region_across`](`frame.rs` + `layout/block.rs`),
/// 所以把盒子搬进 `layout/block.rs` 的等价重构不假红;抓的是**语义**(用块宽/可用宽度就红)。
#[test]
fn frame_prose_is_built_from_the_prose_width() {
let prose = layout::source::function_body(include_str!("frame.rs"), "pub fn prose<'a>(");
let prose = layout::source::region_across(
&[include_str!("frame.rs"), include_str!("layout/block.rs")],
"pub fn prose<'a>(",
);
assert!(
prose.contains("prose_width(metrics)"),