This commit is contained in:
saarsena@gmail.com 2026-04-16 21:04:50 -04:00
commit e45f121fb9
89 changed files with 336069 additions and 0 deletions

33
test/README Normal file
View file

@ -0,0 +1,33 @@
Tests for the brogue-genesis generator.
Running
-------
make test # goldens + 1000-seed invariant stress
make stress # 5000-seed invariant stress only
Files
-----
run_tests.sh Runs goldens against current binary, then stress.
update_goldens.sh Regenerates goldens.txt. Run this only after an
intentional change to generation logic.
goldens.txt seed|map_sha256|summary_line, one per committed seed.
What's checked
--------------
1. Map hash stability — sha256 of the ASCII map for each committed seed.
2. Summary line stability — room/loop/lake/bridge counts and connectivity.
3. Connectivity invariant — for a rolling sweep of seeds, every passable
cell must be 4-connected to every other. This is the load-bearing
property of Brogue's pipeline.
When to update the goldens
--------------------------
If you intentionally change generation (new room type, tweak CA rule, change
lake sizes, adjust corridor bounds, reorder phases, etc.), the goldens will
break by design. Inspect the diff, confirm it looks right, then:
make && test/update_goldens.sh
make test
If the stress pass ever reports non-zero failures, a connectivity-preserving
invariant has been broken — investigate before committing.

20
test/goldens.txt Normal file
View file

@ -0,0 +1,20 @@
# seed_depth|map_sha256|summary_line
# Generated 2026-04-13T16:05:27Z
1:1|7c7a6b6897f950ffe50cc4617a64ef6dc235c821e8bd0fd2e90be0a91773c0a5|seed=1 depth=1 rooms=31 loops=4 lakes_proposed=6 lakes_rejected=5 lakes_placed=1 bridges=1 machines=1/1 floor=642 connected=1 unreached=0
2:1|7f41699a774c4c23acde501d157f1f5d4561989637b6fd0419688668a162f6ea|seed=2 depth=1 rooms=26 loops=6 lakes_proposed=6 lakes_rejected=5 lakes_placed=1 bridges=2 machines=1/1 floor=534 connected=1 unreached=0
42:1|2d89ffde34b0aa2ce4ffe11dc4feac26b045aef160e8bfa52c85d398e0464ae7|seed=42 depth=1 rooms=27 loops=2 lakes_proposed=6 lakes_rejected=5 lakes_placed=1 bridges=1 machines=1/1 floor=663 connected=1 unreached=0
77:1|af72b9a505777abd87b6d2693b6ee2710f12708ca223b08b0a8a385e110b414a|seed=77 depth=1 rooms=30 loops=4 lakes_proposed=6 lakes_rejected=5 lakes_placed=1 bridges=0 machines=1/1 floor=574 connected=1 unreached=0
1234:1|c62f7b9a68ccaaae6f10621de685b3066d87b098eed9ef9fade351658ca638d9|seed=1234 depth=1 rooms=31 loops=3 lakes_proposed=6 lakes_rejected=4 lakes_placed=2 bridges=0 machines=1/1 floor=646 connected=1 unreached=0
2026:1|bd55089a42166b92daf0814b20aff9b6e0b17d49ed7d53d4f25085bd579e44ea|seed=2026 depth=1 rooms=31 loops=5 lakes_proposed=6 lakes_rejected=6 lakes_placed=0 bridges=0 machines=1/1 floor=664 connected=1 unreached=0
9999:1|e3042b10055bc0ed45667b6804ae05e7a7695a76018d555552c472d8a4d8e159|seed=9999 depth=1 rooms=30 loops=4 lakes_proposed=6 lakes_rejected=4 lakes_placed=2 bridges=1 machines=1/1 floor=652 connected=1 unreached=0
123456:1|cabc305545fbc230c3e4667681bf725d854da3e465f281067077dfc5ddfed435|seed=123456 depth=1 rooms=31 loops=6 lakes_proposed=6 lakes_rejected=5 lakes_placed=1 bridges=8 machines=1/1 floor=680 connected=1 unreached=0
31337:1|f747922a14158050cd871553393d0247becf5f64b4c21a303d36d55e328330c3|seed=31337 depth=1 rooms=29 loops=1 lakes_proposed=6 lakes_rejected=5 lakes_placed=1 bridges=2 machines=1/1 floor=523 connected=1 unreached=0
7:1|e6f748b2690e4ce9fc594f686ee5ddfdfa55c02ca21d428c2eb64c12e042fbdf|seed=7 depth=1 rooms=33 loops=7 lakes_proposed=6 lakes_rejected=6 lakes_placed=0 bridges=0 machines=1/1 floor=673 connected=1 unreached=0
100:1|5291c7836429b2291c2a2e19d31e8503c53b7e6b491bcc3af608eb5bcc99582e|seed=100 depth=1 rooms=28 loops=5 lakes_proposed=6 lakes_rejected=3 lakes_placed=3 bridges=5 machines=1/1 floor=575 connected=1 unreached=0
500:1|11b6eb403ca4d9f5d72d6603097793ad163e6dd33a4840099b1eca86b2c86adc|seed=500 depth=1 rooms=31 loops=5 lakes_proposed=6 lakes_rejected=5 lakes_placed=1 bridges=1 machines=1/1 floor=672 connected=1 unreached=0
2026:10|bd55089a42166b92daf0814b20aff9b6e0b17d49ed7d53d4f25085bd579e44ea|seed=2026 depth=10 rooms=31 loops=5 lakes_proposed=6 lakes_rejected=6 lakes_placed=0 bridges=0 machines=1/1 floor=664 connected=1 unreached=0
2026:15|bd55089a42166b92daf0814b20aff9b6e0b17d49ed7d53d4f25085bd579e44ea|seed=2026 depth=15 rooms=31 loops=5 lakes_proposed=6 lakes_rejected=6 lakes_placed=0 bridges=0 machines=1/1 floor=664 connected=1 unreached=0
2026:20|bd55089a42166b92daf0814b20aff9b6e0b17d49ed7d53d4f25085bd579e44ea|seed=2026 depth=20 rooms=31 loops=5 lakes_proposed=6 lakes_rejected=6 lakes_placed=0 bridges=0 machines=1/1 floor=664 connected=1 unreached=0
2026:25|bd55089a42166b92daf0814b20aff9b6e0b17d49ed7d53d4f25085bd579e44ea|seed=2026 depth=25 rooms=31 loops=5 lakes_proposed=6 lakes_rejected=6 lakes_placed=0 bridges=0 machines=1/1 floor=664 connected=1 unreached=0
1234:18|aa9083fa66adc1fbb8c59540364b12390c3a871091c676cadeaa63c4fd5392fd|seed=1234 depth=18 rooms=31 loops=3 lakes_proposed=6 lakes_rejected=4 lakes_placed=2 bridges=0 machines=1/1 floor=646 connected=1 unreached=0
9999:22|837916e2c833481487443d99cfeddc1c6b6adb01ef4c3f6d790e4cf08c8052d9|seed=9999 depth=22 rooms=30 loops=4 lakes_proposed=6 lakes_rejected=4 lakes_placed=2 bridges=1 machines=1/1 floor=652 connected=1 unreached=0

