Skip to content

Commit

Permalink
Add support for validating against uuid values that are structs which…
Browse files Browse the repository at this point in the history
… implement the Stringer interface.
  • Loading branch information
JoshGlazebrook committed Oct 30, 2023
1 parent 94a637a commit fc09467
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 9 deletions.
18 changes: 9 additions & 9 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package validator

import (
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -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())
}
29 changes: 29 additions & 0 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit fc09467

Please sign in to comment.