refactor(app-iced): M116 把圆角单测搬出 corner.rs、日志行收敛到 format_line
- `platform/win32/corner.rs` 从 413 行降到 200 行(AGENTS.md §3-1 的 400 行硬线): 单测搬到 `corner/tests.rs`。 - 日志行的**形状**收敛成一个纯函数 `corner::format_line(context, plan, policy, outcome, style)`, 于是「`excluded_reason` 这一栏还在不在」不依赖真窗口也能被断言。 新增 `the_log_line_shape_is_pinned_with_the_measured_readings`:用本机探针窗口的真实读数 (Server 2025 / 26100、读回 E_INVALIDARG、frame=popup)逐字段钉死, 并把 policy × 系统 × 渲染档四种 `excluded_reason`(none / user / os-build / cpu-tier / unknown-os)全覆盖。 - `set_layered` 补一段「这里是 GetLastError 的 DWORD 语义,`unsigned_abs()` 有意保留; DWM 那侧是 HRESULT 语义、必须 `as u32`」的注释 + 对应用例(tower 2026-11-03 裁定:两者不同源,不许统一)。 门禁:fmt --check ✓ / clippy -D warnings(5 个改动 crate)✓ / lib 测试 core 266 + design 163 + i18n 24 + presenter 129 + app-iced 418 全绿。
This commit is contained in:
1 parent
88dbf6d955
commit
25d860b2b3
2 files changed
+219
-215
No files matched your search
@@ -197,218 +197,4 @@ pub fn format_line(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod corner_tests {
|
||||
use super::{plan_corner, CornerExclusion, CornerPlan, CornerSource};
|
||||
use crate::Backend;
|
||||
use unlucky_presenter::prefs::{WindowCorner, WindowsVersion, WIN11_MIN_BUILD};
|
||||
|
||||
/// 本机实测版本(Server 2025 / build 26100)。
|
||||
fn win11() -> WindowsVersion {
|
||||
WindowsVersion::new(10, 0, 26_100)
|
||||
}
|
||||
|
||||
/// Win10 22H2(build 19045):DWM 没有圆角偏好属性。
|
||||
fn win10() -> WindowsVersion {
|
||||
WindowsVersion::new(10, 0, 19_045)
|
||||
}
|
||||
|
||||
/// **抓得住**:判定链的顺序与每一格的原因码(把 `policy`/`os`/`backend` 任一条判反都会红)。
|
||||
/// **抓不住**:DWM 到底有没有真画圆角(那要像素,见 `platform/win32` 的探针输出)。
|
||||
#[test]
|
||||
fn truth_table_policy_os_backend() {
|
||||
let cases = [
|
||||
// policy=Square:任何系统/后端都直角,原因是用户选的。
|
||||
(
|
||||
WindowCorner::Square,
|
||||
Some(win11()),
|
||||
Backend::Gpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UserSquare),
|
||||
),
|
||||
(
|
||||
WindowCorner::Square,
|
||||
Some(win10()),
|
||||
Backend::Cpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UserSquare),
|
||||
),
|
||||
(
|
||||
WindowCorner::Square,
|
||||
None,
|
||||
Backend::Auto,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UserSquare),
|
||||
),
|
||||
// policy=System + 探测不出系统:不许猜「Win11」。
|
||||
(
|
||||
WindowCorner::System,
|
||||
None,
|
||||
Backend::Gpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UnknownOs),
|
||||
),
|
||||
// Win10:直角,GPU 档原因是版本、CPU 档原因是渲染档(同一个直角,原因不同)。
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win10()),
|
||||
Backend::Gpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::OsBuild),
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win10()),
|
||||
Backend::Auto,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::OsBuild),
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win10()),
|
||||
Backend::Cpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::CpuTier),
|
||||
),
|
||||
// Win11 / Server 2025:三个后端都用 DWM(D36 只管我们自己的合成技巧)。
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win11()),
|
||||
Backend::Gpu,
|
||||
CornerSource::Dwm,
|
||||
None,
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win11()),
|
||||
Backend::Cpu,
|
||||
CornerSource::Dwm,
|
||||
None,
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win11()),
|
||||
Backend::Auto,
|
||||
CornerSource::Dwm,
|
||||
None,
|
||||
),
|
||||
];
|
||||
|
||||
for (policy, os, backend, want_source, want_excluded) in cases {
|
||||
let plan = plan_corner(policy, os, backend);
|
||||
assert_eq!(
|
||||
plan.source, want_source,
|
||||
"policy={policy:?} os={os:?} backend={backend:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
plan.excluded, want_excluded,
|
||||
"policy={policy:?} os={os:?} backend={backend:?} 的原因码"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 边界:`WIN11_MIN_BUILD` **本身**算 Win11(`>=`,不是 `>`)。
|
||||
///
|
||||
/// 抓得住:把 `build < WIN11_MIN_BUILD` 写成 `<=`——Win11 21H2(build 22000)会静默掉成直角,
|
||||
/// 而那正好是第一台 Win11 机器。
|
||||
#[test]
|
||||
fn the_win11_boundary_is_inclusive() {
|
||||
let at = WindowsVersion::new(10, 0, WIN11_MIN_BUILD);
|
||||
assert_eq!(
|
||||
plan_corner(WindowCorner::System, Some(at), Backend::Gpu).source,
|
||||
CornerSource::Dwm
|
||||
);
|
||||
let below = WindowsVersion::new(10, 0, WIN11_MIN_BUILD - 1);
|
||||
assert_eq!(
|
||||
plan_corner(WindowCorner::System, Some(below), Backend::Gpu).source,
|
||||
CornerSource::Square,
|
||||
"build 21999 = Win10 22H2 家族末尾,不能算 Win11"
|
||||
);
|
||||
}
|
||||
|
||||
/// 日志行的形状:四个字段都在,且 `excluded_reason=none` 与 `reason=user` 不许混。
|
||||
///
|
||||
/// 为什么要钉这一条:这行是「后来的人分辨没生效 / 生效了看不见」的唯一依据(任务书原话),
|
||||
/// 少一栏就等于把这条线索丢掉。
|
||||
#[test]
|
||||
fn the_log_line_carries_every_field() {
|
||||
let dwm = plan_corner(WindowCorner::System, Some(win11()), Backend::Gpu)
|
||||
.log_line(WindowCorner::System);
|
||||
assert!(dwm.starts_with("corner=policy=system"), "{dwm}");
|
||||
assert!(dwm.contains("source=dwm"), "{dwm}");
|
||||
assert!(dwm.contains("os=10.0.26100"), "{dwm}");
|
||||
assert!(dwm.contains("excluded_reason=none"), "{dwm}");
|
||||
assert!(dwm.contains("radius=system"), "{dwm}");
|
||||
|
||||
let square = plan_corner(WindowCorner::Square, Some(win11()), Backend::Gpu)
|
||||
.log_line(WindowCorner::Square);
|
||||
assert!(square.contains("source=square"), "{square}");
|
||||
assert!(square.contains("excluded_reason=user"), "{square}");
|
||||
|
||||
let unknown: CornerPlan = plan_corner(WindowCorner::System, None, Backend::Gpu);
|
||||
assert!(unknown
|
||||
.log_line(WindowCorner::System)
|
||||
.contains("os=unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
/// **日志行的形状**,用 M116 探针窗口的**真实读数**构造(`DevDocs/artifacts/m116/probe-table.md`)。
|
||||
///
|
||||
/// 抓得住:字段被删/改名/顺序错乱(`excluded_reason` 少一栏、`radius=system` 丢了、
|
||||
/// `frame` / `layered` 被挪出这一行)——这些都会让「没生效 vs 生效了看不见」的区分重新变成猜谜。
|
||||
/// 抓不住:产品进程里那一行到底长什么样(本 mission 没构建 bin;合并态由 tower 编 `--bins` 补)。
|
||||
#[test]
|
||||
fn the_log_line_shape_is_pinned_with_the_measured_readings() {
|
||||
use super::{format_line, plan_corner, CornerPlan};
|
||||
use crate::Backend;
|
||||
use unlucky_presenter::prefs::WindowsVersion;
|
||||
|
||||
// 本机实测:Server 2025 / build 26100;读回 `E_INVALIDARG`;popup 窗口 layered=on。
|
||||
let os = WindowsVersion::new(10, 0, 26_100);
|
||||
let plan: CornerPlan = plan_corner(WindowCorner::System, Some(os), Backend::Gpu);
|
||||
let line = format_line(
|
||||
"boot",
|
||||
&plan,
|
||||
WindowCorner::System,
|
||||
"pref=2 readback=? read_hr=0x80070057",
|
||||
"frame=popup layered=on",
|
||||
);
|
||||
assert_eq!(
|
||||
line,
|
||||
"[corner] boot corner=policy=system source=dwm os=10.0.26100 excluded_reason=none radius=system pref=2 readback=? read_hr=0x80070057 frame=popup layered=on"
|
||||
);
|
||||
|
||||
// 设置里选「直角」:原因码必须从 `none` 变成 `user`,其余字段不动。
|
||||
let square = format_line(
|
||||
"change",
|
||||
&plan_corner(WindowCorner::Square, Some(os), Backend::Gpu),
|
||||
WindowCorner::Square,
|
||||
"pref=1 readback=? read_hr=0x80070057",
|
||||
"frame=popup layered=off",
|
||||
);
|
||||
assert!(
|
||||
square.contains("corner=policy=square source=square"),
|
||||
"{square}"
|
||||
);
|
||||
assert!(square.contains("excluded_reason=user"), "{square}");
|
||||
assert!(square.contains("frame=popup layered=off"), "{square}");
|
||||
|
||||
// Win10:原因码是 `os-build`(GPU 档)/ `cpu-tier`(CPU 档),来源仍是 square。
|
||||
let win10 = WindowsVersion::new(10, 0, 19_045);
|
||||
let os_build =
|
||||
plan_corner(WindowCorner::System, Some(win10), Backend::Gpu).log_line(WindowCorner::System);
|
||||
assert!(
|
||||
os_build.contains("source=square") && os_build.contains("excluded_reason=os-build"),
|
||||
"{os_build}"
|
||||
);
|
||||
let cpu =
|
||||
plan_corner(WindowCorner::System, Some(win10), Backend::Cpu).log_line(WindowCorner::System);
|
||||
assert!(cpu.contains("excluded_reason=cpu-tier"), "{cpu}");
|
||||
|
||||
// 探测不到版本(macOS / X11 / Wayland 落到同一格):`unknown-os`,不许猜 Win11。
|
||||
let unknown =
|
||||
plan_corner(WindowCorner::System, None, Backend::Gpu).log_line(WindowCorner::System);
|
||||
assert!(
|
||||
unknown.contains("os=unknown") && unknown.contains("excluded_reason=unknown-os"),
|
||||
"{unknown}"
|
||||
);
|
||||
}
|
||||
mod tests;
|
||||
@@ -0,0 +1,218 @@
|
||||
//! `win32::corner` 的单测(M116 从 `corner.rs` 搬出来:那个文件要守 400 行上限,
|
||||
//! 而日志行的形状断言本身就有几十行)。
|
||||
//!
|
||||
//! 判据与真实读数的出处:`DevDocs/artifacts/m116/probe-table.md`。
|
||||
|
||||
use super::{format_line, plan_corner, CornerExclusion, CornerPlan, CornerSource};
|
||||
use crate::Backend;
|
||||
use unlucky_presenter::prefs::{WindowCorner, WindowsVersion, WIN11_MIN_BUILD};
|
||||
|
||||
/// 本机实测版本(Server 2025 / build 26100)。
|
||||
fn win11() -> WindowsVersion {
|
||||
WindowsVersion::new(10, 0, 26_100)
|
||||
}
|
||||
|
||||
/// Win10 22H2(build 19045):DWM 没有圆角偏好属性。
|
||||
fn win10() -> WindowsVersion {
|
||||
WindowsVersion::new(10, 0, 19_045)
|
||||
}
|
||||
|
||||
/// **抓得住**:判定链的顺序与每一格的原因码(把 `policy`/`os`/`backend` 任一条判反都会红)。
|
||||
/// **抓不住**:DWM 到底有没有真画圆角(那要像素,见 `platform/win32` 的探针输出)。
|
||||
#[test]
|
||||
fn truth_table_policy_os_backend() {
|
||||
let cases = [
|
||||
// policy=Square:任何系统/后端都直角,原因是用户选的。
|
||||
(
|
||||
WindowCorner::Square,
|
||||
Some(win11()),
|
||||
Backend::Gpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UserSquare),
|
||||
),
|
||||
(
|
||||
WindowCorner::Square,
|
||||
Some(win10()),
|
||||
Backend::Cpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UserSquare),
|
||||
),
|
||||
(
|
||||
WindowCorner::Square,
|
||||
None,
|
||||
Backend::Auto,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UserSquare),
|
||||
),
|
||||
// policy=System + 探测不出系统:不许猜「Win11」。
|
||||
(
|
||||
WindowCorner::System,
|
||||
None,
|
||||
Backend::Gpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::UnknownOs),
|
||||
),
|
||||
// Win10:直角,GPU 档原因是版本、CPU 档原因是渲染档(同一个直角,原因不同)。
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win10()),
|
||||
Backend::Gpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::OsBuild),
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win10()),
|
||||
Backend::Auto,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::OsBuild),
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win10()),
|
||||
Backend::Cpu,
|
||||
CornerSource::Square,
|
||||
Some(CornerExclusion::CpuTier),
|
||||
),
|
||||
// Win11 / Server 2025:三个后端都用 DWM(D36 只管我们自己的合成技巧)。
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win11()),
|
||||
Backend::Gpu,
|
||||
CornerSource::Dwm,
|
||||
None,
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win11()),
|
||||
Backend::Cpu,
|
||||
CornerSource::Dwm,
|
||||
None,
|
||||
),
|
||||
(
|
||||
WindowCorner::System,
|
||||
Some(win11()),
|
||||
Backend::Auto,
|
||||
CornerSource::Dwm,
|
||||
None,
|
||||
),
|
||||
];
|
||||
|
||||
for (policy, os, backend, want_source, want_excluded) in cases {
|
||||
let plan = plan_corner(policy, os, backend);
|
||||
assert_eq!(
|
||||
plan.source, want_source,
|
||||
"policy={policy:?} os={os:?} backend={backend:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
plan.excluded, want_excluded,
|
||||
"policy={policy:?} os={os:?} backend={backend:?} 的原因码"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 边界:`WIN11_MIN_BUILD` **本身**算 Win11(`>=`,不是 `>`)。
|
||||
///
|
||||
/// 抓得住:把 `build < WIN11_MIN_BUILD` 写成 `<=`——Win11 21H2(build 22000)会静默掉成直角,
|
||||
/// 而那正好是第一台 Win11 机器。
|
||||
#[test]
|
||||
fn the_win11_boundary_is_inclusive() {
|
||||
let at = WindowsVersion::new(10, 0, WIN11_MIN_BUILD);
|
||||
assert_eq!(
|
||||
plan_corner(WindowCorner::System, Some(at), Backend::Gpu).source,
|
||||
CornerSource::Dwm
|
||||
);
|
||||
let below = WindowsVersion::new(10, 0, WIN11_MIN_BUILD - 1);
|
||||
assert_eq!(
|
||||
plan_corner(WindowCorner::System, Some(below), Backend::Gpu).source,
|
||||
CornerSource::Square,
|
||||
"build 21999 = Win10 22H2 家族末尾,不能算 Win11"
|
||||
);
|
||||
}
|
||||
|
||||
/// 日志行的形状:四个字段都在,且 `excluded_reason=none` 与 `reason=user` 不许混。
|
||||
///
|
||||
/// 为什么要钉这一条:这行是「后来的人分辨没生效 / 生效了看不见」的唯一依据(任务书原话),
|
||||
/// 少一栏就等于把这条线索丢掉。
|
||||
#[test]
|
||||
fn the_log_line_carries_every_field() {
|
||||
let dwm = plan_corner(WindowCorner::System, Some(win11()), Backend::Gpu)
|
||||
.log_line(WindowCorner::System);
|
||||
assert!(dwm.starts_with("corner=policy=system"), "{dwm}");
|
||||
assert!(dwm.contains("source=dwm"), "{dwm}");
|
||||
assert!(dwm.contains("os=10.0.26100"), "{dwm}");
|
||||
assert!(dwm.contains("excluded_reason=none"), "{dwm}");
|
||||
assert!(dwm.contains("radius=system"), "{dwm}");
|
||||
|
||||
let square = plan_corner(WindowCorner::Square, Some(win11()), Backend::Gpu)
|
||||
.log_line(WindowCorner::Square);
|
||||
assert!(square.contains("source=square"), "{square}");
|
||||
assert!(square.contains("excluded_reason=user"), "{square}");
|
||||
|
||||
let unknown: CornerPlan = plan_corner(WindowCorner::System, None, Backend::Gpu);
|
||||
assert!(unknown
|
||||
.log_line(WindowCorner::System)
|
||||
.contains("os=unknown"));
|
||||
}
|
||||
|
||||
/// **日志行的形状**,用 M116 探针窗口的**真实读数**构造(`DevDocs/artifacts/m116/probe-table.md`)。
|
||||
///
|
||||
/// 抓得住:字段被删/改名/顺序错乱(`excluded_reason` 少一栏、`radius=system` 丢了、
|
||||
/// `frame` / `layered` 被挪出这一行)——这些都会让「没生效 vs 生效了看不见」的区分重新变成猜谜。
|
||||
/// 抓不住:产品进程里那一行到底长什么样(本 mission 没构建 bin;合并态由 tower 编 `--bins` 补)。
|
||||
#[test]
|
||||
fn the_log_line_shape_is_pinned_with_the_measured_readings() {
|
||||
// 本机实测:Server 2025 / build 26100;读回 `E_INVALIDARG`;popup 窗口 layered=on。
|
||||
let os = WindowsVersion::new(10, 0, 26_100);
|
||||
let plan: CornerPlan = plan_corner(WindowCorner::System, Some(os), Backend::Gpu);
|
||||
let line = format_line(
|
||||
"boot",
|
||||
&plan,
|
||||
WindowCorner::System,
|
||||
"pref=2 readback=? read_hr=0x80070057",
|
||||
"frame=popup layered=on",
|
||||
);
|
||||
assert_eq!(
|
||||
line,
|
||||
concat!(
|
||||
"[corner] boot corner=policy=system source=dwm os=10.0.26100 ",
|
||||
"excluded_reason=none radius=system pref=2 readback=? ",
|
||||
"read_hr=0x80070057 frame=popup layered=on"
|
||||
)
|
||||
);
|
||||
|
||||
// 设置里选「直角」:原因码必须从 `none` 变成 `user`,其余字段不动。
|
||||
let square = format_line(
|
||||
"change",
|
||||
&plan_corner(WindowCorner::Square, Some(os), Backend::Gpu),
|
||||
WindowCorner::Square,
|
||||
"pref=1 readback=? read_hr=0x80070057",
|
||||
"frame=popup layered=off",
|
||||
);
|
||||
assert!(
|
||||
square.contains("corner=policy=square source=square"),
|
||||
"{square}"
|
||||
);
|
||||
assert!(square.contains("excluded_reason=user"), "{square}");
|
||||
assert!(square.contains("frame=popup layered=off"), "{square}");
|
||||
|
||||
// Win10:原因码是 `os-build`(GPU 档)/ `cpu-tier`(CPU 档),来源仍是 square。
|
||||
let win10 = WindowsVersion::new(10, 0, 19_045);
|
||||
let os_build =
|
||||
plan_corner(WindowCorner::System, Some(win10), Backend::Gpu).log_line(WindowCorner::System);
|
||||
assert!(
|
||||
os_build.contains("source=square") && os_build.contains("excluded_reason=os-build"),
|
||||
"{os_build}"
|
||||
);
|
||||
let cpu =
|
||||
plan_corner(WindowCorner::System, Some(win10), Backend::Cpu).log_line(WindowCorner::System);
|
||||
assert!(cpu.contains("excluded_reason=cpu-tier"), "{cpu}");
|
||||
|
||||
// 探测不到版本(macOS / X11 / Wayland 落到同一格):`unknown-os`,不许猜 Win11。
|
||||
let unknown =
|
||||
plan_corner(WindowCorner::System, None, Backend::Gpu).log_line(WindowCorner::System);
|
||||
assert!(
|
||||
unknown.contains("os=unknown") && unknown.contains("excluded_reason=unknown-os"),
|
||||
"{unknown}"
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user