import { describe, expect, test } from "bun:test"; import { getAllBaseTools, parseToolPreset, getTools } from "../../src/tools.ts"; import { findToolByName, getEmptyToolPermissionContext, buildTool, } from "../../src/Tool.ts"; // ─── Tool Registration & Discovery ────────────────────────────────────── describe("Tool chain: registration and discovery", () => { test("getAllBaseTools returns a non-empty array of tools", () => { const tools = getAllBaseTools(); expect(tools.length).toBeGreaterThan(0); }); test("all base tools have required fields", () => { const tools = getAllBaseTools(); for (const tool of tools) { expect(tool.name).toBeTruthy(); expect(tool.description).toBeTruthy(); expect(tool.inputSchema).toBeDefined(); expect(typeof tool.call).toBe("function"); } }); test("findToolByName finds core tools from the full list", () => { const tools = getAllBaseTools(); const bash = findToolByName(tools, "Bash"); expect(bash).toBeDefined(); expect(bash!.name).toBe("Bash"); const read = findToolByName(tools, "Read"); expect(read).toBeDefined(); expect(read!.name).toBe("Read"); const edit = findToolByName(tools, "Edit"); expect(edit).toBeDefined(); expect(edit!.name).toBe("Edit"); }); test("findToolByName returns undefined for non-existent tool", () => { const tools = getAllBaseTools(); expect(findToolByName(tools, "NonExistentTool")).toBeUndefined(); }); test("findToolByName is case-sensitive (exact match only)", () => { const tools = getAllBaseTools(); expect(findToolByName(tools, "Bash")).toBeDefined(); expect(findToolByName(tools, "bash")).toBeUndefined(); }); test("findToolByName resolves via toolMatchesName", () => { const tools = getAllBaseTools(); const agent = findToolByName(tools, "Agent"); expect(agent).toBeDefined(); // Verify it can also find by checking name directly expect(tools.some(t => t.name === "Agent")).toBe(true); }); test("tool names are unique across the base tool list", () => { const tools = getAllBaseTools(); const names = tools.map(t => t.name); expect(new Set(names).size).toBe(names.length); }); }); // ─── Tool Presets ────────────────────────────────────────────────────── describe("Tool chain: presets", () => { test('parseToolPreset("default") returns "default" string', () => { // parseToolPreset returns a preset name string, not a tool array expect(parseToolPreset("default")).toBe("default"); }); test("parseToolPreset returns null for unknown preset", () => { expect(parseToolPreset("nonexistent")).toBeNull(); }); test("parseToolPreset is case-insensitive", () => { expect(parseToolPreset("DEFAULT")).toBe("default"); }); }); // ─── getTools (with permission context) ──────────────────────────────── describe("Tool chain: getTools with context", () => { test("getTools returns tools (subset of base tools)", () => { const allTools = getAllBaseTools(); const ctx = getEmptyToolPermissionContext(); const tools = getTools(ctx); expect(tools.length).toBeGreaterThan(0); expect(tools.length).toBeLessThanOrEqual(allTools.length); }); test("getTools results all have name and call function", () => { const ctx = getEmptyToolPermissionContext(); const tools = getTools(ctx); for (const tool of tools) { expect(tool.name).toBeTruthy(); expect(typeof tool.call).toBe("function"); } }); }); // ─── buildTool + findToolByName end-to-end ───────────────────────────── describe("Tool chain: buildTool + findToolByName", () => { test("a built tool can be found in a custom list", () => { const customTool = buildTool({ name: "TestTool", description: "A test tool", inputSchema: { type: "object" as const, properties: { input: { type: "string" } }, required: ["input"], }, call: async () => ({ output: "test" }), }); const found = findToolByName([customTool], "TestTool"); expect(found).toBe(customTool); }); test("built tool defaults are correctly applied", () => { const tool = buildTool({ name: "MinimalTool", description: "Minimal", inputSchema: { type: "object" as const, properties: {}, }, call: async () => ({}), }); expect(tool.isEnabled()).toBe(true); expect(tool.isConcurrencySafe()).toBe(false); expect(tool.isReadOnly()).toBe(false); expect(tool.isDestructive()).toBe(false); }); });