package esa import ( "context" "encoding/json" "io" "net/http" "net/http/httptest" "testing" ) func newTestClient(t *testing.T, handler http.Handler) (*Client, func()) { t.Helper() srv := httptest.NewServer(handler) c := NewClient("docs", "test-token") c.BaseURL = srv.URL return c, srv.Close } func TestGetPost(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Method, http.MethodGet; got != want { t.Errorf("method = %q, want %q", got, want) } if got, want := r.URL.Path, "/v1/teams/docs/posts/5"; got != want { t.Errorf("path = %q, want %q", got, want) } if got, want := r.Header.Get("Authorization"), "Bearer test-token"; got != want { t.Errorf("auth header = %q, want %q", got, want) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "number": 5, "name": "hi!", "full_name": "dev/2015/05/10/hi! #api #dev", "wip": false, "body_md": "# Getting Started\n", "tags": ["api", "dev"], "category": "dev/2015/05/10", "revision_number": 1 }`)) }) c, cleanup := newTestClient(t, handler) defer cleanup() post, err := c.GetPost(context.Background(), 5) if err != nil { t.Fatalf("GetPost: %v", err) } if post.Number != 5 { t.Errorf("Number = %d, want 5", post.Number) } if post.Name != "hi!" { t.Errorf("Name = %q, want %q", post.Name, "hi!") } if got, want := post.BodyMD, "# Getting Started\n"; got != want { t.Errorf("BodyMD = %q, want %q", got, want) } if got, want := post.Tags, []string{"api", "dev"}; !equalStrings(got, want) { t.Errorf("Tags = %v, want %v", got, want) } } func TestSearchPosts(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Method, http.MethodGet; got != want { t.Errorf("method = %q, want %q", got, want) } if got, want := r.URL.Path, "/v1/teams/docs/posts"; got != want { t.Errorf("path = %q, want %q", got, want) } q := r.URL.Query() if got, want := q.Get("q"), "hello"; got != want { t.Errorf("q param = %q, want %q", got, want) } if got, want := q.Get("per_page"), "10"; got != want { t.Errorf("per_page = %q, want %q", got, want) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "posts": [ {"number": 1, "name": "hi!", "body_md": "# Getting Started"}, {"number": 2, "name": "bye!", "body_md": "# Bye"} ], "prev_page": null, "next_page": null, "total_count": 2, "page": 1, "per_page": 10, "max_per_page": 100 }`)) }) c, cleanup := newTestClient(t, handler) defer cleanup() resp, err := c.SearchPosts(context.Background(), SearchOptions{Query: "hello", PerPage: 10}) if err != nil { t.Fatalf("SearchPosts: %v", err) } if resp.TotalCount != 2 { t.Errorf("TotalCount = %d, want 2", resp.TotalCount) } if len(resp.Posts) != 2 { t.Fatalf("len(Posts) = %d, want 2", len(resp.Posts)) } if resp.Posts[0].Number != 1 { t.Errorf("Posts[0].Number = %d, want 1", resp.Posts[0].Number) } } func TestCreatePost(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Method, http.MethodPost; got != want { t.Errorf("method = %q, want %q", got, want) } if got, want := r.URL.Path, "/v1/teams/docs/posts"; got != want { t.Errorf("path = %q, want %q", got, want) } if got, want := r.Header.Get("Content-Type"), "application/json"; got != want { t.Errorf("content-type = %q, want %q", got, want) } var body struct { Post PostInput `json:"post"` } raw, _ := io.ReadAll(r.Body) if err := json.Unmarshal(raw, &body); err != nil { t.Fatalf("decode body: %v (raw=%s)", err, raw) } if body.Post.Name != "hi!" { t.Errorf("post.name = %q, want %q", body.Post.Name, "hi!") } if body.Post.WIP == nil || *body.Post.WIP { t.Errorf("post.wip should be false (got %v)", body.Post.WIP) } w.WriteHeader(http.StatusCreated) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "number": 5, "name": "hi!", "body_md": "# Getting Started\n", "wip": false, "category": "dev/2015/05/10", "tags": ["api", "dev"] }`)) }) c, cleanup := newTestClient(t, handler) defer cleanup() wip := false post, err := c.CreatePost(context.Background(), PostInput{ Name: "hi!", BodyMD: "# Getting Started\n", Tags: []string{"api", "dev"}, Category: "dev/2015/05/10", WIP: &wip, Message: "first commit", }) if err != nil { t.Fatalf("CreatePost: %v", err) } if post.Number != 5 { t.Errorf("Number = %d, want 5", post.Number) } if post.WIP { t.Errorf("WIP = true, want false") } } func TestUpdatePost(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got, want := r.Method, http.MethodPatch; got != want { t.Errorf("method = %q, want %q", got, want) } if got, want := r.URL.Path, "/v1/teams/docs/posts/5"; got != want { t.Errorf("path = %q, want %q", got, want) } var body struct { Post PostInput `json:"post"` } raw, _ := io.ReadAll(r.Body) if err := json.Unmarshal(raw, &body); err != nil { t.Fatalf("decode body: %v", err) } if body.Post.Name != "updated" { t.Errorf("post.name = %q, want %q", body.Post.Name, "updated") } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "number": 5, "name": "updated", "body_md": "new body", "revision_number": 2 }`)) }) c, cleanup := newTestClient(t, handler) defer cleanup() post, err := c.UpdatePost(context.Background(), 5, PostInput{ Name: "updated", BodyMD: "new body", }) if err != nil { t.Fatalf("UpdatePost: %v", err) } if post.Name != "updated" { t.Errorf("Name = %q, want %q", post.Name, "updated") } if post.RevisionNumber != 2 { t.Errorf("RevisionNumber = %d, want 2", post.RevisionNumber) } } func equalStrings(a, b []string) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true }