diff --git a/validator/validator.go b/validator/validator.go index 12ae43a..80d738b 100644 --- a/validator/validator.go +++ b/validator/validator.go @@ -8,6 +8,7 @@ import ( "encoding/json" "net" "net/url" + "reflect" "regexp" "strconv" "strings" @@ -159,7 +160,7 @@ func IsEmail(email string) bool { return isEmailRegexMatcher.MatchString(email) } -var isChineseMobileRegexMatcher *regexp.Regexp = regexp.MustCompile("^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$") +var isChineseMobileRegexMatcher *regexp.Regexp = regexp.MustCompile(`^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$`) // IsChineseMobile check if the string is chinese mobile number. func IsChineseMobile(mobileNum string) bool { @@ -253,3 +254,32 @@ func IsWeakPassword(password string) bool { return (num || letter) && !special } + +// IsZeroValue checks if value is a zero value +func IsZeroValue(value any) bool { + if value == nil { + return true + } + + rv := reflect.ValueOf(value) + if !rv.IsValid() { + return true + } + + switch rv.Kind() { + case reflect.String: + return rv.Len() == 0 + case reflect.Bool: + return !rv.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return rv.Uint() == 0 + case reflect.Float32, reflect.Float64: + return rv.Float() == 0 + case reflect.Ptr, reflect.Chan, reflect.Func, reflect.Interface, reflect.Slice, reflect.Map: + return rv.IsNil() + } + + return reflect.DeepEqual(rv.Interface(), reflect.Zero(rv.Type()).Interface()) +} diff --git a/validator/validator_test.go b/validator/validator_test.go index 5a8ed87..ad9a9e1 100644 --- a/validator/validator_test.go +++ b/validator/validator_test.go @@ -1,7 +1,9 @@ package validator import ( + "fmt" "testing" + "time" "github.com/duke-git/lancet/v2/internal" ) @@ -279,3 +281,110 @@ func TestIsWeakPassword(t *testing.T) { assert.Equal(true, IsWeakPassword("abcABC123")) assert.Equal(false, IsWeakPassword("abc123@#$")) } + +func TestIsZeroValue(t *testing.T) { + assert := internal.NewAssert(t, "TestIsZeroValue") + + var ( + zeroPtr *string + zeroSlice []int + zeroFunc func() string + zeroMap map[string]string + nilIface interface{} + zeroIface fmt.Formatter + ) + zeroValues := []interface{}{ + nil, + false, + 0, + int8(0), + int16(0), + int32(0), + int64(0), + uint(0), + uint8(0), + uint16(0), + uint32(0), + uint64(0), + + 0.0, + float32(0.0), + float64(0.0), + + "", + + // func + zeroFunc, + + // array / slice + [0]int{}, + zeroSlice, + + // map + zeroMap, + + // interface + nilIface, + zeroIface, + + // pointer + zeroPtr, + + // struct + time.Time{}, + } + + for _, value := range zeroValues { + assert.Equal(true, IsZeroValue(value)) + } + + var nonZeroIface fmt.Stringer = time.Now() + + nonZeroValues := []interface{}{ + // bool + true, + + // int + 1, + int8(1), + int16(1), + int32(1), + int64(1), + uint8(1), + uint16(1), + uint32(1), + uint64(1), + + // float + 1.0, + float32(1.0), + float64(1.0), + + // string + "test", + + // func + time.Now, + + // array / slice + []int{}, + []int{42}, + [1]int{42}, + + // map + make(map[string]string, 1), + + // interface + nonZeroIface, + + // pointer + &nonZeroIface, + + // struct + time.Now(), + } + + for _, value := range nonZeroValues { + assert.Equal(false, IsZeroValue(value)) + } +}