import { describe, it, expect } from 'vitest'; import { parseSaveDex } from '../src/lib/savedex.js'; // --- Synthetic Gen 1 (R/B/Y) SRAM ------------------------------------- // 32 KB, with the owned/seen bitfields and the byte checksum the parser // verifies. Offsets mirror src/lib/savedex.js `G1`. const G1 = { owned: 0x25a3, seen: 0x25b6, species: 151, ckByte: 0x3523, ckFrom: 0x2598, ckTo: 0x3522, }; function setBits(bytes, start, ids) { for (const n of ids) bytes[start + ((n - 1) >> 3)] |= 1 << ((n - 1) & 7); } function makeGen1Save({ caught, seen }) { const bytes = new Uint8Array(0x8000); setBits(bytes, G1.owned, caught); setBits(bytes, G1.seen, seen); let sum = 0; for (let i = G1.ckFrom; i <= G1.ckTo; i++) sum = (sum + bytes[i]) >>> 0; bytes[G1.ckByte] = ~sum & 0xff; return bytes.buffer; } describe('parseSaveDex — Gen 1', () => { it('reads owned/seen and verifies the checksum', () => { const caught = [1, 25, 151]; const seen = [1, 4, 25, 151]; const dex = parseSaveDex(makeGen1Save({ caught, seen })); expect(dex.gen).toBe(1); expect(dex.game).toBe('Red / Blue / Yellow'); expect(dex.versionGroups).toEqual(['red-blue', 'yellow']); expect(dex.caught).toEqual(caught); expect(dex.seen).toEqual(seen); expect(dex.checksumOk).toBe(true); expect(dex.nationalUnlocked).toBe(true); }); it('still parses (checksumOk false) when the checksum byte is wrong', () => { const buf = makeGen1Save({ caught: [1], seen: [1, 2] }); new Uint8Array(buf)[G1.ckByte] ^= 0xff; const dex = parseSaveDex(buf); expect(dex.gen).toBe(1); expect(dex.caught).toEqual([1]); expect(dex.checksumOk).toBe(false); }); it('rejects a file that is too small', () => { expect(() => parseSaveDex(new Uint8Array(1024).buffer)).toThrow(/too small/i); }); it('rejects a large file with no recognisable Pokédex', () => { expect(() => parseSaveDex(new Uint8Array(0x20000).buffer)).toThrow(); }); });