59 lines
2.0 KiB
TypeScript
59 lines
2.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { strToU8, zipSync } from "fflate";
|
|
import { analyzePackage } from "../../src/package/analyze";
|
|
import { compareSemanticEntry } from "../../src/package/content-compare";
|
|
import { verifyPackageContents } from "../../src/package/content-compare";
|
|
|
|
const bytes = (value: string) => new TextEncoder().encode(value);
|
|
|
|
describe("bounded semantic package comparison", () => {
|
|
it("hashes verified decompressed bytes instead of ZIP representation", async () => {
|
|
const contents = { "same.txt": strToU8("same decompressed value") };
|
|
const left = await analyzePackage(
|
|
new File([zipSync(contents, { level: 0 })], "left.zip"),
|
|
);
|
|
const right = await analyzePackage(
|
|
new File([zipSync(contents, { level: 9 })], "right.zip"),
|
|
);
|
|
const evidence = await verifyPackageContents(left, right);
|
|
expect(evidence["same.txt"]?.leftSha256).toMatch(/^[0-9a-f]{64}$/u);
|
|
expect(evidence["same.txt"]?.leftSha256).toBe(
|
|
evidence["same.txt"]?.rightSha256,
|
|
);
|
|
});
|
|
|
|
it("recognizes equivalent JSON serialization and reports value paths", () => {
|
|
expect(
|
|
compareSemanticEntry(
|
|
"manifest.json",
|
|
bytes('{"name":"demo","items":[1,2]}'),
|
|
bytes('{\n "items": [1, 2], "name": "demo"\n}'),
|
|
),
|
|
).toMatchObject({ kind: "json", equivalent: true });
|
|
expect(
|
|
compareSemanticEntry(
|
|
"manifest.json",
|
|
bytes('{"name":"before"}'),
|
|
bytes('{"name":"after"}'),
|
|
)?.differences,
|
|
).toContain("$.name: value changed");
|
|
});
|
|
|
|
it("normalizes safe XML attributes but rejects active declarations", () => {
|
|
expect(
|
|
compareSemanticEntry(
|
|
"content.xml",
|
|
bytes('<root a="1" b="2"><item>value</item></root>'),
|
|
bytes('<root b="2" a="1">\n<item>value</item>\n</root>'),
|
|
),
|
|
).toMatchObject({ kind: "xml", equivalent: true });
|
|
expect(
|
|
compareSemanticEntry(
|
|
"content.xml",
|
|
bytes("<!DOCTYPE root><root/>"),
|
|
bytes("<root/>"),
|
|
)?.summary,
|
|
).toMatch(/could not/u);
|
|
});
|
|
});
|