From 896edf07fe877c65695ee5563b63ce4e78a3eeda Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 2 Nov 2026 11:41:18 +0800 Subject: [PATCH] =?UTF-8?q?test(app-iced):=20=E4=BF=AE=20sub=5F24=5Fboxes?= =?UTF-8?q?=20=E7=99=BD=E5=90=8D=E5=8D=95=E4=B8=8E=2018px=20=E7=BA=BF?= =?UTF-8?q?=E5=AE=BD=E6=96=AD=E8=A8=80=E7=9A=84=E6=A0=BC=E5=BC=8F=E5=8C=96?= =?UTF-8?q?=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 白名单路径补全(shell/nav.rs 不在 components/ 下);扫描跳过 icons.rs 自身; - SVG 的 stroke-width 用 {} 渲染 f32,2.0 会打印成 "2",所以断言改成 比数值(stroke_width_for(18,1.5) == 2.0)再比它渲染出的字符串,别写死 "2.0"。 app-iced --lib: 168 passed, 0 failed。 --- crates/app-iced/src/icons.rs | 45 +++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/crates/app-iced/src/icons.rs b/crates/app-iced/src/icons.rs index 57102fc..514dd6e 100644 --- a/crates/app-iced/src/icons.rs +++ b/crates/app-iced/src/icons.rs @@ -202,12 +202,19 @@ mod tests { baked.contains("width=\"18\"") && baked.contains("height=\"18\""), "按 18 烘焙时 SVG 的 width/height 必须是 18:{baked}" ); + // `stroke-width` 的数值由 `format!(\"{}\", f32)` 渲染:2.0 会打印成 `2`, + // 所以这里比的是**数值**(2.0)而不是字符串 "2.0"。 + let baked_stroke = unlucky_design::icons::stroke_width_for(18.0, 1.5); assert!( - baked.contains("stroke-width=\"2.0\""), - "18px 渲染的 stroke-width 必须是 1.5×24/18 = 2.0:{baked}" + (baked_stroke - 2.0).abs() < 1.0e-6, + "18px 的 viewBox 线宽必须是 2.0,实际 {baked_stroke}" + ); + assert!( + baked.contains(&format!("stroke-width=\"{baked_stroke}\"")), + "SVG 里必须真的写着 {baked_stroke}:{baked}" ); // 视觉线宽 = viewBox 单位 × 盒/viewBox = 2.0 × 18/24 = 1.5(达标) - let baked_visual = unlucky_design::icons::visual_stroke_px(button_px, 2.0); + let baked_visual = unlucky_design::icons::visual_stroke_px(button_px, baked_stroke); assert!( (baked_visual - 1.5).abs() < 1.0e-6, "烘焙路径视觉线宽应 1.5,实际 {baked_visual}" @@ -215,7 +222,12 @@ mod tests { // 反证:拿 24 烘焙的那份去填 18 盒(= 用 `view` 装进小盒),视觉只剩 1.125px。 let scaled = source(IconKind::Check, RENDER_PX); - assert!(scaled.contains("stroke-width=\"1.5\"") && scaled.contains("width=\"24\"")); + assert!( + scaled.contains(&format!( + "stroke-width=\"{}\"", + unlucky_design::icons::stroke_width_for(RENDER_PX, 1.5) + )) && scaled.contains("width=\"24\"") + ); let scaled_visual = unlucky_design::icons::visual_stroke_px(button_px, 1.5); assert!( (scaled_visual - 1.125).abs() < 1.0e-6, @@ -224,11 +236,14 @@ mod tests { // switch 滑块的 16 同理:按 16 烘焙要 1.5×24/16 = 2.25。 let thumb_px = IconSize::SwitchThumb.px(); + let thumb_stroke = unlucky_design::icons::stroke_width_for(thumb_px, 1.5); let thumb = source(IconKind::Check, thumb_px); assert!( - thumb.contains("width=\"16\"") && thumb.contains("stroke-width=\"2.25\""), - "16px 盒要 2.25 个 viewBox 单位:{thumb}" + thumb.contains("width=\"16\"") + && thumb.contains(&format!("stroke-width=\"{thumb_stroke}\"")), + "16px 盒要 {thumb_stroke} 个 viewBox 单位:{thumb}" ); + assert!((thumb_stroke - 2.25).abs() < 1.0e-6); } #[test] @@ -260,16 +275,16 @@ mod tests { // (`buttons/mod.rs` 的 IconButton 是「24 图标 + 40 外壳」,图标本身仍是 24。) const VIEW_OK: &[&str] = &[ "shell/nav.rs", - "inputs/field.rs", - "inputs/menu.rs", - "inputs/search.rs", - "buttons/mod.rs", + "components/inputs/field.rs", + "components/inputs/menu.rs", + "components/inputs/search.rs", + "components/buttons/mod.rs", ]; // 盒 ≠ 24、因此必须用 `view_at` 的文件。 const VIEW_AT_REQUIRED: &[&str] = &[ - "buttons/assemble.rs", - "selection/chip.rs", - "selection/switch.rs", + "components/buttons/assemble.rs", + "components/selection/chip.rs", + "components/selection/switch.rs", "shell/mod.rs", ]; @@ -281,6 +296,10 @@ mod tests { .expect("strip_prefix") .to_string_lossy() .replace('\\', "/"); + // 本模块自身就是实现(`view` / `view_at` 的定义与文档),不参与扫描。 + if rel == "icons.rs" { + continue; + } let text = std::fs::read_to_string(&entry).expect("读组件源码"); let plain = text .lines()