package tdd_test import ( "context" "encoding/json" "testing" "github.com/mathiasbq/supervisor/internal/session" "github.com/mathiasbq/supervisor/internal/skills/tdd" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestTDDSkillTools(t *testing.T) { skill := tdd.New(tdd.Config{ SkillPrompt: "tdd rules", }) tools := skill.Tools() names := make([]string, len(tools)) for i, tool := range tools { names[i] = tool.Name } assert.ElementsMatch(t, []string{"tdd_red", "tdd_green", "tdd_refactor"}, names) } func TestTDDSkillHandleUnknown(t *testing.T) { skill := tdd.New(tdd.Config{SkillPrompt: "t"}) _, err := skill.Handle(context.Background(), "tdd_unknown", json.RawMessage(`{}`)) assert.ErrorContains(t, err, "unknown tool") } func TestTDDRedRequiresProjectRoot(t *testing.T) { skill := tdd.New(tdd.Config{SkillPrompt: "t"}) _, err := skill.Handle(context.Background(), "tdd_red", json.RawMessage(`{"spec":"add two numbers"}`)) assert.ErrorContains(t, err, "project_root") } func TestTDDRedRequiresSpec(t *testing.T) { skill := tdd.New(tdd.Config{SkillPrompt: "t"}) _, err := skill.Handle(context.Background(), "tdd_red", json.RawMessage(`{"project_root":"/tmp/proj"}`)) assert.ErrorContains(t, err, "spec") } func TestTDDGreenInjectsSessionHistory(t *testing.T) { sessDir := t.TempDir() require.NoError(t, session.Append(sessDir, "sess-1", session.Entry{ SessionID: "sess-1", Skill: "tdd", Phase: "red", FinalStatus: "pass", FilePath: "internal/foo/foo_test.go", Message: "wrote failing test for Foo", })) var capturedTask string fakeFn := func(_ context.Context, _, _, user string) (string, int64, error) { capturedTask = user return "here is my suggestion", 100, nil } sk := tdd.New(tdd.Config{SkillPrompt: "tdd", CompleteFunc: fakeFn, SessionsDir: sessDir}) _, err := sk.Handle(context.Background(), "tdd_green", json.RawMessage( `{"project_root":"/tmp","test_path":"internal/foo/foo_test.go","test_cmd":"go test ./...","session_id":"sess-1"}`, )) require.NoError(t, err) assert.Contains(t, capturedTask, "## Session history") assert.Contains(t, capturedTask, "wrote failing test for Foo") } func TestTDDGreenNoHistoryWhenSessionIDEmpty(t *testing.T) { var capturedTask string fakeFn := func(_ context.Context, _, _, user string) (string, int64, error) { capturedTask = user return "suggestion", 50, nil } sk := tdd.New(tdd.Config{SkillPrompt: "tdd", CompleteFunc: fakeFn, SessionsDir: t.TempDir()}) _, err := sk.Handle(context.Background(), "tdd_green", json.RawMessage( `{"project_root":"/tmp","test_path":"internal/foo/foo_test.go"}`, )) require.NoError(t, err) assert.NotContains(t, capturedTask, "## Session history") } func TestTDDGreenReturnsTextJSON(t *testing.T) { fakeFn := func(_ context.Context, _, _, _ string) (string, int64, error) { return "write a func that adds two ints", 42, nil } sk := tdd.New(tdd.Config{SkillPrompt: "tdd", CompleteFunc: fakeFn}) raw, err := sk.Handle(context.Background(), "tdd_green", json.RawMessage( `{"project_root":"/tmp","test_path":"foo_test.go"}`, )) require.NoError(t, err) var result map[string]any require.NoError(t, json.Unmarshal(raw, &result)) assert.Equal(t, "write a func that adds two ints", result["text"]) assert.Equal(t, float64(42), result["duration_ms"]) }