package discourse import ( "context" "errors" "testing" ) func TestSearchRequiresTerm(t *testing.T) { f := newFake(t) c := testClient(t, f) _, err := c.Search(context.Background(), SearchRequest{}) if !errors.Is(err, ErrInvalidRequest) { t.Fatalf("want ErrInvalidRequest for empty term, got %v", err) } if f.saw("/search.json") { t.Fatal("no request should have been sent for an empty term") } } func TestSearchQueriesAndParses(t *testing.T) { f := newFake(t) c := testClient(t, f) res, err := c.Search(context.Background(), SearchRequest{Term: "fleet briefing"}) if err != nil { t.Fatalf("Search: %v", err) } if !f.sawQuery("/search.json", "term=fleet+briefing") { t.Fatal("search term not sent as the term= query parameter") } if len(res.Posts) != 1 || res.Posts[0].TopicID != 12 || res.Posts[0].Username != "reachableceo" { t.Fatalf("posts not parsed: %+v", res.Posts) } if res.Posts[0].Blurb == "" { t.Fatal("blurb not parsed") } if len(res.Topics) != 1 || res.Topics[0].Title != "Fleet briefing 2026-09-01" { t.Fatalf("topics not parsed: %+v", res.Topics) } if len(res.Users) != 1 || res.Users[0].Username != "reachableceo" { t.Fatalf("users not parsed: %+v", res.Users) } if len(res.Categories) != 1 || res.Categories[0].Slug != "mopac-briefings" { t.Fatalf("categories not parsed: %+v", res.Categories) } } func TestSearchEncodesTermAndPage(t *testing.T) { f := newFake(t) c := testClient(t, f) if _, err := c.Search(context.Background(), SearchRequest{Term: "a b&c=d", Page: 2}); err != nil { t.Fatalf("Search: %v", err) } if !f.sawQuery("/search.json", "term=a+b%26c%3Dd") { t.Fatal("term not url-encoded (a b&c=d must not smuggle extra params)") } if !f.sawQuery("/search.json", "page=2") { t.Fatal("page not sent as the page= query parameter") } } func TestSearchTypedErrors(t *testing.T) { f := newFake(t) c := testClient(t, f) f.searchFail = 403 _, err := c.Search(context.Background(), SearchRequest{Term: "x"}) if !errors.Is(err, ErrForbidden) { t.Fatalf("want ErrForbidden, got %v", err) } }