picoclaw/pkg/tools/update_plan_test.go
2026-05-04 14:35:40 -07:00

101 lines
2.9 KiB
Go

package tools
import (
"context"
"encoding/json"
"strings"
"testing"
)
func TestUpdatePlanToolParameters(t *testing.T) {
tool := NewUpdatePlanTool()
if got := tool.Name(); got != "update_plan" {
t.Fatalf("Name() = %q, want update_plan", got)
}
description := tool.Description()
for _, want := range []string{"non-trivial multi-step work", "exactly one step in_progress", "avoid repeating the whole plan"} {
if !strings.Contains(description, want) {
t.Fatalf("Description() missing %q: %s", want, description)
}
}
params := tool.Parameters()
if params["type"] != "object" {
t.Fatalf("Parameters type = %v, want object", params["type"])
}
if params["properties"] == nil {
t.Fatal("Parameters should include properties")
}
}
func TestUpdatePlanToolExecute(t *testing.T) {
tool := NewUpdatePlanTool()
result := tool.Execute(context.Background(), map[string]any{
"explanation": "Starting implementation.",
"plan": []any{
map[string]any{"step": "Inspect existing tools", "status": "completed"},
map[string]any{"step": "Add update_plan", "status": "in_progress"},
map[string]any{"step": "Run tests", "status": "pending"},
},
})
if result == nil {
t.Fatal("Execute returned nil")
}
if result.IsError {
t.Fatalf("Execute returned error: %s", result.ForLLM)
}
if !result.Silent {
t.Fatal("update_plan should be silent")
}
var response updatePlanResponse
if err := json.Unmarshal([]byte(result.ForLLM), &response); err != nil {
t.Fatalf("result is not JSON: %v\n%s", err, result.ForLLM)
}
if response.Status != "updated" {
t.Fatalf("status = %q, want updated", response.Status)
}
if response.Explanation != "Starting implementation." {
t.Fatalf("explanation = %q", response.Explanation)
}
if len(response.Plan) != 3 {
t.Fatalf("plan length = %d, want 3", len(response.Plan))
}
if response.Plan[1].Status != "in_progress" {
t.Fatalf("second step status = %q, want in_progress", response.Plan[1].Status)
}
}
func TestUpdatePlanToolRejectsMultipleInProgress(t *testing.T) {
tool := NewUpdatePlanTool()
result := tool.Execute(context.Background(), map[string]any{
"plan": []any{
map[string]any{"step": "One", "status": "in_progress"},
map[string]any{"step": "Two", "status": "in_progress"},
},
})
if result == nil || !result.IsError {
t.Fatalf("Execute should reject multiple in_progress steps, got %#v", result)
}
if !strings.Contains(result.ForLLM, "at most one in_progress") {
t.Fatalf("unexpected error: %s", result.ForLLM)
}
}
func TestUpdatePlanToolRejectsInvalidStatus(t *testing.T) {
tool := NewUpdatePlanTool()
result := tool.Execute(context.Background(), map[string]any{
"plan": []any{
map[string]any{"step": "One", "status": "blocked"},
},
})
if result == nil || !result.IsError {
t.Fatalf("Execute should reject invalid status, got %#v", result)
}
if !strings.Contains(result.ForLLM, "must be one of") {
t.Fatalf("unexpected error: %s", result.ForLLM)
}
}