Skip to content

Commit f604b6c

Browse files
joeybloggsjoeybloggs
authored andcommitted
Complete Flatten logic
for #88
1 parent 4d57165 commit f604b6c

File tree

2 files changed

+129
-7
lines changed

2 files changed

+129
-7
lines changed

validator.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,12 @@ func (e *FieldError) Flatten() map[string]*FieldError {
261261

262262
if flat := fe.Flatten(); flat != nil && len(flat) > 0 {
263263
for k, v := range flat {
264-
errs[fmt.Sprintf("[%#v]%s", key, k)] = v
264+
if fe.IsPlaceholderErr {
265+
errs[fmt.Sprintf("[%#v]%s", key, k)] = v
266+
} else {
267+
errs[fmt.Sprintf("[%#v]", key)] = v
268+
}
269+
265270
}
266271
}
267272
} else {
@@ -286,7 +291,11 @@ func (e *FieldError) Flatten() map[string]*FieldError {
286291

287292
if flat := fe.Flatten(); flat != nil && len(flat) > 0 {
288293
for k, v := range flat {
289-
errs[fmt.Sprintf("[%#v]%s", key, k)] = v
294+
if fe.IsPlaceholderErr {
295+
errs[fmt.Sprintf("[%#v]%s", key, k)] = v
296+
} else {
297+
errs[fmt.Sprintf("[%#v]", key)] = v
298+
}
290299
}
291300
}
292301
} else {
@@ -352,7 +361,13 @@ func (e *StructErrors) flatten(isFromStruct bool) map[string]*FieldError {
352361

353362
for k, fe := range flat {
354363

355-
if isFromStruct && k[0:1] == "[" {
364+
// fmt.Println(k)
365+
// if isFromStruct && k[0:1] == "[" {
366+
// errs[f.Field+k] = fe
367+
// } else {
368+
// errs[k] = fe
369+
// }
370+
if f.IsPlaceholderErr {
356371
errs[f.Field+k] = fe
357372
} else {
358373
errs[k] = fe

validator_test.go

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ func TestFlattenValidation(t *testing.T) {
233233
}
234234

235235
type TestMultiDimensionalStructsPtr struct {
236-
Errs [][]*Inner `validate:"gt=0,dive,dive"`
236+
Errs [][]*Inner `validate:"gt=0,dive,dive,required"`
237237
}
238238

239239
var errStructPtrArray [][]*Inner
@@ -271,9 +271,116 @@ func TestFlattenValidation(t *testing.T) {
271271
Equal(t, structErrFlatten.Field, "Name")
272272
Equal(t, structErrFlatten.Tag, "required")
273273

274-
// expect Errs[0][1].Inner.Name = error
275-
// fmt.Println((fieldErr.SliceOrArrayErrs[0].(*FieldError)).Field)
276-
// fmt.Println((fieldErr.SliceOrArrayErrs[0].(*FieldError)).IsPlaceholderErr)
274+
errStructPtrArray = [][]*Inner{}
275+
errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, nil, &Inner{"ok"}})
276+
277+
tmsp = &TestMultiDimensionalStructsPtr{
278+
Errs: errStructPtrArray,
279+
}
280+
281+
errs = validate.Struct(tmsp)
282+
NotEqual(t, errs, nil)
283+
Equal(t, len(errs.Errors), 1)
284+
// for full test coverage
285+
fmt.Sprint(errs.Error())
286+
287+
fieldErr = errs.Errors["Errs"]
288+
Equal(t, fieldErr.IsPlaceholderErr, true)
289+
Equal(t, fieldErr.IsSliceOrArray, true)
290+
Equal(t, fieldErr.Field, "Errs")
291+
Equal(t, len(fieldErr.SliceOrArrayErrs), 1)
292+
293+
innerSlice1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError)
294+
Equal(t, ok, true)
295+
Equal(t, innerSlice1.IsPlaceholderErr, true)
296+
Equal(t, innerSlice1.Field, "Errs[0]")
297+
298+
flatFieldErr, ok = fieldErr.Flatten()["[0][1]"]
299+
Equal(t, ok, true)
300+
Equal(t, flatFieldErr.Field, "Errs[0][1]")
301+
Equal(t, flatFieldErr.Tag, "required")
302+
303+
type TestMapStructPtr struct {
304+
Errs map[int]*Inner `validate:"gt=0,dive,required"`
305+
}
306+
307+
mip := map[int]*Inner{0: &Inner{"ok"}, 3: &Inner{""}, 4: &Inner{"ok"}}
308+
309+
msp := &TestMapStructPtr{
310+
Errs: mip,
311+
}
312+
313+
errs = validate.Struct(msp)
314+
NotEqual(t, errs, nil)
315+
Equal(t, len(errs.Errors), 1)
316+
317+
fieldError := errs.Errors["Errs"]
318+
Equal(t, fieldError.IsPlaceholderErr, true)
319+
Equal(t, fieldError.IsMap, true)
320+
Equal(t, len(fieldError.MapErrs), 1)
321+
322+
innerStructError, ok := fieldError.MapErrs[3].(*StructErrors)
323+
Equal(t, ok, true)
324+
Equal(t, innerStructError.Struct, "Inner")
325+
Equal(t, len(innerStructError.Errors), 1)
326+
327+
innerInnerFieldError, ok := innerStructError.Errors["Name"]
328+
Equal(t, ok, true)
329+
Equal(t, innerInnerFieldError.IsPlaceholderErr, false)
330+
Equal(t, innerInnerFieldError.IsSliceOrArray, false)
331+
Equal(t, innerInnerFieldError.Field, "Name")
332+
Equal(t, innerInnerFieldError.Tag, "required")
333+
334+
flatErrs, ok := errs.Flatten()["Errs[3].Inner.Name"]
335+
Equal(t, ok, true)
336+
Equal(t, flatErrs.Field, "Name")
337+
Equal(t, flatErrs.Tag, "required")
338+
339+
mip2 := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}}
340+
341+
msp2 := &TestMapStructPtr{
342+
Errs: mip2,
343+
}
344+
345+
errs = validate.Struct(msp2)
346+
NotEqual(t, errs, nil)
347+
Equal(t, len(errs.Errors), 1)
348+
349+
fieldError = errs.Errors["Errs"]
350+
Equal(t, fieldError.IsPlaceholderErr, true)
351+
Equal(t, fieldError.IsMap, true)
352+
Equal(t, len(fieldError.MapErrs), 1)
353+
354+
innerFieldError, ok := fieldError.MapErrs[3].(*FieldError)
355+
Equal(t, ok, true)
356+
Equal(t, innerFieldError.IsPlaceholderErr, false)
357+
Equal(t, innerFieldError.IsSliceOrArray, false)
358+
Equal(t, innerFieldError.Field, "Errs[3]")
359+
Equal(t, innerFieldError.Tag, "required")
360+
361+
flatErrs, ok = errs.Flatten()["Errs[3]"]
362+
Equal(t, ok, true)
363+
Equal(t, flatErrs.Field, "Errs[3]")
364+
Equal(t, flatErrs.Tag, "required")
365+
366+
type TestMapInnerArrayStruct struct {
367+
Errs map[int][]string `validate:"gt=0,dive,dive,required"`
368+
}
369+
370+
mias := map[int][]string{0: []string{"ok"}, 3: []string{"ok", ""}, 4: []string{"ok"}}
371+
372+
mia := &TestMapInnerArrayStruct{
373+
Errs: mias,
374+
}
375+
376+
errs = validate.Struct(mia)
377+
NotEqual(t, errs, nil)
378+
Equal(t, len(errs.Errors), 1)
379+
380+
flatErrs, ok = errs.Flatten()["Errs[3][1]"]
381+
Equal(t, ok, true)
382+
Equal(t, flatErrs.Field, "Errs[3][1]")
383+
Equal(t, flatErrs.Tag, "required")
277384
}
278385

279386
func TestInterfaceErrValidation(t *testing.T) {

0 commit comments

Comments
 (0)