package main import ( "bytes" "context" "encoding/json" "io" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func brainQueryServer(t *testing.T, body string) *httptest.Server { t.Helper() return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(body)) })) } func TestRunBrainQuery_Human(t *testing.T) { srv := brainQueryServer(t, `{"results":[{"path":"knowledge/a.md","title":"A","excerpt":"...","score":9},{"path":"knowledge/b.md","title":"B","excerpt":"...","score":3}]}`) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"query", "topic"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) got := out.String() assert.Contains(t, got, "knowledge/a.md") assert.Contains(t, got, "score=9") assert.Contains(t, got, "knowledge/b.md") } func TestRunBrainQuery_JSON(t *testing.T) { srv := brainQueryServer(t, `{"results":[{"path":"x.md","title":"X","excerpt":"e","score":5}]}`) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"query", "--json", "topic"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) assert.Contains(t, out.String(), `"path": "x.md"`) assert.Contains(t, out.String(), `"score": 5`) } func TestRunBrainQuery_Limit(t *testing.T) { gotLimit := -1 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, _ := io.ReadAll(r.Body) var p struct { Query string `json:"query"` Limit int `json:"limit"` } _ = json.Unmarshal(body, &p) gotLimit = p.Limit _, _ = w.Write([]byte(`{"results":[]}`)) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"query", "--limit", "12", "topic"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) assert.Equal(t, 12, gotLimit) } func TestRunBrainQuery_MissingTopic(t *testing.T) { var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"query"}, strings.NewReader(""), &out, &errBuf) assert.Error(t, err) } func TestRunBrain_NoSubsubcommand(t *testing.T) { var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{}, strings.NewReader(""), &out, &errBuf) assert.Error(t, err) assert.Contains(t, err.Error(), "subcommand required") } func TestRunBrain_UnknownSubsubcommand(t *testing.T) { var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"bogus"}, strings.NewReader(""), &out, &errBuf) assert.Error(t, err) } func TestRunBrainWrite_Success(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPost, r.Method) assert.Equal(t, "/write", r.URL.Path) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"path":"knowledge/test-slug.md"}`)) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain( context.Background(), []string{"write", "knowledge", "test-slug"}, strings.NewReader("# Test\n\nSome body content.\n"), &out, &errBuf, ) require.NoError(t, err) assert.Contains(t, out.String(), "knowledge/test-slug.md") } func TestRunBrainWrite_MissingArgs(t *testing.T) { var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"write", "knowledge"}, strings.NewReader("x"), &out, &errBuf) assert.Error(t, err) assert.Contains(t, err.Error(), "type and slug required") } func TestRunBrainWrite_BackendError(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte("invalid slug")) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain( context.Background(), []string{"write", "knowledge", "bad slug"}, strings.NewReader("body"), &out, &errBuf, ) assert.Error(t, err) assert.Contains(t, err.Error(), "400") } func TestRunBrainWrite_EmptyStdin(t *testing.T) { gotLen := -1 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, _ := io.ReadAll(r.Body) var p struct { Content string `json:"content"` } _ = json.Unmarshal(body, &p) gotLen = len(p.Content) _, _ = w.Write([]byte(`{"path":"x.md"}`)) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"write", "knowledge", "empty"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) assert.Equal(t, 0, gotLen, "empty stdin should produce empty content payload") } func TestRunBrainPassRate_Human(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"skill":"tdd","window":"7d","pass":47,"fail":3,"skip":0,"total":50,"pass_rate":0.94}`)) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"pass-rate", "tdd"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) got := out.String() assert.Contains(t, got, "tdd") assert.Contains(t, got, "47 / 50") assert.Contains(t, got, "94%") } func TestRunBrainPassRate_NoData(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"skill":"tdd","window":"7d","pass":0,"fail":0,"skip":0,"total":0,"pass_rate":null}`)) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"pass-rate", "tdd"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) assert.Contains(t, out.String(), "no data") } func TestRunBrainPassRate_JSON(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"skill":"tdd","window":"7d","pass":47,"fail":3,"skip":0,"total":50,"pass_rate":0.94}`)) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"pass-rate", "--json", "tdd"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) assert.Contains(t, out.String(), `"pass_rate": 0.94`) } func TestRunBrainPassRate_MissingSkill(t *testing.T) { var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"pass-rate"}, strings.NewReader(""), &out, &errBuf) assert.Error(t, err) assert.Contains(t, err.Error(), "skill required") } func TestRunBrainPassRate_WindowFlag(t *testing.T) { gotWindow := "" srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotWindow = r.URL.Query().Get("window") _, _ = w.Write([]byte(`{"skill":"tdd","window":"30d","pass":0,"fail":0,"skip":0,"total":0,"pass_rate":null}`)) })) defer srv.Close() t.Setenv("BRAIN_URL", srv.URL) var out, errBuf bytes.Buffer err := runBrain(context.Background(), []string{"pass-rate", "--window", "30d", "tdd"}, strings.NewReader(""), &out, &errBuf) require.NoError(t, err) assert.Equal(t, "30d", gotWindow) }