verify-continuous-traversal.mjs 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. // Exercise installed Cesium base traversal in isolation with injected tile readiness.
  2. // No DOM/GPU/network/browser. This tests actual traversal, not private tree parsing.
  3. import assert from 'node:assert/strict'
  4. import Traversal from '../../node_modules/@cesium/engine/Source/Scene/Cesium3DTilesetTraversal.js'
  5. import Base from '../../node_modules/@cesium/engine/Source/Scene/Cesium3DTilesetBaseTraversal.js'
  6. import Refine from '../../node_modules/@cesium/engine/Source/Scene/Cesium3DTileRefine.js'
  7. const makeTileset = () => ({ _requestedTiles: [], _selectedTiles: [], _selectedTilesToStyle: [], _emptyTiles: [],
  8. memoryAdjustedScreenSpaceError: 96, debugFreezeFrame: false, hasMixedContent: false, loadSiblings: false,
  9. _minimumPriority: {distance:Infinity,depth:Infinity,foveatedFactor:Infinity,reverseScreenSpaceError:Infinity},
  10. _maximumPriority: {distance:0,depth:0,foveatedFactor:0,reverseScreenSpaceError:0},
  11. _statistics: {visited:0}, _cache: {touch(){}}, _cullRequestsWhileMoving:false })
  12. function tile(tileset,name,{empty=false,loaded=true,sse=200}={}) {
  13. return {tileset,name,children:[],parent:null,refine:Refine.REPLACE,hasRenderableContent:!empty,hasEmptyContent:empty,contentAvailable:loaded,
  14. hasUnloadedRenderableContent:!empty&&!loaded,contentExpired:false,_visible:true,_inRequestVolume:true,
  15. get isVisible(){return this._visible&&this._inRequestVolume},_screenSpaceError:sse,_depth:0,_distanceToCamera:1,_foveatedFactor:0,_priorityReverseScreenSpaceError:0,
  16. getScreenSpaceError(){return this._screenSpaceError},updateExpiration(){},updateVisibility(){},updatePriority(){},
  17. contentVisibility(){return 1},content:{featurePropertiesDirty:false},_selectedFrame:-1,
  18. add(...children){for(const c of children){c.parent=this;c._depth=this._depth+1;this.children.push(c)}return this}}
  19. }
  20. const ts=makeTileset(),root=tile(ts,'root',{empty:true,sse:1e6}),far=tile(ts,'far'),near=tile(ts,'near'),fine=tile(ts,'fine',{loaded:false,sse:0})
  21. root.add(far.add(near.add(fine)));ts.root=root
  22. const saved=Traversal.selectTile
  23. // Only replace styling/content GPU-facing selection; traversal/request/readiness logic is real.
  24. Traversal.selectTile=(t)=>ts._selectedTiles.push(t)
  25. const frame={frameNumber:1,camera:{timeSinceMoved:1,positionWCDeltaMagnitude:0,positionWCDeltaMagnitudeLastFrame:0}}
  26. function run(){frame.frameNumber++;Base.selectTiles(ts,frame);return ts._selectedTiles.map(t=>t.name)}
  27. try{
  28. assert.deepEqual(run(),['near'],'coarse must remain while fine is pending')
  29. assert.ok(ts._requestedTiles.includes(fine),'fine requested before replacement')
  30. fine.contentAvailable=true;fine.hasUnloadedRenderableContent=false
  31. assert.deepEqual(run(),['fine'],'ready child replaces only its own parent')
  32. fine.contentAvailable=false;fine.hasUnloadedRenderableContent=true
  33. assert.deepEqual(run(),['near'],'failed/evicted child restores local coarse')
  34. near._screenSpaceError=48;assert.deepEqual(run(),['near'],'SSE-qualified coarse does not request finer geometry')
  35. assert.ok(!ts._requestedTiles.includes(fine))
  36. near._screenSpaceError=200;far._screenSpaceError=48
  37. assert.deepEqual(run(),['far'],'distant view keeps cell coarse')
  38. far._screenSpaceError=200;near.contentAvailable=false;near.hasUnloadedRenderableContent=true
  39. assert.deepEqual(run(),['far'],'not-ready local coarse cannot remove distant fallback')
  40. near.contentAvailable=true;near.hasUnloadedRenderableContent=false
  41. const far2=tile(ts,'other-far'),fine2=tile(ts,'other-fine',{loaded:true,sse:0});root.add(far2.add(fine2))
  42. assert.deepEqual(new Set(run()),new Set(['near','other-fine']),'one cell refinement must not remove another coarse cell')
  43. assert.ok(!ts.hasMixedContent)
  44. console.log(JSON.stringify({passed:true,actualCesiumBaseTraversal:true,cases:7,browserUsed:false,renderingValidated:false,
  45. scope:'pending/ready/failure/SSE/distant/local-replacement; injected tile state only'}))
  46. }finally{Traversal.selectTile=saved}