Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

課題4 徳永 おみくじAPIの作成 #45

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
41 changes: 41 additions & 0 deletions kadai4/tokunaga/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// handler は、 HTTP リクエストの情報を返します。
package main

import (
crand "crypto/rand"
"log"
"math"
"math/big"
"math/rand"
"net/http"
"time"
)

func init() {
if err := serRandSeed(); err != nil {
log.Fatal(err)
}
}

func serRandSeed() error {
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
rand.Seed(seed.Int64())
return err
}

type timeWrapper struct{}
type randWrapper struct{}

func (t timeWrapper) Now() time.Time {
return time.Now()
}

func (r randWrapper) Intn(n int) int {
return rand.Intn(n)
}

func main() {
omikuji := omikuji{nower: timeWrapper{}, intner: randWrapper{}}
http.HandleFunc("/omikuji", omikuji.open)
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
82 changes: 82 additions & 0 deletions kadai4/tokunaga/omikuji.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"time"
)

const daikiti = 0

var box = map[int]string{
0: "大吉",
1: "中吉",
2: "小吉",
3: "凶",
4: "大凶",
}

var syougatu = [...]string{
"01-01",
"01-02",
"01-03",
}

type nower interface {
Now() time.Time
}

type intner interface {
Intn(int) int
}

type response struct {
Result string `json:"result"`
}

type omikuji struct {
nower
intner
response
}

func (o *omikuji) open(w http.ResponseWriter, r *http.Request) {
o.pickUp()
buf := o.encodeJson()
fmt.Fprintf(w, buf.String())
}

func (o *omikuji) encodeJson() bytes.Buffer {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
if err := enc.Encode(o.response); err != nil {
log.Fatal(err)
}
return buf
}

func (o *omikuji) pickUp() {
if isOsyougatu(o.Now()) {
o.Result = getDaikiti()
} else {
o.Result = box[o.Intn(5)]
}

}

func isOsyougatu(date time.Time) bool {
day := date.Format("01-02")
for _, sanganichi := range syougatu {
if day == sanganichi {
return true
}
}
return false
}

func getDaikiti() string {
return box[daikiti]
}
105 changes: 105 additions & 0 deletions kadai4/tokunaga/omikuji_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package main

import (
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)

type testNower struct {
now time.Time
}

type testIntner struct {
randInt int
}

func (t testNower) Now() time.Time {
return t.now
}
func (t testIntner) Intn(_ int) int {
return t.randInt - 1
}

func TestOpen(t *testing.T) {
shougatsu := testNower{now: time.Date(2018, 1, 1, 9, 11, 11, 11, time.UTC)}
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/omikuji", nil)
o := omikuji{nower: shougatsu, intner: testIntner{randInt: 5}}
o.open(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")
}
expected := `{"result":"大吉"}`
if s := strings.TrimSpace(string(b)); s != expected {
t.Fatalf("want: %s, got: %s", expected, s)
}
}

func TestEncodeJson(t *testing.T) {
expected := `{"result":"大吉"}`
o := omikuji{response: response{Result: "大吉"}}
actual := o.encodeJson()
if strings.TrimSpace(actual.String()) != expected {
t.Errorf("want: o.encodeJson() = %s, got: %s ", expected, actual)
}
}

func TestPickUp(t *testing.T) {
nenmatsu := testNower{now: time.Date(2017, 12, 31, 23, 59, 11, 11, time.UTC)}
shougatsu := testNower{now: time.Date(2018, 1, 1, 9, 11, 11, 11, time.UTC)}
cases := []struct {
name string
input omikuji
expected string
}{
{name: "お正月以外", input: omikuji{nower: nenmatsu, intner: testIntner{randInt: 5}}, expected: "大凶"},
{name: "お正月", input: omikuji{nower: shougatsu, intner: testIntner{randInt: 5}}, expected: "大吉"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
c.input.pickUp()
if actual := c.input.Result; actual != c.expected {
t.Errorf("want o.Result = %v, got %v", c.expected, actual)
}
})
}
}

func TestIsOsyougatu(t *testing.T) {
cases := []struct {
name string
input time.Time
expected bool
}{
{name: "12/31", input: time.Date(2017, 12, 31, 23, 59, 11, 11, time.UTC), expected: false},
{name: "1/1", input: time.Date(2018, 1, 1, 9, 11, 11, 11, time.UTC), expected: true},
{name: "1/2", input: time.Date(2018, 1, 2, 10, 12, 11, 11, time.UTC), expected: true},
{name: "1/3", input: time.Date(2018, 1, 3, 11, 12, 11, 11, time.UTC), expected: true},
{name: "1/4", input: time.Date(2018, 1, 4, 0, 0, 0, 0, time.UTC), expected: false},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if actual := isOsyougatu(c.input); actual != c.expected {
t.Errorf("want isOsyougatu(%s) = %v, got %v", c.input, c.expected, actual)
}
})
}
}

func TestGetDaikiti(t *testing.T) {
expected := "大吉"
actual := getDaikiti()
if actual != expected {
t.Errorf("want: getDaikiti() = %s, got: %s ", expected, actual)
}
}