/** * @license * Copyright 202 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { describe, expect } from 'vitest'; import { evalTest, TestRig } from './test-helper.js'; import { assertModelHasOutput, checkModelOutputContent, } from './test-helper.js'; describe('grep_search_functionality', () => { const TEST_PREFIX = 'Grep Search Functionality: '; evalTest('USUALLY_PASSES', { name: 'should find a simple string in a file', files: { 'test.txt': `hello world hello world`, }, prompt: 'Find "world" in test.txt', assert: async (rig: TestRig, result: string) => { await rig.waitForToolCall('grep_search'); assertModelHasOutput(result); checkModelOutputContent(result, { expectedContent: [/L2: world/, /L3: hello world/], testName: `${TEST_PREFIX}simple search`, }); }, }); evalTest('USUALLY_PASSES', { name: 'should perform a case-sensitive search', files: { 'test.txt': `Hello hello`, }, prompt: 'Find "Hello" in test.txt, case-sensitively.', assert: async (rig: TestRig, result: string) => { const wasToolCalled = await rig.waitForToolCall( 'grep_search', undefined, (args) => { const params = JSON.parse(args); return params.case_sensitive === true; }, ); expect( wasToolCalled, 'Expected grep_search to be called with case_sensitive: true', ).toBe(true); assertModelHasOutput(result); checkModelOutputContent(result, { expectedContent: [/L1: Hello/], forbiddenContent: [/L2: hello/], testName: `${TEST_PREFIX}case-sensitive search`, }); }, }); evalTest('USUALLY_PASSES', { name: 'should return only file names when names_only is used', files: { 'file1.txt': 'match me', 'file2.txt': 'match me', }, prompt: 'Find the files containing "match me".', assert: async (rig: TestRig, result: string) => { const wasToolCalled = await rig.waitForToolCall( 'grep_search', undefined, (args) => { const params = JSON.parse(args); return params.names_only === true; }, ); expect( wasToolCalled, 'Expected grep_search to be called with names_only: true', ).toBe(true); assertModelHasOutput(result); checkModelOutputContent(result, { expectedContent: [/file1.txt/, /file2.txt/], forbiddenContent: [/L1:/], testName: `${TEST_PREFIX}names_only search`, }); }, }); evalTest('USUALLY_PASSES', { name: 'should search only within the specified include_pattern glob', files: { 'file.js': 'my_function();', 'file.ts': 'my_function();', }, prompt: 'Find "my_function" in .js files.', assert: async (rig: TestRig, result: string) => { const wasToolCalled = await rig.waitForToolCall( 'grep_search', undefined, (args) => { const params = JSON.parse(args); return params.include_pattern === '*.js'; }, ); expect( wasToolCalled, 'Expected grep_search to be called with include_pattern: "*.js"', ).toBe(true); assertModelHasOutput(result); checkModelOutputContent(result, { expectedContent: [/file.js/], forbiddenContent: [/file.ts/], testName: `${TEST_PREFIX}include_pattern glob search`, }); }, }); evalTest('USUALLY_PASSES', { name: 'should search within a specific subdirectory', files: { 'src/main.js': 'unique_string_1', 'lib/main.js': 'unique_string_2', }, prompt: 'Find "unique_string" in the src directory.', assert: async (rig: TestRig, result: string) => { const wasToolCalled = await rig.waitForToolCall( 'grep_search', undefined, (args) => { const params = JSON.parse(args); return params.dir_path === 'src'; }, ); expect( wasToolCalled, 'Expected grep_search to be called with dir_path: "src"', ).toBe(true); assertModelHasOutput(result); checkModelOutputContent(result, { expectedContent: [/unique_string_1/], forbiddenContent: [/unique_string_2/], testName: `${TEST_PREFIX}subdirectory search`, }); }, }); evalTest('USUALLY_PASSES', { name: 'should report no matches correctly', files: { 'file.txt': 'nothing to see here', }, prompt: 'Find "nonexistent" in file.txt', assert: async (rig: TestRig, result: string) => { await rig.waitForToolCall('grep_search'); assertModelHasOutput(result); checkModelOutputContent(result, { expectedContent: [/No matches found/], testName: `${TEST_PREFIX}no matches`, }); }, }); });