All checks were successful
CI / Build & Test (push) Successful in 34s
- esa.io API クライアントの実装と単体テストを追加 - 記事の取得・検索・作成・更新を行うサブコマンドを実装 - GitHub Actions による CI ワークフローを設定 - プロジェクトの基本ファイル(README、.gitignore、LICENSE、go.mod)を作成
224 lines
5.9 KiB
Go
224 lines
5.9 KiB
Go
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
|
|
}
|