125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
import { assert, assertEquals } from "assert";
|
|
import { b, stubbingWarn } from "../helpers.ts";
|
|
import { PngNodeType } from "../../public/png/constants.js";
|
|
import parsePng from "../../public/png/parsePng.js";
|
|
|
|
const FIXTURES_URL = new URL("./fixtures/", import.meta.url);
|
|
|
|
const getFixture = (name: string): Promise<Uint8Array> =>
|
|
Deno.readFile(new URL(name, FIXTURES_URL));
|
|
|
|
async function* getFixtureNames(): AsyncIterable<string> {
|
|
for await (const dirEntry of Deno.readDir(FIXTURES_URL)) {
|
|
if (!dirEntry.isFile) continue;
|
|
const { name } = dirEntry;
|
|
if (name.endsWith(".png")) yield name;
|
|
}
|
|
}
|
|
|
|
const t = (type: string) => new TextEncoder().encode(type);
|
|
|
|
Deno.test(
|
|
"parses PNG test suite reasonably",
|
|
stubbingWarn(async () => {
|
|
const fixturesToSkip = new Set([
|
|
// Incorrect bit depths, which we don't detect.
|
|
"xd0n2c08.png",
|
|
"xd3n2c08.png",
|
|
"xd9n2c08.png",
|
|
// Incorrect color types, which we don't detect.
|
|
"xc1n0g08.png",
|
|
"xc9n2c08.png",
|
|
// Missing an IDAT chunk, which we don't detect.
|
|
"xdtn0g01.png",
|
|
]);
|
|
|
|
for await (const fixtureName of getFixtureNames()) {
|
|
const fixture = await getFixture(fixtureName);
|
|
|
|
if (fixturesToSkip.has(fixtureName)) continue;
|
|
|
|
if (fixtureName.startsWith("x")) {
|
|
assertEquals(
|
|
parsePng(fixture),
|
|
null,
|
|
`${fixtureName} should fail to parse`,
|
|
);
|
|
} else {
|
|
try {
|
|
parsePng(fixture);
|
|
} catch {
|
|
assert(false, `${fixtureName} should parse`);
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
);
|
|
|
|
Deno.test("parses a basic PNG", async () => {
|
|
const fixture = await getFixture("basn2c16.png");
|
|
assertEquals(parsePng(fixture), {
|
|
type: PngNodeType.root,
|
|
bytes: fixture,
|
|
children: [
|
|
{
|
|
type: PngNodeType.signature,
|
|
bytes: fixture.subarray(0, 8),
|
|
},
|
|
{
|
|
type: PngNodeType.ihdr,
|
|
bytes: fixture.subarray(8, 8 + 25),
|
|
children: [
|
|
{ type: PngNodeType.chunkLength, bytes: b(0, 0, 0, 13) },
|
|
{ type: PngNodeType.chunkType, bytes: t("IHDR") },
|
|
{
|
|
type: PngNodeType.ihdrChunkData,
|
|
bytes: fixture.subarray(16, 16 + 13),
|
|
children: [
|
|
{ type: PngNodeType.ihdrWidth, bytes: b(0, 0, 0, 32) },
|
|
{ type: PngNodeType.ihdrHeight, bytes: b(0, 0, 0, 32) },
|
|
{ type: PngNodeType.ihdrBitDepth, bytes: b(16) },
|
|
{ type: PngNodeType.ihdrColourType, bytes: b(2) },
|
|
{ type: PngNodeType.ihdrCompressionMethod, bytes: b(0) },
|
|
{ type: PngNodeType.ihdrFilterMethod, bytes: b(0) },
|
|
{ type: PngNodeType.ihdrInterlaceMethod, bytes: b(0) },
|
|
],
|
|
},
|
|
{ type: PngNodeType.chunkCrc, bytes: b(172, 136, 49, 224) },
|
|
],
|
|
},
|
|
{
|
|
type: PngNodeType.gama,
|
|
bytes: fixture.subarray(33, 33 + 16),
|
|
children: [
|
|
{ type: PngNodeType.chunkLength, bytes: b(0, 0, 0, 4) },
|
|
{ type: PngNodeType.chunkType, bytes: t("gAMA") },
|
|
{ type: PngNodeType.chunkData, bytes: b(0, 1, 134, 160) },
|
|
{ type: PngNodeType.chunkCrc, bytes: b(49, 232, 150, 95) },
|
|
],
|
|
},
|
|
{
|
|
type: PngNodeType.idat,
|
|
bytes: fixture.subarray(49, 49 + 241),
|
|
children: [
|
|
{ type: PngNodeType.chunkLength, bytes: b(0, 0, 0, 229) },
|
|
{ type: PngNodeType.chunkType, bytes: t("IDAT") },
|
|
{
|
|
type: PngNodeType.idatChunkData,
|
|
bytes: fixture.subarray(57, 57 + 229),
|
|
},
|
|
{ type: PngNodeType.chunkCrc, bytes: b(7, 187, 196, 236) },
|
|
],
|
|
},
|
|
{
|
|
type: PngNodeType.iend,
|
|
bytes: fixture.subarray(290, 290 + 12),
|
|
children: [
|
|
{ type: PngNodeType.iendChunkLength, bytes: b(0, 0, 0, 0) },
|
|
{ type: PngNodeType.chunkType, bytes: t("IEND") },
|
|
{ type: PngNodeType.chunkCrc, bytes: b(0xae, 0x42, 0x60, 0x82) },
|
|
],
|
|
},
|
|
],
|
|
});
|
|
});
|