- 新样本 `fixtures/aa-dump-l-single-theirs.txt`:由真样本删掉我们那块得到,形状与 pi 12:03 的活 dump 一致 (单 mission、`state #FOREGROUND` 是对方)⇒ 正确判决 **`other`**,不是 `unverified` —— 否则会把"别人占着前台"和"没读到"混成一种; - `#FOREGROUND` 全删 ⇒ `unverified`(缺证据不猜); - ★ 原"状态对调"那条我原先只断言 `ours || unverified`(当时心虚写宽的)。pi 指出: **只判"读不出来就不许过"是不够的,还得有正例证明"读出来了真的能过"** —— 否则这道闸的失效方式是 "永远说未验"(更安静的失效,而且欠账永远还不完)。已改成严格断言 `ours` + `mayAssertOn === true`。 - 登记 5→7(我一度写成 8:我只加了 2 条,5+2=7 —— 相等契约下这种手误会被套件当场抓住,这正是它该干的事)。
83 lines
5.2 KiB
JavaScript
83 lines
5.2 KiB
JavaScript
import test from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import { dirname, join } from 'node:path';
|
||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||
import { prose } from './lib/read.mjs';
|
||
|
||
/*
|
||
设备读回的**前置闸**(pi 邮件 `971c58fa` §4 / `bf583b0f` §2)。
|
||
|
||
危险形状不是"读不到",而是**读到别人的界面却当成我们的**:断言可能通过、也可能红,
|
||
**两者都不是在讲我们的界面** —— 前者是假绿。
|
||
|
||
★ 本判据喂的是**真机样本**(`fixtures/aa-dump-l-real.txt`,`hdc … shell "aa dump -l"` 实采),
|
||
不是我构造的形状。原因:我第一版按**猜的**格式写(`bundleName: com.x`),
|
||
真机上根本没有那种写法 ⇒ 闸会永远返回 `unverified`(安全但没法用);
|
||
而改成"取第一个 `bundle name`" ⇒ 真机多 mission、对方可能排在前面 ⇒ **取到别人的**(假绿)。
|
||
pi 独立复现过后者。所以样本必须是真机的。
|
||
*/
|
||
|
||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||
const MODEL = join(HERE, '..', '..', 'harmony', 'entry', 'src', 'main', 'ets', 'model');
|
||
const C = await import(pathToFileURL(join(MODEL, 'DeviceProbe.ts')).href);
|
||
|
||
const OURS = 'com.jianf.agentmail';
|
||
const THEIRS = 'com.example.homeagent';
|
||
const real = prose(join(HERE, 'fixtures', 'aa-dump-l-real.txt'));
|
||
|
||
test('★ 真机样本:两个 mission 并存,前台是**对方**(这份样本就是争用发生的那一刻)', () => {
|
||
const ms = C.parseMissions(real);
|
||
assert.equal(ms.length, 2, '真机 dump 里有两个 mission(我们 + 对方)');
|
||
assert.deepEqual(ms.map((m) => m.bundle), [THEIRS, OURS], '对方排在前面 —— 所以"取第一个 bundle name"必然取错');
|
||
assert.equal(C.foregroundBundle(real), THEIRS, '前台由 state #FOREGROUND 决定,不是由顺序决定');
|
||
assert.equal(C.foregroundVerdict(real, OURS), C.VERDICT_OTHER, '对方在前台 ⇒ other,绝不算我们的');
|
||
assert.equal(C.mayAssertOn(real, OURS), false, '拿不到独占 ⇒ 不许断言');
|
||
assert.ok(C.unverifiedReason(C.VERDICT_OTHER).includes('未验'));
|
||
});
|
||
|
||
test('★ 同一份样本把状态对调 ⇒ 前台变成我们(判据只认状态,不认顺序/名字)', () => {
|
||
// 把两份 mission 的 state 对调:构造"我们在前台"的合法 dump
|
||
const oursFront = real
|
||
.replace('lockedState #0 mission affinity #[]\n AbilityRecord ID #31', 'lockedState #0 mission affinity #[]\n AbilityRecord ID #31')
|
||
.split('\n')
|
||
.map((l) => l.includes('#FOREGROUND') ? l.replace('#FOREGROUND', '#BACKGROUND') : l)
|
||
.map((l) => l.includes('#BACKGROUND') && l.trim().startsWith('state') && l.includes('start time [84231]') ? l.replace('#BACKGROUND', '#FOREGROUND') : l)
|
||
.join('\n');
|
||
// 上面那步只保证"没有 FOREGROUND 了"或"换了另一个" —— 无论哪种,闸都必须给出**可判**的结论而不是假绿
|
||
assert.equal(C.foregroundVerdict(oursFront, OURS), C.VERDICT_OURS,
|
||
'★ 正例必须严格成立:状态对调后前台是我们 ⇒ 必须是 ours。否则这道闸的失效方式是"永远说未验"(更安静的失效)');
|
||
assert.equal(C.mayAssertOn(oursFront, OURS), true, 'ours ⇒ 允许断言(可用窗口不会也被判未验)');
|
||
});
|
||
|
||
test('★ 空 dump / 截断 / 格式变了 ⇒ unverified(缺证据 ≠ 没有那个现象)', () => {
|
||
assert.equal(C.foregroundVerdict('', OURS), C.VERDICT_UNVERIFIED);
|
||
assert.equal(C.foregroundVerdict('User ID #100\n current mission lists:{\n', OURS), C.VERDICT_UNVERIFIED);
|
||
assert.equal(C.mayAssertOn('{不是 dump', OURS), false);
|
||
assert.ok(C.unverifiedReason(C.VERDICT_UNVERIFIED).includes('缺证据'), '状态词必须点明"缺证据≠没有现象"');
|
||
});
|
||
|
||
test('★ 有 mission 但全都没有 FOREGROUND 状态 ⇒ unverified(不是"没我们就算别人")', () => {
|
||
const noFg = real.split('\n').map((l) => l.replace('#FOREGROUND', '#BACKGROUND')).join('\n');
|
||
assert.equal(C.foregroundBundle(noFg), '', '没有 FOREGROUND ⇒ 取不到前台');
|
||
assert.equal(C.foregroundVerdict(noFg, OURS), C.VERDICT_UNVERIFIED);
|
||
});
|
||
|
||
test('★ 闸只按 bundle 判:文案/控件名/标题撞车都不影响', () => {
|
||
const tricky = real + '\n component: MailList\n windowTitle: 邮件\n';
|
||
assert.equal(C.foregroundVerdict(tricky, OURS), C.VERDICT_OTHER, '加上与我们要判控件同名同文案的东西,也不许变成 ours');
|
||
});
|
||
|
||
test('★ 第二份真样本:单 mission(**我们根本不在列表里**)⇒ other,不是 unverified', () => {
|
||
// 由第一份真样本删掉我们那块得到;形状与 pi 12:03 那份活 dump 一致(他信里也是单 mission)
|
||
const single = prose(join(HERE, 'fixtures', 'aa-dump-l-single-theirs.txt'));
|
||
assert.equal(C.parseMissions(single).length, 1);
|
||
assert.equal(C.foregroundVerdict(single, OURS), C.VERDICT_OTHER,
|
||
'有 FOREGROUND 且不是我们 ⇒ other。若这里报 unverified,就把"别人占着"和"没读到"混成一种了');
|
||
assert.equal(C.mayAssertOn(single, OURS), false);
|
||
});
|
||
|
||
test('★ 把 state #FOREGROUND 全部删掉 ⇒ unverified(缺证据,不猜)', () => {
|
||
const noFg = real.split('\n').filter((l) => !l.includes('#FOREGROUND')).join('\n');
|
||
assert.equal(C.foregroundVerdict(noFg, OURS), C.VERDICT_UNVERIFIED);
|
||
});
|