Client.Search(term, page) url-encodes the term (operators like @user / #category / order:latest pass through) and decodes the four hit groups Discourse returns: posts (with blurb and highlighted topic title), topics, users and categories. Empty term is rejected locally with ErrInvalidRequest; server failures keep the typed error classes. Fake-server tests cover encoding, parsing and the 403 path. Part of Redmine 507 (Discourse Go client): search is how the 495 briefing pipeline finds landing spots and prior threads.
71 lines
2.0 KiB
Go
71 lines
2.0 KiB
Go
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)
|
|
}
|
|
}
|