Files
gen1recomp/tests/engine/game3_cache_paths_test.lua
T
Shane McGovern e2454bf568 fix(game3): review v3 fixes (battle, field, script, save) + gated T6 tier
Second wave of fixes from the Gen 3 codebase review (210 findings), the
regressions the full-suite sweep surfaced, and a T6 tier so the top-level
tests/game3_*.lua suites run inside ./scripts/test.sh instead of outside it.

Battle: Knock Off and Thief/Trick item persistence follow the ROM, not the
review - the party slot is never written through during battle, and the
knocked-off mask suppresses the item on later send-outs
(pokefirered/src/battle_script_commands.c:2731 MOVE_EFFECT_KNOCK_OFF with the
STICKY_HOLD guard at :2732, opponent-steal guard at :2610-2622, mask use at
:4489). Rapid Spin keeps its one-per-use chain order (:8435-8474); Growl
keeps pret's target (src/data/battle_moves.h, include/battle.h:63).

Scripting: operand layouts match pret/asm/macros/event.inc - givemon 15 bytes
(:989-997), comparestat {B,W} (:1573-1576), setptr/loadbytefromptr/setptrbyte
take a word pointer (:118-137). 18 of the 20 E10 ops are wired per
src/scrcmd.c (per-op citations in docs/game3/e10-opcode-spec.md), money and
random and the warp family read their operands as VarGets
(src/scrcmd.c:1798-1830, :455-461, :719-731), and the day-care party-full
guard is in place (src/daycare.c:525,:1081).

Field and UI: fishing counts rounds as the ROM does
(src/field_player_avatar.c:1740-1765), an unresolved map section no longer
reports Pallet Town (src/region_map.c:3782), and a font provider sits behind
a FireRed capability/profile seam.

Save data: profile-driven Options.block, a save version round-trip, and slot
id validation that blocks path traversal (slotDiskPath("firered", "../evil")
returns nil).

Importer: the parallel import path now writes both completion markers,
object kind/clone bytes decode as pret defines them
(include/global.fieldmap.h:110-130), and the HM table drops Whirlpool
(include/constants/items.h:411-418).

Tests: six new scenario suites (battle_ai, capture, event, menu, move,
overworld) and eight engine suites (profile, capabilities, cache paths, font
provider, options block, save version round-trip, version dispatch,
versions_game). T6 runs every top-level game3 suite at GAME3_JOBS default 8
with per-suite logs, failure cause classification and a KNOWN_GAME3_FAILURES
ceiling of 23 as a shrinking guard.

Docs: the working notes under docs/game3 (triage ledger, pret citation audit,
e10 opcode spec, RSE seams, sweep v3/v113, test baseline, artifact
conversions, merge trial).

Full gate at this snapshot: exit 0, all tiers passed - engine 624/624,
T6 279/279 (0 known, 0 fresh failures), gen2 146/146, modkit 37/37, luacheck
clean, privacy gate 3/3 over a 9,711-file publication set.
2026-09-22 12:22:50 +01:00

68 lines
2.8 KiB
Lua

-- T6.3a: the shared GBA cache-root module. New file, unwired; this suite
-- pins its contract and keeps it honest with extract_island1.lua until the
-- wiring handoff lands.
-- luajit tests/engine/game3_cache_paths_test.lua
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
local check, eq = T.check, T.eq
local CachePaths = require("src.core.game3.cache_paths")
-- ------------------------------------------------------------- defaults
eq(CachePaths.CACHE_ROOT, "data/generated/gba", "the packaged cache root")
eq(CachePaths.NATIVE_ROOT, "data/generated/gba/native", "native root is derived")
eq(CachePaths.NATIVE_ROOT, CachePaths.CACHE_ROOT .. "/native",
"NATIVE_ROOT is CACHE_ROOT/native")
-- ------------------------------------------------------------ setRoot
check(CachePaths.setRoot("data/generated/gba-rse") == true, "setRoot accepts a root")
eq(CachePaths.CACHE_ROOT, "data/generated/gba-rse", "setRoot writes CACHE_ROOT")
eq(CachePaths.NATIVE_ROOT, "data/generated/gba-rse/native", "setRoot derives NATIVE_ROOT")
check(CachePaths.setRoot("") == false, "setRoot rejects an empty root")
check(CachePaths.setRoot(nil) == false, "setRoot rejects nil")
eq(CachePaths.CACHE_ROOT, "data/generated/gba-rse", "a rejected setRoot changes nothing")
CachePaths.reset()
eq(CachePaths.CACHE_ROOT, "data/generated/gba", "reset restores the packaged root")
eq(CachePaths.NATIVE_ROOT, "data/generated/gba/native", "reset restores the native root")
-- ------------------------------------------- consistency with the extractor
-- Until the T6.3 wiring lands, extract_island1.lua pins the same literals.
-- Both states pass so the handoff can replace the pin with a CachePaths read
-- without editing this suite.
do
local f = io.open("src/import/gba/extract_island1.lua", "r")
check(f ~= nil, "extract_island1.lua is readable")
if f then
local src = f:read("*a")
f:close()
local pinned = src:find('Extract.CACHE_ROOT = "data/generated/gba"', 1, true) ~= nil
local wired = src:find("cache_paths", 1, true) ~= nil
check(pinned or wired,
"extract_island1 either pins the default or reads CachePaths (T6.3 handoff)")
end
end
-- The defaults must match what the extractor declares, so the handoff is a
-- move, not a behaviour change.
do
local f = io.open("src/import/gba/extract_island1.lua", "r")
if f then
local src = f:read("*a")
f:close()
if src:find('Extract.CACHE_ROOT = "data/generated/gba"', 1, true) then
eq(CachePaths.CACHE_ROOT, "data/generated/gba",
"CachePaths.CACHE_ROOT equals the extractor's pinned default")
eq(CachePaths.NATIVE_ROOT, "data/generated/gba/native",
"CachePaths.NATIVE_ROOT equals the extractor's pinned default")
end
end
end
T.finish("game3_cache_paths_test")