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 { execFileSync } from "node:child_process"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const manifest = JSON.parse(fs.readFileSync(path.join(root, "tests/golden/M12-02B/manifest.json"), "utf8")); const identity = JSON.parse(fs.readFileSync(path.join(root, "tests/golden/M12-02B/identity.json"), "utf8")); const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex"); const blender = process.env.BLENDER_BIN ?? path.join(root, manifest.artifacts.blender.path); const source = path.join(root, manifest.artifacts.source.path); const generator = path.join(root, manifest.artifacts.generator.path); const golden = path.join(root, manifest.artifacts.content.path); assert.match(execFileSync(blender, ["--version"], { encoding: "utf8" }), /^Blender 5\.2\.0 LTS/m); assert.equal(sha256(blender), identity.generator.executableSha256); assert.equal(sha256(generator), identity.generator.scriptSha256); assert.equal(sha256(source), identity.source.sha256); assert.equal(fs.statSync(source).size, identity.source.byteLength); assert.equal(sha256(golden), identity.content.sha256); assert.equal(fs.statSync(golden).size, identity.content.byteLength); const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "m12-asset-preview-identity-")); try { const first = path.join(temporary, "first.png"); const second = path.join(temporary, "second.png"); for (const output of [first, second]) { execFileSync(blender, ["--background", "--factory-startup", "--python", generator, "--", source, output], { cwd: root, stdio: "pipe" }); assert.equal(sha256(output), identity.content.sha256); assert.equal(fs.statSync(output).size, identity.content.byteLength); } const probe = [ "import bpy,json", `a=bpy.data.images.load(${JSON.stringify(source)},check_existing=False)`, `b=bpy.data.images.load(${JSON.stringify(first)},check_existing=False)`, "print('M12_PREVIEW_COMPARE='+json.dumps({'source':list(a.size),'content':list(b.size),'max':max(abs(x-y) for x,y in zip(a.pixels[:],b.pixels[:]))},separators=(',',':')))", ].join(";"); const output = execFileSync(blender, ["--background", "--factory-startup", "--python-expr", probe], { cwd: root, encoding: "utf8" }); const line = output.split(/\r?\n/).find((item) => item.startsWith("M12_PREVIEW_COMPARE=")); assert.ok(line); assert.deepEqual(JSON.parse(line.slice("M12_PREVIEW_COMPARE=".length)), { source: [8, 8], content: [8, 8], max: 0 }); } finally { fs.rmSync(temporary, { recursive: true, force: true }); } process.stdout.write(`asset-preview-identity-ok source=${identity.source.sha256} content=${identity.content.sha256} size=${identity.content.width}x${identity.content.height} next=${manifest.nextTask}\n`);