mirror of
https://github.com/morluto/rea.git
synced 2026-10-11 21:39:55 +00:00
test(cli): consolidate schema coverage and assert input refusals
Remove 30 redundant truthy-JSON schema checks. Validate advertised groups and property parity across every primary command, retain required-field checks, and assert structured malformed-input errors. Exercise JEB positional validation rather than an unknown flag. Validation: 13 public CLI adapter tests, combined checks, and temporary-directory hygiene. Host configuration refusal coverage from main is preserved.
This commit is contained in:
@@ -5,38 +5,6 @@ import {
|
||||
serveCli as serve,
|
||||
} from "./cliServeHarness.js";
|
||||
|
||||
it.each([
|
||||
["inspect-adb-client"],
|
||||
["list-adb-devices"],
|
||||
["inspect-adb-device"],
|
||||
["list-adb-packages"],
|
||||
["pull-adb-package"],
|
||||
["read-adb-logcat"],
|
||||
["inspect-adb-package"],
|
||||
["pull-adb-file"],
|
||||
["push-adb-file"],
|
||||
["capture-adb-screen"],
|
||||
["list-adb-processes"],
|
||||
["list-adb-directory"],
|
||||
["list-adb-features"],
|
||||
["list-adb-services"],
|
||||
["inspect-adb-display"],
|
||||
["inspect-adb-window"],
|
||||
["read-adb-setting"],
|
||||
["collect-adb-bugreport"],
|
||||
["resolve-adb-packages"],
|
||||
["install-adb-package"],
|
||||
["uninstall-adb-package"],
|
||||
["start-adb-app"],
|
||||
["start-adb-activity"],
|
||||
["stop-adb-app"],
|
||||
])("%s advertises a schema through the public CLI", async (command) => {
|
||||
const result = await serve([command, "--schema", "--json"]);
|
||||
expect(result.exitCode, command).toBe(0);
|
||||
const schema = JSON.parse(result.stdout) as { args?: unknown };
|
||||
expect(schema).toBeTruthy();
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
["inspect-adb-client", "--json"],
|
||||
@@ -63,7 +31,10 @@ it.each([
|
||||
|
||||
it("validates device serials before contacting any device", async () => {
|
||||
const result = await serve(["inspect-adb-device", "bad serial", "--json"]);
|
||||
expect(result.stdout).toContain("invalid_input");
|
||||
expect(JSON.parse(result.stdout)).toMatchObject({
|
||||
code: "invalid_request",
|
||||
category: "invalid_input",
|
||||
});
|
||||
});
|
||||
|
||||
it("requires the output directory option on pull", async () => {
|
||||
|
||||
@@ -5,16 +5,6 @@ import {
|
||||
serveCli as serve,
|
||||
} from "./cliServeHarness.js";
|
||||
|
||||
it.each(["inspect-apktool-client", "decode-android-resources"])(
|
||||
"%s advertises a schema through the public CLI",
|
||||
async (command) => {
|
||||
const result = await serve([command, "--schema", "--json"]);
|
||||
expect(result.exitCode, command).toBe(0);
|
||||
const schema = JSON.parse(result.stdout) as { args?: unknown };
|
||||
expect(schema).toBeTruthy();
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[
|
||||
["inspect-apktool-client", "--json"],
|
||||
@@ -47,5 +37,14 @@ it("validates the locale option before launching apktool", async () => {
|
||||
"not a locale",
|
||||
"--json",
|
||||
]);
|
||||
expect(result.stdout).toContain("invalid");
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(JSON.parse(result.stdout)).toMatchObject({
|
||||
code: "VALIDATION_ERROR",
|
||||
fieldErrors: [
|
||||
{
|
||||
code: "invalid_format",
|
||||
path: "locale",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ const registeredCommands: WeakMap<object, CommandMap> = Cli.toCommands;
|
||||
|
||||
const advertisedGroupSchema = z
|
||||
.object({
|
||||
properties: z.record(z.string(), z.unknown()).optional(),
|
||||
properties: z.record(z.string(), z.unknown()),
|
||||
required: z.array(z.string()).optional(),
|
||||
})
|
||||
.loose();
|
||||
@@ -70,8 +70,27 @@ describe("CLI advertised input schemas", () => {
|
||||
for (const command of createCliInventory(cli).primary) {
|
||||
const advertised = await advertisedSchema(cli, command);
|
||||
for (const group of INPUT_GROUPS) {
|
||||
const required = (advertised[group]?.required ?? []).toSorted();
|
||||
const rejected = omissionRejected(parserSchema(cli, command, group));
|
||||
const parser = parserSchema(cli, command, group);
|
||||
const advertisedGroup = advertised[group];
|
||||
if (parser === undefined) {
|
||||
if (advertisedGroup !== undefined)
|
||||
mismatches.push(`${command} ${group}: advertised without parser`);
|
||||
continue;
|
||||
}
|
||||
if (advertisedGroup === undefined) {
|
||||
mismatches.push(`${command} ${group}: parser group not advertised`);
|
||||
continue;
|
||||
}
|
||||
const parserProperties = Object.keys(parser.shape).toSorted();
|
||||
const advertisedProperties = Object.keys(
|
||||
advertisedGroup.properties,
|
||||
).toSorted();
|
||||
if (advertisedProperties.join() !== parserProperties.join())
|
||||
mismatches.push(
|
||||
`${command} ${group}: advertised properties [${advertisedProperties.join()}], parser properties [${parserProperties.join()}]`,
|
||||
);
|
||||
const required = (advertisedGroup.required ?? []).toSorted();
|
||||
const rejected = omissionRejected(parser);
|
||||
if (required.join() !== rejected.join())
|
||||
mismatches.push(
|
||||
`${command} ${group}: advertised [${required.join()}], parser rejects [${rejected.join()}]`,
|
||||
|
||||
@@ -11,18 +11,6 @@ const serve = async (
|
||||
): Promise<{ readonly stdout: string; readonly exitCode: number }> =>
|
||||
serveCli(argv, jebEnvironment);
|
||||
|
||||
it.each([
|
||||
["inspect-jeb-client"],
|
||||
["open-jeb-project"],
|
||||
["list-jeb-units"],
|
||||
["decompile-jeb-item"],
|
||||
])("%s advertises a schema through the public CLI", async (command) => {
|
||||
const result = await serve([command, "--schema", "--json"]);
|
||||
expect(result.exitCode, command).toBe(0);
|
||||
const schema = JSON.parse(result.stdout) as { args?: unknown };
|
||||
expect(schema).toBeTruthy();
|
||||
});
|
||||
|
||||
it("reports an unreachable engine endpoint with recovery guidance", async () => {
|
||||
const result = await serve(["inspect-jeb-client", "--json"]);
|
||||
expect(result.stdout).toContain("capability_unavailable");
|
||||
@@ -30,13 +18,15 @@ it("reports an unreachable engine endpoint with recovery guidance", async () =>
|
||||
});
|
||||
|
||||
it("validates decompile item input before contacting the engine", async () => {
|
||||
const result = await serve([
|
||||
"decompile-jeb-item",
|
||||
"not-an-address",
|
||||
"--item-kind",
|
||||
"method",
|
||||
"--json",
|
||||
]);
|
||||
expect(result.stdout).toBeTruthy();
|
||||
expect(result.stdout).not.toContain("capability_unavailable");
|
||||
const result = await serve(["decompile-jeb-item", "", "method", "--json"]);
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(JSON.parse(result.stdout)).toMatchObject({
|
||||
code: "VALIDATION_ERROR",
|
||||
fieldErrors: [
|
||||
{
|
||||
code: "too_small",
|
||||
path: "item-address",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user