@@ -1,5 +1,11 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { manifestCsv, manifestJson } from "../../src/file/manifest";
|
||||
import {
|
||||
checksumManifest,
|
||||
joinBlobs,
|
||||
planBatchRename,
|
||||
splitBlob,
|
||||
} from "../../src/file/operations";
|
||||
import {
|
||||
detectKnownSignature,
|
||||
extensionMismatch,
|
||||
@@ -52,4 +58,102 @@ describe("manifests", () => {
|
||||
expect(manifestJson(records)).toBe(manifestJson(records)));
|
||||
it("neutralises spreadsheet-leading formulas", () =>
|
||||
expect(manifestCsv(records)).toContain("'=formula"));
|
||||
it("reports truthful inspection coverage and per-file failures", () => {
|
||||
const text = manifestJson([
|
||||
{
|
||||
...records[0]!,
|
||||
inspectionStatus: "inspected",
|
||||
inspection: {
|
||||
evidence: [],
|
||||
entropy: 0,
|
||||
sampleBytes: 0,
|
||||
strings: [],
|
||||
findings: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
...records[0]!,
|
||||
path: "broken.bin",
|
||||
inspectionStatus: "error",
|
||||
inspectionError: "Timed out",
|
||||
},
|
||||
]);
|
||||
const manifest = JSON.parse(text) as {
|
||||
inspectionCoverage: { inspected: number; failed: number };
|
||||
files: Array<{
|
||||
inspectionStatus: string;
|
||||
inspectionError: string | null;
|
||||
}>;
|
||||
};
|
||||
expect(manifest.inspectionCoverage).toMatchObject({
|
||||
inspected: 1,
|
||||
failed: 1,
|
||||
});
|
||||
expect(
|
||||
manifest.files.find((file) => file.inspectionStatus === "error"),
|
||||
).toMatchObject({ inspectionError: "Timed out" });
|
||||
expect(
|
||||
manifestCsv([{ ...records[0]!, inspectionStatus: "cancelled" }]),
|
||||
).toContain('"cancelled"');
|
||||
});
|
||||
});
|
||||
|
||||
describe("bounded file operations", () => {
|
||||
it("plans sanitized collision-safe rename downloads deterministically", () => {
|
||||
const files = [
|
||||
{ name: "first.txt", blob: new Blob(["one"]) },
|
||||
{ name: "second.txt", blob: new Blob(["two"]) },
|
||||
];
|
||||
const plan = planBatchRename(files, "same.{ext}");
|
||||
expect(plan.map((item) => item.filename)).toEqual([
|
||||
"same.txt",
|
||||
"same (2).txt",
|
||||
]);
|
||||
expect(plan.map((item) => item.originalName)).toEqual([
|
||||
"first.txt",
|
||||
"second.txt",
|
||||
]);
|
||||
});
|
||||
|
||||
it("splits and rejoins byte-exact Blob parts with an offset manifest", async () => {
|
||||
const source = new Blob([new Uint8Array(150_000).map((_, index) => index)]);
|
||||
const split = splitBlob(source, "payload.bin", 65_536);
|
||||
expect(split.parts.map((part) => part.size)).toEqual([
|
||||
65_536, 65_536, 18_928,
|
||||
]);
|
||||
expect(split.manifest.parts[1]).toMatchObject({ offset: 65_536, index: 2 });
|
||||
const joined = joinBlobs(split.parts.map((part) => part.blob));
|
||||
expect(new Uint8Array(await joined.arrayBuffer())).toEqual(
|
||||
new Uint8Array(await source.arrayBuffer()),
|
||||
);
|
||||
});
|
||||
|
||||
it("refuses unbounded split/join and emits sorted checksum files", () => {
|
||||
expect(() => splitBlob(new Blob(["x"]), "x", 1)).toThrow(/Chunk size/u);
|
||||
expect(() =>
|
||||
joinBlobs([new Blob(["abc"]), new Blob(["def"])], "", 5),
|
||||
).toThrow(/exceeds/u);
|
||||
const output = checksumManifest(
|
||||
[
|
||||
{
|
||||
name: "b",
|
||||
path: "b",
|
||||
size: 0,
|
||||
type: "",
|
||||
lastModified: 0,
|
||||
sha256: "b".repeat(64),
|
||||
},
|
||||
{
|
||||
name: "a",
|
||||
path: "a",
|
||||
size: 0,
|
||||
type: "",
|
||||
lastModified: 0,
|
||||
sha256: "a".repeat(64),
|
||||
},
|
||||
],
|
||||
"sha256",
|
||||
);
|
||||
expect(output.split("\n")[0]).toBe(`${"a".repeat(64)} *a`);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user