diff --git a/kadai4/gosagawa/.gitignore b/kadai4/gosagawa/.gitignore new file mode 100644 index 0000000..aca9fba --- /dev/null +++ b/kadai4/gosagawa/.gitignore @@ -0,0 +1,3 @@ +bin/* +!.gitkeep + diff --git a/kadai4/gosagawa/Makefile b/kadai4/gosagawa/Makefile new file mode 100644 index 0000000..b4dd4d9 --- /dev/null +++ b/kadai4/gosagawa/Makefile @@ -0,0 +1,17 @@ +VERSION=1.0.0 +TARGETS_NOVENDOR=$(shell go list ./... | grep -v /vendor/) + +all: bin/main + +bin/main: main.go + go build -o bin/main main.go + +fmt: + @echo ./... | xargs go fmt + +check: + go test -v -cover ./... + +clean: + rm -rf bin/* + diff --git a/kadai4/gosagawa/README.md b/kadai4/gosagawa/README.md new file mode 100644 index 0000000..d760fe9 --- /dev/null +++ b/kadai4/gosagawa/README.md @@ -0,0 +1,38 @@ +# kadai4 + +- おみくじAPIを作ってみよう + - JSON形式でおみくじの結果を返す + - 正月(1/1-1/3)だけ大吉にする + - ハンドラのテストを書いてみる + +#install + +```shell +$ make +``` + +#usage + +- 実行するとポート8080でサーバが起動されます。 +```shell +$ bin/main +``` + +- アクセスすると、その日のおみくじ結果を返します。 +```shell +$ curl "http://127.0.0.1:8080/" +{"result":"吉"} +``` + +- パラメータでdateを指定すると、その日のおみくじ結果を確認できます。 +```shell +$ curl "http://127.0.0.1:8080/?date=2019-01-02" +{"result":"大吉"} +``` + +#test + +```shell +$ make check +``` + diff --git a/kadai4/gosagawa/bin/.gitkeep b/kadai4/gosagawa/bin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/kadai4/gosagawa/main.go b/kadai4/gosagawa/main.go new file mode 100644 index 0000000..2e2b0ea --- /dev/null +++ b/kadai4/gosagawa/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "encoding/json" + "log" + "net/http" + + "github.com/gopherdojo/dojo3/kadai4/gosagawa/omikuzi" +) + +//OmikuziResult おみくじの実行結果 +type OmikuziResult struct { + Result string `json:"result"` +} + +func main() { + http.HandleFunc("/", handler) + err := http.ListenAndServe(":8080", nil) + if err != nil { + log.Println("Error:", err) + } +} + +func handler(w http.ResponseWriter, r *http.Request) { + + date := r.FormValue("date") + var data *OmikuziResult + if date == "" { + data = &OmikuziResult{Result: omikuzi.Draw()} + } else { + data = &OmikuziResult{Result: omikuzi.DrawByDate(date)} + } + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + if err := json.NewEncoder(w).Encode(data); err != nil { + log.Println("Error:", err) + } +} diff --git a/kadai4/gosagawa/main_test.go b/kadai4/gosagawa/main_test.go new file mode 100644 index 0000000..38229ae --- /dev/null +++ b/kadai4/gosagawa/main_test.go @@ -0,0 +1,47 @@ +package main + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" +) + +func TestHandler(t *testing.T) { + + cases := []struct { + name string + date string + isResultFixed bool + result string + }{ + {name: "normal", date: ""}, + {name: "shogatsu_12/31", date: "2018-12-31"}, + {name: "shogatsu_1/1", date: "2019-01-01", isResultFixed: true, result: "大吉"}, + {name: "shogatsu_1/2", date: "2019-01-02", isResultFixed: true, result: "大吉"}, + {name: "shogatsu_1/3", date: "2019-01-03", isResultFixed: true, result: "大吉"}, + {name: "shogatsu_1/4", date: "2019-01-04"}, + } + + for _, v := range cases { + t.Run(v.name, func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/?date="+v.date, nil) + handler(w, r) + rw := w.Result() + defer rw.Body.Close() + if rw.StatusCode != http.StatusOK { + t.Fatal("unexpected status code") + } + var or OmikuziResult + dec := json.NewDecoder(rw.Body) + if err := dec.Decode(&or); err != nil { + t.Fatal(err) + } + + if v.isResultFixed && or.Result != v.result { + t.Errorf("expected %v but %v ", v.result, or.Result) + } + }) + } +} diff --git a/kadai4/gosagawa/omikuzi/omikuzi.go b/kadai4/gosagawa/omikuzi/omikuzi.go new file mode 100644 index 0000000..bb592ad --- /dev/null +++ b/kadai4/gosagawa/omikuzi/omikuzi.go @@ -0,0 +1,121 @@ +package omikuzi + +import ( + "log" + "math/rand" + "time" +) + +//Fortune おみくじ結果 +type Fortune string + +//RandomGenerater ランダム生成器 +type RandomGenerater interface { + Get() int +} + +//OmikuziPattern おみくじ結果配列 +var OmikuziPattern []Fortune + +const ( + //Daikichi 大吉 + Daikichi Fortune = "大吉" + + //Chukichi 中吉 + Chukichi Fortune = "中吉" + + //Kichi 吉 + Kichi Fortune = "吉" + + //Kyo 凶 + Kyo Fortune = "凶" +) + +//TimeLayout 日付レイアウト +const TimeLayout = "2006-01-02" + +//Omikuzi おみくじ構造体 +type Omikuzi struct { + RandomGenerater RandomGenerater + Time time.Time + OmikuziPattern []Fortune +} + +//Draw おみくじを引く +func (o *Omikuzi) Draw() Fortune { + m := int(o.Time.Month()) + d := o.Time.Day() + + var r Fortune + if isShogatsu(m, d) { + r = Daikichi + } else { + r = o.OmikuziPattern[o.RandomGenerater.Get()] + } + return r +} + +func isShogatsu(m int, d int) bool { + if m == 1 && d >= 1 && d <= 3 { + return true + } + return false +} + +func init() { + OmikuziPattern = []Fortune{ + Kyo, + Kichi, + Kichi, + Chukichi, + Chukichi, + Daikichi, + } +} + +//Draw おみくじを引く +func Draw() string { + + now := time.Now() + + //XXX 1日で結果を固定するように当日の00:00を取得するためフォーマット化し、 + //またtime.Timeに戻してている。 + //別のいいやり方がないか検討していた。 + timeFormated := now.Format(TimeLayout) + targetTime, err := time.Parse(TimeLayout, timeFormated) + if err != nil { + log.Println("error:", err) + } + + o := Omikuzi{ + RandomGenerater: &random{TargetTime: targetTime}, + Time: targetTime, + OmikuziPattern: OmikuziPattern, + } + return string(o.Draw()) +} + +//DrawByDate 日付でおみくじを引く +func DrawByDate(targetDate string) string { + + targetTime, err := time.Parse(TimeLayout, targetDate) + if err != nil { + log.Println("error:", err) + } + + o := Omikuzi{ + RandomGenerater: &random{TargetTime: targetTime}, + Time: targetTime, + OmikuziPattern: OmikuziPattern, + } + return string(o.Draw()) +} + +type random struct { + TargetTime time.Time +} + +func (r *random) Get() int { + rand.Seed(r.TargetTime.Unix()) + return rand.Intn(len(OmikuziPattern)) +} diff --git a/kadai4/gosagawa/omikuzi/omikuzi_test.go b/kadai4/gosagawa/omikuzi/omikuzi_test.go new file mode 100644 index 0000000..d3d24c8 --- /dev/null +++ b/kadai4/gosagawa/omikuzi/omikuzi_test.go @@ -0,0 +1,58 @@ +package omikuzi + +import ( + "log" + "testing" + "time" +) + +func TestDraw(t *testing.T) { + cases := []struct { + name string + date string + index int + result Fortune + }{ + {name: "normal_0", date: "2018-09-01", index: 0, result: Kyo}, + {name: "normal_1", date: "2018-09-01", index: 1, result: Kichi}, + {name: "normal_2", date: "2018-09-01", index: 2, result: Kichi}, + {name: "normal_3", date: "2018-09-01", index: 3, result: Chukichi}, + {name: "normal_4", date: "2018-09-01", index: 4, result: Chukichi}, + {name: "normal_5", date: "2018-09-01", index: 5, result: Daikichi}, + {name: "shogatsu_12/31", date: "2018-12-31", index: 0, result: Kyo}, + {name: "shogatsu_1/1", date: "2019-01-01", index: 0, result: Daikichi}, + {name: "shogatsu_1/2", date: "2019-01-02", index: 0, result: Daikichi}, + {name: "shogatsu_1/3", date: "2019-01-03", index: 0, result: Daikichi}, + {name: "shogatsu_1/4", date: "2019-01-04", index: 0, result: Kyo}, + } + layout := "2006-01-02" + for _, v := range cases { + t.Run(v.name, func(t *testing.T) { + time, err := time.Parse(layout, v.date) + if err != nil { + log.Fatal(err) + } + o := Omikuzi{ + RandomGenerater: &TestRandom{index: v.index}, + Time: time, + OmikuziPattern: OmikuziPattern, + } + result := o.Draw() + if result != v.result { + t.Errorf("expected %v but %v ", v.result, result) + } + }) + } +} + +func getTestRandomGenerater(index int) { + +} + +type TestRandom struct { + index int +} + +func (r *TestRandom) Get() int { + return r.index +}