Files
sporel-tool-mapper/tests/gid.test.js
Axel Meyer 2949a96e11 Add GID encode/decode with range validation
Bit layout [atlas:8][tile_id:20][rot:2][res:2] matches
lib-core.maps init.lua so JS-produced GIDs are byte-identical to
engine-produced ones. >>> 0 forces unsigned u32 output.
2026-05-23 13:40:25 +02:00

84 lines
2.8 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const { encodeGid, decodeGid } = require('../src/gid');
test('encodeGid: known reference value (0,12,1) = 196', () => {
assert.equal(encodeGid(0, 12, 1), 196);
});
test('encodeGid: default rotation is 0', () => {
assert.equal(encodeGid(0, 12), 192);
});
test('encodeGid: zero tuple yields 0', () => {
assert.equal(encodeGid(0, 0, 0), 0);
});
test('encodeGid: high atlas (255) produces unsigned u32', () => {
// 255 << 24 = 0xFF000000 = 4278190080 (must NOT be negative)
assert.equal(encodeGid(255, 0, 0), 4278190080);
});
test('encodeGid: max tile_id (1048575) fits 20 bits', () => {
// tile << 4 = 0xFFFFF0 = 16777200
assert.equal(encodeGid(0, 1048575, 0), 16777200);
});
test('encodeGid: throws on out-of-range atlas', () => {
assert.throws(() => encodeGid(256, 0, 0), /atlas/);
assert.throws(() => encodeGid(-1, 0, 0), /atlas/);
});
test('encodeGid: throws on out-of-range tile', () => {
assert.throws(() => encodeGid(0, 1048576, 0), /tile/);
assert.throws(() => encodeGid(0, -1, 0), /tile/);
});
test('encodeGid: throws on out-of-range rotation', () => {
assert.throws(() => encodeGid(0, 0, 4), /rotation/);
assert.throws(() => encodeGid(0, 0, -1), /rotation/);
});
test('encodeGid: throws on non-integer inputs', () => {
assert.throws(() => encodeGid(1.5, 0, 0), /atlas/);
assert.throws(() => encodeGid(0, '12', 0), /tile/);
});
test('decodeGid: empty (0) returns zeros', () => {
assert.deepEqual(decodeGid(0), { atlas: 0, tile: 0, rotation: 0 });
});
test('decodeGid: 196 unpacks to (0,12,1)', () => {
assert.deepEqual(decodeGid(196), { atlas: 0, tile: 12, rotation: 1 });
});
test('decodeGid: 16777232 from real demo map unpacks to (1,1,0)', () => {
// demo_v2.map.json wall layer uses 16777232 = (1<<24)|(1<<4)
assert.deepEqual(decodeGid(16777232), { atlas: 1, tile: 1, rotation: 0 });
});
test('decodeGid: high atlas (255,0,0) round-trip', () => {
assert.deepEqual(decodeGid(4278190080), { atlas: 255, tile: 0, rotation: 0 });
});
test('decodeGid: throws on non-integer or negative', () => {
assert.throws(() => decodeGid(-1), /gid/);
assert.throws(() => decodeGid(1.5), /gid/);
assert.throws(() => decodeGid(0x100000000), /gid/); // > u32 max
});
test('round-trip: 100 random tuples encode→decode losslessly', () => {
for (let i = 0; i < 100; i++) {
const atlas = Math.floor(Math.random() * 256);
const tile = Math.floor(Math.random() * 1048576);
const rotation = Math.floor(Math.random() * 4);
const gid = encodeGid(atlas, tile, rotation);
const decoded = decodeGid(gid);
assert.equal(decoded.atlas, atlas, `atlas mismatch for ${gid}`);
assert.equal(decoded.tile, tile, `tile mismatch for ${gid}`);
assert.equal(decoded.rotation, rotation, `rotation mismatch for ${gid}`);
}
});