Skip to content

Commit 399fda9

Browse files
Dean KarnDean Karn
authored andcommitted
issue-#5
add Flatten function add Test case for Flatten() function
1 parent 3614803 commit 399fda9

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

validator.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type FieldValidationError struct {
3131

3232
// This is intended for use in development + debugging and not intended to be a production error message.
3333
// it also allows FieldValidationError to be used as an Error interface
34-
func (e FieldValidationError) Error() string {
34+
func (e *FieldValidationError) Error() string {
3535
return fmt.Sprintf(validationFieldErrMsg, e.Field, e.ErrorTag)
3636
}
3737

@@ -48,7 +48,7 @@ type StructValidationErrors struct {
4848

4949
// This is intended for use in development + debugging and not intended to be a production error message.
5050
// it also allows StructValidationErrors to be used as an Error interface
51-
func (e StructValidationErrors) Error() string {
51+
func (e *StructValidationErrors) Error() string {
5252

5353
s := fmt.Sprintf(validationStructErrMsg, e.Struct)
5454

@@ -63,6 +63,35 @@ func (e StructValidationErrors) Error() string {
6363
return fmt.Sprintf("%s\n\n", s)
6464
}
6565

66+
// Flatten flattens the StructValidationErrors hierarchical sctructure into a flat namespace style field name
67+
// for those that want/need it
68+
func (e *StructValidationErrors) Flatten() map[string]*FieldValidationError {
69+
70+
if e == nil {
71+
return nil
72+
}
73+
74+
errs := map[string]*FieldValidationError{}
75+
76+
for _, f := range e.Errors {
77+
78+
errs[f.Field] = f
79+
}
80+
81+
for key, val := range e.StructErrors {
82+
83+
otherErrs := val.Flatten()
84+
85+
for _, f2 := range otherErrs {
86+
87+
f2.Field = fmt.Sprintf("%s.%s", key, f2.Field)
88+
errs[f2.Field] = f2
89+
}
90+
}
91+
92+
return errs
93+
}
94+
6695
// ValidationFunc that accepts the value of a field and parameter for use in validation (parameter not always used or needed)
6796
type ValidationFunc func(v interface{}, param string) bool
6897

validator_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,72 @@ func AssertFieldError(s *validator.StructValidationErrors, field string, expecte
8787
c.Assert(val.ErrorTag, Equals, expectedTag)
8888
}
8989

90+
func AssertMapFieldError(s map[string]*validator.FieldValidationError, field string, expectedTag string, c *C) {
91+
92+
val, ok := s[field]
93+
c.Assert(ok, Equals, true)
94+
c.Assert(val, NotNil)
95+
c.Assert(val.Field, Equals, field)
96+
c.Assert(val.ErrorTag, Equals, expectedTag)
97+
}
98+
99+
func (ms *MySuite) TestFlattening(c *C) {
100+
101+
tSuccess := &TestString{
102+
Required: "Required",
103+
Len: "length==10",
104+
Min: "min=1",
105+
Max: "1234567890",
106+
MinMax: "12345",
107+
OmitEmpty: "",
108+
Sub: &SubTest{
109+
Test: "1",
110+
},
111+
SubIgnore: &SubTest{
112+
Test: "",
113+
},
114+
Anonymous: struct {
115+
A string `validate:"required"`
116+
}{
117+
A: "1",
118+
},
119+
}
120+
121+
err1 := validator.ValidateStruct(tSuccess).Flatten()
122+
c.Assert(err1, IsNil)
123+
124+
tFail := &TestString{
125+
Required: "",
126+
Len: "",
127+
Min: "",
128+
Max: "12345678901",
129+
MinMax: "",
130+
OmitEmpty: "12345678901",
131+
Sub: &SubTest{
132+
Test: "",
133+
},
134+
Anonymous: struct {
135+
A string `validate:"required"`
136+
}{
137+
A: "",
138+
},
139+
}
140+
141+
err2 := validator.ValidateStruct(tFail).Flatten()
142+
143+
// Assert Top Level
144+
c.Assert(err2, NotNil)
145+
146+
// Assert Fields
147+
AssertMapFieldError(err2, "Len", "len", c)
148+
149+
// Assert Struct Field
150+
AssertMapFieldError(err2, "Sub.Test", "required", c)
151+
152+
// Assert Anonymous Struct Field
153+
AssertMapFieldError(err2, "Anonymous.A", "required", c)
154+
}
155+
90156
func (ms *MySuite) TestStructStringValidation(c *C) {
91157

92158
tSuccess := &TestString{
@@ -132,6 +198,7 @@ func (ms *MySuite) TestStructStringValidation(c *C) {
132198
err = validator.ValidateStruct(tFail)
133199

134200
// Assert Top Level
201+
c.Assert(err, NotNil)
135202
c.Assert(err.Struct, Equals, "TestString")
136203
c.Assert(len(err.Errors), Equals, 6)
137204
c.Assert(len(err.StructErrors), Equals, 2)
@@ -181,6 +248,7 @@ func (ms *MySuite) TestStructInt32Validation(c *C) {
181248
err = validator.ValidateStruct(tFail)
182249

183250
// Assert Top Level
251+
c.Assert(err, NotNil)
184252
c.Assert(err.Struct, Equals, "TestInt32")
185253
c.Assert(len(err.Errors), Equals, 6)
186254
c.Assert(len(err.StructErrors), Equals, 0)
@@ -220,6 +288,7 @@ func (ms *MySuite) TestStructUint64Validation(c *C) {
220288
err = validator.ValidateStruct(tFail)
221289

222290
// Assert Top Level
291+
c.Assert(err, NotNil)
223292
c.Assert(err.Struct, Equals, "TestUint64")
224293
c.Assert(len(err.Errors), Equals, 6)
225294
c.Assert(len(err.StructErrors), Equals, 0)
@@ -259,6 +328,7 @@ func (ms *MySuite) TestStructFloat64Validation(c *C) {
259328
err = validator.ValidateStruct(tFail)
260329

261330
// Assert Top Level
331+
c.Assert(err, NotNil)
262332
c.Assert(err.Struct, Equals, "TestFloat64")
263333
c.Assert(len(err.Errors), Equals, 6)
264334
c.Assert(len(err.StructErrors), Equals, 0)
@@ -298,6 +368,7 @@ func (ms *MySuite) TestStructSliceValidation(c *C) {
298368
err = validator.ValidateStruct(tFail)
299369

300370
// Assert Top Level
371+
c.Assert(err, NotNil)
301372
c.Assert(err.Struct, Equals, "TestSlice")
302373
c.Assert(len(err.Errors), Equals, 6)
303374
c.Assert(len(err.StructErrors), Equals, 0)

0 commit comments

Comments
 (0)