feat(app-iced,pages): M100 取证密闭 + harness 参数拆分 + 设置页测试按 section 下放
四件前置事,都是为了设置页正文四条 section 线能并行(不写任何 section 正文):
1. 取证密闭(两条通道各有各的机制,证据分开算)
- 产品 bin:`cli::ForcedState` 加 `Rest`(静息态),给了 `--screenshot` 且没显式
`--force-state` 时默认 `Some(Rest)`;交互模式仍是 `None`(`shell::overridden`
与 `app/view.rs` 的 `model()` 各补一支)。
- harness:截图窗口开 `window::enable_mouse_passthrough`(winit 的
`set_cursor_hittest(false)`)⇒ 窗口收不到指针事件 ⇒ 全树控件恒为 Active。
为什么用通道级而不是逐控件灌 forced:设置页「外观」区的滑块/文本框/裸 button 都不消费
forced,逐控件做要改十几个组件文件,而新产品组件随时会漏。
- harness 同时数指针事件并打进日志(`指针事件=N`):让「这张图见过几个鼠标事件」变成
可读数字,替代「连跑几次 hash 一样」那种恒真的假绿。
2. harness 的外观真状态入口:`--appearance=real` 让设置页走 `appearance: Some(..)`
(工厂态 + `ULL_APPEARANCE_*`),新入口 `pages::app_with_appearance`。
`--screen=settings` 之前就有了,但 `appearance` 恒为 None,D30 要的那一屏根本不存在。
3. `pages/harness.rs` 400 行 → 拆 `pages/harness/request.rs`(`#[path]` 范式),
纯搬移部分 240 行 + 新增密闭代码。拆分等价性:同一 argv 的 PNG sha256 与拆分前一致。
4. `pages/settings/tests.rs` 按 section 下放成 `tests/{general,appearance,java,download}_section.rs`,
mod 层只留跨 section 断言(每条写清守什么、为什么不能下放)。
给某组加一条新断言 = 只改它自己那个文件。
顺带:`shell/mod.rs` 在 HEAD 就 399 行、`cli.rs` 394 行,两处都按同一范式把 tests 搬成
`shell/tests.rs` / `cli/tests.rs`(断言一字不动,逐字节可 diff)。
变异验证:把四处实现各改坏一处(默认 Rest、passthrough 默认值、overridden 的 Rest 分支、
view 的 Rest 映射),对应 4 条断言全红(390 passed / 4 failed),恢复后 394 passed。
This commit is contained in:
1 parent
2ad808d55c
commit
2061296615
16 files changed
+1152
-469
No files matched your search
@@ -0,0 +1,146 @@
|
||||
//! 设置页的**跨 section** 守门测试(M100 按 section 下放之后,留在 mod 层的那一份)。
|
||||
//!
|
||||
//! ## 为什么这里只剩「跨 section」的断言
|
||||
//!
|
||||
//! 设置页正文接下来由四条线并行接(java / download / language+appearance / ai+about)。每条线要能
|
||||
//! **只改自己的测试**就跑通,所以「某一组自己的行文案 / 图标 / body 现状」一律下放到
|
||||
//! `tests/<section>_section.rs`;本文件只留**必须四组一起看**的断言——下放到任何单组文件里,
|
||||
//! 都会变成「某组替其它三组说话」,四条线并行时必然互相踩。
|
||||
//!
|
||||
//! 判据(M100 报告里正面回答的那条):**给 java 加一条新断言,改几个文件?** —— 1 个
|
||||
//! (`tests/java_section.rs`)。本文件不动。
|
||||
//!
|
||||
//! ## 站位
|
||||
//!
|
||||
//! 本文件是 `pages::settings::tests`:`super` = `pages::settings`,`super::super` = `pages`。
|
||||
//!
|
||||
//! ## 命名
|
||||
//!
|
||||
//! 子模块带 `_section` 后缀,是为了不和 `use super::*` 带进来的分组模块(`settings::java` 等)
|
||||
//! 撞名——撞名时显式 `mod` 会静默盖掉 glob,读代码的人会以为 `java` 指的是分组的那个。
|
||||
|
||||
mod appearance_section;
|
||||
mod download_section;
|
||||
mod general_section;
|
||||
mod java_section;
|
||||
|
||||
use super::super::layout::{self, frame_metrics, measure_cap_px, PaneKit, SIDE_NAV_WIDTH};
|
||||
use super::*;
|
||||
use crate::pages::appearance::{APPEARANCE_GROUP, GROUP_LABEL};
|
||||
|
||||
// --------------------------------------------------------------- 版面(不属于任何一组)
|
||||
|
||||
/// 守的是**版面契约**:分组导航走 drawer 240(D33),不是 rail 的 88。
|
||||
///
|
||||
/// 不能下放到分组:它不是「某一组」的属性,而是整个 supporting-pane 的几何。
|
||||
#[test]
|
||||
fn side_nav_reuses_the_drawer_width() {
|
||||
assert_eq!(SIDE_NAV_WIDTH, 240.0);
|
||||
let metrics = frame_metrics(PaneKit::Supporting, 1180.0);
|
||||
assert_eq!(metrics.secondary, Some(240.0));
|
||||
assert_ne!(metrics.secondary, Some(layout::rail_width()));
|
||||
}
|
||||
|
||||
/// 守的是**行宽上限**(逐行 67 字符 ≤72)在所有宽度档下都成立。
|
||||
///
|
||||
/// 不能下放:它是四个分组共用的正文列,任何一组把列撑宽都会连带别人。
|
||||
#[test]
|
||||
fn form_column_never_exceeds_the_measure_cap() {
|
||||
for width in [720.0, 840.0, 1180.0, 1920.0] {
|
||||
let metrics = frame_metrics(PaneKit::Supporting, width);
|
||||
assert!(
|
||||
metrics.column <= measure_cap_px() + f32::EPSILON,
|
||||
"{width} 宽下表单列 {:?} 超过行宽上限",
|
||||
metrics.column
|
||||
);
|
||||
assert!(metrics.column >= layout::measure_floor_px());
|
||||
}
|
||||
}
|
||||
|
||||
/// 守的是**窄窗退化**:<720 时侧列消失、分组改为按组堆叠。
|
||||
///
|
||||
/// 不能下放:退化是整页行为,四组一起变(单组文件里没法验证「侧列没了」)。
|
||||
#[test]
|
||||
fn narrow_window_stacks_the_groups_instead_of_the_side_nav() {
|
||||
let narrow = frame_metrics(PaneKit::Supporting, 700.0);
|
||||
assert_eq!(narrow.layout, PageLayout::SingleColumn);
|
||||
assert!(narrow.secondary.is_none(), "窄窗不许留侧列");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- 注册表(四组一起看)
|
||||
|
||||
/// 守的是**注册表的结构不变量**:每组都有名字、图标、演示行,且演示下标在范围内。
|
||||
///
|
||||
/// 下放不了:它遍历的是 `GROUPS`(四组拼出来的数组),单组文件拿不到其它三组,
|
||||
/// 而「新增一组忘了填 rows」正是这条要抓的。
|
||||
#[test]
|
||||
fn every_group_has_a_name_icon_and_rows() {
|
||||
assert!(GROUPS.len() >= 3);
|
||||
assert!(SELECTED < GROUPS.len());
|
||||
for group in &GROUPS {
|
||||
assert!(!group.name.is_empty());
|
||||
assert!(!group.icon.icon().path.is_empty(), "{} 缺图标", group.name);
|
||||
assert!(!group.rows.is_empty(), "{} 没有设置行", group.name);
|
||||
for (label, value) in group.rows {
|
||||
assert!(!label.is_empty() && !value.is_empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// M93:设置页「外观」分组的下标与 `pages::appearance` 声明的常量必须一致。
|
||||
///
|
||||
/// 抓得住:谁把 `GROUPS` 的顺序调了却忘了改 `APPEARANCE_GROUP`(那样真控件会画到别的分组上,
|
||||
/// 而支持列显示的分组名也对不上)。
|
||||
/// 抓不住:控件本身画得对不对(那由截图与 app 侧测试管)。
|
||||
///
|
||||
/// 下放不了:它同时读 `GROUPS`(注册表)与 `pages::appearance` 的常量,横跨两处;
|
||||
/// 放进 `appearance_section.rs` 会让「外观那条线」替注册表顺序作证。
|
||||
#[test]
|
||||
fn the_appearance_group_is_where_the_module_says_it_is() {
|
||||
assert_eq!(GROUPS[APPEARANCE_GROUP].name, GROUP_LABEL);
|
||||
assert!(SELECTED < GROUPS.len(), "演示下标仍在范围内");
|
||||
}
|
||||
|
||||
/// M99:拆分后**左列顺序**必须还是拆分前那四项(顺序变了就是观感变了,不是「纯搬移」)。
|
||||
///
|
||||
/// 抓得住:① 注册表顺序被调换(`GROUPS` 是四条线各自文件拼出来的,最容易在合并时错位);
|
||||
/// ② 某组被误删/误加(长度不等)。
|
||||
/// 抓不住:组内那些行还在不在、译文对不对(各组自己的文件与 `catalog` 金表各管一段)。
|
||||
///
|
||||
/// 下放不了:它是一句「四组顺序 = 这四个名字」的断言,任何单组文件都只能看到自己那一个名字。
|
||||
#[test]
|
||||
fn the_split_kept_the_left_column_order() {
|
||||
let names: Vec<&str> = GROUPS.iter().map(|group| group.name).collect();
|
||||
assert_eq!(names, vec!["General", "Appearance", "Java", "Downloads"]);
|
||||
}
|
||||
|
||||
/// M99:「外观」是**当前唯一**接了真控件的那一组。
|
||||
///
|
||||
/// 抓得住:拆分时把 `body: Some(…)` 搬丢 / 搬到了别的组(那会让真控件消失,退回演示行——
|
||||
/// 而截图对这种「只在有外观状态时出现」的差别不一定抓得住,见报告「没验的部分」);
|
||||
/// 也抓「别组偷偷接了 body 却没人知道」。
|
||||
/// 抓不住:`body` 指向的那个渲染器画得对不对(那是 `pages::appearance` 的事)。
|
||||
///
|
||||
/// **为什么不能下放**(任务书点名要求写清):这条断言的全部内容是**四组的 body 现状对比**
|
||||
/// ——「只有第 2 组是 Some,其余三组都是 None」。放进 `appearance_section.rs` 它就得替 java /
|
||||
/// download / general 三组作证(那三条线一接真控件,本文件以外的地方无缘无故变红,且责任方
|
||||
/// 不是改代码的人);拆成四份「我这组是 None」又会丢掉「唯一」这个要点。
|
||||
/// 它是**绊线**:哪条线接上真控件,就必须来本文件手工改这一条(T1:绊线保持字面量,
|
||||
/// 动态取活值等于把绊线剪了)。
|
||||
#[test]
|
||||
fn only_the_appearance_group_carries_a_real_control_body() {
|
||||
assert!(
|
||||
GROUPS[APPEARANCE_GROUP].body.is_some(),
|
||||
"外观分组必须是接了真控件的那一组"
|
||||
);
|
||||
for (index, group) in GROUPS.iter().enumerate() {
|
||||
if index == APPEARANCE_GROUP {
|
||||
continue;
|
||||
}
|
||||
assert!(
|
||||
group.body.is_none(),
|
||||
"{} 现在应该还是演示行(真控件由它自己那条 section 线接)",
|
||||
group.name
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user