diff --git a/kadai4/hokita/README.md b/kadai4/hokita/README.md new file mode 100644 index 0000000..7f98265 --- /dev/null +++ b/kadai4/hokita/README.md @@ -0,0 +1,30 @@ +# 課題4 +## おみくじAPIを作ってみよう +- JSON形式でおみくじの結果を返す +- 正月(1/1-1/3)だけ大吉にする +- ハンドラのテストを書いてみる + +## 動作 +```shell +$ go build -o omkj +$ ./omkj +``` + +別ターミナルで +```shell +$ curl localhost:8080/omikuji/ +{"result":"末吉"} + +$ curl localhost:8080/omikuji/ +{"result":"吉"} + +$ curl localhost:8080/omikuji/ +{"result":"中吉"} + +$ curl localhost:8080/omikuji/ +{"result":"凶"} +``` + +## 参考 +- https://github.com/quii/learn-go-with-tests/blob/main/http-server.md +- https://github.com/quii/learn-go-with-tests/blob/main/json.md diff --git a/kadai4/hokita/go.mod b/kadai4/hokita/go.mod new file mode 100644 index 0000000..53e970d --- /dev/null +++ b/kadai4/hokita/go.mod @@ -0,0 +1,3 @@ +module github.com/gopherdojo/dojo8/kadai4/hokita/omikuji + +go 1.14 diff --git a/kadai4/hokita/main.go b/kadai4/hokita/main.go new file mode 100644 index 0000000..6b63513 --- /dev/null +++ b/kadai4/hokita/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "math/rand" + "time" + + "github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func main() { + server.Run() +} diff --git a/kadai4/hokita/omikuji/omikuji.go b/kadai4/hokita/omikuji/omikuji.go new file mode 100644 index 0000000..b0b1f69 --- /dev/null +++ b/kadai4/hokita/omikuji/omikuji.go @@ -0,0 +1,42 @@ +package omikuji + +import ( + "math/rand" + "time" +) + +type Omikuji struct { + Time time.Time +} + +type Result struct { + Result string `json:"result"` +} + +func New(t time.Time) *Omikuji { + return &Omikuji{t} +} + +func (o *Omikuji) Draw() *Result { + results := []string{"大吉", "中吉", "吉", "末吉", "凶", "大凶"} + + if o.isNewYear(o.Time) { + return &Result{results[0]} + } + return &Result{results[rand.Intn(6)]} +} + +func (o *Omikuji) isNewYear(time time.Time) bool { + newYearDays := []string{ + "Jan 1", + "Jan 2", + "Jan 3", + } + + for _, day := range newYearDays { + if day == time.Format("Jan 2") { + return true + } + } + return false +} diff --git a/kadai4/hokita/omikuji/omikuji_test.go b/kadai4/hokita/omikuji/omikuji_test.go new file mode 100644 index 0000000..1df1415 --- /dev/null +++ b/kadai4/hokita/omikuji/omikuji_test.go @@ -0,0 +1,54 @@ +package omikuji_test + +import ( + "math/rand" + "reflect" + "testing" + "time" + + "github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji" +) + +func TestMain(m *testing.M) { + m.Run() + rand.Seed(time.Now().UnixNano()) +} + +func TestOmikuji_Draw(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + inTime time.Time + want1 *omikuji.Result + want2 *omikuji.Result + }{ + "standard day": { + inTime: time.Date(2000, 1, 4, 0, 0, 0, 0, time.Local), + want1: &omikuji.Result{"大凶"}, + want2: &omikuji.Result{"末吉"}, + }, + "new year": { + inTime: time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local), + want1: &omikuji.Result{"大吉"}, + want2: &omikuji.Result{"大吉"}, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + rand.Seed(1) + + o := &omikuji.Omikuji{ + test.inTime, + } + got1 := o.Draw() + if !reflect.DeepEqual(got1, test.want1) { + t.Fatalf(`want1: "%v" actual1: "%v"`, test.want1, got1) + } + got2 := o.Draw() + if !reflect.DeepEqual(got2, test.want2) { + t.Fatalf(`want2: "%v" actual2: "%v"`, test.want2, got2) + } + }) + } +} diff --git a/kadai4/hokita/profile b/kadai4/hokita/profile new file mode 100644 index 0000000..6cdc4b5 --- /dev/null +++ b/kadai4/hokita/profile @@ -0,0 +1,17 @@ +mode: set +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:16.32,18.2 1 0 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:20.34,23.25 2 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:26.2,26.39 1 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:23.25,25.3 1 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:29.50,36.34 2 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:41.2,41.14 1 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:36.34,37.34 1 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji/omikuji.go:37.34,39.4 1 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:21.12,23.2 1 0 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:25.16,28.61 2 0 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:32.2,32.10 1 0 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:28.61,31.3 2 0 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:35.27,37.2 1 0 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:39.68,44.2 3 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:46.73,47.68 1 1 +github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server/server.go:47.68,50.3 2 0 diff --git a/kadai4/hokita/server/server.go b/kadai4/hokita/server/server.go new file mode 100644 index 0000000..a8494cf --- /dev/null +++ b/kadai4/hokita/server/server.go @@ -0,0 +1,51 @@ +package server + +import ( + "encoding/json" + "fmt" + "net/http" + "os" + "time" + + "github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji" +) + +type Omikuji interface { + Draw() *omikuji.Result +} + +type Server struct { + Omikuji Omikuji +} + +func Run() { + os.Exit(run()) +} + +func run() int { + server := &Server{NewOmikuji()} + + if err := http.ListenAndServe(":8080", server); err != nil { + fmt.Fprintf(os.Stderr, "could not listen on port 8080 %v\n", err) + return 1 + } + return 0 +} + +func NewOmikuji() Omikuji { + return omikuji.New(time.Now()) +} + +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + router := http.NewServeMux() + router.Handle("/omikuji/", http.HandlerFunc(s.omikujiHandler)) + + router.ServeHTTP(w, r) +} + +func (s *Server) omikujiHandler(w http.ResponseWriter, r *http.Request) { + if err := json.NewEncoder(w).Encode(s.Omikuji.Draw()); err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } +} diff --git a/kadai4/hokita/server/server_test.go b/kadai4/hokita/server/server_test.go new file mode 100644 index 0000000..0fac461 --- /dev/null +++ b/kadai4/hokita/server/server_test.go @@ -0,0 +1,60 @@ +package server_test + +import ( + "encoding/json" + "math/rand" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/omikuji" + "github.com/gopherdojo/dojo8/kadai4/hokita/omikuji/server" +) + +func TestGETOmikuji(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + time time.Time + want omikuji.Result + }{ + "standard day": { + time: time.Date(2000, 1, 4, 0, 0, 0, 0, time.Local), + want: omikuji.Result{ + Result: "大凶", + }, + }, + "new year": { + time: time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local), + want: omikuji.Result{ + Result: "大吉", + }, + }, + } + + for name, test := range tests { + rand.Seed(1) + + server := &server.Server{ + omikuji.New(test.time), + } + + request, _ := http.NewRequest(http.MethodGet, "/omikuji/", nil) + response := httptest.NewRecorder() + + server.ServeHTTP(response, request) + + t.Run(name, func(t *testing.T) { + var got omikuji.Result + + err := json.NewDecoder(response.Body).Decode(&got) + if err != nil { + t.Fatalf(`unable to parse json. error: "%v"`, got) + } + if got != test.want { + t.Fatalf(`want:"%v" actual:"%v"`, test.want, got) + } + }) + } +}