Files
rea/tests/boundary/filesystem/hopperLauncherSelection.test.ts
T
Ysopwnable 044fb9127a fix(hopper): skip non-file launcher candidates
Require automatically discovered Hopper launchers to be executable regular
files so POSIX directory search permission cannot hide a later valid
application bundle. Preserve file symlinks, explicit caller configuration,
and the shared candidate ordering.

Cover canonical and renamed user bundles through the production filesystem
predicate; respect existing canonical or renamed system installations in
the isolated fixtures. Clarify launcher eligibility in the installation guide.

Follow-up to #3085 and #3054 after their shared path discovery landed on main.

Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-15 00:09:42 +08:00

35 lines
1.3 KiB
TypeScript

import { accessSync, constants, statSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { expect, it } from "vitest";
import { defaultHopperLauncherPath } from "../../../src/config/parseConfig.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
// A real system installation legitimately precedes this isolated user fixture.
const installedSystemHopper = (home: string): boolean => {
try {
const launcher = defaultHopperLauncherPath("darwin", home);
accessSync(launcher, constants.X_OK);
return statSync(launcher).isFile();
} catch {
return false;
}
};
it.for(["Hopper Disassembler.app", "Hopper A.app"])(
"skips a directory launcher in %s and selects a real file",
async (name, context) => {
const home = await createTestTempDirectory("rea-hopper-selection-");
if (installedSystemHopper(home)) context.skip();
const invalid = join(home, "Applications", name, "Contents/MacOS/hopper");
const valid = join(home, "Applications/Hopper Z.app/Contents/MacOS/hopper");
await mkdir(invalid, { recursive: true });
await mkdir(dirname(valid), { recursive: true });
await writeFile(valid, "#!/bin/sh\nexit 0\n", { mode: 0o700 });
expect(defaultHopperLauncherPath("darwin", home)).toBe(valid);
},
);