import { test } from 'node:test'; import assert from 'node:assert/strict'; import { composeInventoryFrame } from './inventory.ts'; import type { Mask, Source } from '../capture/capture.types'; const makePhoto = (w: number, h: number, paint: (x: number, y: number) => [number, number, number, number] = () => [255, 255, 255, 255]) => { const rgba = new Uint8Array(w * h * 4); for (let y = 0; y < h; y++) { for (let x = 0; x < w; x++) { const [r, g, b, a] = paint(x, y); const i = (y * w + x) * 4; rgba[i] = r; rgba[i + 1] = g; rgba[i + 2] = b; rgba[i + 3] = a; } } return { width: w, height: h, rgba }; }; const maskFor = (bitset: Uint8Array, slabBounds: Mask['slabBounds']): Pick => ({ bitset, slabBounds }); test('alpha contract: removed pixels transparent, slab pixels keep RGB at alpha 255', () => { const W = 8, H = 8; const bitset = new Uint8Array(W * H); for (let y = 1; y < 5; y++) for (let x = 1; x < 5; x++) bitset[y * W + x] = 1; bitset[2 * W + 2] = 0; bitset[3 * W + 3] = 0; const SLAB = [200, 40, 20, 255] as const; const SHEET = [0, 255, 0, 255] as const; const src = makePhoto(W, H, (x, y) => (bitset[y * W + x] === 1 ? [...SLAB] : [...SHEET])); const source: Pick = { widthPx: W, heightPx: H }; const out = composeInventoryFrame(src, maskFor(bitset, { x: 1, y: 1, w: 4, h: 4 }), source); assert.equal(out.sourceBelowFloor, true); assert.ok(out.width < 800, 'undersized source stays small'); let opaque = 0; let transparent = 0; for (let i = 0; i < out.rgba.length; i += 4) { const a = out.rgba[i + 3]; if (a === 0) { transparent++; assert.equal(out.rgba[i], 0); assert.equal(out.rgba[i + 1], 0); assert.equal(out.rgba[i + 2], 0); continue; } opaque++; assert.equal(a, 255); assert.deepEqual( [out.rgba[i], out.rgba[i + 1], out.rgba[i + 2]], [SLAB[0], SLAB[1], SLAB[2]], 'opaque pixel must be slab RGB, never sheet green', ); } assert.ok(opaque > 0, 'slab pixels are opaque'); assert.ok(transparent > 0, 'frame has transparent pixels'); }); test('3:4 frame at the floor: 2000×1800 slab → 800×1067', () => { const source: Pick = { widthPx: 2000, heightPx: 1800 }; const bitset = new Uint8Array(source.widthPx * source.heightPx).fill(1); const out = composeInventoryFrame( makePhoto(source.widthPx, source.heightPx), maskFor(bitset, { x: 0, y: 0, w: 2000, h: 1800 }), source, ); assert.equal(out.width, 800); assert.equal(out.height, 1067); assert.equal(out.sourceBelowFloor, false); }); test('mid-band: slab shorter side 1000 (between 800 and 1600) → at floor, not belowFloor', () => { const source: Pick = { widthPx: 1200, heightPx: 1000 }; const bitset = new Uint8Array(source.widthPx * source.heightPx).fill(1); const out = composeInventoryFrame( makePhoto(source.widthPx, source.heightPx), maskFor(bitset, { x: 0, y: 0, w: 1200, h: 1000 }), source, ); assert.equal(out.sourceBelowFloor, false); assert.equal(out.width, 800); }); test('90% fill: limiting dimension maps to 0.9 × frame side (#68)', () => { const source: Pick = { widthPx: 2200, heightPx: 2000 }; const bitset = new Uint8Array(source.widthPx * source.heightPx).fill(1); const out = composeInventoryFrame( makePhoto(source.widthPx, source.heightPx), maskFor(bitset, { x: 100, y: 100, w: 2000, h: 1800 }), source, ); let minx = out.width, maxx = -1, miny = out.height, maxy = -1; for (let y = 0; y < out.height; y++) { for (let x = 0; x < out.width; x++) { if (out.rgba[(y * out.width + x) * 4 + 3] !== 0) { if (x < minx) minx = x; if (x > maxx) maxx = x; if (y < miny) miny = y; if (y > maxy) maxy = y; } } } const xs = [minx, maxx], ys = [miny, maxy]; const wExtent = Math.max(...xs) - Math.min(...xs) + 1; const hExtent = Math.max(...ys) - Math.min(...ys) + 1; assert.ok(Math.abs(wExtent - 720) <= 2, `width extent ${wExtent} ≈ 720 (0.9×800)`); assert.ok(Math.abs(hExtent - 648) <= 2, `height extent ${hExtent} ≈ 648 (1800×0.36)`); }); test('belowFloor: small slab → sourceBelowFloor, outW capped at floor (no upscale)', () => { const source: Pick = { widthPx: 900, heightPx: 700 }; const bitset = new Uint8Array(source.widthPx * source.heightPx).fill(1); const out = composeInventoryFrame( makePhoto(source.widthPx, source.heightPx), maskFor(bitset, { x: 0, y: 0, w: 900, h: 700 }), source, ); assert.equal(out.sourceBelowFloor, true); assert.ok(out.width <= 800, `outW ${out.width} must not exceed the floor`); });