import { describe, expect, it } from "vitest"; import { cleanPath, contentType, fileBytes, isBinaryFile, isImageValue, isSupportedFile, parseDataUrl, stripCommonRoot, toDataUrl, validateFiles } from "@/lib/codehub"; describe("codehub rules", () => { it("rejects path traversal and git metadata", () => { expect(cleanPath("../secret.txt")).toBeNull(); expect(cleanPath("app/.git/config")).toBeNull(); expect(cleanPath("./src//index.html")).toBe("src/index.html"); }); it("rejects files over 512 KB", () => { expect(validateFiles({ "big.js": "a".repeat(512 * 1024 + 1) })).toMatch(/512 KB/); expect(validateFiles({ "index.html": "
hi
" })).toBeNull(); }); it("strips one shared zip folder", () => { expect(stripCommonRoot({ "site/index.html": "a", "site/a.css": "b" })).toEqual({ "index.html": "a", "a.css": "b" }); }); it("supports code, images and fonts but not video", () => { for (const p of ["index.html", "style.css", "app.js", "app.tsx", "data.json", "readme.md", "icon.svg", "logo.png", "photo.jpeg", "font.woff2", "doc.pdf"]) { expect(isSupportedFile(p)).toBe(true); expect(cleanPath(p)).toBe(p); } expect(isBinaryFile("logo.png")).toBe(true); expect(isBinaryFile("style.css")).toBe(false); expect(isSupportedFile("clip.mp4")).toBe(false); }); it("blocks secret-bearing files but keeps .env.example", () => { expect(cleanPath(".env")).toBeNull(); expect(cleanPath("config/.env.production")).toBeNull(); expect(cleanPath(".env.example")).toBe(".env.example"); expect(cleanPath("server.pem")).toBeNull(); expect(cleanPath("id_rsa")).toBeNull(); }); it("stores images as data URLs and reads them back", () => { const url = toDataUrl("logo.png", "aGk="); expect(url).toBe("data:image/png;base64,aGk="); expect(parseDataUrl(url)).toEqual({ mime: "image/png", base64: "aGk=" }); expect(isImageValue(url)).toBe(true); expect(isImageValue("hi
")).toBe(false); expect(fileBytes(url)).toBe(2); }); it("counts stored images by decoded bytes, not base64 length", () => { const big = toDataUrl("photo.jpg", "A".repeat(800 * 1024)); // ~600 KB decoded expect(validateFiles({ "photo.jpg": big })).toBeNull(); expect(validateFiles({ "photo.jpg": toDataUrl("photo.jpg", "A".repeat(3 * 1024 * 1024)) })).toMatch(/2 MB/); }); it("publishes every stored type with the right content type", () => { expect(contentType("index.html")).toBe("text/html"); expect(contentType("app.mjs")).toBe("application/javascript"); expect(contentType("app.jsx")).toBe("application/javascript"); expect(contentType("app.tsx")).toBe("text/plain"); expect(contentType("logo.png")).toBe("image/png"); expect(contentType("font.woff2")).toBe("font/woff2"); expect(contentType("notes.txt")).toBe("text/plain"); }); });