From 320e0db417ae95549d1982d84936c8d419a1c4d9 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 15 Mar 2019 00:22:39 +0800 Subject: [PATCH] fix int-overflow issue in gconv.String when converting int64 to string; add more unit test cases for package gconv --- g/util/gconv/gconv.go | 39 ++++++++++++-- g/util/gconv/gconv_z_unit_basic_test.go | 33 ++++++------ g/util/gconv/gconv_z_unit_bool_test.go | 42 +++++++++++++++ g/util/gconv/gconv_z_unit_string_test.go | 65 ++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 g/util/gconv/gconv_z_unit_bool_test.go create mode 100644 g/util/gconv/gconv_z_unit_string_test.go diff --git a/g/util/gconv/gconv.go b/g/util/gconv/gconv.go index 2b4ae31fd..f5ab6f2b0 100644 --- a/g/util/gconv/gconv.go +++ b/g/util/gconv/gconv.go @@ -13,6 +13,7 @@ package gconv import ( "encoding/json" "github.com/gogf/gf/g/encoding/gbinary" + "reflect" "strconv" "strings" ) @@ -22,6 +23,16 @@ type apiString interface { String() string } +var ( + // 为空的字符串 + emptyStringMap = map[string]struct{}{ + "" : struct {}{}, + "0" : struct {}{}, + "off" : struct {}{}, + "false" : struct {}{}, + } +) + // 将变量i转换为字符串指定的类型t,非必须参数extraParams用以额外的参数传递 func Convert(i interface{}, t string, extraParams...interface{}) interface{} { switch t { @@ -63,6 +74,7 @@ func Convert(i interface{}, t string, extraParams...interface{}) interface{} { } } +// 转换为二进制[]byte func Bytes(i interface{}) []byte { if i == nil { return nil @@ -80,11 +92,11 @@ func String(i interface{}) string { return "" } switch value := i.(type) { - case int: return strconv.Itoa(value) + case int: return strconv.FormatInt(int64(value), 10) case int8: return strconv.Itoa(int(value)) case int16: return strconv.Itoa(int(value)) case int32: return strconv.Itoa(int(value)) - case int64: return strconv.Itoa(int(value)) + case int64: return strconv.FormatInt(int64(value), 10) case uint: return strconv.FormatUint(uint64(value), 10) case uint8: return strconv.FormatUint(uint64(value), 10) case uint16: return strconv.FormatUint(uint64(value), 10) @@ -107,7 +119,7 @@ func String(i interface{}) string { } } -//false: "", 0, false, off +//false: false, "", 0, "false", "off", empty slice/map func Bool(i interface{}) bool { if i == nil { return false @@ -115,10 +127,27 @@ func Bool(i interface{}) bool { if v, ok := i.(bool); ok { return v } - if s := String(i); s != "" && s != "0" && s != "false" && s != "off" { + if s, ok := i.(string); ok { + if _, ok := emptyStringMap[s]; ok { + return false + } return true } - return false + rv := reflect.ValueOf(i) + switch rv.Kind() { + case reflect.Ptr: return !rv.IsNil() + case reflect.Map: fallthrough + case reflect.Array: fallthrough + case reflect.Slice: return rv.Len() != 0 + case reflect.Struct: return true + default: + s := String(i) + if _, ok := emptyStringMap[s]; ok { + return false + } + return true + + } } func Int(i interface{}) int { diff --git a/g/util/gconv/gconv_z_unit_basic_test.go b/g/util/gconv/gconv_z_unit_basic_test.go index 2c89407bf..5814384a3 100644 --- a/g/util/gconv/gconv_z_unit_basic_test.go +++ b/g/util/gconv/gconv_z_unit_basic_test.go @@ -15,20 +15,23 @@ import ( func Test_Basic(t *testing.T) { gtest.Case(t, func() { - value := 123.456 - gtest.AssertEQ(gconv.Int(value), int(123)) - gtest.AssertEQ(gconv.Int8(value), int8(123)) - gtest.AssertEQ(gconv.Int16(value), int16(123)) - gtest.AssertEQ(gconv.Int32(value), int32(123)) - gtest.AssertEQ(gconv.Int64(value), int64(123)) - gtest.AssertEQ(gconv.Uint(value), uint(123)) - gtest.AssertEQ(gconv.Uint8(value), uint8(123)) - gtest.AssertEQ(gconv.Uint16(value), uint16(123)) - gtest.AssertEQ(gconv.Uint32(value), uint32(123)) - gtest.AssertEQ(gconv.Uint64(value), uint64(123)) - gtest.AssertEQ(gconv.Float32(value), float32(123.456)) - gtest.AssertEQ(gconv.Float64(value), float64(123.456)) - gtest.AssertEQ(gconv.Bool(value), true) - gtest.AssertEQ(gconv.String(value), "123.456") + vint := 123.456 + vint64 := 1552578474888 + gtest.AssertEQ(gconv.Int(vint), int(123)) + gtest.AssertEQ(gconv.Int8(vint), int8(123)) + gtest.AssertEQ(gconv.Int16(vint), int16(123)) + gtest.AssertEQ(gconv.Int32(vint), int32(123)) + gtest.AssertEQ(gconv.Int64(vint), int64(123)) + gtest.AssertEQ(gconv.Int64(vint), int64(123)) + gtest.AssertEQ(gconv.Uint(vint), uint(123)) + gtest.AssertEQ(gconv.Uint8(vint), uint8(123)) + gtest.AssertEQ(gconv.Uint16(vint), uint16(123)) + gtest.AssertEQ(gconv.Uint32(vint), uint32(123)) + gtest.AssertEQ(gconv.Uint64(vint), uint64(123)) + gtest.AssertEQ(gconv.Float32(vint), float32(123.456)) + gtest.AssertEQ(gconv.Float64(vint), float64(123.456)) + gtest.AssertEQ(gconv.Bool(vint), true) + gtest.AssertEQ(gconv.String(vint), "123.456") + gtest.AssertEQ(gconv.String(vint64), "1552578474888") }) } diff --git a/g/util/gconv/gconv_z_unit_bool_test.go b/g/util/gconv/gconv_z_unit_bool_test.go new file mode 100644 index 000000000..d3b07e878 --- /dev/null +++ b/g/util/gconv/gconv_z_unit_bool_test.go @@ -0,0 +1,42 @@ +// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv_test + +import ( + "github.com/gogf/gf/g/util/gconv" + "github.com/gogf/gf/g/test/gtest" + "testing" +) + +type boolStruct struct { + +} + +func Test_Bool(t *testing.T) { + gtest.Case(t, func() { + var i interface{} = nil + gtest.AssertEQ(gconv.Bool(i), false) + gtest.AssertEQ(gconv.Bool(false), false) + gtest.AssertEQ(gconv.Bool(nil), false) + gtest.AssertEQ(gconv.Bool(0), false) + gtest.AssertEQ(gconv.Bool("0"), false) + gtest.AssertEQ(gconv.Bool(""), false) + gtest.AssertEQ(gconv.Bool("false"), false) + gtest.AssertEQ(gconv.Bool("off"), false) + gtest.AssertEQ(gconv.Bool([]byte{}), false) + gtest.AssertEQ(gconv.Bool([]string{}), false) + gtest.AssertEQ(gconv.Bool([]interface{}{}), false) + gtest.AssertEQ(gconv.Bool([]map[int]int{}), false) + + gtest.AssertEQ(gconv.Bool("1"), true) + gtest.AssertEQ(gconv.Bool("on"), true) + gtest.AssertEQ(gconv.Bool(1), true) + gtest.AssertEQ(gconv.Bool(123.456), true) + gtest.AssertEQ(gconv.Bool(boolStruct{}), true) + gtest.AssertEQ(gconv.Bool(&boolStruct{}), true) + }) +} diff --git a/g/util/gconv/gconv_z_unit_string_test.go b/g/util/gconv/gconv_z_unit_string_test.go new file mode 100644 index 000000000..4869f5d81 --- /dev/null +++ b/g/util/gconv/gconv_z_unit_string_test.go @@ -0,0 +1,65 @@ +// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv_test + +import ( + "github.com/gogf/gf/g/util/gconv" + "github.com/gogf/gf/g/test/gtest" + "testing" +) + + +type stringStruct1 struct { + Name string +} + +type stringStruct2 struct { + Name string +} + +func (s *stringStruct1) String() string { + return s.Name +} + +func Test_String(t *testing.T) { + gtest.Case(t, func() { + gtest.AssertEQ(gconv.String(int(123)), "123") + gtest.AssertEQ(gconv.String(int(-123)), "-123") + gtest.AssertEQ(gconv.String(int8(123)), "123") + gtest.AssertEQ(gconv.String(int8(-123)), "-123") + gtest.AssertEQ(gconv.String(int16(123)), "123") + gtest.AssertEQ(gconv.String(int16(-123)), "-123") + gtest.AssertEQ(gconv.String(int32(123)), "123") + gtest.AssertEQ(gconv.String(int32(-123)), "-123") + gtest.AssertEQ(gconv.String(int64(123)), "123") + gtest.AssertEQ(gconv.String(int64(-123)), "-123") + gtest.AssertEQ(gconv.String(int64(1552578474888)), "1552578474888") + gtest.AssertEQ(gconv.String(int64(-1552578474888)), "-1552578474888") + + gtest.AssertEQ(gconv.String(uint(123)), "123") + gtest.AssertEQ(gconv.String(uint8(123)), "123") + gtest.AssertEQ(gconv.String(uint16(123)), "123") + gtest.AssertEQ(gconv.String(uint32(123)), "123") + gtest.AssertEQ(gconv.String(uint64(155257847488898765)), "155257847488898765") + + gtest.AssertEQ(gconv.String(float32(123.456)), "123.456") + gtest.AssertEQ(gconv.String(float32(-123.456)), "-123.456") + gtest.AssertEQ(gconv.String(float64(1552578474888.456)), "1552578474888.456") + gtest.AssertEQ(gconv.String(float64(-1552578474888.456)), "-1552578474888.456") + + gtest.AssertEQ(gconv.String(true), "true") + gtest.AssertEQ(gconv.String(false), "false") + + gtest.AssertEQ(gconv.String([]byte("bytes")), "bytes") + + gtest.AssertEQ(gconv.String(stringStruct1{"john"}), `{"Name":"john"}`) + gtest.AssertEQ(gconv.String(&stringStruct1{"john"}), "john") + + gtest.AssertEQ(gconv.String(stringStruct2{"john"}), `{"Name":"john"}`) + gtest.AssertEQ(gconv.String(&stringStruct2{"john"}), `{"Name":"john"}`) + }) +}