Files
shanhe-puzzle/tests/county-packaging.test.cjs
codex-bot 4845826deb
Shanhe source and offline package checks / verify (pull_request) Failing after 5s
feat: sync Shanhe 2.2 source and add remote package verification
2026-11-01 17:13:46 +08:00

10 lines
4.6 KiB
JavaScript

const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs'),vm=require('node:vm'),os=require('node:os'),path=require('node:path'),{execFileSync,spawnSync}=require('node:child_process');
const packCountyMaps=require('../scripts/pack-county-maps.cjs'),createAtlas=require('../src/atlas.js'),box={window:{}};for(const file of ['maps.js','county-index.js'])vm.runInNewContext(fs.readFileSync('src/'+file,'utf8'),box);const {MAP_DATA:data,COUNTY_INDEX:index}=box.window,packed=packCountyMaps(index,id=>fs.readFileSync('src/county/'+id+'.js','utf8'));
function registerPackage(atlas,meta){vm.runInNewContext(packed.files.get(meta.path.slice(2)),{window:{PuzzleAtlas:{register:level=>atlas.register(level)}}});}
test('全部329县区合成173个同省双关文件,186个发行文件满足200上限且不改源目录',()=>{assert.equal(packed.files.size,173);assert.ok(packed.files.size+13<=200);const seen=new Set();for(const [file,source] of packed.files){const metas=Array.from(packed.index.levels).filter(m=>m.path==='./'+file);assert.ok(metas.length>=1&&metas.length<=2);assert.equal(new Set(metas.map(m=>m.province)).size,1);assert.equal(source,metas.map(m=>fs.readFileSync('src/county/'+m.id+'.js','utf8')).join('\n'));vm.runInNewContext(source,{window:{PuzzleAtlas:{register:l=>{assert.ok(!seen.has(l.id));seen.add(l.id);}}}});}assert.equal(seen.size,329);assert.equal(index.levels[1].path,'./county/'+index.levels[1].id+'.js');});
test('同包两关并发只加载一次脚本,均返回各自关卡并保留3关LRU',async()=>{let atlas,reads=0;atlas=createAtlas(data,packed.index,(meta,done)=>{reads++;registerPackage(atlas,meta);done(null);});const [a,b]=packed.index.levels;assert.equal(a.path,b.path);const [one,two]=await Promise.all([atlas.load(a.id),atlas.load(b.id)]);assert.equal(reads,1);assert.equal(one.id,a.id);assert.equal(two.id,b.id);for(const meta of packed.index.levels.slice(2,12)){assert.equal((await atlas.load(meta.id)).id,meta.id);assert.ok(atlas.cacheSize()<=3);}const count=reads;assert.equal((await atlas.load(a.id)).id,a.id);assert.equal(reads,count+1);});
test('多个双关包并发且发生缓存淘汰时,每个请求都能拿到自己图形',async()=>{let atlas,reads=0;atlas=createAtlas(data,packed.index,(meta,done)=>{reads++;registerPackage(atlas,meta);Promise.resolve().then(()=>done(null));});const metas=Array.from(packed.index.levels.slice(0,12)),levels=await Promise.all(metas.map(m=>atlas.load(m.id)));assert.deepEqual(levels.map(l=>l.id),metas.map(m=>m.id));assert.equal(reads,new Set(metas.map(m=>m.path)).size);assert.ok(atlas.cacheSize()<=3);});
test('同包加载失败同时拒绝两个请求,后续可以共同重试',async()=>{let atlas,reads=0;atlas=createAtlas(data,packed.index,(meta,done)=>{reads++;if(reads===1){done(Error('fixture missing package'));return;}registerPackage(atlas,meta);done(null);});const [a,b]=packed.index.levels,failed=await Promise.allSettled([atlas.load(a.id),atlas.load(b.id)]);assert.ok(failed.every(r=>r.status==='rejected'));assert.equal(reads,1);const levels=await Promise.all([atlas.load(a.id),atlas.load(b.id)]);assert.deepEqual(levels.map(l=>l.id),[a.id,b.id]);assert.equal(reads,2);});
function fixture(count){const dir=fs.mkdtempSync(path.join(os.tmpdir(),'shanhe-budget-'));fs.mkdirSync(path.join(dir,'dist'));fs.mkdirSync(path.join(dir,'artifacts'));fs.writeFileSync(path.join(dir,'dist/index.html'),'<!doctype html><html lang="zh-CN"></html>');for(let i=1;i<count;i++)fs.writeFileSync(path.join(dir,'dist',i+'.js'),'void 0;');return dir;}
test('打包器接受200文件,拒绝201文件且不产生超限ZIP;预检也拦截201',()=>{const script=path.resolve('scripts/package.py'),check=path.resolve('scripts/check.mjs');for(const count of [200,201]){const dir=fixture(count);try{const result=spawnSync('python3',[script],{cwd:dir,encoding:'utf8'});if(count===200){assert.equal(result.status,0,result.stderr);const report=JSON.parse(fs.readFileSync(path.join(dir,'artifacts/package-report.json'),'utf8'));assert.equal(report.fileCount,200);assert.equal(report.fileLimit,200);execFileSync('python3',['-c','import zipfile; z=zipfile.ZipFile("artifacts/shanhe-puzzle-xhs.zip"); assert len(z.infolist()) == 200; assert z.testzip() is None'],{cwd:dir});}else{assert.notEqual(result.status,0);assert.match(result.stderr,/200/);assert.ok(!fs.existsSync(path.join(dir,'artifacts/shanhe-puzzle-xhs.zip')));const gate=spawnSync(process.execPath,[check],{cwd:dir,encoding:'utf8'});assert.notEqual(gate.status,0);const report=JSON.parse(fs.readFileSync(path.join(dir,'artifacts/check-report.json'),'utf8'));assert.ok(report.issues.some(message=>message.includes('200')));}}finally{fs.rmSync(dir,{recursive:true,force:true});}}});