From 883731a774dcdcbe4d60aee19d29a822dbae3a87 Mon Sep 17 00:00:00 2001 From: joeybloggs Date: Tue, 18 Aug 2015 22:10:26 -0400 Subject: [PATCH] Updates + Benchmarks update documentation. add benchmarks for StructPartial, dive tag, cross field and cross struct cross field. --- benchmarks_test.go | 196 ++++++++++++++++++++++++++++++++++++++------- validator.go | 4 + 2 files changed, 172 insertions(+), 28 deletions(-) diff --git a/benchmarks_test.go b/benchmarks_test.go index af201e6..1cd19b2 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -4,6 +4,7 @@ import ( sql "database/sql/driver" "reflect" "testing" + "time" ) func BenchmarkFieldSuccess(b *testing.B) { @@ -18,6 +19,18 @@ func BenchmarkFieldFailure(b *testing.B) { } } +func BenchmarkFieldDiveSuccess(b *testing.B) { + for n := 0; n < b.N; n++ { + validate.Field([]string{"val1", "val2", "val3"}, "required,dive,required") + } +} + +func BenchmarkFieldDiveFailure(b *testing.B) { + for n := 0; n < b.N; n++ { + validate.Field([]string{"val1", "", "val3"}, "required,dive,required") + } +} + func BenchmarkFieldCustomTypeSuccess(b *testing.B) { customTypes := map[reflect.Type]CustomTypeFunc{} @@ -62,34 +75,6 @@ func BenchmarkFieldOrTagFailure(b *testing.B) { } } -func BenchmarkStructSimpleSuccess(b *testing.B) { - - type Foo struct { - StringValue string `validate:"min=5,max=10"` - IntValue int `validate:"min=5,max=10"` - } - - validFoo := &Foo{StringValue: "Foobar", IntValue: 7} - - for n := 0; n < b.N; n++ { - validate.Struct(validFoo) - } -} - -func BenchmarkStructSimpleFailure(b *testing.B) { - - type Foo struct { - StringValue string `validate:"min=5,max=10"` - IntValue int `validate:"min=5,max=10"` - } - - invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} - - for n := 0; n < b.N; n++ { - validate.Struct(invalidFoo) - } -} - func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) { customTypes := map[reflect.Type]CustomTypeFunc{} @@ -136,6 +121,161 @@ func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) { } } +func BenchmarkStructPartialSuccess(b *testing.B) { + + type Test struct { + Name string `validate:"required"` + NickName string `validate:"required"` + } + + test := &Test{ + Name: "Joey Bloggs", + } + + for n := 0; n < b.N; n++ { + validate.StructPartial(test, "Name") + } +} + +func BenchmarkStructPartialFailure(b *testing.B) { + + type Test struct { + Name string `validate:"required"` + NickName string `validate:"required"` + } + + test := &Test{ + Name: "Joey Bloggs", + } + + for n := 0; n < b.N; n++ { + validate.StructPartial(test, "NickName") + } +} + +func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) { + + type Test struct { + Start time.Time + End time.Time `validate:"gtfield=Start"` + } + + now := time.Now().UTC() + then := now.Add(time.Hour * 5) + + test := &Test{ + Start: now, + End: then, + } + + for n := 0; n < b.N; n++ { + validate.Struct(test) + } +} + +func BenchmarkStructSimpleCrossFieldFailure(b *testing.B) { + + type Test struct { + Start time.Time + End time.Time `validate:"gtfield=Start"` + } + + now := time.Now().UTC() + then := now.Add(time.Hour * -5) + + test := &Test{ + Start: now, + End: then, + } + + for n := 0; n < b.N; n++ { + validate.Struct(test) + } +} + +func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) { + + type Inner struct { + Start time.Time + } + + type Outer struct { + Inner *Inner + CreatedAt time.Time `validate:"eqcsfield=Inner.Start"` + } + + now := time.Now().UTC() + + inner := &Inner{ + Start: now, + } + + outer := &Outer{ + Inner: inner, + CreatedAt: now, + } + + for n := 0; n < b.N; n++ { + validate.Struct(outer) + } +} + +func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) { + + type Inner struct { + Start time.Time + } + + type Outer struct { + Inner *Inner + CreatedAt time.Time `validate:"eqcsfield=Inner.Start"` + } + + now := time.Now().UTC() + then := now.Add(time.Hour * 5) + + inner := &Inner{ + Start: then, + } + + outer := &Outer{ + Inner: inner, + CreatedAt: now, + } + + for n := 0; n < b.N; n++ { + validate.Struct(outer) + } +} + +func BenchmarkStructSimpleSuccess(b *testing.B) { + + type Foo struct { + StringValue string `validate:"min=5,max=10"` + IntValue int `validate:"min=5,max=10"` + } + + validFoo := &Foo{StringValue: "Foobar", IntValue: 7} + + for n := 0; n < b.N; n++ { + validate.Struct(validFoo) + } +} + +func BenchmarkStructSimpleFailure(b *testing.B) { + + type Foo struct { + StringValue string `validate:"min=5,max=10"` + IntValue int `validate:"min=5,max=10"` + } + + invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} + + for n := 0; n < b.N; n++ { + validate.Struct(invalidFoo) + } +} + func BenchmarkStructSimpleSuccessParallel(b *testing.B) { type Foo struct { diff --git a/validator.go b/validator.go index 39f0f6a..3542569 100644 --- a/validator.go +++ b/validator.go @@ -213,6 +213,8 @@ func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string // StructPartial validates the fields passed in only, ignoring all others. // Fields may be provided in a namespaced fashion relative to the struct provided // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name +// NOTE: This is normally not needed, however in some specific cases such as: tied to a +// legacy data structure, it will be useful func (v *Validate) StructPartial(current interface{}, fields ...string) ValidationErrors { sv, _ := v.extractType(reflect.ValueOf(current)) @@ -269,6 +271,8 @@ func (v *Validate) StructPartial(current interface{}, fields ...string) Validati // StructExcept validates all fields except the ones passed in. // Fields may be provided in a namespaced fashion relative to the struct provided // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name +// NOTE: This is normally not needed, however in some specific cases such as: tied to a +// legacy data structure, it will be useful func (v *Validate) StructExcept(current interface{}, fields ...string) ValidationErrors { sv, _ := v.extractType(reflect.ValueOf(current))