From 408043c8fa963d2bf022aaf683743e1d19b5e697 Mon Sep 17 00:00:00 2001 From: yveshield Date: Sat, 15 Jan 2022 20:43:35 +0800 Subject: [PATCH] Add support for json.Number Closes #115 Closes #61 --- cast_test.go | 89 ++++++++++++++++++++++++++++++++++++++++++ caste.go | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/cast_test.go b/cast_test.go index 3d93dfb..69b5bdc 100644 --- a/cast_test.go +++ b/cast_test.go @@ -6,6 +6,7 @@ package cast import ( + "encoding/json" "errors" "fmt" "html/template" @@ -18,6 +19,10 @@ import ( ) func TestToUintE(t *testing.T) { + var jn, nj, jne json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("-8"), &nj) + _ = json.Unmarshal([]byte("8.0"), &jne) tests := []struct { input interface{} expect uint @@ -38,6 +43,7 @@ func TestToUintE(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {int(-8), 0, true}, @@ -48,6 +54,8 @@ func TestToUintE(t *testing.T) { {float32(-8.31), 0, true}, {float64(-8.31), 0, true}, {"-8", 0, true}, + {nj, 0, true}, + {jne, 0, true}, {"test", 0, true}, {testing.T{}, 0, true}, } @@ -71,6 +79,10 @@ func TestToUintE(t *testing.T) { } func TestToUint64E(t *testing.T) { + var jn, nj, jne json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("-8"), &nj) + _ = json.Unmarshal([]byte("8.0"), &jne) tests := []struct { input interface{} expect uint64 @@ -91,6 +103,7 @@ func TestToUint64E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {int(-8), 0, true}, @@ -101,6 +114,8 @@ func TestToUint64E(t *testing.T) { {float32(-8.31), 0, true}, {float64(-8.31), 0, true}, {"-8", 0, true}, + {nj, 0, true}, + {jne, 0, true}, {"test", 0, true}, {testing.T{}, 0, true}, } @@ -124,6 +139,10 @@ func TestToUint64E(t *testing.T) { } func TestToUint32E(t *testing.T) { + var jn, nj, jne json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("-8"), &nj) + _ = json.Unmarshal([]byte("8.0"), &jne) tests := []struct { input interface{} expect uint32 @@ -144,6 +163,7 @@ func TestToUint32E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, {int(-8), 0, true}, {int8(-8), 0, true}, @@ -153,7 +173,9 @@ func TestToUint32E(t *testing.T) { {float32(-8.31), 0, true}, {float64(-8.31), 0, true}, {"-8", 0, true}, + {nj, 0, true}, // errors + {jne, 0, true}, {"test", 0, true}, {testing.T{}, 0, true}, } @@ -177,6 +199,10 @@ func TestToUint32E(t *testing.T) { } func TestToUint16E(t *testing.T) { + var jn, nj, jne json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("-8"), &nj) + _ = json.Unmarshal([]byte("8.0"), &jne) tests := []struct { input interface{} expect uint16 @@ -197,6 +223,7 @@ func TestToUint16E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {int(-8), 0, true}, @@ -207,6 +234,8 @@ func TestToUint16E(t *testing.T) { {float32(-8.31), 0, true}, {float64(-8.31), 0, true}, {"-8", 0, true}, + {nj, 0, true}, + {jne, 0, true}, {"test", 0, true}, {testing.T{}, 0, true}, } @@ -230,6 +259,10 @@ func TestToUint16E(t *testing.T) { } func TestToUint8E(t *testing.T) { + var jn, nj, jne json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("-8"), &nj) + _ = json.Unmarshal([]byte("8.0"), &jne) tests := []struct { input interface{} expect uint8 @@ -250,6 +283,7 @@ func TestToUint8E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {int(-8), 0, true}, @@ -260,6 +294,8 @@ func TestToUint8E(t *testing.T) { {float32(-8.31), 0, true}, {float64(-8.31), 0, true}, {"-8", 0, true}, + {nj, 0, true}, + {jne, 0, true}, {"test", 0, true}, {testing.T{}, 0, true}, } @@ -283,6 +319,9 @@ func TestToUint8E(t *testing.T) { } func TestToIntE(t *testing.T) { + var jn, nj json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("8.0"), &nj) tests := []struct { input interface{} expect int @@ -303,9 +342,11 @@ func TestToIntE(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {"test", 0, true}, + {nj, 0, true}, {testing.T{}, 0, true}, } @@ -328,6 +369,9 @@ func TestToIntE(t *testing.T) { } func TestToInt64E(t *testing.T) { + var jn, nj json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte(".8"), &nj) tests := []struct { input interface{} expect int64 @@ -348,9 +392,11 @@ func TestToInt64E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {"test", 0, true}, + {nj, 0, true}, {testing.T{}, 0, true}, } @@ -373,6 +419,9 @@ func TestToInt64E(t *testing.T) { } func TestToInt32E(t *testing.T) { + var jn, nj json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("8.0"), &nj) tests := []struct { input interface{} expect int32 @@ -393,9 +442,11 @@ func TestToInt32E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {"test", 0, true}, + {nj, 0, true}, {testing.T{}, 0, true}, } @@ -418,6 +469,9 @@ func TestToInt32E(t *testing.T) { } func TestToInt16E(t *testing.T) { + var jn, nj json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("8.0"), &nj) tests := []struct { input interface{} expect int16 @@ -438,9 +492,11 @@ func TestToInt16E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {"test", 0, true}, + {nj, 0, true}, {testing.T{}, 0, true}, } @@ -463,6 +519,9 @@ func TestToInt16E(t *testing.T) { } func TestToInt8E(t *testing.T) { + var jn, nj json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte("8.0"), &nj) tests := []struct { input interface{} expect int8 @@ -483,9 +542,11 @@ func TestToInt8E(t *testing.T) { {true, 1, false}, {false, 0, false}, {"8", 8, false}, + {jn, 8, false}, {nil, 0, false}, // errors {"test", 0, true}, + {nj, 0, true}, {testing.T{}, 0, true}, } @@ -508,6 +569,9 @@ func TestToInt8E(t *testing.T) { } func TestToFloat64E(t *testing.T) { + var jn, nj json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte(".8"), &nj) tests := []struct { input interface{} expect float64 @@ -526,10 +590,12 @@ func TestToFloat64E(t *testing.T) { {float32(8), 8, false}, {float64(8.31), 8.31, false}, {"8", 8, false}, + {jn, 8, false}, {true, 1, false}, {false, 0, false}, // errors {"test", 0, true}, + {nj, 0, true}, {testing.T{}, 0, true}, } @@ -552,6 +618,9 @@ func TestToFloat64E(t *testing.T) { } func TestToFloat32E(t *testing.T) { + var jn, nj json.Number + _ = json.Unmarshal([]byte("8"), &jn) + _ = json.Unmarshal([]byte(".8"), &nj) tests := []struct { input interface{} expect float32 @@ -570,10 +639,12 @@ func TestToFloat32E(t *testing.T) { {float32(8.31), 8.31, false}, {float64(8.31), 8.31, false}, {"8", 8, false}, + {jn, 8, false}, {true, 1, false}, {false, 0, false}, // errors {"test", 0, true}, + {nj, 0, true}, {testing.T{}, 0, true}, } @@ -596,6 +667,8 @@ func TestToFloat32E(t *testing.T) { } func TestToStringE(t *testing.T) { + var jn json.Number + _ = json.Unmarshal([]byte("8"), &jn) type Key struct { k string } @@ -618,6 +691,7 @@ func TestToStringE(t *testing.T) { {uint64(8), "8", false}, {float32(8.31), "8.31", false}, {float64(8.31), "8.31", false}, + {jn, "8", false}, {true, "true", false}, {false, "false", false}, {nil, "", false}, @@ -1120,12 +1194,17 @@ func TestToDurationSliceE(t *testing.T) { } func TestToBoolE(t *testing.T) { + var jf, jt, je json.Number + _ = json.Unmarshal([]byte("0"), &jf) + _ = json.Unmarshal([]byte("1"), &jt) + _ = json.Unmarshal([]byte("1.0"), &je) tests := []struct { input interface{} expect bool iserr bool }{ {0, false, false}, + {jf, false, false}, {nil, false, false}, {"false", false, false}, {"FALSE", false, false}, @@ -1140,11 +1219,13 @@ func TestToBoolE(t *testing.T) { {"t", true, false}, {"T", true, false}, {1, true, false}, + {jt, true, false}, {true, true, false}, {-1, true, false}, // errors {"test", false, true}, + {je, false, true}, {testing.T{}, false, true}, } @@ -1197,6 +1278,9 @@ func TestIndirectPointers(t *testing.T) { } func TestToTime(t *testing.T) { + var jntime, jnetime json.Number + _ = json.Unmarshal([]byte("1234567890"), &jntime) + _ = json.Unmarshal([]byte("123.4567890"), &jnetime) tests := []struct { input interface{} expect time.Time @@ -1235,9 +1319,11 @@ func TestToTime(t *testing.T) { {uint(1482597504), time.Date(2016, 12, 24, 16, 38, 24, 0, time.UTC), false}, {uint64(1234567890), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false}, {uint32(1234567890), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false}, + {jntime, time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false}, {time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false}, // errors {"2006", time.Time{}, true}, + {jnetime, time.Time{}, true}, {testing.T{}, time.Time{}, true}, } @@ -1261,6 +1347,8 @@ func TestToTime(t *testing.T) { func TestToDurationE(t *testing.T) { var td time.Duration = 5 + var jn json.Number + _ = json.Unmarshal([]byte("5"), &jn) tests := []struct { input interface{} @@ -1280,6 +1368,7 @@ func TestToDurationE(t *testing.T) { {uint8(5), td, false}, {float64(5), td, false}, {float32(5), td, false}, + {jn, td, false}, {string("5"), td, false}, {string("5ns"), td, false}, {string("5us"), time.Microsecond * td, false}, diff --git a/caste.go b/caste.go index c04af6a..e0b8a43 100644 --- a/caste.go +++ b/caste.go @@ -34,6 +34,12 @@ func ToTimeInDefaultLocationE(i interface{}, location *time.Location) (tim time. return v, nil case string: return StringToDateInDefaultLocation(v, location) + case json.Number: + s, err1 := v.Int64() + if err1 != nil { + return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i) + } + return time.Unix(s, 0), nil case int: return time.Unix(int64(v), 0), nil case int64: @@ -71,6 +77,11 @@ func ToDurationE(i interface{}) (d time.Duration, err error) { d, err = time.ParseDuration(s + "ns") } return + case json.Number: + var v float64 + v, err = s.Float64() + d = time.Duration(v) + return default: err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i) return @@ -93,6 +104,12 @@ func ToBoolE(i interface{}) (bool, error) { return false, nil case string: return strconv.ParseBool(i.(string)) + case json.Number: + v, err := b.Int64() + if err == nil { + return v != 0, nil + } + return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i) default: return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i) } @@ -133,6 +150,12 @@ func ToFloat64E(i interface{}) (float64, error) { return v, nil } return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) + case json.Number: + v, err := s.Float64() + if err == nil { + return v, nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) case bool: if s { return 1, nil @@ -178,6 +201,12 @@ func ToFloat32E(i interface{}) (float32, error) { return float32(v), nil } return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) + case json.Number: + v, err := s.Float64() + if err == nil { + return float32(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) case bool: if s { return 1, nil @@ -223,6 +252,12 @@ func ToInt64E(i interface{}) (int64, error) { return v, nil } return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) + case json.Number: + v, err := s.Int64() + if err == nil { + return v, nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) case bool: if s { return 1, nil @@ -270,6 +305,12 @@ func ToInt32E(i interface{}) (int32, error) { return int32(v), nil } return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) + case json.Number: + v, err := s.Int64() + if err == nil { + return int32(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) case bool: if s { return 1, nil @@ -317,6 +358,12 @@ func ToInt16E(i interface{}) (int16, error) { return int16(v), nil } return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) + case json.Number: + v, err := s.Int64() + if err == nil { + return int16(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) case bool: if s { return 1, nil @@ -364,6 +411,12 @@ func ToInt8E(i interface{}) (int8, error) { return int8(v), nil } return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) + case json.Number: + v, err := s.Int64() + if err == nil { + return int8(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) case bool: if s { return 1, nil @@ -411,6 +464,12 @@ func ToIntE(i interface{}) (int, error) { return int(v), nil } return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i) + case json.Number: + v, err := s.Int64() + if err == nil { + return int(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i) case bool: if s { return 1, nil @@ -434,6 +493,15 @@ func ToUintE(i interface{}) (uint, error) { return uint(v), nil } return 0, fmt.Errorf("unable to cast %#v to uint: %s", i, err) + case json.Number: + v, err := s.Int64() + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint(v), nil + } + return 0, fmt.Errorf("unable to cast %#v to uint: %s", i, err) case int: if s < 0 { return 0, errNegativeNotAllowed @@ -502,6 +570,15 @@ func ToUint64E(i interface{}) (uint64, error) { return v, nil } return 0, fmt.Errorf("unable to cast %#v to uint64: %s", i, err) + case json.Number: + v, err := s.Int64() + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint64(v), nil + } + return 0, fmt.Errorf("unable to cast %#v to uint64: %s", i, err) case int: if s < 0 { return 0, errNegativeNotAllowed @@ -570,6 +647,15 @@ func ToUint32E(i interface{}) (uint32, error) { return uint32(v), nil } return 0, fmt.Errorf("unable to cast %#v to uint32: %s", i, err) + case json.Number: + v, err := s.Int64() + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint32(v), nil + } + return 0, fmt.Errorf("unable to cast %#v to uint32: %s", i, err) case int: if s < 0 { return 0, errNegativeNotAllowed @@ -638,6 +724,15 @@ func ToUint16E(i interface{}) (uint16, error) { return uint16(v), nil } return 0, fmt.Errorf("unable to cast %#v to uint16: %s", i, err) + case json.Number: + v, err := s.Int64() + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint16(v), nil + } + return 0, fmt.Errorf("unable to cast %#v to uint16: %s", i, err) case int: if s < 0 { return 0, errNegativeNotAllowed @@ -706,6 +801,15 @@ func ToUint8E(i interface{}) (uint8, error) { return uint8(v), nil } return 0, fmt.Errorf("unable to cast %#v to uint8: %s", i, err) + case json.Number: + v, err := s.Int64() + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint8(v), nil + } + return 0, fmt.Errorf("unable to cast %#v to uint8: %s", i, err) case int: if s < 0 { return 0, errNegativeNotAllowed @@ -835,6 +939,8 @@ func ToStringE(i interface{}) (string, error) { return strconv.FormatUint(uint64(s), 10), nil case uint8: return strconv.FormatUint(uint64(s), 10), nil + case json.Number: + return s.String(), nil case []byte: return string(s), nil case template.HTML: