Skip to content

Commit 8bf793a

Browse files
joeybloggsjoeybloggs
authored andcommitted
correct map references pointing to slice after copy/paste
for#78
1 parent 14f176e commit 8bf793a

File tree

2 files changed

+88
-39
lines changed

2 files changed

+88
-39
lines changed

validator.go

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,20 @@ import (
2020
)
2121

2222
const (
23-
utf8HexComma = "0x2C"
24-
tagSeparator = ","
25-
orSeparator = "|"
26-
noValidationTag = "-"
27-
tagKeySeparator = "="
28-
structOnlyTag = "structonly"
29-
omitempty = "omitempty"
30-
required = "required"
31-
fieldErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag"
32-
sliceErrMsg = "Field validation for \"%s\" failed at index \"%d\" with error(s): %s"
33-
mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s"
34-
structErrMsg = "Struct:%s\n"
35-
diveTag = "dive"
36-
diveSplit = "," + diveTag
23+
utf8HexComma = "0x2C"
24+
tagSeparator = ","
25+
orSeparator = "|"
26+
noValidationTag = "-"
27+
tagKeySeparator = "="
28+
structOnlyTag = "structonly"
29+
omitempty = "omitempty"
30+
required = "required"
31+
fieldErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag"
32+
sliceErrMsg = "Field validation for \"%s\" failed at index \"%d\" with error(s): %s"
33+
mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s"
34+
structErrMsg = "Struct:%s\n"
35+
diveTag = "dive"
36+
// diveSplit = "," + diveTag
3737
arrayIndexFieldName = "%s[%d]"
3838
mapIndexFieldName = "%s[%v]"
3939
)
@@ -457,7 +457,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
457457
case reflect.Slice, reflect.Array:
458458
cField.isSliceOrArray = true
459459
cField.sliceSubtype = cField.typ.Elem()
460-
cField.isTimeSubtype = cField.sliceSubtype == reflect.TypeOf(time.Time{})
460+
cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{}))
461461
cField.sliceSubKind = cField.sliceSubtype.Kind()
462462

463463
if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
@@ -469,7 +469,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
469469
case reflect.Map:
470470
cField.isMap = true
471471
cField.mapSubtype = cField.typ.Elem()
472-
cField.isTimeSubtype = cField.mapSubtype == reflect.TypeOf(time.Time{})
472+
cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{}))
473473
cField.mapSubKind = cField.mapSubtype.Kind()
474474

475475
if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
@@ -537,11 +537,13 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
537537

538538
switch cField.kind {
539539
case reflect.Slice, reflect.Array:
540+
isSingleField = false // cached tags mean nothing because it will be split up while diving
540541
cField.isSliceOrArray = true
541542
cField.sliceSubtype = cField.typ.Elem()
542543
cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{}))
543544
cField.sliceSubKind = cField.sliceSubtype.Kind()
544545
case reflect.Map:
546+
isSingleField = false // cached tags mean nothing because it will be split up while diving
545547
cField.isMap = true
546548
cField.mapSubtype = cField.typ.Elem()
547549
cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{}))
@@ -556,7 +558,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
556558
case reflect.Struct, reflect.Interface, reflect.Invalid:
557559

558560
if cField.typ != reflect.TypeOf(time.Time{}) {
559-
panic("Invalid field passed to ValidateFieldWithTag")
561+
panic("Invalid field passed to fieldWithNameAndValue")
560562
}
561563
}
562564

@@ -568,22 +570,12 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
568570

