import { test } from "node:test"; import assert from "node:assert/strict"; import { datasetSchema, parseUploadManifest, panoramaPath, } from "../shared/protocol"; import { selectDraftLocations } from "../shared/draft-selection"; const root = "11111111-1111-4111-8111-111111111111", child = "22222222-2222-4222-8222-222222222222"; const point = (i: number) => ({ id: `p${i}`, x: i, y: 65, z: i }); const manifest = { format: "minegeo-dataset/v1", minecraftVersion: "1.21.11", dimension: "minecraft:overworld", source: "plugin", name: "Random world", serverName: "Test server", north: "-z", bounds: { minX: 0, minZ: 0, maxX: 64, maxZ: 64 }, viewpoints: Array.from({ length: 24 }, (_, i) => point(i)), assets: [{ path: "terrain.json.gz", bytes: 10, sha256: "a".repeat(64) }], }; test("maps permit 24 captures and reject a 25th, including deselected locations", () => { assert.equal(parseUploadManifest(manifest).viewpoints.length, 24); assert.throws(() => parseUploadManifest({ ...manifest, viewpoints: [...manifest.viewpoints, point(24)], }), ); assert.throws(() => datasetSchema.parse({ ...manifest, viewpoints: manifest.viewpoints.slice(0, 5), availableViewpoints: [...manifest.viewpoints, point(24)], }), ); }); test("contributions can contain one panorama, while new maps still need five", () => { const contribution = parseUploadManifest({ ...manifest, contributionTo: root, viewpoints: [point(0)], }); assert.equal(selectDraftLocations(contribution, ["p0"]).viewpoints.length, 1); assert.throws(() => parseUploadManifest({ ...manifest, viewpoints: [point(0)] }), ); }); test("clients cannot choose other uploads' media or claim server-assigned provenance", () => { const mapPath = `${root}/maps/${child}.webp`; assert.equal(datasetSchema.parse({ ...manifest, mapPath }).mapPath, mapPath); assert.throws(() => parseUploadManifest({ ...manifest, mapPath })); for (const field of ["assetRoot", "assetId", "contributorId", "source"]) assert.throws(() => parseUploadManifest({ ...manifest, viewpoints: manifest.viewpoints.map((p) => ({ ...p, [field]: field === "assetId" ? "p0" : field === "source" ? "fabric" : child, })), }), ); assert.throws(() => parseUploadManifest({ ...manifest, availableViewpoints: manifest.viewpoints, }), ); }); test("merged Fabric maps preserve external cubemaps without requiring them in the original capture", () => { const external = { ...point(5), id: "c_child_1", assetRoot: child, assetId: "p0", source: "plugin" as const, }; const local = manifest.viewpoints.slice(0, 5); const merged = datasetSchema.parse({ ...manifest, source: "fabric", viewpoints: [...local, external], assets: [ "map.png", ...local.flatMap((p) => ["px", "nx", "py", "ny", "pz", "nz"].map((f) => `${p.id}/${f}.png`), ), ].map((path) => ({ path, bytes: 10, sha256: "a".repeat(64) })), }); assert.equal( panoramaPath(root, merged.viewpoints[5], "nz.webp"), `${child}/p0/nz.webp`, ); assert.equal( panoramaPath(root, merged.viewpoints[0], "preview.webp"), `${root}/p0/preview.webp`, ); const selection = selectDraftLocations( merged, local.map((p) => p.id), ); assert.equal(selection.availableViewpoints?.length, 6); });