diff --git a/kadai4/pei/Makefile b/kadai4/pei/Makefile new file mode 100644 index 0000000..011a05d --- /dev/null +++ b/kadai4/pei/Makefile @@ -0,0 +1,17 @@ +ROOT=github.com/gopherdojo/dojo6/kadai4/pei +BIN=fortune +MAIN=main.go +TEST=... + +.PHONY: build +build: ${MAIN} + go build -o ${BIN} ${GOPATH}/src/${ROOT}/$? + +.PHONY: test +test: + go test -v -cover ${ROOT}/${TEST} + +.PHONY: clean +clean: + rm ${BIN} + go clean diff --git a/kadai4/pei/README.md b/kadai4/pei/README.md new file mode 100644 index 0000000..0b12fe7 --- /dev/null +++ b/kadai4/pei/README.md @@ -0,0 +1,5 @@ +## 課題4 おみくじAPIを作ってみよう + +- JSON形式でおみくじの結果を返す +- 正月(1/1-1/3)だけ大吉にする +- ハンドラのテストを書いてみる diff --git a/kadai4/pei/main.go b/kadai4/pei/main.go new file mode 100644 index 0000000..f12a73c --- /dev/null +++ b/kadai4/pei/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "flag" + "fmt" + "net/http" + + "github.com/gopherdojo/dojo6/kadai4/pei/pkg/fortune" +) + +var port int + +func init() { + flag.IntVar(&port, "p", 8080, "server port") +} + +func main() { + flag.Parse() + f := fortune.NewFortune(fortune.DefaultClock{}) + http.HandleFunc("/", f.Handler) + http.ListenAndServe(fmt.Sprintf(":%d", port), nil) +} diff --git a/kadai4/pei/pkg/fortune/fortune.go b/kadai4/pei/pkg/fortune/fortune.go new file mode 100644 index 0000000..bb3d927 --- /dev/null +++ b/kadai4/pei/pkg/fortune/fortune.go @@ -0,0 +1,88 @@ +package fortune + +import ( + "bytes" + "encoding/json" + "fmt" + "math/rand" + "net/http" + "time" +) + +var fortuneList = []string{ + "大吉", + "中吉", + "吉", + "小吉", + "凶", +} + +// Clock +type Clock interface { + GetCurrentTime() time.Time +} + +// DefaultClock +type DefaultClock struct{} + +// Fortune +type Fortune struct { + clock Clock +} + +// DrawingResult +type DrawingResult struct { + Result string `json:"result"` +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// GetCurrentTime return current time +func (d DefaultClock) GetCurrentTime() time.Time { + return time.Now() +} + +// NewFortune return fortune instance +func NewFortune(c Clock) * Fortune { + return &Fortune{clock: c} +} + +func (f Fortune) drawingForNewYearDay() string { + return "大吉" +} + +func (f Fortune) defaultDrawing() string { + return fortuneList[rand.Intn(len(fortuneList))] +} + +func (f Fortune) isNewYearDay() bool { + c := f.clock.GetCurrentTime() + + return c.Month() == 1 && 1 <= c.Day() && c.Day() <= 3 +} + +// Drawing return drawing result +func (f Fortune) Drawing() string { + if f.isNewYearDay() { + return f.drawingForNewYearDay() + } + return f.defaultDrawing() +} + +// GetFortuneList return fortuneList +func (f Fortune) GetFortuneList() []string { + return fortuneList +} + +// Handler +func (f Fortune) Handler(w http.ResponseWriter, r *http.Request) { + var buf bytes.Buffer + dr := DrawingResult{Result: f.Drawing()} + enc := json.NewEncoder(&buf) + if err := enc.Encode(dr); err != nil { + fmt.Errorf("error: %v", err) + } + fmt.Fprint(w, buf.String()) +} diff --git a/kadai4/pei/pkg/fortune/fortune_test.go b/kadai4/pei/pkg/fortune/fortune_test.go new file mode 100644 index 0000000..96362e6 --- /dev/null +++ b/kadai4/pei/pkg/fortune/fortune_test.go @@ -0,0 +1,73 @@ +package fortune_test + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/gopherdojo/dojo6/kadai4/pei/pkg/fortune" +) + +func TestFortune_Handler(t *testing.T) { + f := fortune.NewFortune(fortune.DefaultClock{}) + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/", nil) + f.Handler(w, r) + + rw := w.Result() + defer rw.Body.Close() + if rw.StatusCode != http.StatusOK { + t.Error("unexpected status code") + } + + b, err := ioutil.ReadAll(rw.Body) + if err != nil { + t.Error("unexpected error") + } + + dr := &fortune.DrawingResult{} + if err := json.Unmarshal(b, &dr); err != nil { + t.Error("failed json unmarshal") + } + + fortuneList := f.GetFortuneList() + contain := false + for _, v := range fortuneList { + if v == dr.Result { + contain = true + break + } + } + + if !contain { + t.Errorf("unexpected response: %s", string(b)) + } +} + +type MockClock struct { + currentTime time.Time +} + +func (mc MockClock) GetCurrentTime() time.Time { + return mc.currentTime +} + +func TestFortune_Drawing(t *testing.T) { + cases := []struct { + clock time.Time + }{ + {time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)}, + {time.Date(2019, 1, 3, 23, 59, 59, 0, time.UTC)}, + } + + for _, c := range cases { + mc := &MockClock{c.clock} + f := fortune.NewFortune(mc) + if actual := f.Drawing(); actual != "大吉" { + t.Errorf("unexpected result: %s on %v", actual, mc.GetCurrentTime()) + } + } +}