Skip to content

Commit

Permalink
Merge pull request #644 from longit644/bugfix/make-unique-tag-work-wi…
Browse files Browse the repository at this point in the history
…th-pointer-fields

Make unique tag work with pointer fields.
  • Loading branch information
Dean Karn authored Sep 27, 2020
2 parents d9e95d5 + 67c4fdf commit 57b4fab
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 5 deletions.
20 changes: 15 additions & 5 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,23 +247,33 @@ func isUnique(fl FieldLevel) bool {

switch field.Kind() {
case reflect.Slice, reflect.Array:
elem := field.Type().Elem()
if elem.Kind() == reflect.Ptr {
elem = elem.Elem()
}

if param == "" {
m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type()))
m := reflect.MakeMap(reflect.MapOf(elem, v.Type()))

for i := 0; i < field.Len(); i++ {
m.SetMapIndex(field.Index(i), v)
m.SetMapIndex(reflect.Indirect(field.Index(i)), v)
}
return field.Len() == m.Len()
}

sf, ok := field.Type().Elem().FieldByName(param)
sf, ok := elem.FieldByName(param)
if !ok {
panic(fmt.Sprintf("Bad field name %s", param))
}

m := reflect.MakeMap(reflect.MapOf(sf.Type, v.Type()))
sfTyp := sf.Type
if sfTyp.Kind() == reflect.Ptr {
sfTyp = sfTyp.Elem()
}

m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type()))
for i := 0; i < field.Len(); i++ {
m.SetMapIndex(field.Index(i).FieldByName(param), v)
m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v)
}
return field.Len() == m.Len()
case reflect.Map:
Expand Down
67 changes: 67 additions & 0 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,18 @@ func StructLevelInvalidError(sl StructLevel) {
}
}

func stringPtr(v string) *string {
return &v
}

func intPtr(v int) *int {
return &v
}

func float64Ptr(v float64) *float64 {
return &v
}

func TestStructLevelInvalidError(t *testing.T) {

validate := New()
Expand Down Expand Up @@ -8144,6 +8156,12 @@ func TestUniqueValidation(t *testing.T) {
{[2]string{"a", "a"}, false},
{[2]interface{}{"a", "a"}, false},
{[4]interface{}{"a", 1, "b", 1}, false},
{[2]*string{stringPtr("a"), stringPtr("b")}, true},
{[2]*int{intPtr(1), intPtr(2)}, true},
{[2]*float64{float64Ptr(1), float64Ptr(2)}, true},
{[2]*string{stringPtr("a"), stringPtr("a")}, false},
{[2]*float64{float64Ptr(1), float64Ptr(1)}, false},
{[2]*int{intPtr(1), intPtr(1)}, false},
// Slices
{[]string{"a", "b"}, true},
{[]int{1, 2}, true},
Expand All @@ -8155,6 +8173,12 @@ func TestUniqueValidation(t *testing.T) {
{[]string{"a", "a"}, false},
{[]interface{}{"a", "a"}, false},
{[]interface{}{"a", 1, "b", 1}, false},
{[]*string{stringPtr("a"), stringPtr("b")}, true},
{[]*int{intPtr(1), intPtr(2)}, true},
{[]*float64{float64Ptr(1), float64Ptr(2)}, true},
{[]*string{stringPtr("a"), stringPtr("a")}, false},
{[]*float64{float64Ptr(1), float64Ptr(1)}, false},
{[]*int{intPtr(1), intPtr(1)}, false},
// Maps
{map[string]string{"one": "a", "two": "b"}, true},
{map[string]int{"one": 1, "two": 2}, true},
Expand Down Expand Up @@ -8235,6 +8259,49 @@ func TestUniqueValidationStructSlice(t *testing.T) {
PanicMatches(t, func() { validate.Var(testStructs, "unique=C") }, "Bad field name C")
}

func TestUniqueValidationStructPtrSlice(t *testing.T) {
testStructs := []*struct {
A *string
B *string
}{
{A: stringPtr("one"), B: stringPtr("two")},
{A: stringPtr("one"), B: stringPtr("three")},
}

tests := []struct {
target interface{}
param string
expected bool
}{
{testStructs, "unique", true},
{testStructs, "unique=A", false},
{testStructs, "unique=B", true},
}

validate := New()

for i, test := range tests {

errs := validate.Var(test.target, test.param)

if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "unique" {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
}
}
}
PanicMatches(t, func() { validate.Var(testStructs, "unique=C") }, "Bad field name C")
}

func TestHTMLValidation(t *testing.T) {
tests := []struct {
param string
Expand Down

0 comments on commit 57b4fab

Please sign in to comment.