diff --git a/kadai4/akuchii/fortune/export_test.go b/kadai4/akuchii/fortune/export_test.go new file mode 100644 index 0000000..96ac810 --- /dev/null +++ b/kadai4/akuchii/fortune/export_test.go @@ -0,0 +1,5 @@ +package fortune + +func (f Fortune) GetFortuneList() []string { + return fortuneList +} diff --git a/kadai4/akuchii/fortune/fortune.go b/kadai4/akuchii/fortune/fortune.go new file mode 100644 index 0000000..026e4b3 --- /dev/null +++ b/kadai4/akuchii/fortune/fortune.go @@ -0,0 +1,78 @@ +package fortune + +import ( + "bytes" + "encoding/json" + "fmt" + "log" + "math/rand" + "net/http" + "time" +) + +var fortuneList = []string{"大吉", "吉", "中吉", "小吉", "末吉", "凶", "大凶"} + +// Clock is interface to get current time +type Clock interface { + GetCurrentTime() time.Time +} + +// DefaultClock equals current time +type DefaultClock struct{} + +// Fortune lots fortune depends on time +type Fortune struct { + clock Clock +} + +// LotResult contains result of fortune +type LotResult struct { + Result string `json:"result"` +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// GetCurrentTime returns current time +func (d DefaultClock) GetCurrentTime() time.Time { + return time.Now() +} + +// NewFortune returns fortune instance +func NewFortune(c Clock) *Fortune { + return &Fortune{clock: c} +} + +func (f Fortune) lotForNewYearDay() string { + return "大吉" +} + +func (f Fortune) defaultLot() 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 +} + +// Lot lots fortune +func (f Fortune) Lot() string { + if f.isNewYearDay() { + return f.lotForNewYearDay() + } + return f.defaultLot() +} + +// Handler returns fortune result +func (f Fortune) Handler(w http.ResponseWriter, r *http.Request) { + var buf bytes.Buffer + fr := LotResult{Result: f.Lot()} + enc := json.NewEncoder(&buf) + if err := enc.Encode(fr); err != nil { + log.Fatal(err) + } + fmt.Fprint(w, buf.String()) +} diff --git a/kadai4/akuchii/fortune/fortune_test.go b/kadai4/akuchii/fortune/fortune_test.go new file mode 100644 index 0000000..570bae4 --- /dev/null +++ b/kadai4/akuchii/fortune/fortune_test.go @@ -0,0 +1,72 @@ +package fortune_test + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/gopherdojo/dojo4/kadai4/akuchii/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.Fatal("unexpected status code") + } + b, err := ioutil.ReadAll(rw.Body) + if err != nil { + t.Fatal("unexpected error") + } + + fr := &fortune.LotResult{} + if err := json.Unmarshal(b, &fr); err != nil { + t.Fatal("failed json unmarshal") + } + + var fortuneList = f.GetFortuneList() + contain := false + for _, v := range fortuneList { + if v == fr.Result { + contain = true + break + } + } + + if !contain { + t.Fatalf("unexpected response: %s", string(b)) + } +} + +type MockClock struct { + currentTime time.Time +} + +func (mc MockClock) GetCurrentTime() time.Time { + return mc.currentTime +} + +func TestFortune_LotOnNewYearDay(t *testing.T) { + cases := []struct { + newYearDay time.Time + }{ + {time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)}, + {time.Date(2018, 1, 2, 0, 0, 0, 0, time.UTC)}, + {time.Date(2017, 1, 3, 23, 59, 59, 0, time.UTC)}, + } + for _, c := range cases { + mc := &MockClock{c.newYearDay} + f := fortune.NewFortune(mc) + result := f.Lot() + if result != "大吉" { + t.Errorf("unexpected result: %s on %v", result, mc.GetCurrentTime()) + } + } +} diff --git a/kadai4/akuchii/main.go b/kadai4/akuchii/main.go new file mode 100644 index 0000000..21ea27a --- /dev/null +++ b/kadai4/akuchii/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "flag" + "fmt" + "net/http" + + "github.com/gopherdojo/dojo4/kadai4/akuchii/fortune" +) + +// servert port +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) +}