53
test/run_tests.sh Executable file
View file

@ -0,0 +1,53 @@
#!/usr/bin/env bash
# Golden-seed regression. For each seed in goldens.txt, regenerate the map and
# compare (sha256 of map + summary line). Non-zero exit on any mismatch.
set -u
cd "$(dirname "$0")/.."
BIN=./bin/genesis
GOLDENS=test/goldens.txt
if [[ ! -x "$BIN" ]]; then
echo "error: $BIN not built. Run 'make' first." >&2
exit 2
fi
if [[ ! -f "$GOLDENS" ]]; then
echo "error: $GOLDENS missing. Run test/update_goldens.sh to create." >&2
exit 2
fi
fail=0
total=0
while IFS='|' read -r key expected_hash expected_summary; do
[[ -z "${key:-}" || "${key:0:1}" == "#" ]] && continue
seed="${key%:*}"
depth="${key#*:}"
[[ "$depth" == "$seed" ]] && depth=1
total=$((total + 1))
actual_hash=$("$BIN" --seed "$seed" --depth "$depth" 2>/dev/null | sha256sum | awk '{print $1}')
actual_summary=$("$BIN" --seed "$seed" --depth "$depth" --quiet 2>&1 >/dev/null)
if [[ "$actual_hash" != "$expected_hash" ]]; then
echo "FAIL $key hash mismatch"
echo " expected: $expected_hash"
echo " actual: $actual_hash"
fail=$((fail + 1))
continue
fi
if [[ "$actual_summary" != "$expected_summary" ]]; then
echo "FAIL $key summary mismatch"
echo " expected: $expected_summary"
echo " actual: $actual_summary"
fail=$((fail + 1))
continue
fi
echo "PASS $key"
done < "$GOLDENS"
echo "----"
echo "$((total - fail))/$total passed"
# Invariant sweep: run a wider stress check to catch regressions the goldens
# might miss.
echo "---- stress (connectivity invariant, 1000 seeds) ----"
"$BIN" --stress 1000 2>&1 | tail -1
exit $fail

34
test/update_goldens.sh Executable file
View file

@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Regenerate test/goldens.txt from current binary output. Run only after
# intentional changes to generation logic.
set -eu
cd "$(dirname "$0")/.."
BIN=./bin/genesis
OUT=test/goldens.txt
if [[ ! -x "$BIN" ]]; then
echo "error: $BIN not built. Run 'make' first." >&2
exit 2
fi
# Pairs of seed:depth. Mix shallow (water) and deep (lava/chasm/brimstone) to
# cover the full liquid range.
PAIRS=(
"1:1" "2:1" "42:1" "77:1" "1234:1" "2026:1" "9999:1"
"123456:1" "31337:1" "7:1" "100:1" "500:1"
"2026:10" "2026:15" "2026:20" "2026:25"
"1234:18" "9999:22"
)
{
echo "# seed_depth|map_sha256|summary_line"
echo "# Generated $(date -u +%Y-%m-%dT%H:%M:%SZ)"
for pair in "${PAIRS[@]}"; do
seed="${pair%:*}"
depth="${pair#*:}"
hash=$("$BIN" --seed "$seed" --depth "$depth" 2>/dev/null | sha256sum | awk '{print $1}')
summary=$("$BIN" --seed "$seed" --depth "$depth" --quiet 2>&1 >/dev/null)
printf '%s:%s|%s|%s\n' "$seed" "$depth" "$hash" "$summary"
done
} > "$OUT"
echo "wrote $OUT ($(wc -l < "$OUT") lines)"