import assert from "node:assert/strict"; import { createHash } from "node:crypto"; import test from "node:test"; import sharp from "sharp"; import { verifySourcePixelCrop } from "./source-pixel-crop-proof.mjs"; const digest = bytes => createHash("sha256").update(bytes).digest("hex"); async function fixture() { const pixels = Buffer.from([10, 20, 30, 0, 40, 50, 60, 255, 70, 80, 90, 128, 100, 110, 120, 255]); const source = await sharp(pixels, { raw: { width: 2, height: 2, channels: 4 } }).png().toBuffer(); const rect = { left: 0, top: 0, width: 1, height: 2 }; const crop = await sharp(source).extract(rect).png().toBuffer(); const cropPixels = await sharp(crop).ensureAlpha().raw().toBuffer(); const metadata = { version: 1, policyId: "fixture-island", sourceImageName: "native-atlas", sourceWidth: 2, sourceHeight: 2, sourcePreparedPngSha256: digest(source), rect, croppedPngSha256: digest(crop), croppedRgbaSha256: digest(cropPixels) }; return { source, crop, metadata, shipped: { width: 1, height: 2 } }; } test("exact source crop retains native RGBA and distinguishes island dimensions from downsampling", async () => { const f = await fixture(); assert.equal((await verifySourcePixelCrop(f.metadata, f.source, f.crop, f.shipped)).canonicalPixelsByteIdentical, true); }); test("crop proof rejects changed pixels, out-of-bounds metadata, and shipping downsampling", async () => { const f = await fixture(); const changed = await sharp(f.crop).removeAlpha().png().toBuffer(); await assert.rejects(verifySourcePixelCrop({ ...f.metadata, croppedPngSha256: digest(changed) }, f.source, changed, f.shipped), /RGBA pixels/u); await assert.rejects(verifySourcePixelCrop({ ...f.metadata, rect: { ...f.metadata.rect, left: 2 } }, f.source, f.crop, f.shipped), /exceeds/u); await assert.rejects(verifySourcePixelCrop(f.metadata, f.source, f.crop, { width: 1, height: 1 }), /Shipped crop/u); await assert.rejects(verifySourcePixelCrop(f.metadata, f.source, f.crop, { ...f.shipped, levelCount: 1 }), /mip chain/u); });