import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import vm from 'node:vm' import * as Cesium from 'cesium' import { toPipeNetwork, filterPipeNetwork } from '../../../src/modules/cockpit/domain/pipeNetwork.js' import { planModeLayers } from '../../../src/modules/cockpit/domain/modeLayerPlan.js' import { planViewMode } from '../../../src/modules/cockpit/domain/viewModes.js' import { syncPipeLayer, clearPipeLayer } from '../../../src/modules/cockpit/services/cesiumPipeLayer.js' // Offline only: real domain functions and Cesium entities; GPU picking returns controlled hits. // No network, server, browser, file mutations, or in-place mutation testing. const source = readFileSync(new URL('../../../src/modules/cockpit/services/cesiumEngine.js', import.meta.url), 'utf8') const code = source.replace(/^import\s+[^]*?from\s+['"][^'"\n]+['"][ \t]*$/gm, '') .replace(/^import\s+['"][^'"\n]+['"][ \t]*$/gm, '') .replace(/^export /gm, '') const context = vm.createContext({ ...Cesium, CesiumMath: Cesium.Math }) vm.runInContext(`${code}\nglobalThis.engine = { pickPointMarkerAt, pickDeviceMarkerAt };`, context) const engine = context.engine let failed = 0 let passed = 0 async function check(name, action) { try { await action(); passed += 1; console.log(`PASS ${name}`) } catch (error) { failed += 1; console.error(`FAIL ${name}: ${error.message}`) } } const path = [[110.39, 28.44], [110.395, 28.445], [110.40, 28.45]] function feature(coordinates = path, properties = {}) { return { type: 'Feature', id: 'P-1', geometry: { type: 'LineString', coordinates }, properties: { code: 'P-1', industry: 'GAS', diameter: '400', material: '钢', coordinateValidation: { renderable: true }, ...properties, } } } const network = toPipeNetwork({ features: [feature()] }) await check('完整路径、源管径和可选材质原样映射', () => { assert.deepEqual(network.pipes[0].positions, path) assert.equal(network.pipes[0].diameter, 400) assert.equal(network.pipes[0].material, '钢') const missing = toPipeNetwork({ features: [feature(path, { diameter: null, material: null })] }).pipes[0] assert.equal(missing.diameter, null) assert.equal(missing.material, '') }) await check('任一坏顶点整条不上图,保留清单,不跨点重连', () => { for (const bad of [null, [], ['110.395', 28.445], [NaN, 28.445], [110.395, Infinity]]) { const result = toPipeNetwork({ features: [feature([path[0], bad, path[2]])] }) assert.equal(result.pipes.length, 0) assert.equal(result.blocked.length, 1) assert.equal(result.blocked[0].code, 'P-1') assert.equal(result.blocked[0].reasonText, '无地图位置') } }) await check('后端未准入即不上图,不用合法结构替代后端校核', () => { const result = toPipeNetwork({ features: [feature(path, { coordinateValidation: { renderable: false, reason: 'UNVERIFIED_COORDINATE' } })] }) assert.equal(result.pipes.length, 0) assert.equal(result.blocked[0].reasonText, '坐标未经校验') }) await check('行业筛选同样裁剪无地图位置清单,不修改原始网络', () => { const all = toPipeNetwork({ features: [feature(), feature(path, { code: 'W', industry: 'WATER_SUPPLY' }), feature([path[0]], { code: 'X', industry: 'WATER_SUPPLY' })] }) assert.deepEqual(filterPipeNetwork(all, { industry: 'gas' }).pipes.map((p) => p.code), ['P-1']) assert.equal(filterPipeNetwork(all, { industry: 'gas' }).blocked.length, 0) const water = filterPipeNetwork(all, { industry: 'water' }) assert.deepEqual(water.pipes.map((p) => p.code), ['W']) assert.equal(water.blocked.length, 1) assert.equal(filterPipeNetwork(all, { industry: 'all' }).pipes.length, 2) assert.equal(all.blocked.length, 1) }) await check('四种模式均保留管线,引导态隐藏,切视图不裁管线', () => { for (const mode of ['overview', 'infrastructure', 'monitoring', 'warningResponse']) { const input = { mode, entered: true, objects: [], facilities: [], pipelines: network.pipes } assert.equal(planModeLayers(input).pipelines, network.pipes) assert.equal(planModeLayers({ ...input, entered: false }).pipelines.length, 0) } for (const mode of ['ground', 'pipeline']) { const plan = planViewMode(mode) assert.ok(plan.terrainAlpha > 0 && plan.tilesetAlpha > 0) assert.equal(plan.terrainAlpha < 1, mode === 'pipeline') assert.equal(plan.tilesetAlpha < 1, mode === 'pipeline') } }) const pipes = new Cesium.CustomDataSource('cockpit-pipelines') const devices = new Cesium.CustomDataSource('cockpit-associated-device-markers') const pipe = pipes.entities.add({ id: 'pipe:P-1', properties: { kind: 'pipe', code: 'P-1' } }) const component = pipes.entities.add({ id: 'component:C-1', properties: { kind: 'component', code: 'C-1' } }) const point = new Cesium.Entity({ id: 'point:M', properties: { pointCode: 'M', pointKind: 'monitoring-point', pointStatus: 'NORMAL' } }) const device = new Cesium.Entity({ id: 'device:D', properties: { deviceCode: 'D', monitoringPointCode: 'M', deviceStatus: 'NORMAL' } }) const model = { kind: 'pipe-model-batch', key: 'batch', instances: ['pipe:P-1'] } const building = { id: 'building' } let hits = [] let drills = 0 let pickedPosition = null const viewer = { dataSources: { getByName: (name) => name === pipes.name ? [pipes] : name === devices.name ? [devices] : [] }, canvas: { getBoundingClientRect: () => ({ left: 20, top: 30 }) }, scene: { pick(position) { pickedPosition = position; return hits[0] }, drillPick() { drills += 1; return hits }, }, } await check('普通点选不触发多层拾取,窗口坐标转画布坐标', () => { hits = [{ id: point }]; drills = 0 assert.equal(engine.pickPointMarkerAt(viewer, 120, 230).code, 'M') assert.equal(drills, 0) assert.equal(pickedPosition.x, 100) assert.equal(pickedPosition.y, 200) }) await check('管线、构件、模型都不能吞掉监测点', () => { for (const foreground of [pipe, component, model]) { hits = [{ id: foreground }, { id: point }] assert.equal(engine.pickPointMarkerAt(viewer, 120, 230).code, 'M') } }) await check('管线遮挡设备时仍回设备身份与父点位', () => { hits = [{ id: model }, { id: pipe }, { id: device }] const hit = engine.pickDeviceMarkerAt(viewer, 120, 230) assert.equal(hit.code, 'D') assert.equal(hit.pointCode, 'M') }) await check('不穿透建筑/其它对象,也不把单独管线当监测点或设备', () => { for (const list of [[{ id: building }, { id: point }], [{ id: pipe }, { id: building }, { id: point }], [{ id: model }]]) { hits = list assert.equal(engine.pickPointMarkerAt(viewer, 120, 230), null) assert.equal(engine.pickDeviceMarkerAt(viewer, 120, 230), null) } }) await check('名字相似但不属于管线源的对象不能被穿透', () => { hits = [{ id: new Cesium.Entity({ id: 'pipe:foreign' }) }, { id: point }] assert.equal(engine.pickPointMarkerAt(viewer, 120, 230), null) }) await check('无多层拾取能力时不伪造命中', () => { hits = [{ id: pipe }, { id: point }] const limited = { ...viewer, scene: { pick: viewer.scene.pick } } assert.equal(engine.pickPointMarkerAt(limited, 120, 230), null) }) await check('真实Cesium折线写入且相同输入不重赋值,筛空后移除', async () => { const target = { dataSources: new Cesium.DataSourceCollection() } const first = await syncPipeLayer(target, network) assert.equal(first.pipes, 1) const entity = target.dataSources.getByName(pipes.name)[0].entities.getById('pipe:P-1') assert.equal(entity.polyline.positions.getValue().length, path.length) const positions = entity.polyline.positions const second = await syncPipeLayer(target, network) assert.equal(second.unchanged, 1) assert.equal(entity.polyline.positions, positions) const empty = await syncPipeLayer(target, { pipes: [], components: [] }) assert.equal(empty.removed, 1) await clearPipeLayer(target) }) console.log(`T22: ${passed} passed, ${failed} failed`) process.exitCode = failed ? 1 : 0