diff --git a/pkg/award/award.go b/pkg/award/award.go index 9ca1026..f7600bd 100644 --- a/pkg/award/award.go +++ b/pkg/award/award.go @@ -2,8 +2,11 @@ package award import ( + "bytes" "encoding/json" "fmt" + "reflect" + "strconv" "strings" ) @@ -69,6 +72,80 @@ func (a T) MarshalJSON() ([]byte, error) { return json.Marshal(ao) } +// UnmarshalJSON decodes the JSON string b. +func (a T) UnmarshalJSON(b []byte) error { + r := bytes.NewReader(b) + dec := json.NewDecoder(r) + dec.UseNumber() // Don't use floats + + // All this to make sure we get `[` + if t, err := dec.Token(); err != nil { + return err + } else { + switch token := t.(type) { + case json.Delim: + if token.String() != "[" { + return &json.UnmarshalTypeError{ + Value: token.String(), + Type: reflect.TypeOf(a), + Offset: 0, + } + } + default: + return &json.UnmarshalTypeError{ + Value: fmt.Sprintf("%v", t), + Type: reflect.TypeOf(a), + Offset: 0, + } + } + } + + var num json.Number + var err error + if err := dec.Decode(&num); err != nil { + return err + } + if a.When, err = strconv.ParseInt(string(num), 10, 64); err != nil { + return err + } + if err := dec.Decode(&a.Category); err != nil { + return err + } + if err := dec.Decode(&a.TeamID); err != nil { + return err + } + if err := dec.Decode(&num); err != nil { + return err + } + if a.Points, err = strconv.Atoi(string(num)); err != nil { + return err + } + + // All this to make sure we get `]` + if t, err := dec.Token(); err != nil { + return err + } else { + switch token := t.(type) { + case json.Delim: + if token.String() != "]" { + return &json.UnmarshalTypeError{ + Value: token.String(), + Type: reflect.TypeOf(a), + Offset: 0, + } + } + default: + return &json.UnmarshalTypeError{ + Value: fmt.Sprintf("%v", t), + Type: reflect.TypeOf(a), + Offset: 0, + } + } + } + + return nil +} + // Equal returns true if two award events represent the same award. // Timestamps are ignored in this comparison! func (a T) Equal(o T) bool { diff --git a/pkg/award/award_test.go b/pkg/award/award_test.go index 59a9c88..d1ca716 100644 --- a/pkg/award/award_test.go +++ b/pkg/award/award_test.go @@ -42,7 +42,8 @@ func TestAward(t *testing.T) { t.Error("Different pount values compare equal") } - if ja, err := a.MarshalJSON(); err != nil { + ja, err := a.MarshalJSON() + if err != nil { t.Error(err) } else if string(ja) != `[1536958399,"1a2b3c4d","counting",10]` { t.Error("JSON wrong") @@ -54,6 +55,20 @@ func TestAward(t *testing.T) { if _, err := Parse("1 bad bad bad"); err == nil { t.Error("Not throwing error on bad points") } + + if err := b.UnmarshalJSON(ja); err != nil { + t.Error(err) + } else if !b.Equal(a) { + t.Error("UnmarshalJSON didn't work") + } + + for _, s := range []string{`12`, `"moo"`, `{"a":1}`, `[1 2 3 4]`, `[]`, `[1,"a"]`, `[1,"a","b",4, 5]`} { + buf := []byte(s) + if err := a.UnmarshalJSON(buf); err == nil { + t.Error("Bad unmarshal didn't return error:", s) + } + } + } func TestAwardList(t *testing.T) {