|
|
@@ -0,0 +1,61 @@
|
|
|
+import assert from 'node:assert/strict'
|
|
|
+import { readFileSync } from 'node:fs'
|
|
|
+import vm from 'node:vm'
|
|
|
+import { planModeLayers } from '../../../src/modules/cockpit/domain/modeLayerPlan.js'
|
|
|
+const store = readFileSync(new URL('../../../src/modules/cockpit/stores/deviceLayerStore.js', import.meta.url), 'utf8')
|
|
|
+const fn = (name) => store.match(new RegExp(` function ${name}\\([^]*?\\n \\}`))[0]
|
|
|
+let failures = 0
|
|
|
+function check(name, action) { try { action(); console.log(`PASS ${name}`) } catch(e) { failures++;console.error(`FAIL ${name}: ${String(e.message).split('\n')[0]}`) } }
|
|
|
+check('overview permits fixed detail for no-location monitoring point',()=>{
|
|
|
+ const point={kind:'monitoring-point',code:'P',deviceCodes:['A'],coordinate:{renderable:false,state:'UNVERIFIED'}}
|
|
|
+ const plan=planModeLayers({mode:'overview',entered:true,objects:[point],selection:{level:'point',pointCode:'P'}})
|
|
|
+ assert.equal(plan.selection.visible,true)
|
|
|
+ assert.equal(plan.markers.length,0)
|
|
|
+})
|
|
|
+check('same identities with changed coordinates/status invalidate engine plan',()=>{
|
|
|
+ const ctx=vm.createContext({});vm.runInContext(fn('planKeyOf'),ctx)
|
|
|
+ const row={code:'A',longitude:1,latitude:2,status:'NORMAL',shape:'circle',size:14}
|
|
|
+ ctx.a=[row];ctx.b=[{...row,longitude:3}];ctx.c=[{...row,status:'ALARM'}]
|
|
|
+ assert.notEqual(vm.runInContext("planKeyOf('P',a)",ctx),vm.runInContext("planKeyOf('P',b)",ctx))
|
|
|
+ assert.notEqual(vm.runInContext("planKeyOf('P',a)",ctx),vm.runInContext("planKeyOf('P',c)",ctx))
|
|
|
+ assert.equal(vm.runInContext("planKeyOf('P',a)",ctx),vm.runInContext("planKeyOf('P',a)",ctx))
|
|
|
+})
|
|
|
+check('non-drawn device selection cancels previous terrain work',()=>{
|
|
|
+ let cancelled=0
|
|
|
+ const ctx=vm.createContext({deviceFlightToken:0,pendingDeviceTier:false,cancelPointLocate(){cancelled++},DEVICE_FLIGHT:{NONE:'none',CENTER_ONLY:'center-only'},rows:{value:[{code:'B',placement:'no-location'}]},locateMonitoringPoint(){throw Error('must not locate')}})
|
|
|
+ vm.runInContext(fn('applyDeviceFlight'),ctx)
|
|
|
+ vm.runInContext("applyDeviceFlight('center-only','B')",ctx)
|
|
|
+ assert.equal(cancelled,1)
|
|
|
+})
|
|
|
+check('closing detail through level change cancels terrain work',()=>{
|
|
|
+ let cancelled=0
|
|
|
+ const ctx=vm.createContext({deviceFlightToken:0,pendingDeviceTier:false,cancelPointLocate(){cancelled++},DETAIL_LEVEL:{NONE:'none',EQUIPMENT:'equipment'},lastLevel:'equipment',lastDeviceCode:'A'})
|
|
|
+ vm.runInContext(fn('noteLevel'),ctx);vm.runInContext("noteLevel('none','')",ctx)
|
|
|
+ assert.equal(cancelled,1)
|
|
|
+})
|
|
|
+check('hidden parent gates associated devices when abnormal linkage is unavailable',()=>{
|
|
|
+ const point={kind:'monitoring-point',code:'P',deviceCodes:['A'],coordinate:{renderable:true}}
|
|
|
+ const plan=planModeLayers({mode:'warningResponse',entered:true,objects:[point],abnormalDevices:null,
|
|
|
+ associatedDevices:[{code:'A',pointCode:'P',status:'ALARM',placement:'drawn'}],selection:{level:'equipment',pointCode:'P',deviceCode:'A'}})
|
|
|
+ assert.equal(plan.markers.length,0)
|
|
|
+ assert.equal(plan.associatedDevices.length,0)
|
|
|
+ assert.equal(plan.selection.visible,false)
|
|
|
+})
|
|
|
+let requests=[]
|
|
|
+const flightContext=vm.createContext({
|
|
|
+ DEVICE_FLIGHT:{NONE:'none',CENTER_ONLY:'center-only',DEVICE_TIER:'device-tier'},
|
|
|
+ rows:{value:[{code:'A',placement:'drawn'},{code:'B',placement:'drawn'}]},
|
|
|
+ deviceFlightToken:0,pendingDeviceTier:false,cancelPointLocate(){},
|
|
|
+ locateMonitoringPoint(device,options){return new Promise((resolve)=>requests.push({device,options,resolve}))},
|
|
|
+})
|
|
|
+vm.runInContext(fn('applyDeviceFlight'),flightContext)
|
|
|
+vm.runInContext("applyDeviceFlight('device-tier','A');applyDeviceFlight('center-only','B')",flightContext)
|
|
|
+check('rapid A to B inherits an unapplied device tier',()=>{
|
|
|
+ assert.equal(requests.length,2)
|
|
|
+ assert.equal(requests[0].options.centerOnly,false)
|
|
|
+ assert.equal(requests[1].options.centerOnly,false)
|
|
|
+})
|
|
|
+requests.forEach((request)=>request.resolve(true))
|
|
|
+await Promise.resolve()
|
|
|
+console.log(`T48 linkage invariants: ${failures?'FAILED':'passed'}`)
|
|
|
+process.exitCode=failures?1:0
|