mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
6be2de2844
- Save Editor: Implement full Gen 3 FireRed save editing including PID/personality, IVs/EVs, natures, ability slots, gender, shiny toggles, held items, Pokédex flags, and event/trainer toggles. - Scripting & Specials: Add Pokédex rating evaluations, Magikarp/Heracross size records, Trainer Fan Club tracking, and FireRed event flag mappings. - Overworld & Rendering: Interleave metatile and actor draw calls by row bucket with OAM elevation priority sorting for bridges and overhead layers. - ROM Extractor: Parallelize Gen 3 extraction across 4 concurrent love.thread workers with love.filesystem searchers for cross-platform support (Switch/Xbox/Mobile/Desktop). - LZ77 Decompressor: Accelerate GBA LZ77 with preallocated FFI buffers and 0-based displacement indexing ensuring 100% byte-for-byte asset parity. - Testing: Add unit test suites for LZ77, size records, Pokédex rating, Fan Club, elevation priority, Seafoam puzzles, and Gen 3 save editor operations.
58 lines
2.0 KiB
Lua
58 lines
2.0 KiB
Lua
-- Unit test for GBA LZ77 decompression
|
|
local Lz77 = require("src.import.gba.lz77")
|
|
|
|
local function test_lz77_basic()
|
|
local payload = "HELLO WORLD, THIS IS A TEST OF GBA LZ77 COMPRESSION AND DECOMPRESSION!"
|
|
local compressed = Lz77.compressStore(payload)
|
|
assert(compressed[1] == 0x10, "header type 0x10")
|
|
|
|
local decomp, consumed = Lz77.decompressFromBytes(compressed, 0)
|
|
assert(#decomp == #payload, ("decomp length %d != payload %d"):format(#decomp, #payload))
|
|
local decompStr = Lz77.toString(decomp)
|
|
assert(decompStr == payload, "decompressed string must match original payload")
|
|
print("✓ test_lz77_basic passed")
|
|
end
|
|
|
|
local function test_lz77_matches()
|
|
-- Create a payload with repeated patterns to test LZ77 sliding window references
|
|
local raw = "ABCDEFGHABCDEFGH" -- 16 bytes: 8 literals, then 1 match of length 8 at disp 8
|
|
local bytes = {
|
|
0x10, 16, 0, 0,
|
|
0x00, -- flags: 8 literals
|
|
string.byte("A"), string.byte("B"), string.byte("C"), string.byte("D"),
|
|
string.byte("E"), string.byte("F"), string.byte("G"), string.byte("H"),
|
|
0x80, -- flags: bit 7 is match
|
|
0x50, 0x07, -- length=8 (0x5+3), disp=7 (goes back 7+1=8 bytes)
|
|
}
|
|
|
|
local decomp, consumed = Lz77.decompressFromBytes(bytes, 0)
|
|
local decompStr = Lz77.toString(decomp)
|
|
assert(decompStr == raw, ("expected '%s', got '%s'"):format(raw, decompStr))
|
|
print("✓ test_lz77_matches passed")
|
|
end
|
|
|
|
local function test_lz77_bounds_safety()
|
|
-- Corrupted match with negative / out-of-bounds displacement
|
|
local bytes = {
|
|
0x10, 4, 0, 0,
|
|
0x80, -- match on first byte! read_pos = 0 - 100 < 0
|
|
0x10, 0x64, -- length=4, disp=100
|
|
}
|
|
-- Should NOT crash or segfault; safely writes 0s
|
|
local decomp, consumed = Lz77.decompressFromBytes(bytes, 0)
|
|
assert(#decomp == 4, "should decompress 4 bytes")
|
|
for i = 1, 4 do
|
|
assert(decomp[i] == 0, "OOB read should produce 0")
|
|
end
|
|
print("✓ test_lz77_bounds_safety passed")
|
|
end
|
|
|
|
local function run_all()
|
|
test_lz77_basic()
|
|
test_lz77_matches()
|
|
test_lz77_bounds_safety()
|
|
print("All LZ77 unit tests passed!")
|
|
end
|
|
|
|
run_all()
|