import zlib from "node:zlib"; function crc32(buffer) { let table = []; for (let n = 0; n < 256; n += 1) { let c = n; for (let k = 0; k < 8; k += 1) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; table[n] = c >>> 0; } let crc = 0xffffffff; for (const byte of buffer) crc = table[(crc ^ byte) & 0xff] ^ (crc >>> 8); return (crc ^ 0xffffffff) >>> 0; } function chunk(type, data) { const length = Buffer.alloc(4); length.writeUInt32BE(data.length); const typed = Buffer.concat([Buffer.from(type, "ascii"), data]); const crc = Buffer.alloc(4); crc.writeUInt32BE(crc32(typed)); return Buffer.concat([length, typed, crc]); } // Mostly flat images so the fixtures compress small; the tests identify slides // by asset ID rather than by pixels. export function makePng(width, height, [r, g, b]) { const header = Buffer.alloc(13); header.writeUInt32BE(width, 0); header.writeUInt32BE(height, 4); header[8] = 8; header[9] = 2; const raw = Buffer.alloc(height * (1 + width * 3)); for (let y = 0; y < height; y += 1) { const offset = y * (1 + width * 3); raw[offset] = 0; for (let x = 0; x < width; x += 1) { const p = offset + 1 + x * 3; raw[p] = r; raw[p + 1] = g; raw[p + 2] = x < 64 && y < 64 ? 255 : b; } } return Buffer.concat([ Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]), chunk("IHDR", header), chunk("IDAT", zlib.deflateSync(raw, { level: 9 })), chunk("IEND", Buffer.alloc(0)), ]); } export const FIXTURES = [ { name: "wide-a", width: 1920, height: 1080, rgb: [200, 30, 30] }, { name: "wide-b", width: 1920, height: 1080, rgb: [30, 200, 30] }, { name: "wide-c", width: 1280, height: 720, rgb: [30, 30, 200] }, { name: "wide-d", width: 1920, height: 1080, rgb: [200, 200, 30] }, { name: "portrait", width: 1080, height: 1920, rgb: [180, 60, 200] }, { name: "square", width: 1200, height: 1200, rgb: [60, 180, 200] }, { name: "standalone", width: 1920, height: 1080, rgb: [240, 140, 20] }, ]; const API = process.env.DISPLAY_BASE_URL || "http://127.0.0.1:5199"; // Uploads are content-addressed, so re-running the suite reuses the same assets // instead of piling up duplicates. export async function ensureFixtures(request) { const existing = await (await request.fetch(`${API}/api/assets`)).json(); const byName = new Map(existing.assets.map((asset) => [asset.displayName, asset])); for (const fixture of FIXTURES) { if (byName.has(fixture.name)) continue; const response = await request.fetch(`${API}/api/assets`, { method: "POST", multipart: { files: { name: `${fixture.name}.png`, mimeType: "image/png", buffer: makePng(fixture.width, fixture.height, fixture.rgb), }, }, }); if (!response.ok()) { throw new Error(`fixture upload failed: ${response.status()} ${await response.text()}`); } } const refreshed = await (await request.fetch(`${API}/api/assets`)).json(); return Object.fromEntries(refreshed.assets.map((asset) => [asset.displayName, asset])); }