| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- // 锚点迁移对抗式验证(验收清单第 2 项):
- // 1. 新断言(verticalOrigin=BOTTOM + 尺寸随母版比例)在「未迁移的旧实现」上必须失败;
- // 2. 旧断言(CENTER + 方形 18×18)在「已迁移的新实现」上也必须失败;
- // 两向都能失败 → 迁移是真实的,不是「改完还是绿的」。
- import { readFileSync } from 'node:fs'
- import vm from 'node:vm'
- // —— 加载引擎模块的精简副本(跳过 cesium import;用 stub 顶住) ——
- const src = readFileSync('src/modules/cockpit/services/cesiumEngine.js', 'utf8')
- // 砍掉静态 import(stub 由沙箱注入)
- .replace(/^import[\s\S]*?from\s+['"][^'"]+['"];?\s*$/gm, '')
- // 砍掉 Cesium 常量解构(沙箱注入)
- .replace(/^const\s*\{[\s\S]*?\}\s*=\s*Cesium;?/m, '')
- function loadEngine() {
- const created = []
- const ctx = vm.createContext({
- // Cesium stub(含 BOTTOM,供新锚点断言)
- VerticalOrigin: { CENTER: 'CENTER', BOTTOM: 'BOTTOM' },
- HeightReference: { CLAMP_TO_GROUND: 'CLAMP_TO_GROUND' },
- Cartesian2: class { constructor(x, y) { this.x = x; this.y = y } },
- Cartesian3: { fromDegrees: (a, b) => ({ lon: a, lat: b }) },
- Color: { WHITE: { withAlpha: (a) => ({ alpha: a }) }, BLACK: { withAlpha: (a) => ({ alpha: a }) } },
- LabelStyle: { FILL_AND_OUTLINE: 0 },
- DistanceDisplayCondition: class {},
- // 引擎模块引用的其他域模块(按需最小 stub;本验证只走 syncPointMarkers)
- EMPHASIS_STYLE: {}, shouldEmphasize: () => false,
- MAP_LABEL_STYLE: {}, mapLabelText: () => ({ text: '', font: '', pixelOffset: {} }),
- createTilesetLoadingController: () => ({}), tilesetOptions: {},
- createRegionLoadingController: () => ({}), contentAdmission: {}, removeSceneTileset: () => {},
- DEVICE_EFFECT: {}, RING_LAYERS: 0, blinkStrengthAt: () => 0, glowScaleAt: () => 0,
- glowStrengthAt: () => 0, hasGlow: () => false, pulseStrengthAt: () => 0,
- ringEntityCount: () => 0, ringFrameAt: () => 0, spinAngleAt: () => 0,
- GRADE_DEFAULTS: {}, parseHexColor: () => null,
- planToDataset: (plan) => ({ markerMaster: plan.master, markerInner: plan.inner.enabled ? plan.inner.icon : '', markerAnchor: `${plan.anchor.x},${plan.anchor.y}`, markerDesaturate: plan.desaturate ? 'yes' : 'no' }),
- renderMarker: async () => 'data:,',
- // 引擎内部可能引用的 DOM/全局
- console, setTimeout, clearTimeout, Math, JSON, Number, Object, Array, Map, Set, WeakMap, Promise,
- document: undefined,
- __created: created,
- pointMarkerSource: () => ({ entities: { removeAll() {}, remove() {}, add(e) { created.push(e); return e }, values: [] } }),
- deviceMarkerSource: () => ({ entities: { removeAll() {}, add(e) { created.push(e); return e }, values: [] } }),
- deviceBaseStyle: { clear() {}, set() {}, get() { return null } },
- stopDeviceEffects() {}, applyDeviceEffects() {}, ringEntities: new Map(), blinkEntities: new Map(), spinEntities: new Map(),
- })
- try { vm.runInContext(src + '\nglobalThis.__engine = { syncPointMarkers };', ctx) } catch (e) {
- console.log('(引擎加载跳过部分依赖错误,尝试仅提取 syncPointMarkers)', e.message.slice(0, 80))
- // 提取函数体 + 其紧邻的模块级依赖(markerEntityIndex / markerFingerprint)单独执行
- const idxDecl = /const markerEntityIndex = new WeakMap\(\)[^\n]*/.exec(src)[0]
- const fpFn = /function markerFingerprint\(marker\)[\s\S]*?\n\}/.exec(src)[0]
- const fnMatch = src.match(/export function syncPointMarkers[\s\S]*?\n\}/)
- vm.runInContext(
- idxDecl + '\n' + fpFn + '\n' +
- 'globalThis.__engine = { syncPointMarkers: ' + fnMatch[0].replace('export function syncPointMarkers', 'function syncPointMarkers') + ' };',
- ctx,
- )
- }
- return { syncPointMarkers: ctx.__engine.syncPointMarkers, created }
- }
- const marker = {
- key: 'MP-001|monitoring-point', kind: 'monitoring-point', code: 'MP-001', name: '',
- deviceCodes: [], status: 'ALARM', visualKey: 'ALARM', tone: 'lv1', shape: 'triangle',
- label: '报警', longitude: 110.4, latitude: 28.4,
- }
- const plan = {
- master: 'solid',
- inner: { icon: '', enabled: false, diameterRatio: 0.6, center: { x: 0.499, y: 0.397 } },
- size: { width: 27, height: 33.93 },
- anchor: { x: 0.4987, y: 1.0 },
- tint: 'lv1', desaturate: false,
- labelOffsetY: -39.93, labelMaxWidth: 43.2,
- draw: { width: 86.06, height: 92.99, pad: 2.86 },
- }
- let pass = 0
- let fail = 0
- const check = (cond, label) => { if (cond) { pass++; console.log(` ✓ ${label}`) } else { fail++; console.log(` ✗ ${label}`) } }
- console.log('① 新断言 × 新实现(传 planOf):BOTTOM 锚定 + 母版比例尺寸')
- {
- const { syncPointMarkers, created } = loadEngine()
- syncPointMarkers({}, [marker], () => '#ff3b52', () => 'data:,', () => plan, () => '#ff3b52')
- const bb = created[0].billboard
- check(bb.verticalOrigin === 'BOTTOM', `verticalOrigin = BOTTOM(实际 ${bb.verticalOrigin})`)
- check(bb.width === 86.06 && bb.height === 92.99, `尺寸 = draw 86.06×92.99(实际 ${bb.width}×${bb.height})`)
- check(created[0].properties.markerMaster && created[0].properties.markerMaster === 'solid', '宿主读数含 markerMaster=solid')
- }
- console.log('② 新断言 × 旧实现(不传 planOf):必须仍 CENTER/18×18 —— 新断言对旧实现失败即「能查到未迁移」')
- {
- const { syncPointMarkers, created } = loadEngine()
- syncPointMarkers({}, [marker], () => '#ff3b52', () => 'data:,')
- const bb = created[0].billboard
- check(bb.verticalOrigin === 'CENTER', `旧实现保持 CENTER(实际 ${bb.verticalOrigin})—— 新断言若在此判 BOTTOM 会假红`)
- check(!(bb.width === 27 && bb.height === 33.93), `旧实现尺寸非 18×22.63(实际 ${bb.width}×${bb.height})—— 新断言在此失败是预期`)
- }
- console.log('③ 旧断言 × 新实现:CENTER/18×18 的旧断言对新实现必须失败(防「改完仍是绿的」)')
- {
- const { syncPointMarkers, created } = loadEngine()
- syncPointMarkers({}, [marker], () => '#ff3b52', () => 'data:,', () => plan, () => '#ff3b52')
- const bb = created[0].billboard
- check(bb.verticalOrigin !== 'CENTER', `新实现 verticalOrigin ≠ CENTER(实际 ${bb.verticalOrigin})→ 旧 CENTER 断言会失败`)
- check(!(bb.width === 18 && bb.height === 18), `新实现尺寸 ≠ 18×18(实际 ${bb.width}×${bb.height})→ 旧方形断言会失败`)
- }
- console.log(`\n对抗式验证:${pass} 过 / ${fail} 败`)
- if (fail) process.exitCode = 1
|