diff --git a/kadai4/matsumatsu20/.gitignore b/kadai4/matsumatsu20/.gitignore new file mode 100644 index 0000000..2dd3cba --- /dev/null +++ b/kadai4/matsumatsu20/.gitignore @@ -0,0 +1,95 @@ +# Created by https://www.gitignore.io/api/go,intellij+all + +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +matsukuji + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +### Go Patch ### +/vendor/ +/Godeps/ + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +### Intellij+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# End of https://www.gitignore.io/api/go,intellij+all \ No newline at end of file diff --git a/kadai4/matsumatsu20/Makefile b/kadai4/matsumatsu20/Makefile new file mode 100644 index 0000000..8d260bc --- /dev/null +++ b/kadai4/matsumatsu20/Makefile @@ -0,0 +1,15 @@ +# Go パラメータ +GOCMD=go +GOBUILD=$(GOCMD) build +GOCLEAN=$(GOCMD) clean +GOTEST=$(GOCMD) test +BINARY_NAME=matsukuji + all: test build +build: + $(GOBUILD) -o $(BINARY_NAME) -v +test: + $(GOTEST) -v ./... +clean: + $(GOCLEAN) + rm -f $(BINARY_NAME) + rm -f $(BINARY_UNIX) diff --git a/kadai4/matsumatsu20/README.md b/kadai4/matsumatsu20/README.md new file mode 100644 index 0000000..fe7b214 --- /dev/null +++ b/kadai4/matsumatsu20/README.md @@ -0,0 +1,16 @@ +# おみくじAPIを作ってみよう + +## 課題事項 +- [x] JSON形式でおみくじの結果を返す +- [x] 正月(1/1-1/3)だけ大吉にする +- [x] ハンドラのテストを書いてみる + +## Usage +### build +```bash +% make build +``` + ### run +```bash +% ./matsukuji +``` \ No newline at end of file diff --git a/kadai4/matsumatsu20/dateUtil/dateUtil.go b/kadai4/matsumatsu20/dateUtil/dateUtil.go new file mode 100644 index 0000000..13c5590 --- /dev/null +++ b/kadai4/matsumatsu20/dateUtil/dateUtil.go @@ -0,0 +1,22 @@ +package dateUtil + +import ( + "log" + "time" +) + +var timeNow = time.Now() + +func IsNewYearsHoliday() bool { + jst, err := time.LoadLocation("Asia/Tokyo") + if err != nil { + log.Println(err) + } + + _, month, day := timeNow.In(jst).Date() + if month == time.January && (day == 1 || day == 2 || day == 3) { + return true + } + + return false +} diff --git a/kadai4/matsumatsu20/dateUtil/dateUtil_test.go b/kadai4/matsumatsu20/dateUtil/dateUtil_test.go new file mode 100644 index 0000000..5c1c8cd --- /dev/null +++ b/kadai4/matsumatsu20/dateUtil/dateUtil_test.go @@ -0,0 +1,36 @@ +package dateUtil + +import ( + "log" + "testing" + "time" +) + +func TestIsNewYearsHoliday(t *testing.T) { + jst, err := time.LoadLocation("Asia/Tokyo") + if err != nil { + log.Println(err) + } + + cases := []struct { + year int + month time.Month + day int + expected bool + }{ + {2018, 12, 31, false}, + {2019, 1, 1, true}, + {2019, 1, 2, true}, + {2019, 1, 3, true}, + {2019, 1, 4, false}, + } + + for _, c := range cases { + timeNow = time.Date(c.year, c.month, c.day, 0, 0, 0, 0, jst) + actual := IsNewYearsHoliday() + + if actual != c.expected { + t.Errorf("%v is expected, but returned %v", c.expected, actual) + } + } +} diff --git a/kadai4/matsumatsu20/main.go b/kadai4/matsumatsu20/main.go new file mode 100644 index 0000000..13efc7d --- /dev/null +++ b/kadai4/matsumatsu20/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "flag" + "log" + "net/http" + + "github.com/gopherdojo/dojo3/kadai4/matsumatsu20/omikuji" +) + +var port = flag.String("p", "8080", "listen port") + +func main() { + http.HandleFunc("/kuji", omikuji.Handler) + + if err := http.ListenAndServe(":"+*port, nil); err != nil { + log.Fatal("ListenAndServe: ", err) + } +} diff --git a/kadai4/matsumatsu20/omikuji/omikuji.go b/kadai4/matsumatsu20/omikuji/omikuji.go new file mode 100644 index 0000000..26bf6c9 --- /dev/null +++ b/kadai4/matsumatsu20/omikuji/omikuji.go @@ -0,0 +1,55 @@ +package omikuji + +import ( + "encoding/json" + "log" + "math/rand" + "net/http" + "time" + + "github.com/gopherdojo/dojo3/kadai4/matsumatsu20/dateUtil" +) + +type response struct { + Status int `json:"status"` + Result string `json:"result"` +} + +const ( + daikichi = "大吉" + kichi = "吉" + chukichi = "中吉" + shokichi = "小吉" + suekichi = "末吉" + kyo = "凶" + daikyo = "大凶" +) + +var ( + luck = []string{daikichi, kichi, chukichi, shokichi, suekichi, kyo, daikyo} + isNewYearsHolidayFunc = dateUtil.IsNewYearsHoliday + fetchKujiFunc = fetchKuji +) + +func Handler(w http.ResponseWriter, r *http.Request) { + var result string + + if isNewYearsHolidayFunc() { + result = daikichi + } else { + rand.Seed(time.Now().UnixNano()) + result = fetchKujiFunc() + } + + res := &response{Status: 200, Result: result} + + encoder := json.NewEncoder(w) + if err := encoder.Encode(res); err != nil { + log.Fatal(err) + } +} + +func fetchKuji() string { + rand.Seed(time.Now().UnixNano()) + return luck[rand.Intn(len(luck))] +} diff --git a/kadai4/matsumatsu20/omikuji/omikuji_test.go b/kadai4/matsumatsu20/omikuji/omikuji_test.go new file mode 100644 index 0000000..3c45894 --- /dev/null +++ b/kadai4/matsumatsu20/omikuji/omikuji_test.go @@ -0,0 +1,56 @@ +package omikuji + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" +) + +func TestHandler(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(Handler)) + defer ts.Close() + + cases := []struct { + luck string + isNewYearsHoliday bool + expected response + }{ + {daikichi, false, response{200, "大吉"}}, + {kyo, false, response{200, "凶"}}, + {shokichi, true, response{200, "大吉"}}, + } + + for _, c := range cases { + fetchKujiFunc = func() string { + return c.luck + } + isNewYearsHolidayFunc = func() bool { + return c.isNewYearsHoliday + } + + res, err := http.Get(ts.URL) + + if err != nil { + t.Fatal(err) + } + + body, err := ioutil.ReadAll(res.Body) + + if err != nil { + t.Fatal(err) + } + + if res.StatusCode != 200 { + t.Errorf("expedted status %v, but returned %v", c.expected, 200) + } + + var actual response + json.Unmarshal(body, &actual) + + if actual != c.expected { + t.Errorf("expedted %v, but returned %v", c.expected, actual) + } + } +}