Files
rea/tests/hopperProviderSelection.test.ts
T
N0zoM1z0 941d7101dd feat(session): add explicit provider registry and target binding
Introduce deterministic deep-provider discovery and immutable per-target routing while retaining disjoint artifact and native capability families.

Expose provider selection consistently through MCP, CLI, environment configuration, session status, prompt completion, typed diagnostics, and generated documentation. Preserve exact provider/profile provenance without request racing or transparent fallback.

Cover overlapping providers, ambiguity, rejection details, cancellation, restoration, package installation, and real Hopper target switching.
2026-07-15 22:13:48 +09:00

93 lines
2.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { parseConfig } from "../src/config.js";
import type { BinaryTarget } from "../src/domain/binaryTarget.js";
import { HopperProvider } from "../src/hopper/HopperProvider.js";
import { silentLogger } from "../src/logger.js";
describe("Hopper provider discovery", () => {
it("reports bounded launcher availability without starting Hopper", () => {
const available = provider(process.execPath).inspectAvailability();
expect(available).toEqual({
status: "available",
code: null,
reason: null,
diagnostics: {
launcher_path: process.execPath,
platform: process.platform,
},
});
const missingPath = "/missing/rea-hopper-launcher";
expect(provider(missingPath).inspectAvailability()).toEqual({
status: "unavailable",
code: "executable_missing",
reason: `Hopper launcher is missing or not executable: ${missingPath}`,
diagnostics: {
launcher_path: missingPath,
platform: process.platform,
},
});
});
it("separates target kind, format, and architecture support", () => {
const hopper = provider(process.execPath);
expect(hopper.inspectTargetSupport(databaseTarget())).toMatchObject({
status: "supported",
});
expect(
hopper.inspectTargetSupport(executableTarget("elf", "x86_64")),
).toMatchObject({ status: "supported" });
expect(hopper.inspectTargetSupport(artifactTarget())).toMatchObject({
status: "unsupported",
code: "target_kind_unsupported",
diagnostics: { target_kind: "archive", target_format: "asar" },
});
expect(
hopper.inspectTargetSupport(executableTargetWithoutArchitecture()),
).toMatchObject({
status: "unsupported",
code: "architecture_unsupported",
});
});
});
const provider = (launcherPath: string): HopperProvider => {
const config = parseConfig({ HOPPER_LAUNCHER_PATH: launcherPath });
if (!config.ok) throw config.error;
return new HopperProvider(config.value, silentLogger);
};
const databaseTarget = (): BinaryTarget => ({
path: "/tmp/fixture.hop",
sha256: "a".repeat(64),
kind: "database",
format: "analysis-database",
});
const executableTarget = (
format: "mach-o" | "elf" | "pe",
architecture: "x86" | "x86_64" | "arm" | "arm64",
): BinaryTarget => ({
path: "/tmp/fixture",
sha256: "b".repeat(64),
kind: "executable",
format,
architecture,
availableArchitectures: [architecture],
});
const executableTargetWithoutArchitecture = (): BinaryTarget => ({
path: "/tmp/fixture",
sha256: "b".repeat(64),
kind: "executable",
format: "elf",
});
const artifactTarget = (): BinaryTarget => ({
path: "/tmp/app.asar",
sha256: "c".repeat(64),
kind: "archive",
format: "asar",
});