Files
osmedeus/internal/functions/file_functions_test.go
T
j3ssie 438d8ec138 feat: implement agent executor with tool calling, sub-agents, and comprehensive test suite
- Add AgentExecutor implementing LLM-based agentic loop with tool calling, max iterations, and stop conditions
- Introduce agent preset tools (bash, file_exists, http_get, run_module, etc.) with extensible registry pattern
- Add sub-agent spawning capability via spawn_agent tool call with recursive depth limits and validation
- Implement ToolExecutor for custom tool execution with template rendering and error handling
- Add agent session persistence and memory management with sliding window configuration
- Create comprehensive E2E test suite covering 15+ agent workflow scenarios (minimal, custom tools, planning, multi-goal, structured output, tracing hooks, file tools, orchestration, Python tools, sub-agents, nested sub-agents, and validation)
- Add agent-and-llm test data directory with 17 YAML workflow fixtures
- Update integration tests to include agent workflow directories
- Add AgentTool and AgentConfig types with validation for duplicate names and unknown presets
- Implement LLM streaming test utilities
- Update documentation (CLAUDE.md, HACKING.md, README.md) with agent features and CLI examples
2026-02-10 08:44:48 +07:00

323 lines
10 KiB
Go

package functions
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRemoveBlankLines(t *testing.T) {
runtime := NewOttoRuntime()
t.Run("removes blank lines from file", func(t *testing.T) {
tmpDir := t.TempDir()
testFile := filepath.Join(tmpDir, "test.txt")
content := "line1\n\nline2\n \nline3\n\n"
err := os.WriteFile(testFile, []byte(content), 0644)
require.NoError(t, err)
result, err := runtime.Execute(`remove_blank_lines("`+testFile+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
// Read back the file and verify
data, err := os.ReadFile(testFile)
require.NoError(t, err)
assert.Equal(t, "line1\nline2\nline3\n", string(data))
})
t.Run("handles file with only blank lines", func(t *testing.T) {
tmpDir := t.TempDir()
testFile := filepath.Join(tmpDir, "blanks.txt")
content := "\n\n \n\t\n"
err := os.WriteFile(testFile, []byte(content), 0644)
require.NoError(t, err)
result, err := runtime.Execute(`remove_blank_lines("`+testFile+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
// File should be empty (no trailing newline since no lines)
data, err := os.ReadFile(testFile)
require.NoError(t, err)
assert.Equal(t, "", string(data))
})
t.Run("handles file with no blank lines", func(t *testing.T) {
tmpDir := t.TempDir()
testFile := filepath.Join(tmpDir, "noblanks.txt")
content := "line1\nline2\nline3\n"
err := os.WriteFile(testFile, []byte(content), 0644)
require.NoError(t, err)
result, err := runtime.Execute(`remove_blank_lines("`+testFile+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
// File should be unchanged
data, err := os.ReadFile(testFile)
require.NoError(t, err)
assert.Equal(t, "line1\nline2\nline3\n", string(data))
})
t.Run("empty path returns false", func(t *testing.T) {
result, err := runtime.Execute(`remove_blank_lines("")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("non-existent file returns false", func(t *testing.T) {
result, err := runtime.Execute(`remove_blank_lines("/nonexistent/file.txt")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("directory path returns false", func(t *testing.T) {
tmpDir := t.TempDir()
result, err := runtime.Execute(`remove_blank_lines("`+tmpDir+`")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("preserves whitespace-only lines at start/middle", func(t *testing.T) {
tmpDir := t.TempDir()
testFile := filepath.Join(tmpDir, "whitespace.txt")
// Lines with content should be preserved, blank/whitespace-only removed
content := " line with leading spaces\n\n\tmiddle with tab\n \nlast line\n"
err := os.WriteFile(testFile, []byte(content), 0644)
require.NoError(t, err)
result, err := runtime.Execute(`remove_blank_lines("`+testFile+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
data, err := os.ReadFile(testFile)
require.NoError(t, err)
// Lines with actual content (even with leading whitespace) should be kept
assert.Equal(t, " line with leading spaces\n\tmiddle with tab\nlast line\n", string(data))
})
}
func TestChunkFile(t *testing.T) {
runtime := NewOttoRuntime()
t.Run("splits file into equal chunks", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "urls.txt")
output := filepath.Join(tmpDir, "chunks.txt")
// Write 6 lines
content := "line1\nline2\nline3\nline4\nline5\nline6\n"
require.NoError(t, os.WriteFile(input, []byte(content), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 2, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
// Verify manifest
manifest, err := os.ReadFile(output)
require.NoError(t, err)
lines := strings.Split(strings.TrimSpace(string(manifest)), "\n")
assert.Len(t, lines, 3, "should have 3 chunks for 6 lines with chunk_size=2")
// Verify chunk 0
chunk0, err := os.ReadFile(lines[0])
require.NoError(t, err)
assert.Equal(t, "line1\nline2\n", string(chunk0))
// Verify chunk 1
chunk1, err := os.ReadFile(lines[1])
require.NoError(t, err)
assert.Equal(t, "line3\nline4\n", string(chunk1))
// Verify chunk 2
chunk2, err := os.ReadFile(lines[2])
require.NoError(t, err)
assert.Equal(t, "line5\nline6\n", string(chunk2))
})
t.Run("handles uneven split (last chunk smaller)", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "data.txt")
output := filepath.Join(tmpDir, "chunks.txt")
// Write 5 lines
content := "a\nb\nc\nd\ne\n"
require.NoError(t, os.WriteFile(input, []byte(content), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 3, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
manifest, err := os.ReadFile(output)
require.NoError(t, err)
lines := strings.Split(strings.TrimSpace(string(manifest)), "\n")
assert.Len(t, lines, 2, "should have 2 chunks for 5 lines with chunk_size=3")
// First chunk has 3 lines
chunk0, err := os.ReadFile(lines[0])
require.NoError(t, err)
assert.Equal(t, "a\nb\nc\n", string(chunk0))
// Second chunk has 2 lines
chunk1, err := os.ReadFile(lines[1])
require.NoError(t, err)
assert.Equal(t, "d\ne\n", string(chunk1))
})
t.Run("skips blank lines", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "mixed.txt")
output := filepath.Join(tmpDir, "chunks.txt")
content := "line1\n\nline2\n \nline3\n\n"
require.NoError(t, os.WriteFile(input, []byte(content), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 2, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
manifest, err := os.ReadFile(output)
require.NoError(t, err)
lines := strings.Split(strings.TrimSpace(string(manifest)), "\n")
assert.Len(t, lines, 2, "should have 2 chunks for 3 non-blank lines with chunk_size=2")
chunk0, err := os.ReadFile(lines[0])
require.NoError(t, err)
assert.Equal(t, "line1\nline2\n", string(chunk0))
chunk1, err := os.ReadFile(lines[1])
require.NoError(t, err)
assert.Equal(t, "line3\n", string(chunk1))
})
t.Run("preserves extension in chunk names", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "urls.txt")
output := filepath.Join(tmpDir, "chunks.txt")
content := "url1\nurl2\nurl3\n"
require.NoError(t, os.WriteFile(input, []byte(content), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 2, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
manifest, err := os.ReadFile(output)
require.NoError(t, err)
lines := strings.Split(strings.TrimSpace(string(manifest)), "\n")
assert.Contains(t, lines[0], "urls_part_0.txt")
assert.Contains(t, lines[1], "urls_part_1.txt")
})
t.Run("empty file produces empty manifest", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "empty.txt")
output := filepath.Join(tmpDir, "chunks.txt")
require.NoError(t, os.WriteFile(input, []byte(""), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 10, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
manifest, err := os.ReadFile(output)
require.NoError(t, err)
assert.Equal(t, "", string(manifest))
})
t.Run("file with only blank lines produces empty manifest", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "blanks.txt")
output := filepath.Join(tmpDir, "chunks.txt")
require.NoError(t, os.WriteFile(input, []byte("\n\n \n\n"), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 5, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
manifest, err := os.ReadFile(output)
require.NoError(t, err)
assert.Equal(t, "", string(manifest))
})
t.Run("chunk size larger than file creates single chunk", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "small.txt")
output := filepath.Join(tmpDir, "chunks.txt")
content := "a\nb\nc\n"
require.NoError(t, os.WriteFile(input, []byte(content), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 100, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, true, result)
manifest, err := os.ReadFile(output)
require.NoError(t, err)
lines := strings.Split(strings.TrimSpace(string(manifest)), "\n")
assert.Len(t, lines, 1, "should have 1 chunk when chunk_size > total lines")
chunk, err := os.ReadFile(lines[0])
require.NoError(t, err)
assert.Equal(t, "a\nb\nc\n", string(chunk))
})
t.Run("empty input path returns false", func(t *testing.T) {
tmpDir := t.TempDir()
output := filepath.Join(tmpDir, "chunks.txt")
result, err := runtime.Execute(`chunk_file("", 10, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("empty output path returns false", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "input.txt")
require.NoError(t, os.WriteFile(input, []byte("line\n"), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 10, "")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("chunk size zero returns false", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "input.txt")
output := filepath.Join(tmpDir, "chunks.txt")
require.NoError(t, os.WriteFile(input, []byte("line\n"), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", 0, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("negative chunk size returns false", func(t *testing.T) {
tmpDir := t.TempDir()
input := filepath.Join(tmpDir, "input.txt")
output := filepath.Join(tmpDir, "chunks.txt")
require.NoError(t, os.WriteFile(input, []byte("line\n"), 0644))
result, err := runtime.Execute(`chunk_file("`+input+`", -5, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("non-existent input file returns false", func(t *testing.T) {
tmpDir := t.TempDir()
output := filepath.Join(tmpDir, "chunks.txt")
result, err := runtime.Execute(`chunk_file("/nonexistent/input.txt", 10, "`+output+`")`, nil)
require.NoError(t, err)
assert.Equal(t, false, result)
})
}