diff --git a/README.md b/README.md index 8f9933e..0c00871 100644 --- a/README.md +++ b/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 diff --git a/validator.go b/validator.go index 71268f0..3ca8419 100644 --- a/validator.go +++ b/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 } } } diff --git a/validator_test.go b/validator_test.go index 48dc3b0..eca7baf 100644 --- a/validator_test.go +++ b/validator_test.go @@ -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") }