#!/usr/bin/env bash # Host-side regression tests for the AGI port. # # Compiles tests/agi/testAgiRes.c + examples/agi/agiRes.c with the # host gcc and runs it against every game directory in # examples/agi/gamedata/. Each game is exercised in isolation; the # script aggregates pass/fail counts and exits non-zero if any test # fails. # # Why a host build instead of running the emulator binaries: the AGI # resource loader is plain stdio C with no platform dependencies, so # the parsing logic is identical on every JoeyLib target. Validating # it on the build host means each iteration takes a second instead # of the 15-30s of an emulator boot, and reproducible failures don't # depend on capturing video / log output through DOSBox or MAME. # # Usage: # scripts/test-agi.sh # test every subdir of gamedata/ # scripts/test-agi.sh kq3 agidemo # test only the named subdirs set -euo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) gamedata=$repo/examples/agi/gamedata build=$repo/build/tests testRes=$build/testAgiRes testPic=$build/testAgiPic testView=$build/testAgiView testVm=$build/testAgiVm testPipeline=$build/testAgiPipeline mkdir -p "$build" # Shared host compile flags. agiPic.c calls jlDrawPixel in the blit # step, which the host test never invokes; we stub it as an empty # function via the link-line shim below so the host build can resolve # the symbol without dragging in the JoeyLib runtime. # Pick a JoeyLib platform for the host build. None of the platform- # specific code paths are exercised by the host test (it only touches # the AGI parsers, never the JoeyLib HAL), but joey/platform.h #errors # unless exactly one is defined. DOS is the closest fit for a Linux # host (chunky, little-endian, x86 lineage). hostCflags=(-std=c99 -Wall -Wextra -Werror -O2 -DJOEYLIB_PLATFORM_DOS -I "$repo/include" -I "$repo/examples/agi" -I "$repo/src/core") stubSrc=$build/hostStubs.c cat > "$stubSrc" <<'EOF' #include "joey/draw.h" #include "joey/core.h" #include "surfaceInternal.h" #include void jlDrawPixel(jlSurfaceT *s, int16_t x, int16_t y, uint8_t c) { (void)s; (void)x; (void)y; (void)c; } void jlFillRect(jlSurfaceT *s, int16_t x, int16_t y, uint16_t w, uint16_t h, uint8_t c) { (void)s; (void)x; (void)y; (void)w; (void)h; (void)c; } uint32_t jlRandom(void) { return (uint32_t)rand(); } uint16_t jlRandomRange(uint16_t bound) { return (bound == 0u) ? 0u : (uint16_t)((unsigned)rand() % bound); } void jlRandomSeed(uint32_t seed) { srand((unsigned)seed); } void surfaceMarkDirtyRect(const jlSurfaceT *s, int16_t x, int16_t y, int16_t w, int16_t h) { (void)s; (void)x; (void)y; (void)w; (void)h; } void surfaceMarkDirtyAll(const jlSurfaceT *s) { (void)s; } EOF echo "Building host tests..." gcc "${hostCflags[@]}" \ "$repo/tests/agi/testAgiRes.c" \ "$repo/examples/agi/agiRes.c" \ -o "$testRes" gcc "${hostCflags[@]}" \ "$repo/tests/agi/testAgiPic.c" \ "$repo/examples/agi/agiRes.c" \ "$repo/examples/agi/agiPic.c" \ "$stubSrc" \ -o "$testPic" gcc "${hostCflags[@]}" \ "$repo/tests/agi/testAgiView.c" \ "$repo/examples/agi/agiRes.c" \ "$repo/examples/agi/agiPic.c" \ "$repo/examples/agi/agiView.c" \ "$stubSrc" \ -o "$testView" gcc "${hostCflags[@]}" \ "$repo/tests/agi/testAgiVm.c" \ "$repo/examples/agi/agiRes.c" \ "$repo/examples/agi/agiVm.c" \ "$repo/examples/agi/agiObj.c" \ "$stubSrc" \ -o "$testVm" gcc "${hostCflags[@]}" \ "$repo/tests/agi/testAgiPipeline.c" \ "$repo/examples/agi/agiRes.c" \ "$repo/examples/agi/agiVm.c" \ "$repo/examples/agi/agiObj.c" \ "$stubSrc" \ -o "$testPipeline" # Pick the game directories to exercise. With no args, every # subdirectory of examples/agi/gamedata that contains LOGDIR is a # candidate (skips stray README files etc). if [[ $# -gt 0 ]]; then games=("$@") else games=() if [[ -d $gamedata ]]; then for dir in "$gamedata"/*/; do [[ -d $dir ]] || continue name=$(basename "$dir") if [[ -f $dir/LOGDIR ]]; then games+=("$name") fi done fi fi if [[ ${#games[@]} -eq 0 ]]; then echo echo "No AGI game directories found under $gamedata" echo "Drop an AGI v2 game in examples/agi/gamedata// and rerun." echo "See examples/agi/gamedata/README.md for the required files." exit 0 fi passed=0 failed=0 echo for game in "${games[@]}"; do dir=$gamedata/$game echo "===== $game =====" if [[ ! -d $dir ]]; then echo " FAIL: $dir does not exist" failed=$((failed + 1)) continue fi gameOk=1 echo "--- resource loader ---" if ! "$testRes" "$dir"; then gameOk=0 fi echo "--- PIC decoder ---" if ! "$testPic" "$dir"; then gameOk=0 fi echo "--- VIEW decoder ---" if ! "$testView" "$dir"; then gameOk=0 fi echo "--- LOGIC VM (logic.0) ---" if ! "$testVm" "$dir"; then gameOk=0 fi echo "--- VM pipeline (callbacks + room transitions) ---" if ! "$testPipeline" "$dir"; then gameOk=0 fi if [[ $gameOk -eq 1 ]]; then passed=$((passed + 1)) else failed=$((failed + 1)) fi echo done total=$((passed + failed)) echo "===== summary: $passed/$total passed =====" if [[ $failed -gt 0 ]]; then exit 1 fi exit 0