Added comprehensive test coverage for FilesystemTool (ReadFileTool, WriteFileTool, ListDirTool) with 10 test cases: - TestFilesystemTool_ReadFile_Success: Verifies file content goes to ForLLM - TestFilesystemTool_ReadFile_NotFound: Verifies error handling for missing files - TestFilesystemTool_ReadFile_MissingPath: Verifies missing parameter handling - TestFilesystemTool_WriteFile_Success: Verifies SilentResult behavior - TestFilesystemTool_WriteFile_CreateDir: Verifies automatic directory creation - TestFilesystemTool_WriteFile_MissingPath: Verifies missing path parameter handling - TestFilesystemTool_WriteFile_MissingContent: Verifies missing content parameter handling - TestFilesystemTool_ListDir_Success: Verifies directory listing functionality - TestFilesystemTool_ListDir_NotFound: Verifies error handling for invalid paths - TestFilesystemTool_ListDir_DefaultPath: Verifies default to current directory FilesystemTool implementation already conforms to ToolResult specification: - ReadFile/ListDir return NewToolResult (ForLLM only, ForUser empty) - WriteFile returns SilentResult (Silent=true, ForUser empty) - Errors return ErrorResult with IsError=true Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
250 lines
7.2 KiB
Go
250 lines
7.2 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestFilesystemTool_ReadFile_Success verifies successful file reading
|
|
func TestFilesystemTool_ReadFile_Success(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
testFile := filepath.Join(tmpDir, "test.txt")
|
|
os.WriteFile(testFile, []byte("test content"), 0644)
|
|
|
|
tool := &ReadFileTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"path": testFile,
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Success should not be an error
|
|
if result.IsError {
|
|
t.Errorf("Expected success, got IsError=true: %s", result.ForLLM)
|
|
}
|
|
|
|
// ForLLM should contain file content
|
|
if !strings.Contains(result.ForLLM, "test content") {
|
|
t.Errorf("Expected ForLLM to contain 'test content', got: %s", result.ForLLM)
|
|
}
|
|
|
|
// ReadFile returns NewToolResult which only sets ForLLM, not ForUser
|
|
// This is the expected behavior - file content goes to LLM, not directly to user
|
|
if result.ForUser != "" {
|
|
t.Errorf("Expected ForUser to be empty for NewToolResult, got: %s", result.ForUser)
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_ReadFile_NotFound verifies error handling for missing file
|
|
func TestFilesystemTool_ReadFile_NotFound(t *testing.T) {
|
|
tool := &ReadFileTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"path": "/nonexistent_file_12345.txt",
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Failure should be marked as error
|
|
if !result.IsError {
|
|
t.Errorf("Expected error for missing file, got IsError=false")
|
|
}
|
|
|
|
// Should contain error message
|
|
if !strings.Contains(result.ForLLM, "failed to read") && !strings.Contains(result.ForUser, "failed to read") {
|
|
t.Errorf("Expected error message, got ForLLM: %s, ForUser: %s", result.ForLLM, result.ForUser)
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_ReadFile_MissingPath verifies error handling for missing path
|
|
func TestFilesystemTool_ReadFile_MissingPath(t *testing.T) {
|
|
tool := &ReadFileTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Should return error result
|
|
if !result.IsError {
|
|
t.Errorf("Expected error when path is missing")
|
|
}
|
|
|
|
// Should mention required parameter
|
|
if !strings.Contains(result.ForLLM, "path is required") && !strings.Contains(result.ForUser, "path is required") {
|
|
t.Errorf("Expected 'path is required' message, got ForLLM: %s", result.ForLLM)
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_WriteFile_Success verifies successful file writing
|
|
func TestFilesystemTool_WriteFile_Success(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
testFile := filepath.Join(tmpDir, "newfile.txt")
|
|
|
|
tool := &WriteFileTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"path": testFile,
|
|
"content": "hello world",
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Success should not be an error
|
|
if result.IsError {
|
|
t.Errorf("Expected success, got IsError=true: %s", result.ForLLM)
|
|
}
|
|
|
|
// WriteFile returns SilentResult
|
|
if !result.Silent {
|
|
t.Errorf("Expected Silent=true for WriteFile, got false")
|
|
}
|
|
|
|
// ForUser should be empty (silent result)
|
|
if result.ForUser != "" {
|
|
t.Errorf("Expected ForUser to be empty for SilentResult, got: %s", result.ForUser)
|
|
}
|
|
|
|
// Verify file was actually written
|
|
content, err := os.ReadFile(testFile)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read written file: %v", err)
|
|
}
|
|
if string(content) != "hello world" {
|
|
t.Errorf("Expected file content 'hello world', got: %s", string(content))
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_WriteFile_CreateDir verifies directory creation
|
|
func TestFilesystemTool_WriteFile_CreateDir(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
testFile := filepath.Join(tmpDir, "subdir", "newfile.txt")
|
|
|
|
tool := &WriteFileTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"path": testFile,
|
|
"content": "test",
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Success should not be an error
|
|
if result.IsError {
|
|
t.Errorf("Expected success with directory creation, got IsError=true: %s", result.ForLLM)
|
|
}
|
|
|
|
// Verify directory was created and file written
|
|
content, err := os.ReadFile(testFile)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read written file: %v", err)
|
|
}
|
|
if string(content) != "test" {
|
|
t.Errorf("Expected file content 'test', got: %s", string(content))
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_WriteFile_MissingPath verifies error handling for missing path
|
|
func TestFilesystemTool_WriteFile_MissingPath(t *testing.T) {
|
|
tool := &WriteFileTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"content": "test",
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Should return error result
|
|
if !result.IsError {
|
|
t.Errorf("Expected error when path is missing")
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_WriteFile_MissingContent verifies error handling for missing content
|
|
func TestFilesystemTool_WriteFile_MissingContent(t *testing.T) {
|
|
tool := &WriteFileTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"path": "/tmp/test.txt",
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Should return error result
|
|
if !result.IsError {
|
|
t.Errorf("Expected error when content is missing")
|
|
}
|
|
|
|
// Should mention required parameter
|
|
if !strings.Contains(result.ForLLM, "content is required") && !strings.Contains(result.ForUser, "content is required") {
|
|
t.Errorf("Expected 'content is required' message, got ForLLM: %s", result.ForLLM)
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_ListDir_Success verifies successful directory listing
|
|
func TestFilesystemTool_ListDir_Success(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
os.WriteFile(filepath.Join(tmpDir, "file1.txt"), []byte("content"), 0644)
|
|
os.WriteFile(filepath.Join(tmpDir, "file2.txt"), []byte("content"), 0644)
|
|
os.Mkdir(filepath.Join(tmpDir, "subdir"), 0755)
|
|
|
|
tool := &ListDirTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"path": tmpDir,
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Success should not be an error
|
|
if result.IsError {
|
|
t.Errorf("Expected success, got IsError=true: %s", result.ForLLM)
|
|
}
|
|
|
|
// Should list files and directories
|
|
if !strings.Contains(result.ForLLM, "file1.txt") || !strings.Contains(result.ForLLM, "file2.txt") {
|
|
t.Errorf("Expected files in listing, got: %s", result.ForLLM)
|
|
}
|
|
if !strings.Contains(result.ForLLM, "subdir") {
|
|
t.Errorf("Expected subdir in listing, got: %s", result.ForLLM)
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_ListDir_NotFound verifies error handling for non-existent directory
|
|
func TestFilesystemTool_ListDir_NotFound(t *testing.T) {
|
|
tool := &ListDirTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{
|
|
"path": "/nonexistent_directory_12345",
|
|
}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Failure should be marked as error
|
|
if !result.IsError {
|
|
t.Errorf("Expected error for non-existent directory, got IsError=false")
|
|
}
|
|
|
|
// Should contain error message
|
|
if !strings.Contains(result.ForLLM, "failed to read") && !strings.Contains(result.ForUser, "failed to read") {
|
|
t.Errorf("Expected error message, got ForLLM: %s, ForUser: %s", result.ForLLM, result.ForUser)
|
|
}
|
|
}
|
|
|
|
// TestFilesystemTool_ListDir_DefaultPath verifies default to current directory
|
|
func TestFilesystemTool_ListDir_DefaultPath(t *testing.T) {
|
|
tool := &ListDirTool{}
|
|
ctx := context.Background()
|
|
args := map[string]interface{}{}
|
|
|
|
result := tool.Execute(ctx, args)
|
|
|
|
// Should use "." as default path
|
|
if result.IsError {
|
|
t.Errorf("Expected success with default path '.', got IsError=true: %s", result.ForLLM)
|
|
}
|
|
}
|