Merge branch 'feat/m288-tokenguard-test-colors-no-longer-tr'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好等于期望) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
GPU evidence / GPU 证据 — 真实产物判据 (push) Canceled after 0s
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Canceled after 0s
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Canceled after 0s
Dev Guards / GPU 证据门禁(同 main 口径;无 GPU 只跑自测) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s

This commit is contained in:
AskaEth committed 2026-11-13 00:04:21 +08:00
commit 53de2a3922
1 file changed
+81 -9
@@ -8,6 +8,8 @@
use super::*;
use crate::app::components::motion::FRAME_MS;
use crate::theme::to_iced;
use unlucky_design::color::{BrandBoard, Role, SchemeFlavor};
use unlucky_design::motion::MotionScale;
const STANDARD: MotionScale = MotionScale::STANDARD;
@@ -123,23 +125,93 @@ fn current_from(layer: &Layer) -> (Interaction, Interaction, f32) {
with_current(*layer, || current().expect("刚压进去的层必须在栈顶"))
}
/// 两个不透明色的插值:**端点逐位相等**,中点严格落在两者之间。
/// 两个不透明令牌色的插值:**端点逐位相等**,中点严格落在两者之间。
///
/// ## 端点为什么是角色,而不是 `Color::from_rgb(…)` 写死的数值
///
/// 这两行原先随手写了 `from_rgb(0.1, 0.2, 0.3)` / `from_rgb(0.7, 0.8, 0.9)`,撞上
/// `tests/no_hardcoded_tokens.rs` 的色值守门(它扫 `src/**`,测试模块也算在里面)。修法是
/// **改测试、不动守门**:端点取状态层真正会插值的那一对——容器 [`Role::Surface`] 与内容
/// [`Role::OnSurface`]——经产品同一条令牌路径(`Scheme::get` → [`to_iced`])翻成 iced 色。
///
/// ⚠️ 本文件里连**注释**都不许出现「构造名 + 数字」的写法:守门按行做子串匹配,不区分代码与
/// 文档(`the_gate_itself_catches_a_planted_violation` 也把这条钉住了)。要举例就写 `from_rgb(…)`。
///
/// ## 为什么这不算「削弱守卫」(将来别顺手把测试全排除)
///
/// 守卫的规则是「组件层的颜色一律来自 `unlucky_design` 的 `Role`」,它不区分测试代码与产品
/// 代码——也不该区分:测试里的色字面量**就是**组件层源码里长出来的一串数字,例外一旦开在
/// 「测试」名下,下一个「临时」的 `from_rgb` 只会多一个借口。所以这里不削弱、不豁免、不给守卫
/// 加任何例外:**扫描范围一行没改**,只是把被它正确抓到的那两行换成令牌色。
///
/// 反过来说,按路径排除 `*/tests.rs` 也排不干净:`#[cfg(test)] mod tests` 与产品代码**同文件**
/// (本模块就是 `layer.rs` 末尾的 `#[cfg(test)] mod tests;`),路径分不开「同文件里的测试」与
/// 「同文件里的产品代码」;而任何文件都能被改名叫 `tests.rs` 来藏字面量。结论:守卫保持全量
/// 覆盖,误判在**被判的那一侧**修。
///
/// ## 判据(三条一条不少)
///
/// 1. 端点逐位相等(`p = 0 / 1` 直接返回原值,不许「差不多」);
/// 2. 中点**严格**落在两端之间(每个通道用两端现算的 `min`/`max`,不是抄来的数字);
/// 3. α 全程 1.0(D27 的「两个后端逐像素一致」就靠这条守着)。
///
/// 浅/深两套品牌板各跑一遍,判据值全部现算 ⇒ 换板、换品牌色都不会让这条用例变哑。
///
/// 抓得住:①把端点写成「差不多」(`p == 0` 时返回插值结果 0.999…)——逐位断言红;
/// ②引入 α(`a` 不再是 1.0)——D27 的「两个后端逐像素一致」就靠这条守着。
/// ②引入 α(`a` 不再是 1.0)——第 3 条红;③插值写成线性之外的东西(端点仍对、中点越界)——第 2 条红。
/// 抓不住:色值本身好不好看(那是角色映射的事)。
#[test]
fn blend_hits_both_endpoints_bit_for_bit() {
let from = iced::Color::from_rgb(0.1, 0.2, 0.3);
let to = iced::Color::from_rgb(0.7, 0.8, 0.9);
for flavor in [SchemeFlavor::Light, SchemeFlavor::Dark] {
let from = board_color(flavor, Role::Surface);
let to = board_color(flavor, Role::OnSurface);
assert_eq!(blend(from, to, 0.0), from);
assert_eq!(blend(from, to, 1.0), to);
// 「严格介于」的前提:两端不透明,且每个通道真的不同(分量可排序)。
assert_eq!(
(from.a, to.a),
(1.0, 1.0),
"{flavor:?}:Surface / OnSurface 必须都不透明(D27)"
);
assert!(
differs_in_every_channel(from, to),
"{flavor:?}:两端有通道相同({from:?} / {to:?}),中点不可能严格介于——换一对角色"
);
assert_eq!(
blend(from, to, 0.0),
from,
"{flavor:?}:p = 0 必须逐位等于起点"
);
assert_eq!(
blend(from, to, 1.0),
to,
"{flavor:?}:p = 1 必须逐位等于终点"
);
for p in [0.25, 0.5, 0.75] {
let mid = blend(from, to, p);
assert!((0.1..=0.7).contains(&mid.r), "r 必须落在两端之间");
assert!((0.2..=0.8).contains(&mid.g));
assert!((0.3..=0.9).contains(&mid.b));
for (name, value, start, end) in [
("r", mid.r, from.r, to.r),
("g", mid.g, from.g, to.g),
("b", mid.b, from.b, to.b),
] {
let (lo, hi) = (start.min(end), start.max(end));
assert!(
value > lo && value < hi,
"{flavor:?} p = {p}:{name} 必须**严格**落在两端之间({lo} < {value} < {hi})"
);
}
assert_eq!(mid.a, 1.0, "中间态也不许引入半透明(D27)");
}
}
}
/// 品牌板上某个角色的 iced 颜色(与产品同一条令牌路径)。
fn board_color(flavor: SchemeFlavor, role: Role) -> iced::Color {
to_iced(BrandBoard::for_flavor(flavor).scheme().get(role))
}
/// 三个通道是否都不同——只有全不同,「严格介于」才有定义。
fn differs_in_every_channel(from: iced::Color, to: iced::Color) -> bool {
from.r != to.r && from.g != to.g && from.b != to.b
}