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

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

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

Loading…
Cancel
Save