bend_puzzle/test/architecture-boundaries-test.js
33333-33333 9d70afb4cc
Some checks failed
BEND FIELD CI / release (push) Has been cancelled
BEND FIELD CI / production-bridge (push) Has been cancelled
t
2026-08-01 22:31:04 +09:00

51 lines
4 KiB
JavaScript

'use strict';
const {assert,read,functionSource}=require('./helpers/app-source');
const {createHttpRouter}=require('../server/http-router');
const {createAuthenticator}=require('../server/auth');
const {createJsonRepository}=require('../server/json-repository');
const {createCursorModel}=require('../client/ui/cursor');
(async()=>{
const calls=[],router=createHttpRouter({notFound:()=>calls.push('missing')});
router.add('GET','/ok',(_req,_res,url)=>calls.push(url.pathname));
await router.dispatch({method:'GET'},null,{pathname:'/ok'});
await router.dispatch({method:'POST'},null,{pathname:'/ok'});
assert(calls.join(',')==='/ok,missing'&&router.routes().length===1,'HTTP route dispatch does not isolate method/path selection');
const auth=createAuthenticator({
playerPattern:/^[a-f0-9]{16,64}$/i,
tokenPattern:/^[a-f0-9]{32,128}$/i,
readPlayer:async()=>({tokenHash:'aa'}),
hashToken:()=> 'aa',
safeEqual:(a,b)=>a===b
});
const request={headers:{authorization:`Bearer ${'a'.repeat(16)}.${'b'.repeat(32)}`}};
assert((await auth.player(request)).playerId==='a'.repeat(16),'Authentication middleware rejected a valid injected repository result');
let unauthorized=false;try{auth.parse({headers:{}})}catch(error){unauthorized=error.status===401}
assert(unauthorized,'Authentication middleware did not reject a missing bearer token');
let renameAttempts=0;const files=new Map(),fsp={
async readFile(file){const value=files.get(file);if(value==null)throw Object.assign(new Error('missing'),{code:'ENOENT'});return value},
async writeFile(file,value){files.set(file,value)},
async rename(from,to){if(++renameAttempts<3)throw Object.assign(new Error('busy'),{code:'EPERM'});files.set(to,files.get(from));files.delete(from)},
async unlink(file){if(!files.delete(file))throw Object.assign(new Error('missing'),{code:'ENOENT'})}
};
const repository=createJsonRepository({fsp,crypto:{randomBytes:()=>Buffer.from('abcdef','hex')},processId:1});
await repository.write('world.json',{revision:3});
assert((await repository.read('world.json')).revision===3&&renameAttempts===3,'JSON repository did not retry and publish a transiently blocked atomic record');
await repository.remove('world.json');assert(await repository.read('world.json',{missing:null})===null,'JSON repository missing-value behavior is incorrect');
const cursor=createCursorModel([{cursorStyle:'smile',cursorEmoji:'🙂'},{cursorStyle:'flag',flagAsset:'flag.svg'}]);
assert(cursor.presentation('smile').mode==='dom'&&cursor.presentation('smile').pickup.kind==='glyph','Cursor model did not map glyph presentation');
assert(cursor.presentation('flag').pickup.asset==='flag.svg'&&cursor.presentation('missing').mode==='default','Cursor model did not map flag or default presentation');
const server=read('server.js'),style=read('style.css'),html=read('index.html');
assert(functionSource('handleApi',server).includes('apiRouter.dispatch')&&functionSource('handleApi',server).length<120,'Server route selection is still coupled to domain behavior');
assert(server.includes("require('./server/player-service')")&&server.includes("require('./server/json-repository')"),'Server services or repositories are not wired through explicit boundaries');
assert(style.startsWith('@import url("client/styles/tokens.css") layer(tokens);')&&style.includes('@import url("client/styles/base.css") layer(base);')&&style.includes('@import url("client/ui/cursor.css") layer(cursor);')&&style.includes('@layer tokens,base,layout,board,interactions,hud,dialogs,cursor,responsive,accessibility,legacy;'),'CSS cascade ownership is not explicit');
assert(!style.includes('.board-card.claimed-other:not(.solved) .board-card.claimed-other'),'Unmatchable nested claimed-board selector remains');
assert(html.indexOf('client/ui/cursor.js')<html.indexOf('app.js'),'Cursor model is not loaded before the application');
console.log('HTTP, authentication, repository, cursor, and CSS ownership boundaries passed');
})().catch(error=>{console.error(error);process.exitCode=1});