From aade41f9bbb40de8456e5d5a8a0c9960245adc2c Mon Sep 17 00:00:00 2001 From: Ammaar Esmailjee Date: Mon, 1 Feb 2021 09:49:53 -0500 Subject: [PATCH] remove if nil { new(T) } initializers + first test (Price) + stretchr/testify dependency --- fields/coordinates.go | 8 ---- fields/currency.go | 4 -- fields/email.go | 4 -- fields/enums.go | 16 -------- fields/language.go | 4 -- fields/numbers.go | 12 +----- fields/price.go | 39 +++++++++---------- fields/tests/price_test.go | 76 ++++++++++++++++++++++++++++++++------ fields/time.go | 28 +++----------- fields/uri.go | 4 -- fields/url.go | 4 -- fields/utils.go | 14 +++++-- gbfs.go | 9 ++--- go.mod | 7 +++- go.sum | 16 ++++++++ 15 files changed, 124 insertions(+), 121 deletions(-) diff --git a/fields/coordinates.go b/fields/coordinates.go index b573242..aa8837c 100644 --- a/fields/coordinates.go +++ b/fields/coordinates.go @@ -10,10 +10,6 @@ var ErrLatitude = errors.New("Latitude must in range [-90.0, 90.0]") // UnmarshalJSON implements json.Unmarshaler interface func (l *Latitude) UnmarshalJSON(data []byte) error { - if l == nil { - l = new(Latitude) - } - f, err := unmarshalToFloat64(data) if err != nil { return err @@ -35,10 +31,6 @@ var ErrLongitude = errors.New("Longitude must in range [-180.0, 180.0]") // UnmarshalJSON implements json.Unmarshaler interface func (l *Longitude) UnmarshalJSON(data []byte) error { - if l == nil { - l = new(Longitude) - } - f, err := unmarshalToFloat64(data) if err != nil { return err diff --git a/fields/currency.go b/fields/currency.go index 889876a..218fd6a 100644 --- a/fields/currency.go +++ b/fields/currency.go @@ -9,10 +9,6 @@ type Currency struct { // UnmarshalJSON implements json.Unmarshaler interface func (c *Currency) UnmarshalJSON(data []byte) error { - if c == nil { - c = new(Currency) - } - s, err := unmarshalToString(data) if err != nil { return err diff --git a/fields/email.go b/fields/email.go index 68aaed9..2b0504f 100644 --- a/fields/email.go +++ b/fields/email.go @@ -9,10 +9,6 @@ type Email struct { // UnmarshalJSON implements json.Unmarshaler interface func (e *Email) UnmarshalJSON(data []byte) error { - if e == nil { - e = new(Email) - } - s, err := unmarshalToString(data) if err != nil { return err diff --git a/fields/enums.go b/fields/enums.go index 81f8e6f..3e0fb53 100644 --- a/fields/enums.go +++ b/fields/enums.go @@ -74,10 +74,6 @@ var ErrUnknownDayOfWeek = errors.New("unknown day") // UnmarshalJSON implements json.Unmarshaler interface func (d *DayOfWeek) UnmarshalJSON(data []byte) error { - if d == nil { - d = new(DayOfWeek) - } - s, err := unmarshalToString(data) if err != nil { return err @@ -108,10 +104,6 @@ var ErrUnknownMobile = errors.New("unknown mobile") // UnmarshalJSON implements json.Unmarshaler interface func (m *Mobile) UnmarshalJSON(data []byte) error { - if m == nil { - m = new(Mobile) - } - s, err := unmarshalToString(data) if err != nil { return err @@ -148,10 +140,6 @@ var ErrUnknownRentalMethod = errors.New("unknown rental method") // UnmarshalJSON implements json.Unmarshaler interface func (r *RentalMethod) UnmarshalJSON(data []byte) error { - if r == nil { - r = new(RentalMethod) - } - s, err := unmarshalToString(data) if err != nil { return err @@ -182,10 +170,6 @@ var ErrUnknownUserType = errors.New("unknown user type") // UnmarshalJSON implements json.Unmarshaler interface func (u *UserType) UnmarshalJSON(data []byte) error { - if u == nil { - u = new(UserType) - } - s, err := unmarshalToString(data) if err != nil { return err diff --git a/fields/language.go b/fields/language.go index 4d3b81b..4adbb6b 100644 --- a/fields/language.go +++ b/fields/language.go @@ -9,10 +9,6 @@ type Language struct { // UnmarshalJSON implements json.Unmarshaler interface func (l *Language) UnmarshalJSON(data []byte) error { - if l == nil { - l = new(Language) - } - s, err := unmarshalToString(data) if err != nil { return err diff --git a/fields/numbers.go b/fields/numbers.go index ff69696..4118a1c 100644 --- a/fields/numbers.go +++ b/fields/numbers.go @@ -13,10 +13,6 @@ var ErrNonNegativeInt = errors.New("NonNegativeInt must have value >= 0") // UnmarshalJSON implements json.Unmarshaler interface func (n *NonNegativeInt) UnmarshalJSON(data []byte) error { - if n == nil { - n = new(NonNegativeInt) - } - i, err := unmarshalToInt(data) if err != nil { return err @@ -42,10 +38,6 @@ var ErrNonNegativeFloat = errors.New("NonNegativeFloat must have value >= 0.0") // UnmarshalJSON implements json.Unmarshaler interface func (n *NonNegativeFloat) UnmarshalJSON(data []byte) error { - if n == nil { - n = new(NonNegativeFloat) - } - f, err := unmarshalToFloat64(data) if err != nil { return err @@ -59,6 +51,6 @@ func (n *NonNegativeFloat) UnmarshalJSON(data []byte) error { return nil } -func (n *NonNegativeFloat) String() string { - return strconv.FormatFloat(float64(*n), 'g', -1, 64) +func (n NonNegativeFloat) String() string { + return strconv.FormatFloat(float64(n), 'g', -1, 64) } diff --git a/fields/price.go b/fields/price.go index fa1a33f..531f506 100644 --- a/fields/price.go +++ b/fields/price.go @@ -1,8 +1,8 @@ package fields import ( + "errors" "reflect" - "strconv" ) // Price ... @@ -13,48 +13,43 @@ type Price struct { n NonNegativeFloat } +// ErrInvalidPriceType ... +var ErrInvalidPriceType = errors.New("price must be string or float") + // UnmarshalJSON implements json.Unmarshaler interface func (p *Price) UnmarshalJSON(data []byte) error { - if p == nil { - p = new(Price) + v, err := unmarshal(data) + if err != nil { + return err } - switch data[0] { + switch v.(type) { default: + return ErrInvalidPriceType + case float64: p.k = reflect.Float64 - - n, err := unmarshalToNonNegativeFloat(data) + p.n, err = unmarshalToNonNegativeFloat(data) if err != nil { return err } - - p.n = *n - p.s = n.String() - case '"': + p.s = p.n.String() + case string: p.k = reflect.String - - s, err := unmarshalToString(data) + p.s = v.(string) + p.n, err = unmarshalToNonNegativeFloat([]byte(p.s)) if err != nil { return err } - - f, err := strconv.ParseFloat(s, 64) - if err != nil { - return err - } - - p.s = s - p.n = NonNegativeFloat(f) } return nil } // Float64 ... -func (p *Price) Float64() float64 { +func (p Price) Float64() float64 { return float64(p.n) } -func (p *Price) String() string { +func (p Price) String() string { return p.s } diff --git a/fields/tests/price_test.go b/fields/tests/price_test.go index 00ae83b..c3d82d2 100644 --- a/fields/tests/price_test.go +++ b/fields/tests/price_test.go @@ -3,23 +3,75 @@ package tests import ( "encoding/json" "testing" -) -// PriceStruct ... -type PriceStruct struct { - Price fields.Price `json:"price"` -} + "github.com/marz619/gbfs-go/fields" + "github.com/stretchr/testify/assert" +) // TestPriceUnmarshalJSON ... func TestPriceUnmarshalJSON(t *testing.T) { - raw := []byte(`{"price":"3.14"`) + // standalone + for _, tc := range []struct { + raw []byte + expS string + expF float64 + }{ + {[]byte(`"3.14159"`), "3.14159", 3.14159}, + {[]byte(`3.14159`), "3.14159", 3.14159}, + } { + t.Run("field: "+string(tc.raw), func(t *testing.T) { + var p fields.Price + assert.NoError(t, json.Unmarshal(tc.raw, &p)) + assert.Equal(t, tc.expS, p.String()) + assert.Equal(t, tc.expF, p.Float64()) + }) + } - var ps PriceStruct - err := json.Unmarshal(raw, &ps) - if err != nil { - t.Error(err) + // simple json struct + type S struct { + P fields.Price `json:"price"` } - p := ps.Price - if p.String() != + for _, tc := range []struct { + raw []byte + expS string + expF float64 + }{ + {[]byte(`{"price":"2.71828"}`), "2.71828", 2.71828}, + {[]byte(`{"price":2.71828}`), "2.71828", 2.71828}, + } { + t.Run("struct with value: "+string(tc.raw), func(t *testing.T) { + var s S + assert.NoError(t, json.Unmarshal(tc.raw, &s)) + assert.Equal(t, tc.expS, s.P.String()) + assert.Equal(t, tc.expF, s.P.Float64()) + }) + } + + // simple json struct with pointer + type U struct { + P *fields.Price `json:"price"` + } + + for _, tc := range []struct { + raw []byte + expS string + expF float64 + isNil bool + }{ + {[]byte(`{"price":"1.61803"}`), "1.61803", 1.61803, false}, + {[]byte(`{"price":1.61803}`), "1.61803", 1.61803, false}, + {[]byte(`{}`), "", 0.0, true}, + } { + t.Run("struct with pointer: "+string(tc.raw), func(t *testing.T) { + var u U + assert.NoError(t, json.Unmarshal(tc.raw, &u)) + if !tc.isNil { + assert.Equal(t, tc.expS, u.P.String()) + assert.Equal(t, tc.expF, u.P.Float64()) + } else { + assert.Nil(t, u.P) + } + }) + } } diff --git a/fields/time.go b/fields/time.go index 3c84725..1b04c9e 100644 --- a/fields/time.go +++ b/fields/time.go @@ -16,10 +16,6 @@ const dateFmt = "2006-01-02" // UnmarshalJSON implements json.Unmarshaler interface func (d *Date) UnmarshalJSON(data []byte) error { - if d == nil { - d = new(Date) - } - s, err := unmarshalToString(data) if err != nil { return err @@ -46,11 +42,11 @@ func (d *Day) UnmarshalJSON(data []byte) error { return err } - if *n < 1 || *n > 31 { + if n < 1 || n > 31 { return ErrInvalidDay } - *d = Day(*n) + *d = Day(n) return nil } @@ -67,11 +63,11 @@ func (m *Month) UnmarshalJSON(data []byte) error { return err } - if *n < 1 || *n > 12 { + if n < 1 || n > 12 { return ErrInvalidMonth } - *m = Month(*n) + *m = Month(n) return nil } @@ -88,11 +84,11 @@ func (y *Year) UnmarshalJSON(data []byte) error { return err } - if *n < 0 || *n > 9999 { + if n < 0 || n > 9999 { return ErrInvalidYear } - *y = Year(*n) + *y = Year(n) return nil } @@ -106,10 +102,6 @@ const timeFmt = "15:04:05" // UnmarshalJSON implements json.Unmarshaler interface func (t *Time) UnmarshalJSON(data []byte) error { - if t == nil { - t = new(Time) - } - s, err := unmarshalToString(data) if err != nil { return err @@ -134,10 +126,6 @@ type Timestamp struct { // UnmarshalJSON implements json.Unmarshaler interface func (t *Timestamp) UnmarshalJSON(data []byte) error { - if t == nil { - t = new(Timestamp) - } - i, err := unmarshalToInt(data) if err != nil { return err @@ -158,10 +146,6 @@ type Timezone struct { // UnmarshalJSON implements json.Unmarshaler interface func (t *Timezone) UnmarshalJSON(data []byte) error { - if t == nil { - t = new(Timezone) - } - zone, err := unmarshalToString(data) if err != nil { return err diff --git a/fields/uri.go b/fields/uri.go index 51973d0..d7ec6f9 100644 --- a/fields/uri.go +++ b/fields/uri.go @@ -9,10 +9,6 @@ type URI struct { // UnmarshalJSON implements json.Unmarshaler interface func (u *URI) UnmarshalJSON(data []byte) (err error) { - if u == nil { - u = new(URI) - } - (*u).URL, err = unmarshalToURL(data) return err } diff --git a/fields/url.go b/fields/url.go index d60468c..b623d14 100644 --- a/fields/url.go +++ b/fields/url.go @@ -15,10 +15,6 @@ var ErrURLScheme = errors.New("URL Scheme must be 'http' OR 'https'") // UnmarshalJSON implements json.Unmarshaler interface func (u *URL) UnmarshalJSON(data []byte) error { - if u == nil { - u = new(URL) - } - url, err := unmarshalToURL(data) if err != nil { return err diff --git a/fields/utils.go b/fields/utils.go index 5bbdb4d..044acba 100644 --- a/fields/utils.go +++ b/fields/utils.go @@ -21,6 +21,12 @@ func ContainsSpaces(s string) bool { return ContainsRuneFunc(s, unicode.IsSpace) } +// unmarshal returns an interface value +func unmarshal(data []byte) (v interface{}, err error) { + err = json.Unmarshal(data, &v) + return +} + // unmarshalToFloat64 is a convenience method to unmarshal some bytes into a // float64 func unmarshalToFloat64(data []byte) (f float64, err error) { @@ -69,14 +75,14 @@ func unmarshalToURL(data []byte) (u *url.URL, err error) { // unmarshalToNonNegativeInt is a convenience method to unmarshal some bytes // into *NonNegativeInt -func unmarshalToNonNegativeInt(data []byte) (n *NonNegativeInt, err error) { - err = json.Unmarshal(data, n) +func unmarshalToNonNegativeInt(data []byte) (n NonNegativeInt, err error) { + err = json.Unmarshal(data, &n) return } // unmarshalToNonNegativeFloat is a convenience method to unmarshal some bytes // into *NonNegativeInt -func unmarshalToNonNegativeFloat(data []byte) (n *NonNegativeFloat, err error) { - err = json.Unmarshal(data, n) +func unmarshalToNonNegativeFloat(data []byte) (n NonNegativeFloat, err error) { + err = json.Unmarshal(data, &n) return } diff --git a/gbfs.go b/gbfs.go index 0ae41ee..084547c 100644 --- a/gbfs.go +++ b/gbfs.go @@ -19,20 +19,17 @@ type Client interface { // New Client with default http.Client func New(discovery string) Client { - return &gbfs{ - discovery: discovery, - c: http.DefaultClient, - } + return NewWithClient(discovery, nil) } // NewWithClient Client with custom http.Client func NewWithClient(discovery string, c *http.Client) Client { if c == nil { - panic("nil c") + c = http.DefaultClient } return &gbfs{ - discovery: discovery, c: c, + discovery: discovery, } } diff --git a/go.mod b/go.mod index ead1250..3bc29dc 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,9 @@ module github.com/marz619/gbfs-go go 1.15 -require golang.org/x/text v0.3.5 +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/stretchr/testify v1.7.0 + golang.org/x/text v0.3.5 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect +) diff --git a/go.sum b/go.sum index bbd33e8..dcfc9c1 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,19 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=