diff --git a/tests/acceptance/applications/peResources.test.ts b/tests/acceptance/applications/peResources.test.ts index 73a49a144c..202a19e9d4 100644 --- a/tests/acceptance/applications/peResources.test.ts +++ b/tests/acceptance/applications/peResources.test.ts @@ -11,14 +11,17 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { parseMcpToolError } from "../../fixtures/mcpToolError.js"; import { cliTest, type TestCli } from "../../support/cli/cliFixture.js"; +type PeResourceCall = ( + arguments_: Record, +) => ReturnType; + const expectPeInputFailureAcrossAdapters = async (input: { readonly cli: TestCli; - readonly client: Client; - readonly toolName: string; + readonly call: PeResourceCall; readonly path: string; readonly reason: "invalid_format" | "invalid_value"; }) => { - const { cli, client, toolName, path, reason } = input; + const { cli, call, path, reason } = input; const result = await cli.run({ arguments: ["inspect-pe-resources", path, "--json"], }); @@ -31,21 +34,17 @@ const expectPeInputFailureAcrossAdapters = async (input: { issues: [{ path: ["path"], reason }], }, }); - const response = await client.callTool({ - name: toolName, - arguments: { path }, - }); + const response = await call({ path }); expect(response.isError).toBe(true); expect(parseMcpToolError(response)).toEqual({ error: result.json }); }; const expectPePaddingFailureAcrossAdapters = async (input: { readonly cli: TestCli; - readonly client: Client; - readonly toolName: string; + readonly call: PeResourceCall; readonly path: string; }) => { - const { cli, client, toolName, path } = input; + const { cli, call, path } = input; const fixture = peResourceFixture(); const virtualSize = fixture.bytes.readUInt32LE(fixture.sectionAt + 8); fixture.bytes.writeUInt32LE( @@ -58,10 +57,7 @@ const expectPePaddingFailureAcrossAdapters = async (input: { arguments: ["inspect-pe-resources", path, "--json"], }); expect(cliResult.exitCode).not.toBe(0); - const mcpResult = await client.callTool({ - name: toolName, - arguments: { path }, - }); + const mcpResult = await call({ path }); expect(mcpResult.isError).toBe(true); expect(peResourcesSchema.safeParse(mcpResult.structuredContent).success).toBe( false, @@ -70,11 +66,10 @@ const expectPePaddingFailureAcrossAdapters = async (input: { const expectPeInputFailuresAcrossAdapters = async (input: { readonly cli: TestCli; - readonly client: Client; - readonly toolName: string; + readonly call: PeResourceCall; readonly root: string; }) => { - const { cli, client, toolName, root } = input; + const { cli, call, root } = input; const malformedPath = join(root, "malformed.exe"); await writeFile(malformedPath, Buffer.from("not a PE image")); for (const [path, reason] of [ @@ -83,8 +78,7 @@ const expectPeInputFailuresAcrossAdapters = async (input: { ] as const) await expectPeInputFailureAcrossAdapters({ cli, - client, - toolName, + call, path, reason, }); @@ -94,13 +88,10 @@ const contract = toolContract("inspect_pe_resources"); const expectPeWordAlignedRecordsAcrossAdapters = async (input: { readonly cli: TestCli; - readonly client: Client; + readonly call: PeResourceCall; readonly root: string; - readonly definition: Awaited< - ReturnType - >["tools"][number]; }): Promise => { - const { cli, client, root, definition } = input; + const { cli, call, root } = input; for (const plus of [false, true]) { for (const [index, identities] of [ { type: 10, name: 1, language: "AB" }, @@ -131,10 +122,7 @@ const expectPeWordAlignedRecordsAcrossAdapters = async (input: { expect(report.resources[0]?.payload.sha256).toBe( createHash("sha256").update("opaque resource").digest("hex"), ); - const response = await client.callTool( - { name: definition.name, arguments: { path } }, - { toolDefinition: definition }, - ); + const response = await call({ path }); expect(response.isError).not.toBe(true); expect( contract.outputSchema.parse(response.structuredContent) @@ -147,7 +135,7 @@ const expectPeWordAlignedRecordsAcrossAdapters = async (input: { const expectPeMappingOwnershipAcrossAdapters = async ( cli: TestCli, - client: Client, + call: PeResourceCall, root: string, ): Promise => { for (const { name, payloadRva, payloadBytes, section, expectedOffset } of [ @@ -202,8 +190,7 @@ const expectPeMappingOwnershipAcrossAdapters = async ( if (expectedOffset === null) { await expectPeInputFailureAcrossAdapters({ cli, - client, - toolName: contract.name, + call, path, reason: "invalid_format", }); @@ -214,10 +201,7 @@ const expectPeMappingOwnershipAcrossAdapters = async ( }); expect(result.exitCode, name).toBe(0); const evidence = contract.outputSchema.parse(result.json); - const response = await client.callTool({ - name: contract.name, - arguments: { path }, - }); + const response = await call({ path }); expect(response.isError, name).not.toBe(true); const mcp = contract.outputSchema.parse(response.structuredContent); expect(mcp.subject).toEqual(evidence.subject); @@ -245,7 +229,7 @@ const expectPeMappingOwnershipAcrossAdapters = async ( const expectPeInventoriesAcrossAdapters = async ( cli: TestCli, - client: Client, + call: PeResourceCall, root: string, ): Promise => { for (const [plus, empty] of [ @@ -304,10 +288,7 @@ const expectPeInventoriesAcrossAdapters = async ( same_language_resource_index: null, }, ]); - const response = await client.callTool({ - name: contract.name, - arguments: { path }, - }); + const response = await call({ path }); expect(response.isError).not.toBe(true); const mcp = contract.outputSchema.parse(response.structuredContent); expect(mcp.subject).toEqual(evidence.subject); @@ -351,41 +332,45 @@ cliTest( }), }), ); - const session = await client.callTool({ - name: "binary_session", - arguments: {}, - }); + const call: PeResourceCall = (arguments_) => + client.callTool( + { name: definition.name, arguments: arguments_ }, + { toolDefinition: definition }, + ); + const sessionDefinition = inventory.tools.find( + ({ name }) => name === "binary_session", + ); + if (sessionDefinition === undefined) + throw new Error("Missing binary_session tool contract"); + const session = await client.callTool( + { name: sessionDefinition.name, arguments: {} }, + { toolDefinition: sessionDefinition }, + ); expect(JSON.stringify(session.structuredContent)).toContain( "inspect_pe_resources", ); - await expectPeInventoriesAcrossAdapters(cli, client, root); + await expectPeInventoriesAcrossAdapters(cli, call, root); await expectPeWordAlignedRecordsAcrossAdapters({ cli, - client, + call, root, - definition, }); - await expectPeMappingOwnershipAcrossAdapters(cli, client, root); + await expectPeMappingOwnershipAcrossAdapters(cli, call, root); await expectPePaddingFailureAcrossAdapters({ cli, - client, - toolName: contract.name, + call, path: join(root, "raw-padding.exe"), }); await expectPeInputFailuresAcrossAdapters({ cli, - client, - toolName: contract.name, + call, root, }); const absent = peResourceFixture(); absent.bytes.fill(0, absent.directoryAt, absent.directoryAt + 8); const path = join(root, "absent.exe"); await writeFile(path, absent.bytes); - const empty = await client.callTool({ - name: contract.name, - arguments: { path }, - }); + const empty = await call({ path }); expect(empty.isError).not.toBe(true); expect( contract.outputSchema.parse(empty.structuredContent).normalized_result, @@ -399,10 +384,7 @@ cliTest( { path: "relative.exe" }, { path, extra: true }, ]) { - const rejected = await client.callTool({ - name: contract.name, - arguments: arguments_, - }); + const rejected = await call(arguments_); expect(rejected.isError).toBe(true); expect( contract.outputSchema.safeParse(rejected.structuredContent).success, @@ -412,10 +394,7 @@ cliTest( damaged.bytes.writeUInt32LE(17, damaged.directoryAt + 4); const badPath = join(root, "damaged.exe"); await writeFile(badPath, damaged.bytes); - const rejected = await client.callTool({ - name: contract.name, - arguments: { path: badPath }, - }); + const rejected = await call({ path: badPath }); expect(rejected.isError).toBe(true); expect( contract.outputSchema.safeParse(rejected.structuredContent).success,