Files

41 lines
3.3 KiB
JavaScript

// Exercise the real GSC identity adapter under a small VM shim; native policy tests are separate.
import assert from 'node:assert/strict';
import {readFileSync} from 'node:fs';
import vm from 'node:vm';
for (const game of ['t5','t6']) {
const source=readFileSync(new URL(`../${game}/scripts/tws_${game}_moderation.gsc`,import.meta.url),'utf8');
assert.equal((source.match(/level waittill\("connected"/g)??[]).length,0,'must use the shared connection dispatcher');
assert(source.includes('register_connect_handler(::moderation_connected)'));
assert(!source.includes('executeCommand'),'all effects belong to the native synchronous adapter');
const start=source.indexOf('moderation_observe(player)\n{');
const end=source.indexOf('\nmoderation_loop()',start);
let body=source.slice(start,end).replace('moderation_observe(player)','function observe(player)');
body=body.replace(' guid =',' var guid =').replace(' name =',' var name =');
body=body.replace('player getGuid()','getGuid(player)').replaceAll('typeof(', 'kind(').replace('player moderationObserve(guid, name)', 'record(player,guid,name)');
const calls=[];
const c=vm.createContext({isDefined:v=>v!==null&&v!==undefined,kind:v=>typeof v==='number'?(Number.isInteger(v)?'int':'float'):typeof v,
getGuid:p=>p.identity,record:(...args)=>calls.push(args)});
vm.runInContext(body,c);
const player=identity=>({identity,guid:identity,name:'same name'});
c.observe(player('18446744073709551615')); assert.equal(calls.at(-1)[1],'18446744073709551615');
c.observe(player(2741626)); assert.equal(calls.at(-1)[1],'2741626');
c.observe(player('0000123')); assert.equal(calls.at(-1)[1],'0000123');
const count=calls.length; for(const value of [undefined,null,1.5,{},[]])c.observe(player(value)); assert.equal(calls.length,count);
c.observe(undefined); assert.equal(calls.length,count);
c.observe({...player('abc'),name:undefined}); assert.equal(calls.at(-1)[2],'Unknown player');
let loop=source.slice(source.indexOf('moderation_loop()\n{'))
.replace('moderation_loop()', 'function* loop()').replaceAll(/wait ([0-9.]+);/g, 'yield $1;')
.replace('players = getPlayers();', 'var players = getPlayers();').replace('for (i = 0;', 'for (var i = 0;').replace('players.size', 'players.length');
let enabled=true, configured=false, stopped=0, pumped=0, observed=0;
const level={moderation_ready:false};
const runtime=vm.createContext({level,GetDvar:key=>key==='tws_moderation_enabled'?(enabled?'1':'0'):'configured',GetDvarInt:()=>1,
moderationConfigure:()=>configured,moderationStop:()=>++stopped,moderationPump:()=>++pumped,getPlayers:()=>[{guid:'123'}],moderation_observe:()=>++observed});
vm.runInContext(loop,runtime); const poll=runtime.loop();
assert.equal(poll.next().value,3); assert.equal(level.moderation_ready,false);
configured=true; assert.equal(poll.next().value,0.5); assert.equal(level.moderation_ready,true);
assert.equal(pumped,1); assert.equal(observed,1);
enabled=false; assert.equal(poll.next().value,3); assert.equal(level.moderation_ready,false); assert.equal(stopped,1);
enabled=true; assert.equal(poll.next().value,0.5); assert.equal(pumped,2);
console.log(`PASS ${game}: actual moderation identity, retry/disable/resume loop and shared dispatcher integration`);
}