import test from 'node:test'; import assert from 'node:assert/strict'; import topHud from '../src/assets/controller/top-hud.js'; import leftStatus from '../src/assets/controller/left-status.js'; import rightControls from '../src/assets/controller/right-controls.js'; import cannonRoundel from '../src/assets/controller/cannon-roundel.js'; import helmFrame from '../src/assets/controller/helm-frame.js'; import helmKnob from '../src/assets/controller/helm-knob.js'; import playerHealth from '../src/assets/controller/player-health.js'; import enemyHealth from '../src/assets/controller/enemy-health.js'; const assets = { topHud, leftStatus, rightControls, cannonRoundel, helmFrame, helmKnob, playerHealth, enemyHealth, }; const decodeWebP = (name, dataUrl) => { const match = /^data:image\/webp;base64,([A-Za-z0-9+/=]+)$/.exec(dataUrl); assert.ok(match, `${name} must be a WebP data URL`); const bytes = Buffer.from(match[1], 'base64'); assert.equal(bytes.subarray(0, 4).toString('ascii'), 'RIFF', `${name} RIFF header`); assert.equal(bytes.subarray(8, 12).toString('ascii'), 'WEBP', `${name} WEBP signature`); const declaredSize = bytes.readUInt32LE(4) + 8; assert.equal( bytes.length, declaredSize, `${name} must not be truncated: declared ${declaredSize}, actual ${bytes.length}`, ); assert.ok(bytes.length > 100, `${name} should contain real image data`); }; for (const [name, dataUrl] of Object.entries(assets)) { test(`${name} WebP payload is structurally complete`, () => { decodeWebP(name, dataUrl); }); } const alphaAssets = { topHud, playerHealth, enemyHealth, }; for (const [name, dataUrl] of Object.entries(alphaAssets)) { test(`${name} carries WebP transparency data`, () => { const match = /^data:image\/webp;base64,([A-Za-z0-9+/=]+)$/.exec(dataUrl); assert.ok(match, `${name} must be a WebP data URL`); const bytes = Buffer.from(match[1], 'base64'); const hasAlphaChunk = bytes.includes(Buffer.from('ALPH')); const usesLosslessWebP = bytes.includes(Buffer.from('VP8L')); assert.ok(hasAlphaChunk || usesLosslessWebP, `${name} should preserve transparent background data`); }); } const webpDimensions = (name, dataUrl) => { const match = /^data:image\/webp;base64,([A-Za-z0-9+/=]+)$/.exec(dataUrl); assert.ok(match, `${name} must be a WebP data URL`); const bytes = Buffer.from(match[1], 'base64'); let offset = 12; while (offset + 18 <= bytes.length) { const type = bytes.subarray(offset, offset + 4).toString('ascii'); const size = bytes.readUInt32LE(offset + 4); const dataOffset = offset + 8; if (type === 'VP8X') { const width = 1 + bytes[dataOffset + 4] + (bytes[dataOffset + 5] << 8) + (bytes[dataOffset + 6] << 16); const height = 1 + bytes[dataOffset + 7] + (bytes[dataOffset + 8] << 8) + (bytes[dataOffset + 9] << 16); return { width, height }; } offset = dataOffset + size + (size % 2); } assert.fail(`${name} must expose VP8X dimensions`); }; test('playerHealth native frame preserves usable HUD resolution', () => { const { width, height } = webpDimensions('playerHealth', playerHealth); assert.ok(width >= 300, `playerHealth width must stay >= 300px, got ${width}px`); assert.ok(height >= 96, `playerHealth height must stay >= 96px, got ${height}px`); }); test('enemyHealth health sheet stays high resolution', () => { const { width, height } = webpDimensions('enemyHealth', enemyHealth); assert.ok(width >= 1200, `enemyHealth width must stay >= 1200px, got ${width}px`); assert.ok(height >= 300, `enemyHealth height must stay >= 300px, got ${height}px`); assert.ok(width / 4 >= 300, 'enemyHealth frame width must stay >= 300px'); assert.ok(height / 3 >= 100, 'enemyHealth frame height must stay >= 100px'); });