diff --git a/baked_in.go b/baked_in.go index 0b623307..19fa415e 100644 --- a/baked_in.go +++ b/baked_in.go @@ -508,47 +508,47 @@ func isASCII(fl FieldLevel) bool { // isUUID5 is the validation function for validating if the field's value is a valid v5 UUID. func isUUID5(fl FieldLevel) bool { - return uUID5Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID5Regex, fl) } // isUUID4 is the validation function for validating if the field's value is a valid v4 UUID. func isUUID4(fl FieldLevel) bool { - return uUID4Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID4Regex, fl) } // isUUID3 is the validation function for validating if the field's value is a valid v3 UUID. func isUUID3(fl FieldLevel) bool { - return uUID3Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID3Regex, fl) } // isUUID is the validation function for validating if the field's value is a valid UUID of any version. func isUUID(fl FieldLevel) bool { - return uUIDRegex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUIDRegex, fl) } // isUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID. func isUUID5RFC4122(fl FieldLevel) bool { - return uUID5RFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID5RFC4122Regex, fl) } // isUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID. func isUUID4RFC4122(fl FieldLevel) bool { - return uUID4RFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID4RFC4122Regex, fl) } // isUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID. func isUUID3RFC4122(fl FieldLevel) bool { - return uUID3RFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID3RFC4122Regex, fl) } // isUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version. func isUUIDRFC4122(fl FieldLevel) bool { - return uUIDRFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUIDRFC4122Regex, fl) } // isULID is the validation function for validating if the field's value is a valid ULID. func isULID(fl FieldLevel) bool { - return uLIDRegex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uLIDRegex, fl) } // isMD4 is the validation function for validating if the field's value is a valid MD4. diff --git a/util.go b/util.go index 4bd947bd..c8b901db 100644 --- a/util.go +++ b/util.go @@ -1,7 +1,9 @@ package validator import ( + "fmt" "reflect" + "regexp" "strconv" "strings" "time" @@ -292,3 +294,12 @@ func panicIf(err error) { panic(err.Error()) } } + +// Checks if field value matches regex. If fl.Field can be cast to Stringer, it uses the Stringer interfaces +// String() return value. Otherwise, it uses fl.Field's String() value. +func fieldMatchesRegexByStringerValOrString(regex *regexp.Regexp, fl FieldLevel) bool { + if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok { + return regex.MatchString(stringer.String()) + } + return regex.MatchString(fl.Field().String()) +} diff --git a/validator_test.go b/validator_test.go index 230ab61b..b5949ac7 100644 --- a/validator_test.go +++ b/validator_test.go @@ -4105,6 +4105,16 @@ func TestUUID3Validation(t *testing.T) { } } +type uuidTestType struct { + val string +} + +func (u uuidTestType) String() string { + return u.val +} + +var _ fmt.Stringer = uuidTestType{} + func TestUUIDValidation(t *testing.T) { tests := []struct { param string @@ -4141,6 +4151,25 @@ func TestUUIDValidation(t *testing.T) { } } } + + // Test UUID validation on uuid structs type that implements Stringer interface. + structWithValidUUID := struct { + UUID uuidTestType `validate:"uuid"` + }{ + UUID: uuidTestType{val: "a987fbc9-4bed-3078-cf07-9141ba07c9f3"}, + } + structWithInvalidUUID := struct { + UUID uuidTestType `validate:"uuid"` + }{ + UUID: uuidTestType{val: "934859"}, + } + + if err := validate.Struct(structWithValidUUID); err != nil { + t.Fatalf("UUID failed Error: %s", err) + } + if err := validate.Struct(structWithInvalidUUID); err == nil { + t.Fatal("UUID failed Error expected but received nil") + } } func TestUUID5RFC4122Validation(t *testing.T) {