569571
if !isCached {
570572

571-
for k, t := range strings.Split(tag, tagSeparator) {
573+
for _, t := range strings.Split(tag, tagSeparator) {
572574

573575
if t == diveTag {
574576

575577
cField.dive = true
576-
577-
if k == 0 {
578-
if len(tag) == 4 {
579-
cField.diveTag = ""
580-
} else {
581-
cField.diveTag = tag[5:]
582-
}
583-
} else {
584-
cField.diveTag = strings.SplitN(tag, diveSplit, 2)[1][1:]
585-
}
586-
578+
cField.diveTag = strings.TrimLeft(strings.SplitN(tag, diveTag, 2)[1], ",")
587579
break
588580
}
589581

@@ -700,12 +692,14 @@ func (v *Validate) traverseMap(val interface{}, current interface{}, valueField
700692

701693
idxField := valueField.MapIndex(key)
702694

703-
if cField.sliceSubKind == reflect.Ptr && !idxField.IsNil() {
695+
if cField.mapSubKind == reflect.Ptr && !idxField.IsNil() {
704696
idxField = idxField.Elem()
705-
cField.sliceSubKind = idxField.Kind()
697+
cField.mapSubKind = idxField.Kind()
706698
}
707699

708-
switch cField.sliceSubKind {
700+
// fmt.Println(cField.sliceSubKind)
701+
702+
switch cField.mapSubKind {
709703
case reflect.Struct, reflect.Interface:
710704

711705
if cField.isTimeSubtype {
@@ -730,7 +724,7 @@ func (v *Validate) traverseMap(val interface{}, current interface{}, valueField
730724
Tag: required,
731725
Value: idxField.Interface(),
732726
Kind: reflect.Ptr,
733-
Type: cField.sliceSubtype,
727+
Type: cField.mapSubtype,
734728
}
735729
}
736730

validator_test.go

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,21 +228,76 @@ func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, e
228228

229229
func TestMapDiveValidation(t *testing.T) {
230230

231-
type Test struct {
232-
Errs map[int]string `validate:"gt=0,dive,required"`
231+
m := map[int]string{0: "ok", 3: "", 4: "ok"}
232+
233+
err := validate.Field(m, "len=3,dive,required")
234+
NotEqual(t, err, nil)
235+
Equal(t, err.IsPlaceholderErr, true)
236+
Equal(t, err.IsMap, true)
237+
Equal(t, len(err.MapErrs), 1)
238+
239+
err = validate.Field(m, "len=2,dive,required")
240+
NotEqual(t, err, nil)
241+
Equal(t, err.IsPlaceholderErr, false)
242+
Equal(t, err.IsMap, false)
243+
Equal(t, len(err.MapErrs), 0)
244+
245+
type Inner struct {
246+
Name string `validate:"required"`
233247
}
234248

235-
test := &Test{
236-
Errs: map[int]string{0: "ok", 1: "", 4: "ok"},
249+
type TestMapStruct struct {
250+
Errs map[int]Inner `validate:"gt=0,dive"`
237251
}
238252

239-
errs := validate.Struct(test)
253+
mi := map[int]Inner{0: Inner{"ok"}, 3: Inner{""}, 4: Inner{"ok"}}
254+
255+
ms := &TestMapStruct{
256+
Errs: mi,
257+
}
258+
259+
errs := validate.Struct(ms)
240260

241261
fmt.Println(errs)
262+
263+
// type Test struct {
264+
// Errs map[int]string `validate:"gt=0,dive,required"`
265+
// }
266+
267+
// test := &Test{
268+
// Errs: map[int]string{0: "ok", 1: "", 4: "ok"},
269+
// }
270+
271+
// errs := validate.Struct(test)
272+
// NotEqual(t, errs, nil)
242273
}
243274

244275
func TestArrayDiveValidation(t *testing.T) {
245276

277+
arr := []string{"ok", "", "ok"}
278+
279+
err := validate.Field(arr, "len=3,dive,required")
280+
NotEqual(t, err, nil)
281+
Equal(t, err.IsPlaceholderErr, true)
282+
Equal(t, err.IsSliceOrArray, true)
283+
Equal(t, len(err.SliceOrArrayErrs), 1)
284+
285+
err = validate.Field(arr, "len=2,dive,required")
286+
NotEqual(t, err, nil)
287+
Equal(t, err.IsPlaceholderErr, false)
288+
Equal(t, err.IsSliceOrArray, false)
289+
Equal(t, len(err.SliceOrArrayErrs), 0)
290+
291+
type BadDive struct {
292+
Name string `validate:"dive"`
293+
}
294+
295+
bd := &BadDive{
296+
Name: "TEST",
297+
}
298+
299+
PanicMatches(t, func() { validate.Struct(bd) }, "dive error! can't dive on a non slice or map")
300+
246301
type Test struct {
247302
Errs []string `validate:"gt=0,dive,required"`
248303
}
@@ -3204,7 +3259,7 @@ func TestInvalidField(t *testing.T) {
32043259
Test: "1",
32053260
}
32063261

3207-
PanicMatches(t, func() { validate.Field(s, "required") }, "Invalid field passed to ValidateFieldWithTag")
3262+
PanicMatches(t, func() { validate.Field(s, "required") }, "Invalid field passed to fieldWithNameAndValue")
32083263
}
32093264

32103265
func TestInvalidTagField(t *testing.T) {

0 commit comments

Comments
 (0)