mirror of
https://github.com/Fishwaldo/validator.git
synced 2025-03-15 19:51:38 +00:00
Complete adding StructPartial and StructExcept
for issue-#149
This commit is contained in:
parent
656ae32e8b
commit
387cfe5aa9
3 changed files with 108 additions and 121 deletions
30
README.md
30
README.md
|
@ -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
|
||||
|
|
19
validator.go
19
validator.go
|
@ -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.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")
|
||||
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 = ""
|
||||
// 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)
|
||||
// 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)
|
||||
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")
|
||||
// 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)
|
||||
// AssertError(t, errs, "TestPartial.Anonymous.A", "A", "required")
|
||||
// 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)
|
||||
// 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 = ""
|
||||
// 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)
|
||||
// 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)
|
||||
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)
|
||||
// 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)
|
||||
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 = ""
|
||||
// Unset second slice member concurrently to test dive behavior:
|
||||
tPartial.SubSlice[1].Test = ""
|
||||
|
||||
// errs = validate.StructPartial(tPartial, p1)
|
||||
// Equal(t, errs, nil)
|
||||
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")
|
||||
// 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")
|
||||
|
||||
// // 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.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)
|
||||
// //Equal(t, errs, nil)
|
||||
// AssertError(t, errs, "TestPartial.SubSlice[0].Test", "Test", "required")
|
||||
// Equal(t, len(errs), 1)
|
||||
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"
|
||||
// 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)
|
||||
// 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.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)
|
||||
// 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")
|
||||
|
||||
// // 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")
|
||||
errs = validate.StructExcept(tPartial, p2...)
|
||||
NotEqual(t, errs, nil)
|
||||
AssertError(t, errs, "TestPartial.SubSlice[1].Test", "Test", "required")
|
||||
|
||||
// tPartial.SubSlice[1].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)
|
||||
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.StructPartial(tPartial, p2...)
|
||||
Equal(t, errs, nil)
|
||||
|
||||
// errs = validate.StructExcept(tPartial, p1)
|
||||
// AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required")
|
||||
errs = validate.StructExcept(tPartial, p1...)
|
||||
NotEqual(t, errs, nil)
|
||||
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.StructExcept(tPartial, p2...)
|
||||
NotEqual(t, errs, nil)
|
||||
AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "required")
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue