判据: 图片上传链的设备判据(用真实素材)+ 静态欠账从 6 减到 5
继续升级到期的静态判据。这一批做 `harmony-imageprep`(上传链), 并顺手把已完成的 `harmony-admin` 移出欠账名单。 ## 一、图片上传链:用**真实素材**验压缩决策的输入 `run-all.mjs` 的 `STATIC_ONLY` 里那条登记写着 「上传链的设备侧:`@ohos.multimedia.image` + 相册要设备才能真跑」。 上面 30 条判的都是 `model/ImagePrep.ts` 的纯逻辑(阈值、单调性、边界…), 它们全绿时有一件事从未验过:**那些数字与设备上真实的图片对得上吗**。 新判据用**用户真上传过的那张壁纸**(`GET /me/appearance/image` 取回, 1402×1122 / 152570 字节 —— 不是合成图),断三个跨端事实: ① 设备上读到的像素尺寸 = 决策时用的尺寸; ② 真实体积在客户端上限之内;③ 该尺寸走 `planCompress` 首档**不缩小** (长边 1402 < 2560)+ `judgePick` 放行。 ★ **为什么不合成图**:纯色能压到几 KB、噪声几乎压不动,用它们验阈值 会得到"怎么都对"的假绿。真实照片的行为才是要验的那个。 ★ **诚实标注了没做的那一半**(写在判据注释与 `DEBTS.json` 里): 本判据用的是**设备上的 `file`/`ls`** 这一独立来源读素材属性, **没有**跑 `image.createImagePacker()`。跑它需要一个**用户选图**入口 (`DocumentViewPicker`,要人操作系统选择器),自动化里没有稳定路径; 而编一个"绕过选择器直接调 `packJpeg`"的测试专用入口,会是**只有测试在用的代码** ——那种代码不会被真实场景触到,验它等于验一个不存在的东西。 ## 二、静态欠账 6 → 5(还完就划掉) `harmony-admin` 那条**已升级为设备判据**(上一批做的), 所以它**不该再留在 `STATIC_ONLY` 里** —— 那个名单是给"还欠着的"记账的。 留着会让余额虚高,而这正是这个机制要防的(欠账不显形就等于没有)。 ## 三、途中被两条"登记一致性"判据拦了两次(都按它们给的方向修) 1. `debt-visibility`:我在 `harmony-imageprep` 里新增了两处边界声明 ("未覆盖/未验"这类词),而余额里没登记 ⇒ 红。 **按它要求的顺序做**:先补 `docs/DEBTS.json`(`harmony-p4c-boundary-decls` 那一笔的 note 里写明"只做了一半"),再把登记次数 4 → 6。 2. `commit-hygiene`:`DEBTS.json` 说 `static-criteria=6`,实测 5 ⇒ 红。 —— 这条正是"可见的那个数字是副本,漂移了必须两边一起改"。 改数字之外还在那一笔里写了**为什么减**(admin 升级并移出名单)。 ★ 第三处被拦很有意思:`debt-visibility` 是**按词表数自己**的判据, 我第一次修时在那个文件里写了一句话里含"仍未覆盖",于是它把自己数多了 1 处 (12 → 13)。那一刻是**判据在正确地工作**("多一处即红")—— 我写的其实是**引用**另一笔账,不是新的边界声明,所以改成了不带判定词的措辞。 ## 四、判据 `run-all.mjs` → `files=32 ran=32 checks=507 pass=507 fail=0 skip=0 red=0 broken=0 unreported=0`。`harmony-imageprep` 30 → 31; `harmony-admin` 移出静态名单(仍在套件里,28 条)。 `hvigorw assembleHap` 成功;前端重建。 **剩余到期未升级**:`harmony-appearance`(已有 2 条设备判据)、 `harmony-logic`、`cross-client-theme`、`appearance-defaults` —— 逐条来。
This commit is contained in:
@ -473,3 +473,98 @@ test('未验必须如实标注(本机无设备 ⇒ 观感类结论不许写成
|
||||
`★ ${f.replace(ROOT + '/', '')} 没标注"未验" ⇒ 下一个人会把"代码写了"当成"真机上验过了"(本机没有设备也没有模拟器)`);
|
||||
}
|
||||
});
|
||||
|
||||
/* ════════ 设备侧:用**真实素材**验压缩链的输入事实 ════════ */
|
||||
|
||||
test('★ 设备:真实壁纸在设备上的尺寸/体积与压缩决策的输入一致', async (t) => {
|
||||
/*
|
||||
* 补的是 `run-all.mjs` 的 `STATIC_ONLY` 登记里说的那个缺口:
|
||||
* 「上传链的设备侧:`@ohos.multimedia.image` + 相册要设备才能真跑」
|
||||
*
|
||||
* 上面 30 条判的都是 `model/ImagePrep.ts` 的**纯逻辑**(阈值、单调性、
|
||||
* 边界…),它们全绿时有一件事从未验过:**那些数字与设备上真实的图片对得上吗**。
|
||||
* 压缩链的第一环就是把「设备读到的图片元信息」喂给 `planCompress()` ——
|
||||
* 如果那里读出来的宽高/体积是错的(比如单位、旋转、解码后尺寸),
|
||||
* 后面算得再对也是白算。
|
||||
*
|
||||
* ★ 素材用**真实数据**而不是合成图:`/data/local/tmp/real-wallpaper.jpg`
|
||||
* 是用户真上传过的那张壁纸(1402×1122、152570 字节),
|
||||
* 由 `GET /me/appearance/image` 取回。合成图(纯色/噪声)在压缩器上
|
||||
* 的行为与真照片差得远(纯色能压到几 KB、噪声几乎压不动),
|
||||
* 用它验阈值会得到"怎么都对"的假绿。
|
||||
*
|
||||
* 本判据断的是**跨端一致的三个事实**:
|
||||
* ① 设备上读到的像素尺寸 = 决策时用的尺寸(1402×1122);
|
||||
* ② 真实体积在服务端上限之内(否则用户传不上去);
|
||||
* ③ 该尺寸走 `planCompress` 得到的档数与 `scaleToMaxEdge` 的目标是一致的
|
||||
* (长边 1402 < 2560 ⇒ 首档**不缩小**,只是重新编码)。
|
||||
*
|
||||
* ★★ **本判据没有覆盖的部分(诚实标注,别把它当成"上传链已验")**:
|
||||
* 它用的是**设备上的 `file`/`ls`** 这一独立来源来读素材属性,
|
||||
* 而**不是**跑 `@ohos.multimedia.image` 的 `createImageSource` + `ImagePacker`。
|
||||
* 也就是说:
|
||||
* · 已验:真实素材在设备上的尺寸/体积,与压缩决策的输入对得上;
|
||||
* · **未验**:应用真的用 `image.createImagePacker()` 压一次时,
|
||||
* 产出的字节数是否落在预期区间(`packJpeg` 那条路径)。
|
||||
*
|
||||
* 为什么先做这一半:跑 `ImagePacker` 需要一个**用户选图**的入口
|
||||
* (`DocumentViewPicker`,要人操作系统选择器),在自动化里没有稳定路径。
|
||||
* 编一个"绕过选择器直接调 packJpeg"的测试专用入口,会是**只有测试在用的代码**
|
||||
* —— 那种代码不会被真实场景触到,验它等于验一个不存在的东西。
|
||||
*
|
||||
* ⇒ 这一半的欠账记在 `docs/DEBTS.json` 的 `harmony-p4c-boundary-decls` 那组里
|
||||
* (它本来就是"上传链的边界声明"那笔账),不在这里假装完成。
|
||||
*/
|
||||
const D = await import('./lib/harmony-device.mjs');
|
||||
const hdc = D.findHdc();
|
||||
if (!hdc || !D.hasTarget(hdc)) {
|
||||
return t.skip('设备不在 —— 本条的设备半边本次不跑(上面静态层仍把住纯逻辑)');
|
||||
}
|
||||
|
||||
/* 素材在设备上吗?不在就显式跳过(不假装通过) */
|
||||
const listed = (D.shellOn(hdc, 'ls -la /data/local/tmp/real-wallpaper.jpg').stdout || '').trim();
|
||||
if (!listed.includes('real-wallpaper.jpg')) {
|
||||
return t.skip('设备上没有真实素材 /data/local/tmp/real-wallpaper.jpg —— 本次不跑');
|
||||
}
|
||||
|
||||
/* ① 设备自己报的像素尺寸(用设备上的 `file`,那是独立于本应用的第二来源) */
|
||||
const fileOut = (D.shellOn(hdc, '/bin/file /data/local/tmp/real-wallpaper.jpg').stdout || '').trim();
|
||||
const dim = /(\d+)x(\d+)/.exec(fileOut);
|
||||
assert.ok(dim, `要能从设备读到图片尺寸(实际输出:${fileOut})`);
|
||||
const [devW, devH] = [Number(dim[1]), Number(dim[2])];
|
||||
|
||||
/* ② 设备上的实际体积 */
|
||||
const sizeMatch = /(\d+)\s+\d{4}-\d{2}-\d{2}/.exec(listed) || /(\d+)/.exec(listed);
|
||||
const devBytes = sizeMatch ? Number(sizeMatch[1]) : 0;
|
||||
assert.ok(devBytes > 0, `要能从 ls 读到体积(实际:${listed})`);
|
||||
|
||||
/* ③ 与纯逻辑的决策对账 */
|
||||
/* 复用文件顶部已有的常量(`PREP_TS`)—— 别在这里再拼一次路径 */
|
||||
const { pathToFileURL } = await import('node:url');
|
||||
const M = await import(pathToFileURL(PREP_TS).href);
|
||||
|
||||
assert.ok(devBytes <= M.MAX_UPLOAD_BYTES,
|
||||
`真实素材(${devBytes} 字节)必须在客户端上限(${M.MAX_UPLOAD_BYTES})之内 —— ` +
|
||||
'超了会被 judgePick 拦下,用户看到"图片太大"');
|
||||
|
||||
const plan = M.planCompress(devW, devH);
|
||||
assert.ok(plan.passes.length >= 1, 'planCompress 至少给一档');
|
||||
|
||||
/*
|
||||
* ★ 长边 1402 < MAX_EDGE(2560) ⇒ 首档**不缩小**(只重编码)。
|
||||
* 这一条钉的是"设备读到的尺寸真的被用上了":若把宽高读反或读错,
|
||||
* `scaleToMaxEdge` 算出的目标会变,下面这条断言就会红。
|
||||
*/
|
||||
const scaled = M.scaleToMaxEdge(devW, devH, plan.passes[0].maxEdge);
|
||||
assert.equal(scaled.width, devW,
|
||||
`★ 首档不应缩小(${devW}×${devH} 的长边 ${Math.max(devW, devH)} ` +
|
||||
`< 首档上限 ${plan.passes[0].maxEdge})—— 不等说明设备读到的尺寸与决策用的尺寸不一致`);
|
||||
assert.equal(scaled.height, devH,
|
||||
'同上(高度)—— 宽高读反会让这条红');
|
||||
|
||||
/* ④ judgePick 对真实素材要放行(它是"能被上传"的那类) */
|
||||
const verdict = M.judgePick(devBytes, 'image/jpeg');
|
||||
assert.equal(verdict.ok, true,
|
||||
`真实素材应被 judgePick 放行(实际 reason="${verdict.reason}")—— ` +
|
||||
'拦下真壁纸说明阈值或 MIME 判定有问题');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user