diff --git a/kadai4/go.mod b/kadai4/go.mod new file mode 100644 index 00000000..a71bfa85 --- /dev/null +++ b/kadai4/go.mod @@ -0,0 +1,3 @@ +module github.com/kotaaaa/gopherdojo-studyroom/kadai4 + +go 1.14 diff --git a/kadai4/kotaaaa/README.md b/kadai4/kotaaaa/README.md new file mode 100644 index 00000000..9dfb0e30 --- /dev/null +++ b/kadai4/kotaaaa/README.md @@ -0,0 +1,23 @@ +# Let's make a fortune API. +- Returning omikuji results in JSON format +- Only New Year's Day (Jan. 1 - Jan. 3) is set to "Daikichi". +- Writing tests for the handler + +# How to use +``` +$ go build -o fortune-api +$ ./fortune-api +$ curl "http://localhost:8080/draw?p=2021-11-14" +{"status":"Success","result":"末吉"} +$ curl "http://localhost:8080/draw" +{"status":"Success","result":"小吉"} +``` + +# How to Test +``` +$ go test ./... --count=1 -cover +? github.com/kotaaaa/gopherdojo-studyroom/kadai4/kotaaaa [no test files] +ok github.com/kotaaaa/gopherdojo-studyroom/kadai4/kotaaaa/fortune 0.007s coverage: 46.2% of statements +ok github.com/kotaaaa/gopherdojo-studyroom/kadai4/kotaaaa/handler 0.013s coverage: 73.1% of statements +$ go test ./... -v +``` diff --git a/kadai4/kotaaaa/fortune/fortune.go b/kadai4/kotaaaa/fortune/fortune.go new file mode 100644 index 00000000..28f080fe --- /dev/null +++ b/kadai4/kotaaaa/fortune/fortune.go @@ -0,0 +1,46 @@ +package fortune + +import ( + "math/rand" + "time" +) + +type Luck int + +const ( + Great Luck = iota // 大吉 + Middle // 中吉 + Small // 小吉 + Normal // 吉 + Uncertain // 末吉 + Curse // 凶 + GreatCurse // 大凶 + Kind // 種類数 +) + +func (c Luck) String() string { + switch c { + case Great: + return "大吉" + case Middle: + return "中吉" + case Small: + return "小吉" + case Normal: + return "吉" + case Uncertain: + return "末吉" + case Curse: + return "凶" + case GreatCurse: + return "大凶" + } + panic("Unknown value") +} + +func Draw(t time.Time) Luck { + if t.Month() == time.January && t.Day() >= 1 && t.Day() <= 3 { + return Great + } + return Luck(rand.Intn(int(Kind))) +} diff --git a/kadai4/kotaaaa/fortune/fortune_test.go b/kadai4/kotaaaa/fortune/fortune_test.go new file mode 100644 index 00000000..683b8ec3 --- /dev/null +++ b/kadai4/kotaaaa/fortune/fortune_test.go @@ -0,0 +1,29 @@ +package fortune + +import ( + "testing" + "time" +) + +func TestForecast(t *testing.T) { + ti := time.Date(2021, 1, 1, 8, 4, 18, 0, time.UTC) + res := Draw(ti) + if res.String() != "大吉" { + t.Error("Forecast is illigal. Expected 大吉, Result ", res.String()) + } +} + +func TestForecastNormal(t *testing.T) { + ti := time.Date(2021, 1, 1, 8, 4, 18, 0, time.UTC) + res := Draw(ti) + if res >= 7 { + t.Error("Forecast is illigal. Expected <= 7, Result ", res) + } +} +func TestString(t *testing.T) { + c := Luck(2) + res := c.String() + if res != "小吉" { + t.Error("Forecast is illigal. Expected 中吉, Result ", res) + } +} diff --git a/kadai4/kotaaaa/handler/handler.go b/kadai4/kotaaaa/handler/handler.go new file mode 100644 index 00000000..ec211773 --- /dev/null +++ b/kadai4/kotaaaa/handler/handler.go @@ -0,0 +1,61 @@ +package handler + +import ( + "bytes" + "encoding/json" + "fmt" + "log" + "net/http" + "time" + + "github.com/kotaaaa/gopherdojo-studyroom/kadai4/kotaaaa/fortune" +) + +// API response model +type ResModel struct { + Status string `json:"status"` + Result string `json:"result"` +} + +func httpHandler(w http.ResponseWriter, r *http.Request) { + p := &ResModel{Status: "", Result: ""} + var t time.Time + var err error + date := r.FormValue("p") + timeFormat := "2006-01-02" + + // If request parameter exists + fmt.Println("date:", date) + if date != "" { + t, err = time.Parse(timeFormat, date) + if err != nil { + fmt.Println(fmt.Errorf("Time format invalid: %v", err.Error())) + // w.WriteHeader(http.StatusBadRequest) + } + } else { + t = time.Now() + } + + res := fortune.Draw(t) + p.Status = "Success" + p.Result = res.String() + var buf bytes.Buffer + err = json.NewEncoder(w).Encode(p) + if err != nil { + log.Fatal(err) + } + err = json.NewEncoder(&buf).Encode(p) + if err != nil { + log.Fatal(err) + } + fmt.Println(buf.String()) +} + +//Run application +func Run() { + http.HandleFunc("/draw", httpHandler) + err := http.ListenAndServe(":8080", nil) + if err != nil { + log.Fatal(err) + } +} diff --git a/kadai4/kotaaaa/handler/handler_test.go b/kadai4/kotaaaa/handler/handler_test.go new file mode 100644 index 00000000..2f6b8642 --- /dev/null +++ b/kadai4/kotaaaa/handler/handler_test.go @@ -0,0 +1,48 @@ +package handler + +import ( + "encoding/json" + "net/http/httptest" + "testing" +) + +func TestHandler(t *testing.T) { + cases := []struct { + name string + date string + expectedResult bool + expected string + statusCode int + }{ + {name: "No date", date: "", statusCode: 200}, + {name: "12/31", date: "2020-12-31", statusCode: 200}, + {name: "New Year's Day", date: "2021-01-01", expectedResult: true, expected: "大吉", statusCode: 200}, + {name: "1/2", date: "2021-01-02", expectedResult: true, expected: "大吉", statusCode: 200}, + {name: "1/3", date: "2021-01-03", expectedResult: true, expected: "大吉", statusCode: 200}, + {name: "3/9", date: "2021-03-09", statusCode: 200}, + {name: "Not found a]", date: "2021-03-09", statusCode: 200}, + } + + for _, c := range cases { + c := c + t.Run(c.name, func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/draw?p="+c.date, nil) + httpHandler(w, r) + rw := w.Result() + defer rw.Body.Close() + if rw.StatusCode != c.statusCode { + t.Fatal("Unexpected status code") + } + + var res ResModel + dec := json.NewDecoder(rw.Body) + if err := dec.Decode(&res); err != nil { + t.Fatal(err) + } + if c.expectedResult && c.expected != res.Result { + t.Errorf("Result is illigal. Expected %v, Result %v", c.expected, res.Result) + } + }) + } +} diff --git a/kadai4/kotaaaa/main.go b/kadai4/kotaaaa/main.go new file mode 100644 index 00000000..9bce5ae5 --- /dev/null +++ b/kadai4/kotaaaa/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "math/rand" + "time" + + "github.com/kotaaaa/gopherdojo-studyroom/kadai4/kotaaaa/handler" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func main() { + handler.Run() +}