
























@@ -0,0 +1,79 @@
1+import { spawnSync } from "node:child_process";
2+import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3+import { tmpdir } from "node:os";
4+import path from "node:path";
5+import { afterEach, describe, expect, it } from "vitest";
6+7+const tempDirs: string[] = [];
8+const scriptPath = "scripts/create-dmg.sh";
9+10+function makeApp(plistEntries: string[]): string {
11+const dir = mkdtempSync(path.join(tmpdir(), "openclaw-create-dmg-"));
12+tempDirs.push(dir);
13+const app = path.join(dir, "OpenClaw.app");
14+const contents = path.join(app, "Contents");
15+mkdirSync(contents, { recursive: true });
16+writeFileSync(
17+path.join(contents, "Info.plist"),
18+[
19+'<?xml version="1.0" encoding="UTF-8"?>',
20+'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
21+'<plist version="1.0">',
22+"<dict>",
23+ ...plistEntries,
24+"</dict>",
25+"</plist>",
26+"",
27+].join("\n"),
28+"utf8",
29+);
30+return app;
31+}
32+33+function runScript(args: string[]) {
34+return spawnSync("bash", [scriptPath, ...args], {
35+cwd: process.cwd(),
36+encoding: "utf8",
37+});
38+}
39+40+afterEach(() => {
41+for (const dir of tempDirs.splice(0)) {
42+rmSync(dir, { recursive: true, force: true });
43+}
44+});
45+46+describe("create-dmg plist validation", () => {
47+it("fails closed for required Info.plist reads", () => {
48+const script = readFileSync(scriptPath, "utf8");
49+const readBlock = script.slice(
50+script.indexOf("APP_NAME="),
51+script.indexOf('DMG_NAME="${APP_NAME}-${VERSION}.dmg"'),
52+);
53+54+expect(script).toContain('source "$ROOT_DIR/scripts/lib/plistbuddy.sh"');
55+expect(readBlock).toContain(
56+'APP_NAME="$(plist_print_required "$APP_PATH/Contents/Info.plist" CFBundleName)"',
57+);
58+expect(readBlock).toContain(
59+'VERSION="$(plist_print_required "$APP_PATH/Contents/Info.plist" CFBundleShortVersionString)"',
60+);
61+expect(readBlock).not.toContain("PlistBuddy");
62+expect(readBlock).not.toContain("|| echo");
63+});
64+65+it.runIf(process.platform === "darwin")(
66+"fails before hdiutil when required plist keys are missing",
67+() => {
68+const app = makeApp([
69+"<key>CFBundleName</key>",
70+"<string>OpenClaw</string>",
71+]);
72+const result = runScript([app, path.join(path.dirname(app), "out.dmg")]);
73+74+expect(result.status).toBe(1);
75+expect(result.stderr).toContain("Does Not Exist");
76+expect(result.stdout).not.toContain("Creating DMG:");
77+},
78+);
79+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。