119 lines
3.4 KiB
Go
119 lines
3.4 KiB
Go
package toolexec
|
|
|
|
import "testing"
|
|
|
|
func mustParseSteps(t *testing.T, raw []any) []workflowStep {
|
|
t.Helper()
|
|
steps, err := parseWorkflowSteps(raw)
|
|
if err != nil {
|
|
t.Fatalf("parseWorkflowSteps: unexpected error: %v", err)
|
|
}
|
|
return steps
|
|
}
|
|
|
|
func TestParseWorkflowSteps_Basic(t *testing.T) {
|
|
raw := []any{
|
|
map[string]any{"id": "a", "task": "do a"},
|
|
map[string]any{"id": "b", "task": "do b", "depends_on": []any{"a"}},
|
|
}
|
|
steps := mustParseSteps(t, raw)
|
|
if len(steps) != 2 {
|
|
t.Fatalf("got %d steps, want 2", len(steps))
|
|
}
|
|
if steps[1].DependsOn[0] != "a" {
|
|
t.Errorf("steps[1].DependsOn = %v, want [a]", steps[1].DependsOn)
|
|
}
|
|
}
|
|
|
|
func TestParseWorkflowSteps_Errors(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
raw []any
|
|
}{
|
|
{"empty", nil},
|
|
{"missing id", []any{map[string]any{"task": "x"}}},
|
|
{"missing task", []any{map[string]any{"id": "a"}}},
|
|
{"duplicate id", []any{
|
|
map[string]any{"id": "a", "task": "x"},
|
|
map[string]any{"id": "a", "task": "y"},
|
|
}},
|
|
{"not an object", []any{"not-an-object"}},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if _, err := parseWorkflowSteps(tc.raw); err == nil {
|
|
t.Errorf("parseWorkflowSteps(%s): expected an error, got nil", tc.name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseWorkflowSteps_TooMany(t *testing.T) {
|
|
raw := make([]any, maxWorkflowSteps+1)
|
|
for i := range raw {
|
|
raw[i] = map[string]any{"id": string(rune('a' + i%26)), "task": "x"}
|
|
}
|
|
if _, err := parseWorkflowSteps(raw); err == nil {
|
|
t.Error("expected an error for exceeding maxWorkflowSteps")
|
|
}
|
|
}
|
|
|
|
func TestValidateDependencies_OK(t *testing.T) {
|
|
steps := mustParseSteps(t, []any{
|
|
map[string]any{"id": "a", "task": "x"},
|
|
map[string]any{"id": "b", "task": "x", "depends_on": []any{"a"}},
|
|
map[string]any{"id": "c", "task": "x", "depends_on": []any{"a", "b"}},
|
|
})
|
|
if err := validateDependencies(steps); err != nil {
|
|
t.Errorf("validateDependencies: unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateDependencies_UnknownDep(t *testing.T) {
|
|
steps := mustParseSteps(t, []any{
|
|
map[string]any{"id": "a", "task": "x", "depends_on": []any{"nope"}},
|
|
})
|
|
if err := validateDependencies(steps); err == nil {
|
|
t.Error("expected an error for an unknown dependency")
|
|
}
|
|
}
|
|
|
|
func TestValidateDependencies_SelfDependency(t *testing.T) {
|
|
steps := mustParseSteps(t, []any{
|
|
map[string]any{"id": "a", "task": "x", "depends_on": []any{"a"}},
|
|
})
|
|
if err := validateDependencies(steps); err == nil {
|
|
t.Error("expected an error for a step depending on itself")
|
|
}
|
|
}
|
|
|
|
func TestValidateDependencies_Cycle(t *testing.T) {
|
|
steps := mustParseSteps(t, []any{
|
|
map[string]any{"id": "a", "task": "x", "depends_on": []any{"b"}},
|
|
map[string]any{"id": "b", "task": "x", "depends_on": []any{"a"}},
|
|
})
|
|
if err := validateDependencies(steps); err == nil {
|
|
t.Error("expected an error for a two-step cycle")
|
|
}
|
|
}
|
|
|
|
func TestDefaultWorkflowVerifier(t *testing.T) {
|
|
cases := []struct {
|
|
report string
|
|
wantOK bool
|
|
}{
|
|
{"", false},
|
|
{" ", false},
|
|
{"short", false},
|
|
{"(the sub-agent finished without writing a report — try a more specific task description)", false},
|
|
{"[step failed to run: context deadline exceeded]", false},
|
|
{"This is a plausible, substantial report with real findings in it about the codebase.", true},
|
|
}
|
|
for _, tc := range cases {
|
|
ok, reason := defaultWorkflowVerifier("some task", tc.report)
|
|
if ok != tc.wantOK {
|
|
t.Errorf("defaultWorkflowVerifier(%q) ok = %v (reason %q), want %v", tc.report, ok, reason, tc.wantOK)
|
|
}
|
|
}
|
|
}
|