diff --git a/packages/epub-codec/src/codec.test.ts b/packages/epub-codec/src/codec.test.ts index b8bc8c31b..67fa65e10 100644 --- a/packages/epub-codec/src/codec.test.ts +++ b/packages/epub-codec/src/codec.test.ts @@ -27,6 +27,13 @@ describe("EpubBytesSchema", () => { EpubBytesSchema.safeParse(new Uint8Array([0, 1, 2, 3])).success, ).toBe(false); }); + + it("rejects bytes matching only part of the zip header", () => { + // The first byte matches PK\x03\x04's own 0x50, but the rest don't -- .some() would wrongly accept this, .every() correctly rejects it. + expect( + EpubBytesSchema.safeParse(new Uint8Array([0x50, 0, 0, 0])).success, + ).toBe(false); + }); }); describe("epubContentCodec", () => { diff --git a/packages/epub-codec/src/diagnostics-coverage.test.ts b/packages/epub-codec/src/diagnostics-coverage.test.ts index 31c682e29..2aa730012 100644 --- a/packages/epub-codec/src/diagnostics-coverage.test.ts +++ b/packages/epub-codec/src/diagnostics-coverage.test.ts @@ -49,41 +49,79 @@ function minimalEpubEntries( } describe("every EpubDiagnosticCodes entry is reachable from real input", () => { - it("INVENTED_PAGE_GEOMETRY fires on every read", () => { + it("INVENTED_PAGE_GEOMETRY fires on every read, with a real, non-empty message", () => { const { sink, codes } = collect(); + const seen: EpubDiagnostic[] = []; readEpubContent( zipPackage(minimalEpubEntries("

x

")), - { sink }, + { + sink: (d) => { + sink(d); + seen.push(d); + }, + }, ); expect(codes.has(EpubDiagnosticCodes.INVENTED_PAGE_GEOMETRY)).toBe(true); + const found = seen.find( + (d) => d.code === EpubDiagnosticCodes.INVENTED_PAGE_GEOMETRY, + ); + expect(found?.message).toBe( + "EPUB has no page concept of its own; every section was given A4 + 1in default page geometry", + ); }); - it("SPINE_ITEMREF_UNRESOLVED fires when a spine itemref names no manifest item", () => { + it("SPINE_ITEMREF_UNRESOLVED fires when a spine itemref names no manifest item, naming that idref in its own message", () => { const { sink, codes } = collect(); + const seen: EpubDiagnostic[] = []; readEpubContent( zipPackage( minimalEpubEntries("

x

", { opfExtra: '', }), ), - { sink }, + { + sink: (d) => { + sink(d); + seen.push(d); + }, + }, ); expect(codes.has(EpubDiagnosticCodes.SPINE_ITEMREF_UNRESOLVED)).toBe(true); + const found = seen.find( + (d) => d.code === EpubDiagnosticCodes.SPINE_ITEMREF_UNRESOLVED, + ); + expect(found?.message).toBe( + 'spine itemref "ghost" names no manifest item; skipped', + ); }); - it("MANIFEST_ITEM_MISSING fires when a manifest item's own part is not in the zip", () => { + it("MANIFEST_ITEM_MISSING fires when a manifest item's own part is not in the zip, naming that item's id and href in its own message", () => { const { sink, codes } = collect(); + const seen: EpubDiagnostic[] = []; const entries = minimalEpubEntries("

x

", { manifestExtra: '', opfExtra: '', }); - readEpubContent(zipPackage(entries), { sink }); + readEpubContent(zipPackage(entries), { + sink: (d) => { + sink(d); + seen.push(d); + }, + }); expect(codes.has(EpubDiagnosticCodes.MANIFEST_ITEM_MISSING)).toBe(true); + const found = seen.find( + (d) => d.code === EpubDiagnosticCodes.MANIFEST_ITEM_MISSING, + ); + expect(found?.message).toBe( + 'manifest item "ghost" names a part ("OEBPS/ghost.xhtml") the zip does not contain; skipped', + ); + expect(found?.href).toBe("OEBPS/ghost.xhtml"); }); - it("NAV_DOCUMENT_MISSING fires when the nav-flagged manifest item carries no toc nav", () => { + it("NAV_DOCUMENT_MISSING fires when the nav-flagged manifest item carries no toc nav, naming its own path", () => { const { sink, codes } = collect(); + const seen: EpubDiagnostic[] = []; const encoder = new TextEncoder(); const entries = [ ...minimalEpubEntries("

x

", { @@ -97,12 +135,24 @@ describe("every EpubDiagnosticCodes entry is reachable from real input", () => { }, ] as [string, { bytes: Uint8Array }], ]; - readEpub(zipPackage(entries), { sink }); + readEpub(zipPackage(entries), { + sink: (d) => { + sink(d); + seen.push(d); + }, + }); expect(codes.has(EpubDiagnosticCodes.NAV_DOCUMENT_MISSING)).toBe(true); + const found = seen.find( + (d) => d.code === EpubDiagnosticCodes.NAV_DOCUMENT_MISSING, + ); + expect(found?.message).toBe( + 'the nav document ("OEBPS/nav.xhtml") carries no