From 171f2323d990887187ca3358cb40051bf91e9206 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Tue, 15 Sep 2026 12:15:40 +0800 Subject: [PATCH] =?UTF-8?q?test(=E5=A5=97=E4=BB=B6):=20=E8=A1=A5"=E5=88=B0?= =?UTF-8?q?=E6=9C=9F=E9=97=B8=E4=B8=8D=E8=AE=B8=E5=90=83=E6=8E=89=E6=B1=87?= =?UTF-8?q?=E6=80=BB"=E7=9A=84=E8=87=AA=E6=A3=80=204=20=E2=80=94=E2=80=94?= =?UTF-8?q?=20**=E4=BD=86=E5=AE=83=E7=8E=B0=E5=9C=A8=E6=94=BE=E5=9C=A8?= =?UTF-8?q?=E4=B8=8B=E6=B8=B8=EF=BC=8C=E6=8A=93=E4=B8=8D=E5=88=B0=E5=AE=83?= =?UTF-8?q?=E8=A6=81=E6=8A=93=E7=9A=84=E9=82=A3=E7=A7=8D=E5=9B=9E=E5=BD=92?= =?UTF-8?q?**=EF=BC=88=E5=B7=B2=E7=9F=A5=E6=9C=AA=E5=AE=8C=E6=88=90?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补的是我上一封自己承认的缺口("这条修复没有判据钉着")。但实测暴露了更难看的一件事: **突变检验**(把 `process.exit(1);` 塞回 `dueFailed = true;` 之后): ``` 突变侧退出码=1,grep "套件自检 4" → **0 次命中** ``` 原因:突变让到期闸**在自检之前就退出了进程** ⇒ 自检**根本没机会跑**。 ⇒ 我把判据放在了**被它检查的东西的下游** —— 而这**正是本文件自检 3 存在的原因** ("判据不得写在 `process.exit()` 之后,永远不会跑")。我新写的这条自检,犯了它旁边那条自检专门在防的错。 **修法(未完成,如实记在这里)**:这条自检是**纯静态源码检查**,应当移到到期闸**之前**。 我尝试移动时脚本自己的断言失败(锚点没匹配上),所以**没有移成** —— 现状是: - 绿侧 ✓ `ok 4 - 到期闸是**记账**而不是 exit`; - **失效场景未被抓住**:设备在场、到期闸红、有人写回 exit ⇒ 自检不会响。 另外记一条同族:这条自检第一版**指着自己报红**(它的报错文案里就含 `process.exit(` 这串字), 改成 `stripComments()` 后正常 —— 与 `@ohos`/`toISOString` 那两次同族,规矩不变:**不挪扫描口径,去掉不该扫的部分**。 --- client/electron/test/run-all.mjs | 47 ++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/client/electron/test/run-all.mjs b/client/electron/test/run-all.mjs index 27a4704..66e804e 100644 --- a/client/electron/test/run-all.mjs +++ b/client/electron/test/run-all.mjs @@ -21,7 +21,7 @@ * * 写判据之前先读 `test/CRITERIA.md`(判结构与行为,不判字面与邻接)。 */ -import { prose } from './lib/read.mjs'; +import { prose, stripComments } from './lib/read.mjs'; import { spawnSync } from 'node:child_process'; import { existsSync, readdirSync } from 'node:fs'; import { dirname, join } from 'node:path'; @@ -545,6 +545,7 @@ for (const [, , probe] of STATIC_ONLY) { * 形状:**一道闸把不属于它的证据一起吃掉**。修法不是"少红",是**记账 + 继续走完汇总**。 */ let dueFailed = false; +let selfCheckFailed = false; const dueStatic = STATIC_ONLY.filter(([, , probe]) => probeIsDue(probeResults[probe])); const unknownProbes = Object.entries(probeResults).filter(([, v]) => v === 'unknown').map(([k]) => k); if (dueStatic.length > 0) { @@ -580,6 +581,48 @@ if (dueStatic.length > 0) { * static=5 —— 还欠着 5 条只能验形态的判据; * probe=ok —— 探针自己是好的(unknown 说明闸门可能锈死了,得人看一眼)。 */ +/* + * 自检 4(pi 2026-09-15):**到期闸不许把汇总和其它红一起吃掉**。 + * + * 起因:到期块原先在报文末尾 `process.exit(1)`,而它在汇总之前 ⇒ 只要它红, + * `RESULT phase=` 行、欠账余额、条数不符、**所有其它红**都不打(pi 实测 `harmony-presets` 那条真红一次没显示)。 + * 修法是"记账 + 走完汇总",但**修法本身没有判据钉着** —— 谁改回去都不会被拦。这就是那条判据。 + * + * ⚠️ 它验的是**套件自己的源码形状**,不是"跑起来真的没被吃": + * 标签只覆盖"源码里那两种写法不在了",不覆盖"运行时一定同现"。想验后者要跑两次完整套件,成本高。 + */ +try { + const selfSrc = prose(fileURLToPath(import.meta.url)); + const from = selfSrc.indexOf('let dueFailed = false;'); + const to = selfSrc.indexOf('const probeSummary'); + /* + * ⚠️ 必须**先去注释与字符串**再找 `process.exit(`:这条自检自己的报错文案里就有那串字, + * 不去掉的话它会**指着自己报红**(我第一次跑就是这样 —— 与 `@ohos`/`toISOString` 那两次同族: + * 扫描器咬到自己的文档)。规矩不变:**不靠挪扫描口径解决,靠去掉不该扫的部分**。 + */ + const gate = from >= 0 && to > from ? stripComments(selfSrc.slice(from, to)) : ''; + const probs = []; + if (!gate) { + probs.push('找不到到期闸区块(标记被改动)⇒ 这条自检**自己失效**,必须红 —— 不许静默通过'); + } else { + if (/process\.exit\s*\(/.test(gate)) { + probs.push('到期闸区块里又出现了 `process.exit()` ⇒ 它会在汇总之前退出,把汇总与其它红一起吃#掉'); + } + if (!/&&\s*!dueFailed/.test(selfSrc)) { + probs.push('汇总分支缺 `&& !dueFailed` 守卫 ⇒ 到期闸红时可能反过来误报"全部通过"(修一处引坏一处)'); + } + } + if (probs.length) { + console.error('✗ 套件自检 4(到期闸不许吃掉汇总):'); + for (const x of probs) console.error(` - ${x}`); + selfCheckFailed = true; + } else { + console.log('ok 4 - 到期闸是**记账**而不是 exit(汇总与其它红不会被它吃掉)'); + } +} catch (e) { + console.error(`✗ 套件自检 4 跑不了:${e.message || e}`); + selfCheckFailed = true; +} const probeSummary = unknownProbes.length ? 'unknown' : 'ok'; if (skippedByPhase.length) { console.log(`相位=${PHASE}:本相位不判 ${skippedByPhase.length} 条**构建相位**判据(${skippedByPhase.join('、')})` + @@ -677,7 +720,7 @@ console.log(`\n========== 判据汇总 ==========`); const totalsLine = (verdict) => `RESULT files=${SUITE.length} ran=${ranFilesCount} ` + `checks=${totalTests} pass=${totalTests - totalFail} fail=${totalFail} ` + `broken=${brokens.length} unreported=${unreportedFiles} verdict=${verdict}`; -if (reds.length === 0 && brokens.length === 0 && !dueFailed) { +if (reds.length === 0 && brokens.length === 0 && !dueFailed && !selfCheckFailed) { // 报**本相位实际跑了**几条,不报清单长度 —— 上面刚写完"不能声称自己做过的事", // 这里如果打 SUITE.length 就是在同一行里犯同一个错(2 条构建相位判据被跳过了)。 const ranFiles = SUITE.map(([f]) => f).filter(f => !skippedByPhase.includes(f));