53 lines
3.7 KiB
JavaScript
53 lines
3.7 KiB
JavaScript
'use strict';
|
|
const {vm,assert,app,functionSource}=require('./helpers/app-source');
|
|
|
|
assert(!app.includes('SPECIAL_CELL_DEBUG_ALL_LEVELS'),'Special-cell debug scheduling remains in production code');
|
|
assert(functionSource('addSpecialCellPattern').includes('AppLogic.specialSchedule(level,'),'Special cells do not use the production level directly');
|
|
|
|
const solvedState={paths:[],specialProgress:{crossings:[]},solved:true,expanded:true,solvedBy:'Player',scoreAwarded:500,store:null,rev:10};
|
|
const sanitizeContext={
|
|
puzzleOf:()=>({}),metaState:()=>solvedState,cellSet:()=>new Set(),crossingKeys:()=>[],warpMap:()=>new Map(),
|
|
normalizePath:value=>value,ckey:()=>'',sameCell:()=>false,pathCellsAdjacent:()=>false,nextRevision:()=>11,
|
|
markStateDirty:()=>{throw new Error('A durable clear was marked dirty by route revalidation')},
|
|
isSolved:()=>false,LEGACY_LOCAL_SOLVER:'Legacy'
|
|
};
|
|
vm.createContext(sanitizeContext);
|
|
vm.runInContext(`${functionSource('sanitizeStateForPuzzle')}\nthis.sanitizeStateForPuzzle=sanitizeStateForPuzzle;`,sanitizeContext);
|
|
sanitizeContext.sanitizeStateForPuzzle({id:'B0'},{quiet:true});
|
|
assert(solvedState.solved===true&&solvedState.scoreAwarded===500&&solvedState.solvedBy==='Player','Route revalidation downgraded a durable clear');
|
|
|
|
let center=[0,0];
|
|
const coverageContext={
|
|
overviewCache:{revision:4,width:800,height:600,scale:.2,anchorX:0,anchorY:0,unit:20,overscan:100},
|
|
minimapWorldRevision:4,cam:{scale:.2},MIN_CAMERA_SCALE:.1,getViewportRect:()=>({width:800,height:600}),
|
|
cameraCenterInChunks:()=>center
|
|
};
|
|
vm.createContext(coverageContext);
|
|
vm.runInContext(`${functionSource('overviewCacheNeedsInteractionRebuild')}\nthis.needsRefresh=overviewCacheNeedsInteractionRebuild;`,coverageContext);
|
|
assert(!coverageContext.needsRefresh(),'A centered overview cache was treated as exhausted');
|
|
center=[5,0];
|
|
assert(coverageContext.needsRefresh(),'A held pan beyond overview overscan did not request a cache refresh');
|
|
|
|
let frameCallback=null,idleCallback=null,drawOptions=null;
|
|
const scheduleContext={
|
|
overviewFrame:0,overviewDirty:true,overviewLastDraw:0,overviewDelayTimer:0,overviewAllowInteractionBuild:false,overviewInteractionLastBuild:0,
|
|
OVERVIEW_INTERACTION_REBUILD_INTERVAL:180,AUXILIARY_FRAME_INTERVAL:1000/30,overviewCanvas:{},
|
|
interactionActive:()=>true,inWorldOverview:()=>true,
|
|
requestAnimationFrame:callback=>{frameCallback=callback;return 1},
|
|
requestIdleCallback:callback=>{idleCallback=callback;return 2},
|
|
markVisualFrame:()=>{},drawWorldOverview:options=>{drawOptions=options},perfNow:()=>201
|
|
};
|
|
vm.createContext(scheduleContext);
|
|
vm.runInContext(`${functionSource('scheduleWorldOverview')}\nthis.scheduleWorldOverview=scheduleWorldOverview;`,scheduleContext);
|
|
scheduleContext.scheduleWorldOverview(false,{allowDuringInteraction:true});
|
|
assert(typeof frameCallback==='function','An in-gesture overview refresh was not frame-scheduled');
|
|
frameCallback(200);
|
|
assert(typeof idleCallback==='function','An in-gesture overview refresh was not deferred to idle time');
|
|
idleCallback();
|
|
assert(drawOptions?.allowDuringInteraction===true&&scheduleContext.overviewInteractionLastBuild===201,'The bounded overview refresh was blocked while panning');
|
|
|
|
const applyCamera=functionSource('applyCamera');
|
|
assert(applyCamera.includes('overviewCacheNeedsInteractionRebuild()')&&applyCamera.includes('allowDuringInteraction:cameraGestureActive'),'Camera painting does not replenish an exhausted overview cache during a held pan');
|
|
assert(app.includes('CAMERA_DISPLAY_WATCHDOG_MS=34')&&functionSource('scheduleCustomCursorFrame').includes('requestAnimationFrame(paint)')&&!app.includes('CURSOR_DISPLAY_WATCHDOG_MS'),'A cursor fallback timer can still preempt the next 60 Hz display frame');
|
|
|
|
console.log('v47.84 pan continuity, durable clear, and production gate checks passed');
|