Skip to content

Commit

Permalink
Fix for Boolean Pointer Field Validation Error (#240)
Browse files Browse the repository at this point in the history
* fix: handle pointer values in callValidatorValue function

* fix: correct pointer dereferencing in validation functions
  • Loading branch information
kaptinlin authored Nov 30, 2023
1 parent aafe11f commit 8c4d6aa
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ require (
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/sync v0.4.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
4 changes: 2 additions & 2 deletions issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1076,8 +1076,8 @@ func TestIssue_143(t *testing.T) {

ok = v.Validate()
dump.Println(v.Errors)
assert.False(t, ok)
assert.Equal(t, "age min value is 30", v.Errors.One())
assert.True(t, ok)
assert.Equal(t, "", v.Errors.One())
}

// https://github.com/gookit/validate/issues/148
Expand Down
28 changes: 28 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ func CalcLength(val any) int {
//
// only check for: int(X), uint(X), float(X), string.
func valueCompare(srcVal, dstVal any, op string) (ok bool) {
srcVal = indirectValue(srcVal)

// string compare
if str1, ok := srcVal.(string); ok {
str2, err := strutil.ToString(dstVal)
Expand Down Expand Up @@ -536,6 +538,32 @@ func removeValuePtr(t reflect.Value) reflect.Value {
return t
}

func indirectValue(input any) any {
// Check if input is nil
if input == nil {
return nil
}

// Use reflect to handle the value
val := reflect.ValueOf(input)

// If the value is a pointer, then use reflect.Indirect to get the actual value it points to
if val.Kind() == reflect.Ptr {
// Use reflect.Indirect to safely dereference the pointer
val = reflect.Indirect(val)

// If the dereferenced value is valid (not nil), return the interface
if val.IsValid() {
return val.Interface()
}
// If the dereferenced value is not valid, return nil
return nil
}

// If the input is not a pointer, just return the input as it is
return input
}

// ---- From package "text/template" -> text/template/exec.go

// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
Expand Down
5 changes: 5 additions & 0 deletions validating.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,11 @@ func callValidatorValue(fv reflect.Value, val any, args []any) bool {
rftVal = nilRVal
}

// Add this check to handle pointer values
if rftVal.Kind() == reflect.Ptr && !rftVal.IsNil() {
rftVal = rftVal.Elem()
}

argIn[0] = rftVal
for i := 0; i < argNum; i++ {
rftValA := reflect.ValueOf(args[i])
Expand Down
14 changes: 14 additions & 0 deletions validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,8 @@ func IsUint(val any) bool {

// IsBool check. allow: bool, string.
func IsBool(val any) bool {
val = indirectValue(val)

if _, ok := val.(bool); ok {
return true
}
Expand All @@ -530,6 +532,8 @@ func IsBool(val any) bool {

// IsFloat check. allow: floatX, string
func IsFloat(val any) bool {
val = indirectValue(val)

if val == nil {
return false
}
Expand Down Expand Up @@ -605,6 +609,8 @@ func IsMap(val any) (ok bool) {

// IsInt check, and support length check
func IsInt(val any, minAndMax ...int64) (ok bool) {
val = indirectValue(val)

if val == nil {
return false
}
Expand Down Expand Up @@ -637,6 +643,8 @@ func IsInt(val any, minAndMax ...int64) (ok bool) {
// ok := IsString(val, 5) // with min len check
// ok := IsString(val, 5, 12) // with min and max len check
func IsString(val any, minAndMaxLen ...int) (ok bool) {
val = indirectValue(val)

if val == nil {
return false
}
Expand Down Expand Up @@ -790,6 +798,8 @@ func IsAlphaDash(s string) bool {

// IsNumber string. should >= 0
func IsNumber(v any) bool {
v = indirectValue(v)

if v == nil {
return false
}
Expand All @@ -802,6 +812,8 @@ func IsNumber(v any) bool {

// IsNumeric is string/int number. should >= 0
func IsNumeric(v any) bool {
v = indirectValue(v)

if v == nil {
return false
}
Expand Down Expand Up @@ -1056,6 +1068,8 @@ func Max(val, max any) bool { return valueCompare(val, max, "<=") }
// Between int value in the given range.
// only check for: int(X), uint(X).
func Between(val any, min, max int64) bool {
val = indirectValue(val)

intVal, err := mathutil.Int64(val)
if err != nil {
return false
Expand Down
105 changes: 105 additions & 0 deletions value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,108 @@ func TestVal_enum(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, "input value must be in the enum [go php]", err.Error())
}

func TestVal_indirect(t *testing.T) {
foobar := "foobar"
err := validate.Val(&foobar, "required|string")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|starts_with:foo")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|ends_with:bar")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|contains:oba")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|eq:foobar")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|ne:foo")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|len:6")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|min_len:5")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|max_len:6")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|regex:^foo")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|ascii")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|alpha")
assert.NoError(t, err)

err = validate.Val(&foobar, "required|alpha_num")
assert.NoError(t, err)

foo_bar := "foo bar"

Check warning on line 94 in value_test.go

View workflow job for this annotation

GitHub Actions / linter

var-naming: don't use underscores in Go names; var foo_bar should be fooBar (revive)
err = validate.Val(&foo_bar, "required|hasWhitespace")
assert.NoError(t, err)

email := "[email protected]"
err = validate.Val(&email, "required|email")
assert.NoError(t, err)

url := "https://github.com"
err = validate.Val(&url, "required|url")
assert.NoError(t, err)

ip := "1.1.1.1"
err = validate.Val(&ip, "required|ip")
assert.NoError(t, err)

number := 10
err = validate.Val(&number, "required|int|number")
assert.NoError(t, err)

err = validate.Val(&number, "required|int_eq:10")
assert.NoError(t, err)

err = validate.Val(&number, "required|uint")
assert.NoError(t, err)

err = validate.Val(&number, "required|min:0")
assert.NoError(t, err)

err = validate.Val(&number, "required|max:30")
assert.NoError(t, err)

err = validate.Val(&number, "required|between:0,30")
assert.NoError(t, err)

err = validate.Val(&number, "required|gt:0")
assert.NoError(t, err)

err = validate.Val(&number, "required|lt:30")
assert.NoError(t, err)

float := 0.1
err = validate.Val(&float, "required|float")
assert.NoError(t, err)

boolVal := true
err = validate.Val(&boolVal, "required|bool")
assert.NoError(t, err)

dateVal := "2019-01-01"
err = validate.Val(&dateVal, "required|date")
assert.NoError(t, err)

err = validate.Val(&dateVal, "required|gt_date:2006-01-02")
assert.NoError(t, err)

err = validate.Val(&dateVal, "required|lt_date:2020-01-02")
assert.NoError(t, err)

emptyStr := ""
err = validate.Val(&emptyStr, "required|empty")
assert.NoError(t, err)
}

0 comments on commit 8c4d6aa

Please sign in to comment.