109 lines
3.8 KiB
JavaScript
109 lines
3.8 KiB
JavaScript
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');
|
|
});
|