grokkit/internal/recipe/recipe_test.go

190 lines
4.9 KiB
Go
Raw Normal View History

package recipe
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLoad(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
recipePath := filepath.Join(tmpDir, "test.yaml")
content := `---
name: Test Recipe
description: A recipe for testing
version: 1.0.0
parameters:
target_file:
type: string
default: "main.go"
description: File to process
allowed_shell_commands:
- ls -la
- pwd
project_languages:
- go
extensions:
go: [".go"]
search_pattern: "func main"
---
## Execution Steps
### Step 1: Discover
**Objective:** Find files.
**Instructions:** Use discovery.
**Expected output:** List of files.
### Step 2: Refactor
**Objective:** Refactor files.
**Instructions:** Use refactoring.
**Expected output:** JSON.
This is the final summary prompt.
`
err := os.WriteFile(recipePath, []byte(content), 0600)
require.NoError(t, err)
t.Run("successful load with defaults", func(t *testing.T) {
r, err := Load(recipePath, nil)
require.NoError(t, err)
assert.Equal(t, "Test Recipe", r.Name)
assert.Equal(t, "1.0.0", r.Version)
assert.Equal(t, "main.go", r.ResolvedParams["target_file"])
assert.Len(t, r.Steps, 2)
assert.Equal(t, 1, r.Steps[0].Number)
assert.Equal(t, "Discover", r.Steps[0].Title)
assert.Equal(t, "Find files.", r.Steps[0].Objective)
assert.Equal(t, "Use discovery.", r.Steps[0].Instructions)
assert.Equal(t, "List of files.", r.Steps[0].Expected)
assert.Contains(t, r.FinalSummaryPrompt, "This is the final summary prompt.")
})
t.Run("load with parameter override", func(t *testing.T) {
params := map[string]any{"target_file": "app.go"}
r, err := Load(recipePath, params)
require.NoError(t, err)
assert.Equal(t, "app.go", r.ResolvedParams["target_file"])
})
t.Run("load unsafe command", func(t *testing.T) {
unsafeContent := `---
name: Unsafe Recipe
allowed_shell_commands:
- rm -rf /
---
## Execution Steps
### Step 1: Bad
`
unsafePath := filepath.Join(tmpDir, "unsafe.yaml")
err := os.WriteFile(unsafePath, []byte(unsafeContent), 0600)
require.NoError(t, err)
_, err = Load(unsafePath, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "unsafe shell command")
})
t.Run("missing frontmatter", func(t *testing.T) {
badPath := filepath.Join(tmpDir, "bad.yaml")
err := os.WriteFile(badPath, []byte("no frontmatter here"), 0600)
require.NoError(t, err)
_, err = Load(badPath, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "missing YAML frontmatter")
})
}
func TestResolveWorkDir(t *testing.T) {
// Not using t.Parallel() because it might depend on HOME env which we might want to mock if needed.
r := &Recipe{
ResolvedParams: make(map[string]any),
}
runner := &Runner{Recipe: r}
t.Run("default to dot", func(t *testing.T) {
dir := runner.resolveWorkDir()
absDot, _ := filepath.Abs(".")
assert.Equal(t, absDot, dir)
})
t.Run("explicit path", func(t *testing.T) {
tmpDir := t.TempDir()
r.ResolvedParams["package_path"] = tmpDir
dir := runner.resolveWorkDir()
absTmp, _ := filepath.Abs(tmpDir)
assert.Equal(t, absTmp, dir)
})
t.Run("tilde expansion", func(t *testing.T) {
r.ResolvedParams["package_path"] = "~/projects"
dir := runner.resolveWorkDir()
home, _ := os.UserHomeDir()
expected := filepath.Join(home, "projects")
assert.Equal(t, expected, dir)
})
}
func TestDiscoverFiles(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
// Create some files
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "main.go"), []byte("func main() { if err != nil { return } }"), 0600))
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "app.go"), []byte("package main"), 0600))
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README.md"), []byte("if err != nil"), 0600))
r := &Recipe{
ProjectLanguages: []string{"go"},
Extensions: map[string][]string{"go": {".go"}},
SearchPattern: "if err != nil",
}
runner := &Runner{Recipe: r}
t.Run("finds matching files", func(t *testing.T) {
files := runner.discoverFiles(tmpDir)
assert.Len(t, files, 1)
assert.Contains(t, files[0], "main.go")
})
t.Run("no matching files", func(t *testing.T) {
r.SearchPattern = "nonexistent"
files := runner.discoverFiles(tmpDir)
assert.Len(t, files, 1)
assert.Equal(t, "No files found matching the criteria.", files[0])
})
}
func TestCreateUnifiedPatch(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
patchPath := filepath.Join(tmpDir, "test.patch")
changes := []FileChange{
{
File: "main.go",
Content: "package main\n\nfunc main() {}\n",
},
}
err := createUnifiedPatch(changes, patchPath)
require.NoError(t, err)
content, err := os.ReadFile(patchPath)
require.NoError(t, err)
assert.Contains(t, string(content), "--- main.go")
assert.Contains(t, string(content), "+++ main.go")
assert.Contains(t, string(content), "+package main")
assert.Contains(t, string(content), "+func main() {}")
}