fix(renderer): M97 r1 —— 降级/取证两条路改成可被变异测试抓到的纯函数
复审在 `git archive 72f20d8` 上做了变异:删掉 `respawn` 的
`.env("ICED_BACKEND", fallback.env_value())`,**327 passed / 0 failed**,那条名为
`retry_fallback_flips_the_tier_to_cpu` 的测试照样绿。
名字说它守住了「降级后档位翻转」,实际它只把 `"wgpu"` / `"tiny-skia"` 两个字面量喂给
`backend_from_env` 和 `effective_panel_alpha`,**`respawn` 一行都没执行**(它 `-> !`,
走 `process::exit`)。这和 M97 要修的那行常量日志是同一个结构:**在需要结果的地方验了旁边的东西**。
## 改了什么
1. `respawn` 的两组 env 抽成纯函数 `fallback_env(fallback)`,返回值是
**`[(&'static str, &'static str); 2]`**——数量由类型钉住(删一条直接编译不过,
比测试更早的闸门),键与值由测试钉住。
2. 子进程那一轮的决策抽成 `renderer::decision::fallback_round(kind)`,**兜底恒为 `None`**
(防无限递归重开),`boot_probe` 不再就地拼 `Decision`。
3. 失败分流抽成纯函数 `on_failure(decision, evidence)` → `Respawn(Kind) | Refuse`:
交互降级 / 取证拒绝两条路各自被测试钉住(判据表第 8 行 vs 第 9 行)。
4. 补上复审点名的两处 0 覆盖:`renderer::strict`(剥兜底)与 `renderer::run_once`
(传下去的是 `decision.primary`,且进程内只跑一次)。
5. 改名并改文档 `retry_fallback_flips_the_tier_to_cpu` →
`each_backend_value_maps_to_its_tier_and_alpha`,明确写「本测试**不**守翻转」,
并指到真正守它的那条。
## 变异验证(8/8 被抓到,全部在实现行上做,测试里的同一字面量不动)
| 变异 | 结果 |
|---|---|
| M1 删掉 `ICED_BACKEND` 那条(=复审的变异) | **编译期**红:`expected an array with a size of 2, found one with a size of 1` |
| M2 键打错 `ICED_BAKEND` | `fallback_env_carries_the_backend_and_the_gate` FAILED |
| M3 闸门键打错 `ULL_GPU_FALLBACK_TYPO` | 同上 FAILED |
| M4 闸门值写死(不跟 fallback 走) | 同上 FAILED |
| M5 `fallback_round` 又给兜底 | `fallback_round_never_degrades_again` FAILED |
| M6 取证启动改成也降级 | `evidence_start_refuses_instead_of_degrading` FAILED |
| M7 `strict` 忘了清兜底 | `strict_strips_the_fallback` FAILED |
| M8 `run_once` 传死值 | `run_once_passes_the_decision_primary` FAILED |
复原后 `cargo test -p unlucky-app-iced --lib` = 334 passed。第一次跑变异时 A/B/C 三个
「照样绿」是我脚本自己的 bug:`sed` 把测试期望里的同一字面量一起改了(自指式变异盲区),
改成只在函数体内替换才暴露真实结果——这条也记进报告。
## 顺带(p3-1)
`boot.rs` 模块文档里「字体栈不重算」是旧实现的残留:改成换进程之后,子进程会把字体栈、
配置、presenter 全部重算(实测首帧 493~531 ms),文档已按实际行为重写,并把判据表
第 8/9 行两条路的差异写进模块头部。
运行时行为未变(refactor 只做抽取),已复测:取证启动 + wgpu 不可用 → exit 1、无 PNG、
具名错误 + 「拒绝降级出图」;交互启动 → 具名错误 + 换进程降级 + `[probe] 本次是降级重开`。
This commit is contained in:
1 parent
31cdfd5bbd
commit
fa9dd170d3
4 files changed
+243
-29
No files matched your search
@@ -125,7 +125,7 @@ pub mod decision;
|
||||
pub mod log_bridge;
|
||||
pub mod preflight;
|
||||
|
||||
pub use decision::{decide, demote_after_preflight, strict, Decision, Kind};
|
||||
pub use decision::{decide, demote_after_preflight, fallback_round, strict, Decision, Kind};
|
||||
|
||||
/// 把 `iced::Error` 里的**具名**图形错误掏出来(`Display` 那句笼统的话不算原因)。
|
||||
///
|
||||
@@ -185,3 +185,47 @@ pub fn report_failure(backend: Kind, error: &(impl std::fmt::Display + std::fmt:
|
||||
eprintln!("[gpu] {} 初始化失败(具名):{error}", backend.name());
|
||||
eprintln!("[gpu] 失败详情(具名):{error:?}");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Backend, Probe};
|
||||
|
||||
/// `run_once` **必须**把决策里的起步后端传下去。
|
||||
///
|
||||
/// 抓得住:`run_once` 被改成传死值(例如恒 `Kind::Wgpu`)——那会让「强制 CPU」也去试 GPU。
|
||||
/// 抓不住:真 iced 启动成功/失败(那条只能真跑,见判据表第 6/8/9 行的实测记录)。
|
||||
#[test]
|
||||
fn run_once_passes_the_decision_primary() {
|
||||
for request in [Backend::Cpu, Backend::Gpu] {
|
||||
let decision = decide(request, &Probe::default(), true);
|
||||
let mut seen = None;
|
||||
let result = run_once(decision, |kind| {
|
||||
seen = Some(kind);
|
||||
Ok(())
|
||||
});
|
||||
assert!(result.is_ok(), "闭包返回 Ok 时 run_once 必须原样返回");
|
||||
assert_eq!(
|
||||
seen,
|
||||
Some(decision.primary),
|
||||
"run_once 传给 iced 的后端必须是决策里的起步项"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// `run_once` 只跑一次:失败也**不**在进程内重试(winit 只允许建一次事件循环)。
|
||||
///
|
||||
/// 抓得住:谁把「进程内重试」加回 `run_once`(会 panic:`RecreationAttempt`)。
|
||||
/// 抓不住:`respawn` 那条换进程的路(见 `app::boot::tests`)。
|
||||
#[test]
|
||||
fn run_once_never_retries_in_process() {
|
||||
let mut calls = 0;
|
||||
let _ = run_once(decide(Backend::Gpu, &Probe::default(), true), |_| {
|
||||
calls += 1;
|
||||
Err(iced::Error::WindowCreationFailed(Box::new(
|
||||
std::io::Error::other("测试用"),
|
||||
)))
|
||||
});
|
||||
assert_eq!(calls, 1, "进程内只许跑一次;重试只能换进程");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user