import { ANCHORS, onesCtrlByCard } from '../utils/common/ones-anchor.helper'; import * as fs from 'fs'; import * as path from 'path'; // 模拟"现有 P0 用例回写"覆盖:枚举所有能 emit 的锚点(case号 + 15975/15974 step uuid), // 与 plan 全量(cases + 49 ble + 56 wifi)对比,列出**没有任何用例锚点覆盖的**(漏)。 const wb = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test-plan/ones-writeback-params.json'), 'utf-8')); const emittedCases = new Set(); // add/feature/platform case numbers const emittedBle = new Set(); // 15975 step uuids const emittedWifi = new Set(); // 15974 step uuids // 1) ANCHORS 全量:add(case) + ctrlBle(15975) + ctrlWifi(15974) for (const cat of Object.keys(ANCHORS)) { for (const dev of Object.keys(ANCHORS[cat])) { const a = ANCHORS[cat][dev]; if (a.add) emittedCases.add(a.add); if (a.ctrlBle) emittedBle.add(a.ctrlBle); if (a.ctrlWifi) emittedWifi.add(a.ctrlWifi); } } // 2) 灯类卡片名(P0 实际跑的灯) const LIGHT_CARDS = ['Ceiling Light Pro', 'RGBWW Floor Lamp', 'RGBICWW Floor Lamp', 'RGBWW Strip Light 3', 'RGBIC Neon Rope Light', 'Candle Warmer Lamp', 'Color Bulb', 'Strip Light SB', 'Permanent Outdoor Lights']; for (const card of LIGHT_CARDS) { process.env.PROTO = 'ble'; const b = onesCtrlByCard(card); process.env.PROTO = 'wifi'; const w = onesCtrlByCard(card); const mb = b.match(/15975#(\w+)/); if (mb) emittedBle.add(mb[1]); const mw = w.match(/15974#(\w+)/); if (mw) emittedWifi.add(mw[1]); } // 3) 特殊锚点:bot / meter报警校准(onesBleStep) / air_purifier 双发 / platform emittedBle.add('6e4uZSVe'); emittedWifi.add('Qt4hcgB4'); // bot ['NvpUv9Tt', '3Jm5FAdW', 'QfYLdj8s'].forEach(u => emittedBle.add(u)); // meter 报警/校温/校湿 ['7qxA1ajE', 'R5PDp8BR'].forEach(u => emittedBle.add(u)); // air_purifier 美规/日规 // meter 家族报警/校准(P0 按 METER_*_STEP env 参数化跑 meter_alert_calibration):MeterPlus/OutdoorMeter/MeterPro ['UZCtZRPy', '9mheLMDJ', 'GSZv8BYm', 'QwnZJARA', 'Ncg7BDeR', 'k6cqKqtZ', 'JggzNXDo', 'L967RGHa', '8Wzaj5pB'].forEach(u => emittedBle.add(u)); [15940, 15941, 15942, 15943, 15944, 15945, 15976, 227290, 298968].forEach(n => emittedCases.add(n)); // platform // 3b) 扫所有测试文件的**字面锚点**(捕获硬编码 [ONES:号] / [ONES:15975#step] / [ONES:15974#step],如 bot/color_bulb/urc/meter_control) function walk(dir: string): string[] { const out: string[] = []; for (const e of fs.readdirSync(dir, { withFileTypes: true })) { const p = path.join(dir, e.name); if (e.isDirectory()) out.push(...walk(p)); else if (e.name.endsWith('.test.ts')) out.push(p); } return out; } for (const file of walk(path.resolve(__dirname, '../tests'))) { const src = fs.readFileSync(file, 'utf-8'); for (const m of src.matchAll(/ONES:(\d+)#(\w+)/g)) { // step 锚点:15975→ble / 15974→wifi if (m[1] === '15975') emittedBle.add(m[2]); else if (m[1] === '15974') emittedWifi.add(m[2]); } for (const m of src.matchAll(/ONES:(\d+)(?!#)/g)) emittedCases.add(parseInt(m[1], 10)); // 纯 case 号 } // 4) diff const planCases: any[] = wb.cases; const bleSteps: string[] = wb.controlCases['15975'].steps; // uuid 字符串数组 const wifiSteps: string[] = wb.controlCases['15974'].steps; // 表头 49 步 ble uuid→名(2026-06-11 核对),供可读输出 const BLE_NAME: Record = { '6e4uZSVe': 'Bot', '5YEfmpJz': 'Lock', '774V8bND': 'Curtain', 'NvpUv9Tt': 'Meter报警', '3Jm5FAdW': 'Meter校温', 'QfYLdj8s': 'Meter校湿', 'GkkrZpaC': 'Humidifier', 'TNhSAuUC': 'Bulb', '4poyiVwD': 'StripLight', '2528azD6': '吸顶灯pro', 'V15M64cP': '吸顶灯lte', '2jSFfY4k': 'PlugMini', 'UZCtZRPy': 'MeterPlus报警', '9mheLMDJ': 'MeterPlus校温', 'GSZv8BYm': 'MeterPlus校湿', 'HrigrD2X': 'Motion', 'A8C4BsCm': 'Contact', '3frMRDZj': 'BlindTilt-V20', 'Qbm9VB72': 'BlindTilt-V12', 'QwnZJARA': 'IOSensor报警', 'Ncg7BDeR': 'IOSensor校温', 'k6cqKqtZ': 'IOSensor校湿', 'QqsnPMc3': 'Curtain3', 'CiFPEbNS': 'Battery循环扇', 'LnPNEJmS': 'Lock Pro', '3PmZMk1s': 'Humidifier2', 'JBszgxRS': '无电池循环扇', 'SmzuHtWi': 'RollerShade', '7qxA1ajE': '美规净化器', 'R5PDp8BR': '日规Table净化器', '3wM6fW8W': 'Curtain3-2025', 'JggzNXDo': 'MeterPro报警', 'L967RGHa': 'MeterPro校温', '8Wzaj5pB': 'MeterPro校湿', '3bYsmiZG': 'MeterProCO2报警', 'NDqRQxVx': 'CO2校温', 'DxKG9Acs': 'CO2校湿', '3ob75cjf': 'RGBWW灯带3', 'JVnRz7xY': 'RGBWW落地灯', 'MKgLq1oy': 'Relay1pm', 'A1TLxsFw': 'Relay1', 'PG62s725': 'Relay2pm开关', 'AafJ5tj5': 'Relay2pm覆盖', 'E5YRm4Pg': 'GarageDoor', 'QAHNrXrm': 'RGBICWW灯带', 'AfxmoAEq': 'RGBICWW落地灯', 'E2QCS8xy': 'RGBIC霓虹钢丝', 'TSVKWcJ3': 'eu plug', 'XWmNA9UL': 'Standing循环扇', }; const missingCases = planCases.filter(c => !emittedCases.has(c.number)); const missingBle = bleSteps.filter(u => !emittedBle.has(u)); const missingWifi = wifiSteps.filter(u => !emittedWifi.has(u)); console.log(`\n===== 模拟 P0 回写覆盖 (plan ${wb.defaultPlan}) =====`); console.log(`cases: ${planCases.length} 计划 / ${emittedCases.size} 锚点 → 漏 ${missingCases.length}`); console.log(`ble step(15975): ${bleSteps.length} 计划 / 命中 ${bleSteps.length - missingBle.length} → 漏 ${missingBle.length}`); console.log(`wifi step(15974): ${wifiSteps.length} 计划 / 命中 ${wifiSteps.length - missingWifi.length} → 漏 ${missingWifi.length}`); console.log(`\n--- 漏的 cases(add/feature/platform,无任何用例锚点)---`); for (const c of missingCases) console.log(` ONES:${c.number} ${c.name}`); console.log(`\n--- 漏的 BLE 控制 step(15975)---`); for (const u of missingBle) console.log(` ${u} ${BLE_NAME[u] || '(未知,表头无此uuid)'}`); console.log(`\n--- 漏的 WiFi 控制 step(15974)(共 ${missingWifi.length},uuid)---`); console.log(' ' + missingWifi.join(' ')); // 生成合成 .results.json(所有 emit 的锚点都 PASS),供 sync-ones-results --dry-run 用真实匹配代码验证反写。 if (process.argv.includes('--emit-results')) { const results: any[] = []; emittedCases.forEach(n => results.push({ suite: 'sim', name: `[P0][ONES:${n}] sim`, status: 'PASS', duration: 1, detail: 'sim' })); emittedBle.forEach(u => results.push({ suite: 'sim', name: `[P0][ONES:15975#${u}][ble] sim`, status: 'PASS', duration: 1, detail: 'sim' })); emittedWifi.forEach(u => results.push({ suite: 'sim', name: `[P0][ONES:15974#${u}][wifi] sim`, status: 'PASS', duration: 1, detail: 'sim' })); const out = '/tmp/sim-results.json'; fs.writeFileSync(out, JSON.stringify({ results }, null, 2)); console.log(`\n[--emit-results] 已写合成结果 ${results.length} 条 → ${out}`); }