diff options
| author | Kujtim Hoxha <[email protected]> | 2025-03-27 22:35:48 +0100 |
|---|---|---|
| committer | Kujtim Hoxha <[email protected]> | 2025-04-01 13:38:54 +0200 |
| commit | afd9ad0560d76c2a6d161dad52553b10ff428905 (patch) | |
| tree | 69f78b05ff0d7952cd3e3c9332f001e66abb2faf /internal/llm/tools/write_test.go | |
| parent | 904061c243f70696bfe781e97bf4e392e6954d07 (diff) | |
| download | opencode-afd9ad0560d76c2a6d161dad52553b10ff428905.tar.gz opencode-afd9ad0560d76c2a6d161dad52553b10ff428905.zip | |
rework llm
Diffstat (limited to 'internal/llm/tools/write_test.go')
| -rw-r--r-- | internal/llm/tools/write_test.go | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/internal/llm/tools/write_test.go b/internal/llm/tools/write_test.go new file mode 100644 index 000000000..1c92e3baa --- /dev/null +++ b/internal/llm/tools/write_test.go @@ -0,0 +1,324 @@ +package tools + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "testing" + "time" + + "github.com/kujtimiihoxha/termai/internal/permission" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWriteTool_Info(t *testing.T) { + tool := NewWriteTool() + info := tool.Info() + + assert.Equal(t, WriteToolName, info.Name) + assert.NotEmpty(t, info.Description) + assert.Contains(t, info.Parameters, "file_path") + assert.Contains(t, info.Parameters, "content") + assert.Contains(t, info.Required, "file_path") + assert.Contains(t, info.Required, "content") +} + +func TestWriteTool_Run(t *testing.T) { + // Setup a mock permission handler that always allows + origPermission := permission.Default + defer func() { + permission.Default = origPermission + }() + permission.Default = newMockPermissionService(true) + + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "write_tool_test") + require.NoError(t, err) + defer os.RemoveAll(tempDir) + + t.Run("creates a new file successfully", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + filePath := filepath.Join(tempDir, "new_file.txt") + content := "This is a test content" + + params := WriteParams{ + FilePath: filePath, + Content: content, + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "successfully written") + + // Verify file was created with correct content + fileContent, err := os.ReadFile(filePath) + require.NoError(t, err) + assert.Equal(t, content, string(fileContent)) + }) + + t.Run("creates file with nested directories", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + filePath := filepath.Join(tempDir, "nested/dirs/new_file.txt") + content := "Content in nested directory" + + params := WriteParams{ + FilePath: filePath, + Content: content, + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "successfully written") + + // Verify file was created with correct content + fileContent, err := os.ReadFile(filePath) + require.NoError(t, err) + assert.Equal(t, content, string(fileContent)) + }) + + t.Run("updates existing file", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + // Create a file first + filePath := filepath.Join(tempDir, "existing_file.txt") + initialContent := "Initial content" + err := os.WriteFile(filePath, []byte(initialContent), 0644) + require.NoError(t, err) + + // Record the file read to avoid modification time check failure + recordFileRead(filePath) + + // Update the file + updatedContent := "Updated content" + params := WriteParams{ + FilePath: filePath, + Content: updatedContent, + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "successfully written") + + // Verify file was updated with correct content + fileContent, err := os.ReadFile(filePath) + require.NoError(t, err) + assert.Equal(t, updatedContent, string(fileContent)) + }) + + t.Run("handles invalid parameters", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + call := ToolCall{ + Name: WriteToolName, + Input: "invalid json", + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "error parsing parameters") + }) + + t.Run("handles missing file_path", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + params := WriteParams{ + FilePath: "", + Content: "Some content", + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "file_path is required") + }) + + t.Run("handles missing content", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + params := WriteParams{ + FilePath: filepath.Join(tempDir, "file.txt"), + Content: "", + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "content is required") + }) + + t.Run("handles writing to a directory path", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + // Create a directory + dirPath := filepath.Join(tempDir, "test_dir") + err := os.Mkdir(dirPath, 0755) + require.NoError(t, err) + + params := WriteParams{ + FilePath: dirPath, + Content: "Some content", + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "Path is a directory") + }) + + t.Run("handles permission denied", func(t *testing.T) { + permission.Default = newMockPermissionService(false) + tool := NewWriteTool() + + filePath := filepath.Join(tempDir, "permission_denied.txt") + params := WriteParams{ + FilePath: filePath, + Content: "Content that should not be written", + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "Permission denied") + + // Verify file was not created + _, err = os.Stat(filePath) + assert.True(t, os.IsNotExist(err)) + }) + + t.Run("detects file modified since last read", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + // Create a file + filePath := filepath.Join(tempDir, "modified_file.txt") + initialContent := "Initial content" + err := os.WriteFile(filePath, []byte(initialContent), 0644) + require.NoError(t, err) + + // Record an old read time + fileRecordMutex.Lock() + fileRecords[filePath] = fileRecord{ + path: filePath, + readTime: time.Now().Add(-1 * time.Hour), + } + fileRecordMutex.Unlock() + + // Try to update the file + params := WriteParams{ + FilePath: filePath, + Content: "Updated content", + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "has been modified since it was last read") + + // Verify file was not modified + fileContent, err := os.ReadFile(filePath) + require.NoError(t, err) + assert.Equal(t, initialContent, string(fileContent)) + }) + + t.Run("skips writing when content is identical", func(t *testing.T) { + permission.Default = newMockPermissionService(true) + tool := NewWriteTool() + + // Create a file + filePath := filepath.Join(tempDir, "identical_content.txt") + content := "Content that won't change" + err := os.WriteFile(filePath, []byte(content), 0644) + require.NoError(t, err) + + // Record a read time + recordFileRead(filePath) + + // Try to write the same content + params := WriteParams{ + FilePath: filePath, + Content: content, + } + + paramsJSON, err := json.Marshal(params) + require.NoError(t, err) + + call := ToolCall{ + Name: WriteToolName, + Input: string(paramsJSON), + } + + response, err := tool.Run(context.Background(), call) + require.NoError(t, err) + assert.Contains(t, response.Content, "already contains the exact content") + }) +}
\ No newline at end of file |
