From a356c6f752df6cb867f7fce3bba393a1f88887dd Mon Sep 17 00:00:00 2001 From: hitakats Date: Sun, 16 Sep 2018 14:05:36 +0900 Subject: [PATCH] kadai4 tk3fftk --- kadai4/tk3fftk/README.md | 14 ++++ kadai4/tk3fftk/main.go | 13 ++++ kadai4/tk3fftk/omikuji/handler.go | 88 ++++++++++++++++++++++++ kadai4/tk3fftk/omikuji/handler_test.go | 95 ++++++++++++++++++++++++++ kadai4/tk3fftk/omikuji/omikuji.go | 35 ++++++++++ kadai4/tk3fftk/omikuji/omikuji_test.go | 32 +++++++++ 6 files changed, 277 insertions(+) create mode 100644 kadai4/tk3fftk/README.md create mode 100644 kadai4/tk3fftk/main.go create mode 100644 kadai4/tk3fftk/omikuji/handler.go create mode 100644 kadai4/tk3fftk/omikuji/handler_test.go create mode 100644 kadai4/tk3fftk/omikuji/omikuji.go create mode 100644 kadai4/tk3fftk/omikuji/omikuji_test.go diff --git a/kadai4/tk3fftk/README.md b/kadai4/tk3fftk/README.md new file mode 100644 index 0000000..2cf26c1 --- /dev/null +++ b/kadai4/tk3fftk/README.md @@ -0,0 +1,14 @@ +## おみくじAPIを作ってみよう +### 制約 +- [x] JSON形式でおみくじの結果を返す +- [x] 正月(1/1-1/3)だけ大吉にする + - テストにて動作確認しています +- [x] ハンドラのテストを書いてみる + +### 使い方 +``` +$ go build -o lot +$ ./lot & +$ curl localhost:8080/lot +{"result":"大凶"} +``` diff --git a/kadai4/tk3fftk/main.go b/kadai4/tk3fftk/main.go new file mode 100644 index 0000000..67ec016 --- /dev/null +++ b/kadai4/tk3fftk/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "net/http" + + "github.com/gopherdojo/dojo3/kadai4/tk3fftk/omikuji" +) + +func main() { + handler := omikuji.New(nil) + http.Handle("/lot", &handler) + http.ListenAndServe(":8080", nil) +} diff --git a/kadai4/tk3fftk/omikuji/handler.go b/kadai4/tk3fftk/omikuji/handler.go new file mode 100644 index 0000000..458dd50 --- /dev/null +++ b/kadai4/tk3fftk/omikuji/handler.go @@ -0,0 +1,88 @@ +package omikuji + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "time" +) + +const bigLuckey = "大吉" + +type response struct { + Result string `json:"result"` +} + +type Clock interface { + Now() time.Time +} + +type ClockFunc func() time.Time + +func (f ClockFunc) Now() time.Time { + return f() +} + +type OmikujiHandler struct { + Clock Clock + Omikuji Omikuji +} + +func New(clock Clock) OmikujiHandler { + o := NewOmikuji() + return OmikujiHandler{ + Clock: clock, + Omikuji: o, + } +} + +func (o *OmikujiHandler) createResponseJSON(result string) (string, error) { + res := &response{Result: result} + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + if err := enc.Encode(res); err != nil { + return "", err + } + return buf.String(), nil +} + +func (o *OmikujiHandler) handlerFunc(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + + var res string + var err error + + if o.isNewYear() { + res, err = o.createResponseJSON(bigLuckey) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } else { + lot := o.Omikuji.Do([]string{}) + res, err = o.createResponseJSON(lot) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } + fmt.Fprintf(w, res) +} + +func (o *OmikujiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + o.handlerFunc(w, r) +} + +func (o *OmikujiHandler) now() time.Time { + if o.Clock == nil { + return time.Now() + } + return o.Clock.Now() +} + +func (o *OmikujiHandler) isNewYear() bool { + _, m, d := o.now().Date() + if m == 1 && d <= 3 { + return true + } + return false +} diff --git a/kadai4/tk3fftk/omikuji/handler_test.go b/kadai4/tk3fftk/omikuji/handler_test.go new file mode 100644 index 0000000..320b53b --- /dev/null +++ b/kadai4/tk3fftk/omikuji/handler_test.go @@ -0,0 +1,95 @@ +package omikuji + +import ( + "io/ioutil" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" +) + +func TestIsNewYear(t *testing.T) { + cases := map[string]struct { + month int + day int + expected bool + }{ + "December31st": { + 12, + 31, + false, + }, + "January1st": { + 1, + 1, + true, + }, + "January2nd": { + 1, 2, true, + }, + "January3rd": { + 1, 3, true, + }, + "January4th": { + 1, 4, false, + }, + } + + for k, v := range cases { + k := k + v := v + + t.Run(k, func(t *testing.T) { + t.Helper() + handler := New( + ClockFunc(func() time.Time { + return time.Date(2018, time.Month(v.month), v.day, 6, 0, 0, 0, time.Local) + }), + ) + + if handler.isNewYear() != v.expected { + t.Errorf("expected=%v, actual=%v", v.expected, !v.expected) + } + }) + } +} + +func TestCreateResponseJSON(t *testing.T) { + handler := New(nil) + result := "test" + expected := "{\"result\":\"test\"}\n" + json, err := handler.createResponseJSON(result) + if err != nil { + t.Fatal("should not come here") + } + if strings.Compare(json, expected) != 0 { + t.Errorf("expected='%v', actual='%v'", expected, json) + } +} + +func TestHandler(t *testing.T) { + handler := New(ClockFunc(func() time.Time { + return time.Date(2018, 1, 1, 6, 0, 0, 0, time.Local) + })) + + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/", nil) + handler.handlerFunc(w, r) + rw := w.Result() + defer rw.Body.Close() + + if rw.StatusCode != http.StatusOK { + t.Fatal("unexpected status code") + } + + b, err := ioutil.ReadAll(rw.Body) + if err != nil { + t.Fatal("unexpected error") + } + expected := "{\"result\":\"大吉\"}\n" + + if s := string(b); s != expected { + t.Errorf("expected='%v', actual='%v'", expected, s) + } +} diff --git a/kadai4/tk3fftk/omikuji/omikuji.go b/kadai4/tk3fftk/omikuji/omikuji.go new file mode 100644 index 0000000..a8cc063 --- /dev/null +++ b/kadai4/tk3fftk/omikuji/omikuji.go @@ -0,0 +1,35 @@ +package omikuji + +import ( + "math/rand" + "time" +) + +var defaultLots = []string{ + "大吉", + "吉", + "中吉", + "小吉", + "凶", + "大凶", +} + +type Omikuji struct { + rand *rand.Rand +} + +func NewOmikuji() Omikuji { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + return Omikuji{ + rand: r, + } +} + +func (o *Omikuji) Do(lots []string) string { + l := len(lots) + if l != 0 { + return lots[rand.Intn(l)] + } + + return defaultLots[rand.Intn(len(defaultLots))] +} diff --git a/kadai4/tk3fftk/omikuji/omikuji_test.go b/kadai4/tk3fftk/omikuji/omikuji_test.go new file mode 100644 index 0000000..9e803a3 --- /dev/null +++ b/kadai4/tk3fftk/omikuji/omikuji_test.go @@ -0,0 +1,32 @@ +package omikuji + +import ( + "strings" + "testing" +) + +func TestOmikuji_Do(t *testing.T) { + cases := map[string][]string{ + "default": defaultLots, + "one": {"大吉"}, + "two": {"大吉", "大凶"}, + } + + o := NewOmikuji() + + for c := range cases { + c := c + t.Run(c, func(t *testing.T) { + t.Helper() + + lots := cases[c] + lot := o.Do(lots) + for _, l := range lots { + if strings.Compare(lot, l) == 0 { + return + } + } + t.Errorf("%v should be included in %v", lot, lots) + }) + } +}