import { describe, expect, test } from "bun:test"; import { buildBlobsForContent, extractBlobRefs, parseBlobMetadata, } from "../../src/lib/attachments.ts"; describe("extractBlobRefs", () => { test("extracts blob refs from markdown with images", () => { const content = ` # Hello ![photo](/blob/did:plc:abc123/bafyreiabc) Some text. ![diagram](/blob/did:plc:xyz789/bafyreixyz) `; const refs = extractBlobRefs(content); expect(refs).toEqual([ { did: "did:plc:abc123", cid: "bafyreiabc" }, { did: "did:plc:xyz789", cid: "bafyreixyz" }, ]); }); test("returns empty for no images", () => { const content = "# Hello\n\nNo images here.\n\n[a link](http://example.com)"; expect(extractBlobRefs(content)).toEqual([]); }); test("deduplicates CIDs", () => { const content = ` ![a](/blob/did:plc:abc/bafyreisame) ![b](/blob/did:plc:abc/bafyreisame) `; const refs = extractBlobRefs(content); expect(refs).toHaveLength(1); expect(refs[0]?.cid).toBe("bafyreisame"); }); test("ignores non-blob URLs", () => { const content = ` ![external](https://example.com/image.png) ![local](/blob/local/123-abc.jpg) ![relative](./image.png) `; expect(extractBlobRefs(content)).toEqual([]); }); test("handles alt text with special characters", () => { const content = "![a [bracket] image](/blob/did:plc:a/bafyrei1)"; // The regex expects no ] in alt text, so this should not match expect(extractBlobRefs(content)).toEqual([]); }); test("handles CIDs with various characters", () => { const content = "![img](/blob/did:plc:abc/bafyrei123ABCdef456)"; const refs = extractBlobRefs(content); expect(refs).toEqual([{ did: "did:plc:abc", cid: "bafyrei123ABCdef456" }]); }); test("ignores malformed blob URLs (missing did prefix)", () => { const content = "![img](/blob/notadid/bafyreiabc)"; expect(extractBlobRefs(content)).toEqual([]); }); test("ignores blob URL without CID", () => { const content = "![img](/blob/did:plc:abc/)"; expect(extractBlobRefs(content)).toEqual([]); }); test("does not extract from non-image markdown links", () => { // Regular links (not images) should not match const content = "[click here](/blob/did:plc:abc/bafyreiabc)"; expect(extractBlobRefs(content)).toEqual([]); }); }); describe("parseBlobMetadata", () => { test("returns empty object for null", () => { expect(parseBlobMetadata(null)).toEqual({}); }); test("returns empty object for empty string", () => { expect(parseBlobMetadata("")).toEqual({}); }); test("parses valid JSON", () => { const meta = parseBlobMetadata( '{"bafyreiabc":{"mimeType":"image/png","size":1024},"bafyreixyz":{"mimeType":"image/jpeg","size":2048}}', ); expect(meta).toEqual({ bafyreiabc: { mimeType: "image/png", size: 1024 }, bafyreixyz: { mimeType: "image/jpeg", size: 2048 }, }); }); test("returns empty object for malformed JSON", () => { expect(parseBlobMetadata("{invalid")).toEqual({}); }); test("returns empty object for non-object JSON", () => { expect(parseBlobMetadata('"string"')).toEqual({}); expect(parseBlobMetadata("42")).toEqual({}); }); }); describe("buildBlobsForContent", () => { test("matches CIDs present in blobMeta", () => { const content = "![img](/blob/did:plc:abc/bafyreiabc)"; const blobMeta = { bafyreiabc: { mimeType: "image/png", size: 1024 }, bafyreiother: { mimeType: "image/jpeg", size: 2048 }, }; const blobs = buildBlobsForContent(content, blobMeta); expect(blobs).toEqual([ { $type: "blob", ref: { $link: "bafyreiabc" }, mimeType: "image/png", size: 1024, }, ]); }); test("ignores refs without metadata", () => { const content = "![img](/blob/did:plc:abc/bafyreiunknown)"; const blobMeta = { bafyreiabc: { mimeType: "image/png", size: 1024 } }; const blobs = buildBlobsForContent(content, blobMeta); expect(blobs).toEqual([]); }); test("returns empty for content with no blob refs", () => { const content = "# Hello\nNo images here."; const blobMeta = { bafyreiabc: { mimeType: "image/png", size: 1024 } }; const blobs = buildBlobsForContent(content, blobMeta); expect(blobs).toEqual([]); }); test("returns empty for empty blobMeta", () => { const content = "![img](/blob/did:plc:abc/bafyreiabc)"; const blobs = buildBlobsForContent(content, {}); expect(blobs).toEqual([]); }); });