forked from braintree-go/braintree-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Null(Int64|Float64|Bool) types to support empty XML elements
These fields can be used with elements that either have a primitive value (i.e. float64, int64, bool), but where they can be empty in the response from Braintree.
- Loading branch information
Showing
9 changed files
with
332 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package braintree | ||
|
||
import ( | ||
"database/sql" | ||
"strconv" | ||
) | ||
|
||
// NullInt64 wraps sql.NullInt64 to allow it to be serializable to/from XML | ||
// via TextMarshaler and TextUnmarshaler | ||
type NullInt64 struct { | ||
sql.NullInt64 | ||
} | ||
|
||
// NewNullInt64 creats a new NullInt64 | ||
func NewNullInt64(n int64, valid bool) NullInt64 { | ||
return NullInt64{ | ||
sql.NullInt64{ | ||
Valid: valid, | ||
Int64: n, | ||
}, | ||
} | ||
} | ||
|
||
// UnmarshalText initializes an invalid NullInt64 if text is empty | ||
// otherwise it tries to parse it as an integer in base 10 | ||
func (n *NullInt64) UnmarshalText(text []byte) (err error) { | ||
if len(text) == 0 { | ||
n.Valid = false | ||
return nil | ||
} | ||
|
||
n.Int64, err = strconv.ParseInt(string(text), 10, 64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
n.Valid = true | ||
return nil | ||
} | ||
|
||
// UnmarshalText initializes an invalid NullInt64 if text is empty | ||
// otherwise it tries to parse it as an integer in base 10 | ||
// MarshalText returns "" for invalid NullInt64s, otherwise the integer value | ||
func (n NullInt64) MarshalText() ([]byte, error) { | ||
if !n.Valid { | ||
return []byte{}, nil | ||
} | ||
return []byte(strconv.FormatInt(n.Int64, 10)), nil | ||
} | ||
|
||
// NullFloat64 wraps sql.NullFloat64 to allow it to be serializable to/from XML | ||
// via TextMarshaler and TextUnmarshaler | ||
type NullFloat64 struct { | ||
sql.NullFloat64 | ||
} | ||
|
||
// NewNullFloat64 creats a new NullFloat64 | ||
func NewNullFloat64(n float64, valid bool) NullFloat64 { | ||
return NullFloat64{ | ||
sql.NullFloat64{ | ||
Valid: valid, | ||
Float64: n, | ||
}, | ||
} | ||
} | ||
|
||
// UnmarshalText initializes an invalid NullFloat64 if text is empty | ||
// otherwise it tries to parse it as an integer in base 10 | ||
func (n *NullFloat64) UnmarshalText(text []byte) (err error) { | ||
if len(text) == 0 { | ||
n.Valid = false | ||
return nil | ||
} | ||
|
||
n.Float64, err = strconv.ParseFloat(string(text), 64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
n.Valid = true | ||
return nil | ||
} | ||
|
||
// UnmarshalText initializes an invalid NullFloat64 if text is empty | ||
// otherwise it tries to parse it as an integer in base 10 | ||
// MarshalText returns "" for invalid NullFloat64s, otherwise the float string | ||
func (n NullFloat64) MarshalText() ([]byte, error) { | ||
if !n.Valid { | ||
return []byte{}, nil | ||
} | ||
return []byte(strconv.FormatFloat(n.Float64, 'f', -1, 64)), nil | ||
} | ||
|
||
// NullBool wraps sql.NullBool to allow it to be serializable to/from XML | ||
// via TextMarshaler and TextUnmarshaler | ||
type NullBool struct { | ||
sql.NullBool | ||
} | ||
|
||
// NewNullBool creats a new NullBool | ||
func NewNullBool(b bool, valid bool) NullBool { | ||
return NullBool{ | ||
sql.NullBool{ | ||
Valid: valid, | ||
Bool: b, | ||
}, | ||
} | ||
} | ||
|
||
// UnmarshalText initializes an invalid NullBool if text is empty | ||
// otherwise it tries to parse it as a boolean | ||
func (n *NullBool) UnmarshalText(text []byte) (err error) { | ||
if len(text) == 0 { | ||
n.Valid = false | ||
return nil | ||
} | ||
|
||
n.Bool, err = strconv.ParseBool(string(text)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
n.Valid = true | ||
return nil | ||
} | ||
|
||
// UnmarshalText initializes an invalid NullBool if text is empty | ||
// otherwise it tries to parse it as an integer in base 10 | ||
// MarshalText returns "" for invalid NullBools, otherwise the boolean value | ||
func (n NullBool) MarshalText() ([]byte, error) { | ||
if !n.Valid { | ||
return []byte{}, nil | ||
} | ||
return []byte(strconv.FormatBool(n.Bool)), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package braintree | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func TestNullInt64UnmarshalText(t *testing.T) { | ||
tests := []struct { | ||
in []byte | ||
out NullInt64 | ||
sholudError bool | ||
}{ | ||
{[]byte(""), NewNullInt64(0, false), false}, | ||
{[]byte("10"), NewNullInt64(10, true), false}, | ||
{[]byte("abcd"), NewNullInt64(0, false), true}, | ||
} | ||
|
||
for _, tt := range tests { | ||
n := NullInt64{} | ||
err := n.UnmarshalText(tt.in) | ||
|
||
if tt.sholudError { | ||
if err == nil { | ||
t.Errorf("expected UnmarshalText(%q) => to error, but it did not", tt.in) | ||
} | ||
} else { | ||
if err != nil { | ||
t.Errorf("expected UnmarshalText(%q) => to not error, but it did with %s", tt.in, err) | ||
} | ||
} | ||
|
||
if n != tt.out { | ||
t.Errorf("UnmarshalText(%q) => %q, want %q", tt.in, n, tt.out) | ||
} | ||
} | ||
} | ||
|
||
func TestNullInt64MarshalText(t *testing.T) { | ||
tests := []struct { | ||
in NullInt64 | ||
out []byte | ||
}{ | ||
{NewNullInt64(0, false), []byte("")}, | ||
{NewNullInt64(10, true), []byte("10")}, | ||
} | ||
|
||
for _, tt := range tests { | ||
b, err := tt.in.MarshalText() | ||
|
||
if !bytes.Equal(b, tt.out) || err != nil { | ||
t.Errorf("%q.MarshalText() => (%s, %s), want (%s, %s)", tt.in, b, err, tt.out, nil) | ||
} | ||
} | ||
} | ||
|
||
func TestNullFloat64UnmarshalText(t *testing.T) { | ||
tests := []struct { | ||
in []byte | ||
out NullFloat64 | ||
sholudError bool | ||
}{ | ||
{[]byte(""), NewNullFloat64(0, false), false}, | ||
{[]byte("10"), NewNullFloat64(10, true), false}, | ||
{[]byte("abcd"), NewNullFloat64(0, false), true}, | ||
} | ||
|
||
for _, tt := range tests { | ||
n := NullFloat64{} | ||
err := n.UnmarshalText(tt.in) | ||
|
||
if tt.sholudError { | ||
if err == nil { | ||
t.Errorf("expected UnmarshalText(%q) => to error, but it did not", tt.in) | ||
} | ||
} else { | ||
if err != nil { | ||
t.Errorf("expected UnmarshalText(%q) => to not error, but it did with %s", tt.in, err) | ||
} | ||
} | ||
|
||
if n != tt.out { | ||
t.Errorf("UnmarshalText(%q) => %q, want %q", tt.in, n, tt.out) | ||
} | ||
} | ||
} | ||
|
||
func TestNullFloat64MarshalText(t *testing.T) { | ||
tests := []struct { | ||
in NullFloat64 | ||
out []byte | ||
}{ | ||
{NewNullFloat64(0, false), []byte("")}, | ||
{NewNullFloat64(10, true), []byte("10")}, | ||
} | ||
|
||
for _, tt := range tests { | ||
b, err := tt.in.MarshalText() | ||
|
||
if !bytes.Equal(b, tt.out) || err != nil { | ||
t.Errorf("%q.MarshalText() => (%s, %s), want (%s, %s)", tt.in, b, err, tt.out, nil) | ||
} | ||
} | ||
} | ||
|
||
func TestNullBoolUnmarshalText(t *testing.T) { | ||
tests := []struct { | ||
in []byte | ||
out NullBool | ||
sholudError bool | ||
}{ | ||
{[]byte(""), NewNullBool(false, false), false}, | ||
{[]byte("true"), NewNullBool(true, true), false}, | ||
{[]byte("abcd"), NewNullBool(false, false), true}, | ||
} | ||
|
||
for _, tt := range tests { | ||
n := NullBool{} | ||
err := n.UnmarshalText(tt.in) | ||
|
||
if tt.sholudError { | ||
if err == nil { | ||
t.Errorf("expected UnmarshalText(%q) => to error, but it did not", tt.in) | ||
} | ||
} else { | ||
if err != nil { | ||
t.Errorf("expected UnmarshalText(%q) => to not error, but it did with %s", tt.in, err) | ||
} | ||
} | ||
|
||
if n != tt.out { | ||
t.Errorf("UnmarshalText(%q) => %q, want %q", tt.in, n, tt.out) | ||
} | ||
} | ||
} | ||
|
||
func TestNullBoolMarshalText(t *testing.T) { | ||
tests := []struct { | ||
in NullBool | ||
out []byte | ||
}{ | ||
{NewNullBool(false, false), []byte("")}, | ||
{NewNullBool(true, true), []byte("true")}, | ||
} | ||
|
||
for _, tt := range tests { | ||
b, err := tt.in.MarshalText() | ||
|
||
if !bytes.Equal(b, tt.out) || err != nil { | ||
t.Errorf("%q.MarshalText() => (%s, %s), want (%s, %s)", tt.in, b, err, tt.out, nil) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.