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:
AskaEth committed 2026-11-05 06:35:03 +08:00
1 parent 88dbf6d955
commit 25d860b2b3
2 files changed
+219 -215

No files matched your search

+1 -215
View File
@@ -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}"
);
}