Complete adding StructPartial and StructExcept

for issue-#149
pull/161/head
joeybloggs 9 years ago
parent 656ae32e8b
commit 387cfe5aa9
  1. 30
      README.md
  2. 19
      validator.go
  3. 234
      validator_test.go

@ -194,22 +194,22 @@ hurt parallel performance too much.
```go ```go
$ go test -cpu=4 -bench=. -benchmem=true $ go test -cpu=4 -bench=. -benchmem=true
PASS PASS
BenchmarkFieldSuccess-4 5000000 326 ns/op 16 B/op 1 allocs/op BenchmarkFieldSuccess-4 5000000 332 ns/op 16 B/op 1 allocs/op
BenchmarkFieldFailure-4 5000000 327 ns/op 16 B/op 1 allocs/op BenchmarkFieldFailure-4 5000000 334 ns/op 16 B/op 1 allocs/op
BenchmarkFieldCustomTypeSuccess-4 3000000 490 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccess-4 3000000 502 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-4 2000000 829 ns/op 416 B/op 6 allocs/op BenchmarkFieldCustomTypeFailure-4 2000000 833 ns/op 416 B/op 6 allocs/op
BenchmarkFieldOrTagSuccess-4 500000 2448 ns/op 20 B/op 2 allocs/op BenchmarkFieldOrTagSuccess-4 500000 2520 ns/op 20 B/op 2 allocs/op
BenchmarkFieldOrTagFailure-4 1000000 1290 ns/op 384 B/op 6 allocs/op BenchmarkFieldOrTagFailure-4 1000000 1310 ns/op 384 B/op 6 allocs/op
BenchmarkStructSimpleSuccess-4 1000000 1233 ns/op 24 B/op 3 allocs/op BenchmarkStructSimpleSuccess-4 1000000 1274 ns/op 24 B/op 3 allocs/op
BenchmarkStructSimpleFailure-4 1000000 1847 ns/op 529 B/op 11 allocs/op BenchmarkStructSimpleFailure-4 1000000 1887 ns/op 529 B/op 11 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-4 1000000 1292 ns/op 56 B/op 5 allocs/op BenchmarkStructSimpleCustomTypeSuccess-4 1000000 1374 ns/op 56 B/op 5 allocs/op
BenchmarkStructSimpleCustomTypeFailure-4 1000000 1840 ns/op 577 B/op 13 allocs/op BenchmarkStructSimpleCustomTypeFailure-4 1000000 1871 ns/op 577 B/op 13 allocs/op
BenchmarkStructSimpleSuccessParallel-4 5000000 353 ns/op 24 B/op 3 allocs/op BenchmarkStructSimpleSuccessParallel-4 5000000 353 ns/op 24 B/op 3 allocs/op
BenchmarkStructSimpleFailureParallel-4 2000000 746 ns/op 529 B/op 11 allocs/op BenchmarkStructSimpleFailureParallel-4 2000000 799 ns/op 529 B/op 11 allocs/op
BenchmarkStructComplexSuccess-4 200000 7265 ns/op 368 B/op 30 allocs/op BenchmarkStructComplexSuccess-4 200000 7521 ns/op 368 B/op 30 allocs/op
BenchmarkStructComplexFailure-4 100000 12068 ns/op 2860 B/op 72 allocs/op BenchmarkStructComplexFailure-4 100000 12341 ns/op 2861 B/op 72 allocs/op
BenchmarkStructComplexSuccessParallel-4 1000000 2179 ns/op 368 B/op 30 allocs/op BenchmarkStructComplexSuccessParallel-4 1000000 2463 ns/op 368 B/op 30 allocs/op
BenchmarkStructComplexFailureParallel-4 300000 4436 ns/op 2863 B/op 72 allocs/op BenchmarkStructComplexFailureParallel-4 300000 5141 ns/op 2862 B/op 72 allocs/op
``` ```
How to Contribute How to Contribute

