68 lines
4.2 KiB
JavaScript
68 lines
4.2 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
import test from "node:test";
|
|
import ts from "typescript";
|
|
|
|
const root = path.resolve(import.meta.dirname, "../../..");
|
|
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "library-metadata-first-unit-"));
|
|
const sourcePath = path.join(root, "web/protocol/archive-metadata-first.ts");
|
|
const transpiled = ts.transpileModule(fs.readFileSync(sourcePath, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 },
|
|
fileName: sourcePath,
|
|
reportDiagnostics: true,
|
|
});
|
|
assert.deepEqual(transpiled.diagnostics, []);
|
|
fs.writeFileSync(path.join(temporary, "archive-metadata-first.mjs"), transpiled.outputText);
|
|
const metadata = await import(pathToFileURL(path.join(temporary, "archive-metadata-first.mjs")));
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(root, "tests/golden/M12-04E/manifest.json"), "utf8"));
|
|
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(path.join(root, file))).digest("hex");
|
|
const zip = { schemaVersion: 1, archiveId: "archive:zip-1", format: "ZIP", archiveByteLength: 4096, metadataOffset: 3072, metadataByteLength: 512 };
|
|
const tar = { schemaVersion: 1, archiveId: "archive:tar-1", format: "TAR", archiveByteLength: 4096, metadataOffset: 0, metadataByteLength: 1024 };
|
|
|
|
test("M12-04E binds metadata-first planning and evidence artifacts", () => {
|
|
assert.equal(manifest.task, "M12-04E");
|
|
assert.equal(manifest.parentTask, "M12-04D");
|
|
assert.equal(manifest.nextTask, "M12-04F");
|
|
for (const artifact of Object.values(manifest.artifacts)) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
|
|
});
|
|
|
|
test("M12-04E plans ZIP central-directory and TAR manifest reads without payload ranges", () => {
|
|
assert.deepEqual(metadata.planArchiveMetadataRead(zip), {
|
|
status: "METADATA_ONLY", schemaVersion: 1, archiveId: "archive:zip-1", format: "ZIP",
|
|
firstRead: { kind: "CENTRAL_DIRECTORY", byteOffset: 3072, byteLength: 512 }, payloadReads: [],
|
|
});
|
|
assert.deepEqual(metadata.planArchiveMetadataRead(tar).firstRead, { kind: "MANIFEST", byteOffset: 0, byteLength: 1024 });
|
|
});
|
|
|
|
test("M12-04E accepts a trace only when metadata is the first exact read", () => {
|
|
assert.deepEqual(metadata.validateArchiveReadTrace(zip, {
|
|
schemaVersion: 1, archiveId: "archive:zip-1", reads: [
|
|
{ sequence: 0, kind: "CENTRAL_DIRECTORY", byteOffset: 3072, byteLength: 512 },
|
|
{ sequence: 1, kind: "PAYLOAD", byteOffset: 32, byteLength: 128 },
|
|
],
|
|
}), { status: "VALID", metadataFirst: true, payloadReadsAfterMetadata: true });
|
|
assert.deepEqual(metadata.validateArchiveReadTrace(tar, {
|
|
schemaVersion: 1, archiveId: "archive:tar-1", reads: [{ sequence: 0, kind: "MANIFEST", byteOffset: 0, byteLength: 1024 }],
|
|
}).metadataFirst, true);
|
|
});
|
|
|
|
test("M12-04E rejects payload-first, wrong-range, duplicate-metadata and invalid ranges", () => {
|
|
assert.throws(() => metadata.validateArchiveReadTrace(zip, { schemaVersion: 1, archiveId: "archive:zip-1", reads: [
|
|
{ sequence: 0, kind: "PAYLOAD", byteOffset: 0, byteLength: 16 },
|
|
{ sequence: 1, kind: "CENTRAL_DIRECTORY", byteOffset: 3072, byteLength: 512 },
|
|
] }), { code: "IO_ARCHIVE_UNSAFE" });
|
|
assert.throws(() => metadata.validateArchiveReadTrace(zip, { schemaVersion: 1, archiveId: "archive:zip-1", reads: [{ sequence: 0, kind: "CENTRAL_DIRECTORY", byteOffset: 3000, byteLength: 512 }] }), { code: "IO_ARCHIVE_UNSAFE" });
|
|
assert.throws(() => metadata.validateArchiveReadTrace(zip, { schemaVersion: 1, archiveId: "archive:zip-1", reads: [
|
|
{ sequence: 0, kind: "CENTRAL_DIRECTORY", byteOffset: 3072, byteLength: 512 },
|
|
{ sequence: 1, kind: "CENTRAL_DIRECTORY", byteOffset: 3072, byteLength: 512 },
|
|
] }), { code: "IO_ARCHIVE_UNSAFE" });
|
|
assert.throws(() => metadata.planArchiveMetadataRead({ ...zip, metadataOffset: 4000, metadataByteLength: 200 }), { code: "IO_ARCHIVE_UNSAFE" });
|
|
assert.throws(() => metadata.planArchiveMetadataRead({ ...zip, metadataByteLength: 64 * 1024 * 1024 + 1 }), { code: "IO_ARCHIVE_UNSAFE" });
|
|
});
|
|
|
|
test.after(() => fs.rmSync(temporary, { recursive: true, force: true }));
|