import { spawnSync } from 'node:child_process'; import * as e from './common.mjs'; function command(cmd, args, opts={ }){ const r=spawnSync(cmd, args, { encoding:'utf8', ...opts }); if(r.status!==0)e.fail(r.error?.message??`Command failed (${r.status}): ${cmd}`); return r.stdout; } export function main(){ const a=e.cli(['output'], { zig:'zig', optimize:'ReleaseSafe' }), repo=e.ROOT, output=e.path.resolve(a.output); e.fs.mkdirSync(output, { recursive:true }); const version=command(a.zig, ['version']).trim(); if(version!=='0.14.1')e.fail('Zig 0.14.1 required; found '+version); const zon=e.readText(e.path.join(repo, 'protocol/build.zig.zon')), pkg=zon.match(/\.hash\s*=\s*"(protobuf-[^"]+)"/)?.[1]; if(!pkg)e.fail('Missing protobuf package hash'); const cache=process.env.ZIG_GLOBAL_CACHE_DIR??e.path.join(e.os.homedir(), '.cache/zig'), protobuf=e.path.join(cache, 'p', pkg, 'src/protobuf.zig'); if(!e.fs.existsSync(protobuf))e.fail('Cached protobuf dependency not found: '+protobuf); const scratch=e.fs.mkdtempSync(e.path.join(output, 'gridfight-test-')); e.fs.cpSync(e.path.join(repo, 'gameserver/src'), e.path.join(scratch, 'source/src'), { recursive:true }); e.fs.cpSync(e.path.join(repo, 'protocol/src'), e.path.join(scratch, 'protocol'), { recursive:true }); const runtime=e.path.join(scratch, 'runtime'); e.fs.mkdirSync(runtime); e.fs.symlinkSync(e.path.join(repo, 'resources'), e.path.join(runtime, 'resources'), 'dir'); const entry=e.path.join(scratch, 'source/src/gridfight_test_root.zig'); e.fs.writeFileSync(entry, 'const std = @import("std");\ntest "GridFight imports" { std.testing.refAllDecls(@import("services/grid_fight.zig")); }\n'); const executable=e.path.join(scratch, 'gridfight-tests'), args=['test', `-O${a.optimize}`, '--dep', 'protocol', `-Mroot=${entry}`, '--dep', 'protobuf', `-Mprotocol=${e.path.join(scratch,'protocol/root.zig')}`, `-Mprotobuf=${protobuf}`, '--cache-dir', e.path.join(output, 'test-cache'), '--global-cache-dir', e.path.join(output, 'zig-cache'), `-femit-bin=${executable}`, '--test-no-exec']; function logged(cmd, args, log, opts){ const fd=e.fs.openSync(e.path.join(output, log), 'w'); try{ command(cmd, args, { ...opts, stdio:['ignore', fd, fd] }); } finally{ e.fs.closeSync(fd); } } logged(a.zig, args, 'test-build.log', { cwd:scratch }); logged(executable, [], 'tests.log', { cwd:runtime, env:{ ...process.env, GRIDFIGHT_TEST_RUNTIME:runtime } }); const text=e.readText(e.path.join(output, 'tests.log')), m=text.match(/All (\d+) tests passed\./); if(text.includes('SKIP')||!m)e.fail('Skipped or incomplete suite; inspect tests.log'); e.atomic_json(e.path.join(output, 'test-result.json'), { zig:version, tests_passed:Number(m[1]), runtime, gameplay_verified:false }, 2, true); process.stdout.write(text); } e.runMain(import.meta.url, main);