mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
test: expand unit test coverage (+437 tests, 17 new files)
Add comprehensive unit tests for previously uncovered API lib modules, web stores, and plugin functions. Fix 2 pre-existing editor-store test failures (invertSelection mask values). Coverage: 30.3% -> 36.85% stmts (unit), 57.71% stmts (integration).
This commit is contained in:
@@ -1,5 +1,29 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import sharp from "sharp";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { decodeToSharpCompat, needsCliDecode } from "../../../apps/api/src/lib/format-decoders.js";
|
||||
import { encodeQoi } from "../../../apps/api/src/lib/format-encoders.js";
|
||||
|
||||
const FIXTURES = join(__dirname, "../../fixtures");
|
||||
|
||||
const PNG_MAGIC = [0x89, 0x50, 0x4e, 0x47];
|
||||
|
||||
function isPng(buf: Buffer): boolean {
|
||||
return (
|
||||
buf[0] === PNG_MAGIC[0] &&
|
||||
buf[1] === PNG_MAGIC[1] &&
|
||||
buf[2] === PNG_MAGIC[2] &&
|
||||
buf[3] === PNG_MAGIC[3]
|
||||
);
|
||||
}
|
||||
|
||||
async function assertValidImage(buf: Buffer): Promise<{ width: number; height: number }> {
|
||||
const meta = await sharp(buf).metadata();
|
||||
expect(meta.width).toBeGreaterThan(0);
|
||||
expect(meta.height).toBeGreaterThan(0);
|
||||
return { width: meta.width!, height: meta.height! };
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// needsCliDecode
|
||||
@@ -126,4 +150,205 @@ describe("decodeToSharpCompat", () => {
|
||||
const result = await decodeToSharpCompat(buf, "webp");
|
||||
expect(result).toBe(buf);
|
||||
});
|
||||
|
||||
it("returns buffer unchanged for gif format", async () => {
|
||||
const buf = Buffer.from("gif data");
|
||||
const result = await decodeToSharpCompat(buf, "gif");
|
||||
expect(result).toBe(buf);
|
||||
});
|
||||
|
||||
it("returns buffer unchanged for avif format", async () => {
|
||||
const buf = Buffer.from("avif data");
|
||||
const result = await decodeToSharpCompat(buf, "avif");
|
||||
expect(result).toBe(buf);
|
||||
});
|
||||
|
||||
it("returns buffer unchanged for tiff format", async () => {
|
||||
const buf = Buffer.from("tiff data");
|
||||
const result = await decodeToSharpCompat(buf, "tiff");
|
||||
expect(result).toBe(buf);
|
||||
});
|
||||
|
||||
it("decodes BMP to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.bmp"));
|
||||
const result = await decodeToSharpCompat(input, "bmp");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes ICO to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.ico"));
|
||||
const result = await decodeToSharpCompat(input, "ico");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes TGA to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.tga"));
|
||||
const result = await decodeToSharpCompat(input, "tga");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes PSD to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.psd"));
|
||||
const result = await decodeToSharpCompat(input, "psd");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes EXR to valid PNG (requires EXR delegate)", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.exr"));
|
||||
try {
|
||||
const result = await decodeToSharpCompat(input, "exr");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
} catch (e: unknown) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
if (msg.includes("no decode delegate")) return;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it("decodes HDR to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.hdr"));
|
||||
const result = await decodeToSharpCompat(input, "hdr");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes JXL to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.jxl"));
|
||||
const result = await decodeToSharpCompat(input, "jxl");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes JP2 to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.jp2"));
|
||||
const result = await decodeToSharpCompat(input, "jp2");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes DDS to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.dds"));
|
||||
const result = await decodeToSharpCompat(input, "dds");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes CUR using ICO decoder to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.cur"));
|
||||
const result = await decodeToSharpCompat(input, "cur");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes DPX to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.dpx"));
|
||||
const result = await decodeToSharpCompat(input, "dpx");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes FITS to valid PNG (requires FITS delegate)", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.fits"));
|
||||
try {
|
||||
const result = await decodeToSharpCompat(input, "fits");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
} catch (e: unknown) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
if (msg.includes("no decode delegate") || msg.includes("ENOENT")) return;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it("decodes PPM to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.ppm"));
|
||||
const result = await decodeToSharpCompat(input, "ppm");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes PGM to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.pgm"));
|
||||
const result = await decodeToSharpCompat(input, "pgm");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("decodes PBM to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.pbm"));
|
||||
const result = await decodeToSharpCompat(input, "pbm");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
});
|
||||
|
||||
describe("decodeToSharpCompat - individual decoder verification", () => {
|
||||
const formats = ["bmp", "ico", "tga", "psd", "hdr", "jxl", "jp2", "dds", "dpx"] as const;
|
||||
|
||||
for (const fmt of formats) {
|
||||
it(`${fmt}: output has non-zero dimensions`, async () => {
|
||||
const input = await readFile(join(FIXTURES, `formats/sample.${fmt}`));
|
||||
const result = await decodeToSharpCompat(input, fmt);
|
||||
const { width, height } = await assertValidImage(result);
|
||||
expect(width).toBeGreaterThan(0);
|
||||
expect(height).toBeGreaterThan(0);
|
||||
});
|
||||
}
|
||||
|
||||
const delegateFormats = ["exr", "fits"] as const;
|
||||
|
||||
for (const fmt of delegateFormats) {
|
||||
it(`${fmt}: output has non-zero dimensions (requires delegate)`, async () => {
|
||||
const input = await readFile(join(FIXTURES, `formats/sample.${fmt}`));
|
||||
try {
|
||||
const result = await decodeToSharpCompat(input, fmt);
|
||||
const { width, height } = await assertValidImage(result);
|
||||
expect(width).toBeGreaterThan(0);
|
||||
expect(height).toBeGreaterThan(0);
|
||||
} catch (e: unknown) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
if (msg.includes("no decode delegate") || msg.includes("ENOENT")) return;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("decodeToSharpCompat - QOI decoder", () => {
|
||||
it("decodes QOI fixture to valid PNG", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.qoi"));
|
||||
const result = await decodeToSharpCompat(input, "qoi");
|
||||
expect(isPng(result)).toBe(true);
|
||||
await assertValidImage(result);
|
||||
});
|
||||
|
||||
it("round-trips PNG -> QOI -> PNG", async () => {
|
||||
const png = await readFile(join(FIXTURES, "formats/sample.png"));
|
||||
const qoi = await encodeQoi(png);
|
||||
const decoded = await decodeToSharpCompat(Buffer.from(qoi), "qoi");
|
||||
expect(isPng(decoded)).toBe(true);
|
||||
const { width, height } = await assertValidImage(decoded);
|
||||
const originalMeta = await sharp(png).metadata();
|
||||
expect(width).toBe(originalMeta.width);
|
||||
expect(height).toBe(originalMeta.height);
|
||||
});
|
||||
|
||||
it("decoded QOI produces a buffer sharp can process further", async () => {
|
||||
const input = await readFile(join(FIXTURES, "formats/sample.qoi"));
|
||||
const decoded = await decodeToSharpCompat(input, "qoi");
|
||||
const resized = await sharp(decoded).resize(10, 10).png().toBuffer();
|
||||
expect(resized.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("decodeToSharpCompat - EPS size limit", () => {
|
||||
it("rejects EPS files over 50MB", async () => {
|
||||
const largeBuffer = Buffer.alloc(51 * 1024 * 1024);
|
||||
await expect(decodeToSharpCompat(largeBuffer, "eps")).rejects.toThrow(/EPS file too large/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user