import { describe, expect, test } from "bun:test"; import { ContentMismatchError, validateDownloadedContent, } from "./download-validation.js"; /** Create a minimal valid PNG buffer that file-type can detect. */ function makePngBuffer(): Uint8Array { return new Uint8Array([ // PNG signature 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, // IHDR chunk: length (13) 0x00, 0x00, 0x00, 0x0d, // IHDR type 0x49, 0x48, 0x44, 0x52, // Width: 1 0x00, 0x00, 0x00, 0x01, // Height: 1 0x00, 0x00, 0x00, 0x01, // Bit depth, color type, compression, filter, interlace 0x08, 0x02, 0x00, 0x00, 0x00, // CRC (placeholder) 0x90, 0x77, 0x53, 0xde, ]); } function htmlBuffer(html: string): Uint8Array { return new TextEncoder().encode(html); } describe("validateDownloadedContent", () => { test("throws ContentMismatchError when HTML is received instead of image/png", async () => { const buffer = htmlBuffer( "

Access Denied

", ); await expect( validateDownloadedContent(buffer, "image/png", "F001"), ).rejects.toThrow(ContentMismatchError); await expect( validateDownloadedContent(buffer, "image/png", "F001"), ).rejects.toThrow( "File F001 declared as image/png but content is HTML (likely an auth/error page)", ); }); test("throws ContentMismatchError for HTML with leading whitespace and BOM", async () => { // UTF-8 BOM (EF BB BF) + whitespace + HTML const bom = new Uint8Array([0xef, 0xbb, 0xbf]); const html = new TextEncoder().encode( " \n Error", ); const buffer = new Uint8Array(bom.length + html.length); buffer.set(bom, 0); buffer.set(html, bom.length); await expect( validateDownloadedContent(buffer, "image/jpeg", "F002"), ).rejects.toThrow(ContentMismatchError); }); test("passes for valid PNG buffer with declared image/png", async () => { const buffer = makePngBuffer(); // Should not throw await validateDownloadedContent(buffer, "image/png", "F003"); }); test("passes for valid PNG buffer with declared image/jpeg (same image family)", async () => { const buffer = makePngBuffer(); // file-type detects it as image/png, which still starts with "image/" // so it should pass even though declared as image/jpeg await validateDownloadedContent(buffer, "image/jpeg", "F004"); }); test("passes for plain text buffer with declared text/plain (non-binary)", async () => { const buffer = new TextEncoder().encode("hello world"); // text/plain is not a binary MIME type, so no validation is performed await validateDownloadedContent( new Uint8Array(buffer), "text/plain", "F005", ); }); test("passes for empty buffer with declared image/png", async () => { const buffer = new Uint8Array(0); // Empty buffer: looksLikeHtml returns false, fileTypeFromBuffer returns // undefined, so we allow it through and let downstream handle it await validateDownloadedContent(buffer, "image/png", "F006"); }); });