@ -216,35 +216,28 @@ func (v *Validate) StructPartial(current interface{}, fields ...string) Validati
name := sv.Type().Name() name := sv.Type().Name()
m := map[string]*struct{}{} m := map[string]*struct{}{}
var i int
if fields != nil { if fields != nil {
for _, k := range fields { for _, k := range fields {
flds := strings.Split(k, ".") flds := strings.Split(k, namespaceSeparator)
if len(flds) > 0 { if len(flds) > 0 {
key := name key := name + namespaceSeparator
for _, s := range flds { for _, s := range flds {
idx := strings.Index(s, "[") idx := strings.Index(s, leftBracket)
if idx != -1 { if idx != -1 {
for idx != -1 { for idx != -1 {
i++
key += s[:idx] key += s[:idx]
m[key] = emptyStructPtr m[key] = emptyStructPtr
idx2 := strings.Index(s, "]") idx2 := strings.Index(s, rightBracket)
idx2++ idx2++
key += s[idx:idx2] key += s[idx:idx2]
m[key] = emptyStructPtr m[key] = emptyStructPtr
s = s[idx2:] s = s[idx2:]
idx = strings.Index(s, "[") idx = strings.Index(s, leftBracket)
if i == 10 {
idx = -1
}
} }
} else { } else {
@ -252,7 +245,7 @@ func (v *Validate) StructPartial(current interface{}, fields ...string) Validati
m[key] = emptyStructPtr m[key] = emptyStructPtr
} }
key += "." key += namespaceSeparator
} }
} }
} }

@ -228,9 +228,9 @@ func TestStructPartial(t *testing.T) {
"SubTest.Test", "SubTest.Test",
} }
// p4 := []string{ p4 := []string{
// "A", "A",
// } }
tPartial := &TestPartial{ tPartial := &TestPartial{
NoTag: "NoTag", NoTag: "NoTag",
@ -309,123 +309,117 @@ func TestStructPartial(t *testing.T) {
Equal(t, errs, nil) Equal(t, errs, nil)
// inversion and retesting Partial to generate failures: // inversion and retesting Partial to generate failures:
// errs = validate.StructPartial(tPartial, p1...) errs = validate.StructPartial(tPartial, p1...)
// NotEqual(t, errs, nil) NotEqual(t, errs, nil)
// AssertError(t, errs, "TestPartial.Required", "Required", "required") AssertError(t, errs, "TestPartial.Required", "Required", "required")
// errs = validate.StructExcept(tPartial, p2) errs = validate.StructExcept(tPartial, p2...)
// AssertError(t, errs, "TestPartial.Required", "Required", "required") AssertError(t, errs, "TestPartial.Required", "Required", "required")
// // reset Required field, and set nested struct // reset Required field, and set nested struct
// tPartial.Required = "Required" tPartial.Required = "Required"
// tPartial.Anonymous.A = "" tPartial.Anonymous.A = ""
// // will pass as unset feilds is not going to be tested // will pass as unset feilds is not going to be tested
// errs = validate.StructPartial(tPartial, p1) errs = validate.StructPartial(tPartial, p1...)
// Equal(t, errs, nil) Equal(t, errs, nil)
// errs = validate.StructExcept(tPartial, p2) errs = validate.StructExcept(tPartial, p2...)
// Equal(t, errs, nil) Equal(t, errs, nil)
// // ANON CASE the response here is strange, it clearly does what it is being told to // ANON CASE the response here is strange, it clearly does what it is being told to
// errs = validate.StructExcept(tPartial.Anonymous, p4) errs = validate.StructExcept(tPartial.Anonymous, p4...)
// AssertError(t, errs, ".A", "A", "required") Equal(t, errs, nil)
// // will fail as unset feild is tested // will fail as unset feild is tested
// errs = validate.StructPartial(tPartial, p2) errs = validate.StructPartial(tPartial, p2...)
// AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required") NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required")
// errs = validate.StructExcept(tPartial, p1)
// AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required") errs = validate.StructExcept(tPartial, p1...)
NotEqual(t, errs, nil)
// // reset nested struct and unset struct in slice AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required")
// tPartial.Anonymous.A = "Required"
// tPartial.SubSlice[0].Test = "" // reset nested struct and unset struct in slice
tPartial.Anonymous.A = "Required"
// // these will pass as unset item is NOT tested tPartial.SubSlice[0].Test = ""
// errs = validate.StructPartial(tPartial, p1)
// Equal(t, errs, nil) // these will pass as unset item is NOT tested
errs = validate.StructPartial(tPartial, p1...)
// errs = validate.StructExcept(tPartial, p2) Equal(t, errs, nil)
// Equal(t, errs, nil)
errs = validate.StructExcept(tPartial, p2...)
// // these will fail as unset item IS tested Equal(t, errs, nil)
// errs = validate.StructExcept(tPartial, p1)
// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") // these will fail as unset item IS tested
// Equal(t, len(errs), 1) errs = validate.StructExcept(tPartial, p1...)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required")
// errs = validate.StructPartial(tPartial, p2) Equal(t, len(errs), 1)
// //Equal(t, errs, nil)
// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") errs = validate.StructPartial(tPartial, p2...)
// Equal(t, len(errs), 1) NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required")
// // Unset second slice member concurrently to test dive behavior: Equal(t, len(errs), 1)
// tPartial.SubSlice[1].Test = ""
// Unset second slice member concurrently to test dive behavior:
// errs = validate.StructPartial(tPartial, p1) tPartial.SubSlice[1].Test = ""
// Equal(t, errs, nil)
errs = validate.StructPartial(tPartial, p1...)
// // Case note: Equal(t, errs, nil)
// // were bypassing dive here? by setting a single item?
// // im not sure anyone would or should do this, I cant think of a reason // NOTE: When specifying nested items, it is still the users responsibility
// // why they would but you never know. As for describing this behavior in // to specify the dive tag, the library does not override this.
// // documentation I would be at a loss as to do it errs = validate.StructExcept(tPartial, p2...)
// // especialy concidering the next test NotEqual(t, errs, nil)
// errs = validate.StructExcept(tPartial, p2) AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required")
// Equal(t, errs, nil)
// //AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") errs = validate.StructExcept(tPartial, p1...)
Equal(t, len(errs), 2)
// // test sub validation: AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required")
// // this is diving AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required")
// errs = validate.StructExcept(tPartial, p1)
// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") errs = validate.StructPartial(tPartial, p2...)
// AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") NotEqual(t, errs, nil)
// Equal(t, len(errs), 2) Equal(t, len(errs), 1)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required")
// errs = validate.StructPartial(tPartial, p2)
// //Equal(t, errs, nil) // reset struct in slice, and unset struct in slice in unset posistion
// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required") tPartial.SubSlice[0].Test = "Required"
// Equal(t, len(errs), 1)
// these will pass as the unset item is NOT tested
// // reset struct in slice, and unset struct in slice in unset posistion errs = validate.StructPartial(tPartial, p1...)
// tPartial.SubSlice[0].Test = "Required" Equal(t, errs, nil)
// // these will pass as the unset item is NOT tested errs = validate.StructPartial(tPartial, p2...)
// errs = validate.StructPartial(tPartial, p1) Equal(t, errs, nil)
// Equal(t, errs, nil)
// testing for missing item by exception, yes it dives and fails
// errs = validate.StructPartial(tPartial, p2) errs = validate.StructExcept(tPartial, p1...)
// Equal(t, errs, nil) NotEqual(t, errs, nil)
Equal(t, len(errs), 1)
// // testing for missing item by exception, yes it dives and fails AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required")
// errs = validate.StructExcept(tPartial, p1)
// AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") errs = validate.StructExcept(tPartial, p2...)
// Equal(t, len(errs), 1) NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required")
// // See above case note... this is a variation on the above
// // when all taken into account it seems super strange! tPartial.SubSlice[1].Test = "Required"
// errs = validate.StructExcept(tPartial, p2)
// Equal(t, errs, nil) tPartial.Anonymous.SubAnonStruct[0].Test = ""
// //AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required") // these will pass as the unset item is NOT tested
errs = validate.StructPartial(tPartial, p1...)
// tPartial.SubSlice[1].Test = "Required" Equal(t, errs, nil)
// tPartial.Anonymous.SubAnonStruct[0].Test = "" errs = validate.StructPartial(tPartial, p2...)
// // these will pass as the unset item is NOT tested Equal(t, errs, nil)
// errs = validate.StructPartial(tPartial, p1)
// Equal(t, errs, nil) errs = validate.StructExcept(tPartial, p1...)
NotEqual(t, errs, nil)
// errs = validate.StructPartial(tPartial, p2) AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required")
// Equal(t, errs, nil)
errs = validate.StructExcept(tPartial, p2...)
// errs = validate.StructExcept(tPartial, p1) NotEqual(t, errs, nil)
// AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required") AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required")
// // See above case note... this is a variation on the above
// // when all taken into account it seems super strange!
// errs = validate.StructExcept(tPartial, p2)
// Equal(t, errs, nil)
// //AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required")
} }

Loading…
Cancel
Save