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) }) })