From 8550c1b64624ccdf0bd96aac8a19c8ccd5637d0e Mon Sep 17 00:00:00 2001 From: uobikiemukot Date: Wed, 19 Dec 2018 14:31:16 +0900 Subject: [PATCH 1/4] feature: package fortune --- kadai4/uobikiemukot/fortune/fortune.go | 96 ++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 kadai4/uobikiemukot/fortune/fortune.go diff --git a/kadai4/uobikiemukot/fortune/fortune.go b/kadai4/uobikiemukot/fortune/fortune.go new file mode 100644 index 0000000..29fd89f --- /dev/null +++ b/kadai4/uobikiemukot/fortune/fortune.go @@ -0,0 +1,96 @@ +package fortune + +import ( + "bytes" + "encoding/json" + "fmt" + "math/rand" + "net/http" + "time" +) + +// index of values +const ( + excellent = iota + great + good + bad +) + +var values = []string{ + "大吉", "中吉", "小吉", "凶", +} + +// Clock return current time +type Clock interface { + Now() time.Time +} + +// ClockFunc is an adapter to implement Clock interface +type ClockFunc func() time.Time + +// Now calls f() +func (f ClockFunc) Now() time.Time { + return f() +} + +// Fortune implement Clock interfate +type Fortune struct { + Clock Clock + Err error +} + +// Result is type for JSON encode/decode +type Result struct { + Fortune string `json:"fortune"` +} + +// Encode converts Result into JSON string +func Encode(r Result) (string, error) { + b := bytes.Buffer{} + e := json.NewEncoder(&b) + + err := e.Encode(&r) + if err != nil { + return "", err + } + + return string(b.Bytes()), nil +} + +// Decode converts JSON string into Result +func Decode(s string) (Result, error) { + b := bytes.NewBufferString(s) + d := json.NewDecoder(b) + + var r Result + err := d.Decode(&r) + if err != nil { + return r, err + } + + return r, nil +} + +// Handler http.HandleFunc implementation +func (f *Fortune) Handler(w http.ResponseWriter, r *http.Request) { + var res Result + now := f.Clock.Now() + + if now.Month() == time.January && (1 <= now.Day() && now.Day() <= 3) { + // always return excellent + res.Fortune = values[excellent] + } else { + // random pick up + rand.Seed(now.Unix()) + i := rand.Int() % len(values) + res.Fortune = values[i] + } + + json, err := Encode(res) + if err != nil { + f.Err = err + } else { + fmt.Fprintf(w, json) + } +} From 5d99fdf14811a5ca7305b6c927fa73000689f5c9 Mon Sep 17 00:00:00 2001 From: uobikiemukot Date: Wed, 19 Dec 2018 14:31:28 +0900 Subject: [PATCH 2/4] test: test for fortune package --- kadai4/uobikiemukot/fortune/fortune_test.go | 128 ++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 kadai4/uobikiemukot/fortune/fortune_test.go diff --git a/kadai4/uobikiemukot/fortune/fortune_test.go b/kadai4/uobikiemukot/fortune/fortune_test.go new file mode 100644 index 0000000..6943368 --- /dev/null +++ b/kadai4/uobikiemukot/fortune/fortune_test.go @@ -0,0 +1,128 @@ +package fortune_test + +import ( + "bytes" + "net/http" + "testing" + "time" + + "github.com/gopherdojo/dojo4/kadai4/uobikiemukot/fortune" +) + +// dummyWriter implement http.ResponseWriter +type dummyWriter struct { + buf bytes.Buffer +} + +func (d *dummyWriter) Header() http.Header { + return nil +} + +func (d *dummyWriter) Write(b []byte) (int, error) { + return d.buf.Write(b) +} + +func (d *dummyWriter) WriteHeader(code int) { +} + +// mockWriter creates dummyWriter from bytes.Buffer +func mockWriter(t *testing.T, b bytes.Buffer) dummyWriter { + t.Helper() + return dummyWriter{buf: b} +} + +// mockClock creates fortune.ClockFunc from date string +func mockClock(t *testing.T, s string) fortune.ClockFunc { + t.Helper() + + now, err := time.Parse("2006/01/02", s) + if err != nil { + t.Fatal(err) + } + + return fortune.ClockFunc(func() time.Time { + return now + }) +} + +func parse(t *testing.T, s string) string { + t.Helper() + + r, err := fortune.Decode(s) + if err != nil { + t.Fatal(err) + } + + return r.Fortune +} + +func TestHandler_Success(t *testing.T) { + w := mockWriter(t, bytes.Buffer{}) + + cases := map[string]struct { + writer *dummyWriter + clock fortune.Clock + }{ + "1900/01/01": { + writer: &w, + clock: mockClock(t, "1900/01/01"), + }, + "2000/02/29": { + writer: &w, + clock: mockClock(t, "2000/02/29"), + }, + "2020/12/19": { + writer: &w, + clock: mockClock(t, "2020/12/19"), + }, + } + + for _, c := range cases { + c.writer.buf.Reset() + + f := &fortune.Fortune{Clock: c.clock} + f.Handler(c.writer, nil) + + if f.Err != nil { + t.Errorf("error occurred: %s", f.Err) + } + } +} + +func TestHandler_SpecialDate(t *testing.T) { + w := mockWriter(t, bytes.Buffer{}) + + cases := map[string]struct { + writer *dummyWriter + clock fortune.Clock + msg string + }{ + "2019/01/01": { + writer: &w, + clock: mockClock(t, "2019/01/01"), + msg: "大吉", + }, + "2020/01/02": { + writer: &w, + clock: mockClock(t, "2020/01/02"), + msg: "大吉", + }, + "2021/01/03": { + writer: &w, + clock: mockClock(t, "2021/01/03"), + msg: "大吉", + }, + } + + for _, c := range cases { + c.writer.buf.Reset() + + f := &fortune.Fortune{Clock: c.clock} + f.Handler(c.writer, nil) + + r := parse(t, c.writer.buf.String()) + if r != c.msg { + t.Errorf("want:%s but got:%s\n", c.msg, r) + } + } +} From 4e38c31b228816a07d41643cc7cbb159e03026c8 Mon Sep 17 00:00:00 2001 From: uobikiemukot Date: Wed, 19 Dec 2018 14:32:34 +0900 Subject: [PATCH 3/4] feature: create cmd/server --- kadai4/uobikiemukot/fortune/cmd/server/main.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 kadai4/uobikiemukot/fortune/cmd/server/main.go diff --git a/kadai4/uobikiemukot/fortune/cmd/server/main.go b/kadai4/uobikiemukot/fortune/cmd/server/main.go new file mode 100644 index 0000000..c0208ed --- /dev/null +++ b/kadai4/uobikiemukot/fortune/cmd/server/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "net/http" + "time" + + "github.com/gopherdojo/dojo4/kadai4/uobikiemukot/fortune" +) + +func main() { + clock := fortune.ClockFunc(func() time.Time { + return time.Now() + }) + f := fortune.Fortune{Clock: clock} + + http.HandleFunc("/", f.Handler) + http.ListenAndServe(":8080", nil) +} From 0f5ffa84cb82fb0bf6c6e457d3b3dbdb1ea49dec Mon Sep 17 00:00:00 2001 From: uobikiemukot Date: Wed, 19 Dec 2018 14:33:46 +0900 Subject: [PATCH 4/4] misc: add go.mod --- kadai4/uobikiemukot/fortune/go.mod | 1 + 1 file changed, 1 insertion(+) create mode 100644 kadai4/uobikiemukot/fortune/go.mod diff --git a/kadai4/uobikiemukot/fortune/go.mod b/kadai4/uobikiemukot/fortune/go.mod new file mode 100644 index 0000000..74305ed --- /dev/null +++ b/kadai4/uobikiemukot/fortune/go.mod @@ -0,0 +1 @@ +module github.com/gopherdojo/dojo4/kadai4/uobikiemukot/fortune