t48-linkage-invariants.mjs 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import assert from 'node:assert/strict'
  2. import { readFileSync } from 'node:fs'
  3. import vm from 'node:vm'
  4. import { planModeLayers } from '../../../src/modules/cockpit/domain/modeLayerPlan.js'
  5. const store = readFileSync(new URL('../../../src/modules/cockpit/stores/deviceLayerStore.js', import.meta.url), 'utf8')
  6. const fn = (name) => store.match(new RegExp(` function ${name}\\([^]*?\\n \\}`))[0]
  7. let failures = 0
  8. function check(name, action) { try { action(); console.log(`PASS ${name}`) } catch(e) { failures++;console.error(`FAIL ${name}: ${String(e.message).split('\n')[0]}`) } }
  9. check('overview permits fixed detail for no-location monitoring point',()=>{
  10. const point={kind:'monitoring-point',code:'P',deviceCodes:['A'],coordinate:{renderable:false,state:'UNVERIFIED'}}
  11. const plan=planModeLayers({mode:'overview',entered:true,objects:[point],selection:{level:'point',pointCode:'P'}})
  12. assert.equal(plan.selection.visible,true)
  13. assert.equal(plan.markers.length,0)
  14. })
  15. check('same identities with changed coordinates/status invalidate engine plan',()=>{
  16. const ctx=vm.createContext({});vm.runInContext(fn('planKeyOf'),ctx)
  17. const row={code:'A',longitude:1,latitude:2,status:'NORMAL',shape:'circle',size:14}
  18. ctx.a=[row];ctx.b=[{...row,longitude:3}];ctx.c=[{...row,status:'ALARM'}]
  19. assert.notEqual(vm.runInContext("planKeyOf('P',a)",ctx),vm.runInContext("planKeyOf('P',b)",ctx))
  20. assert.notEqual(vm.runInContext("planKeyOf('P',a)",ctx),vm.runInContext("planKeyOf('P',c)",ctx))
  21. assert.equal(vm.runInContext("planKeyOf('P',a)",ctx),vm.runInContext("planKeyOf('P',a)",ctx))
  22. })
  23. check('non-drawn device selection cancels previous terrain work',()=>{
  24. let cancelled=0
  25. 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')}})
  26. vm.runInContext(fn('applyDeviceFlight'),ctx)
  27. vm.runInContext("applyDeviceFlight('center-only','B')",ctx)
  28. assert.equal(cancelled,1)
  29. })
  30. check('closing detail through level change cancels terrain work',()=>{
  31. let cancelled=0
  32. const ctx=vm.createContext({deviceFlightToken:0,pendingDeviceTier:false,cancelPointLocate(){cancelled++},DETAIL_LEVEL:{NONE:'none',EQUIPMENT:'equipment'},lastLevel:'equipment',lastDeviceCode:'A'})
  33. vm.runInContext(fn('noteLevel'),ctx);vm.runInContext("noteLevel('none','')",ctx)
  34. assert.equal(cancelled,1)
  35. })
  36. check('hidden parent gates associated devices when abnormal linkage is unavailable',()=>{
  37. const point={kind:'monitoring-point',code:'P',deviceCodes:['A'],coordinate:{renderable:true}}
  38. const plan=planModeLayers({mode:'warningResponse',entered:true,objects:[point],abnormalDevices:null,
  39. associatedDevices:[{code:'A',pointCode:'P',status:'ALARM',placement:'drawn'}],selection:{level:'equipment',pointCode:'P',deviceCode:'A'}})
  40. assert.equal(plan.markers.length,0)
  41. assert.equal(plan.associatedDevices.length,0)
  42. assert.equal(plan.selection.visible,false)
  43. })
  44. let requests=[]
  45. const flightContext=vm.createContext({
  46. DEVICE_FLIGHT:{NONE:'none',CENTER_ONLY:'center-only',DEVICE_TIER:'device-tier'},
  47. rows:{value:[{code:'A',placement:'drawn'},{code:'B',placement:'drawn'}]},
  48. deviceFlightToken:0,pendingDeviceTier:false,cancelPointLocate(){},
  49. locateMonitoringPoint(device,options){return new Promise((resolve)=>requests.push({device,options,resolve}))},
  50. })
  51. vm.runInContext(fn('applyDeviceFlight'),flightContext)
  52. vm.runInContext("applyDeviceFlight('device-tier','A');applyDeviceFlight('center-only','B')",flightContext)
  53. check('rapid A to B inherits an unapplied device tier',()=>{
  54. assert.equal(requests.length,2)
  55. assert.equal(requests[0].options.centerOnly,false)
  56. assert.equal(requests[1].options.centerOnly,false)
  57. })
  58. requests.forEach((request)=>request.resolve(true))
  59. await Promise.resolve()
  60. console.log(`T48 linkage invariants: ${failures?'FAILED':'passed'}`)
  61. process.exitCode=failures?1:0