|
Pokered Save Editor 2
Pokemon Red & Blue save file editor - Qt 6 C++/QML
|
A comprehensive automated test suite was created under projects/tests/ (QtTest + CTest). It covers the savefile engine (fields/verbs/Pokémon/items/world/toolset/errors/E2E), common, db integrity, and the randomizer (within its current scope). The app logic was extracted into a static appcore library (see ../../context/architecture.md) so the app layer is now unit-testable (tests/mvc/tst_models.cpp is the first model test). Build/run any time on the real kit: cmake --build <build> && ctest --output-on-failure (set SetErrorMode(0x0003) first so a crashing test fails fast instead of popping qtcdebugger). Full strategy and gaps: ../../plans/testing.md.
The model tests immediately found + drove fixes for real bugs (below, and continuing 2026-06-08).
savefiletoolset.cpp recalcChecksums() wrote data[0x5A4B] = getChecksum(0x4000, 0x1A4B); corrected to data[0x5A4C] = getChecksum(0x4000, 0x1A4C) (matches recalcBoxesChecksums(), the .bt oracle, and real RBY sBank2AllBoxesChecksum). The old code clobbered Box 6's last data byte (0x5A4B, 00→C5) on every save of a progressed file and stored the checksum one byte early. tst_roundtrip now round-trips BaseSAV.sav byte-perfect. The if(data[0x284C]==0) return guard (skip box checksums when the game never formatted the boxes) is intentional and faithful to the game — confirmed. See ../../reference/fix-patterns.md.
Destructor did pokemon->deleteLater() unconditionally; pokemon is null when the Day Care is empty → null-this deref. Now guarded if(pokemon != nullptr) (matching reset()). Masked in the app (SaveFile only destroyed at exit). Found by tst_roundtrip. See ../../reference/fix-patterns.md.
randomizeExpansion() now runs end-to-end and is test-covered (tst_randomizer 10-iteration invariants + tst_verbs byte-fidelity, both green) — authorised. Not-yet-built screens are excluded by commented-out calls (matching the disabled home tiles): Maps (area->randomize() + the two map picks in WorldGeneral::randomize), Hall of Fame (hof->randomize()), Options (the options/letterDelay block). Each carries a re-enable note. Bugs found+fixed along the way: MapSearch::isType() null-deref; HoFPokemon::load() null-deref (also crashed HoFRecord::pokemonNew/new HoFPokemon). Re-enable checklist tracked in ../../status.md → Open Issues (map randomize row).