From c62550c414c4885e1a6dfc3d93f2a4538b66ae4b Mon Sep 17 00:00:00 2001 From: joeybloggs Date: Fri, 10 Jul 2015 11:31:53 -0400 Subject: [PATCH] Investigating difference speed architectures investigation if goroutines in a consumer producer pattern vs passing a map Spoiler: the map wins out big time! --- benchmarks_test.go | 248 +- examples_test.go | 180 +- old/validator_old.go | 989 ++++++ validator.go | 1038 +------ validator_test.go | 6832 +++++++++++++++++++++--------------------- 5 files changed, 4723 insertions(+), 4564 deletions(-) create mode 100644 old/validator_old.go diff --git a/benchmarks_test.go b/benchmarks_test.go index ee836c2..8f09908 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -2,11 +2,11 @@ package validator import "testing" -func BenchmarkValidateField(b *testing.B) { - for n := 0; n < b.N; n++ { - validate.Field("1", "len=1") - } -} +// func BenchmarkValidateField(b *testing.B) { +// for n := 0; n < b.N; n++ { +// validate.Field("1", "len=1") +// } +// } func BenchmarkValidateStructSimple(b *testing.B) { @@ -42,122 +42,122 @@ func BenchmarkTemplateParallelSimple(b *testing.B) { }) } -func BenchmarkValidateStructLarge(b *testing.B) { - - tFail := &TestString{ - Required: "", - Len: "", - Min: "", - Max: "12345678901", - MinMax: "", - Lt: "0123456789", - Lte: "01234567890", - Gt: "1", - Gte: "1", - OmitEmpty: "12345678901", - Sub: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "", - }, - Iface: &Impl{ - F: "12", - }, - } - - tSuccess := &TestString{ - Required: "Required", - Len: "length==10", - Min: "min=1", - Max: "1234567890", - MinMax: "12345", - Lt: "012345678", - Lte: "0123456789", - Gt: "01234567890", - Gte: "0123456789", - OmitEmpty: "", - Sub: &SubTest{ - Test: "1", - }, - SubIgnore: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "1", - }, - Iface: &Impl{ - F: "123", - }, - } - - for n := 0; n < b.N; n++ { - validate.Struct(tSuccess) - validate.Struct(tFail) - } -} - -func BenchmarkTemplateParallelLarge(b *testing.B) { - - tFail := &TestString{ - Required: "", - Len: "", - Min: "", - Max: "12345678901", - MinMax: "", - Lt: "0123456789", - Lte: "01234567890", - Gt: "1", - Gte: "1", - OmitEmpty: "12345678901", - Sub: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "", - }, - Iface: &Impl{ - F: "12", - }, - } - - tSuccess := &TestString{ - Required: "Required", - Len: "length==10", - Min: "min=1", - Max: "1234567890", - MinMax: "12345", - Lt: "012345678", - Lte: "0123456789", - Gt: "01234567890", - Gte: "0123456789", - OmitEmpty: "", - Sub: &SubTest{ - Test: "1", - }, - SubIgnore: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "1", - }, - Iface: &Impl{ - F: "123", - }, - } - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - validate.Struct(tSuccess) - validate.Struct(tFail) - } - }) -} +// func BenchmarkValidateStructLarge(b *testing.B) { + +// tFail := &TestString{ +// Required: "", +// Len: "", +// Min: "", +// Max: "12345678901", +// MinMax: "", +// Lt: "0123456789", +// Lte: "01234567890", +// Gt: "1", +// Gte: "1", +// OmitEmpty: "12345678901", +// Sub: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "", +// }, +// Iface: &Impl{ +// F: "12", +// }, +// } + +// tSuccess := &TestString{ +// Required: "Required", +// Len: "length==10", +// Min: "min=1", +// Max: "1234567890", +// MinMax: "12345", +// Lt: "012345678", +// Lte: "0123456789", +// Gt: "01234567890", +// Gte: "0123456789", +// OmitEmpty: "", +// Sub: &SubTest{ +// Test: "1", +// }, +// SubIgnore: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "1", +// }, +// Iface: &Impl{ +// F: "123", +// }, +// } + +// for n := 0; n < b.N; n++ { +// validate.Struct(tSuccess) +// validate.Struct(tFail) +// } +// } + +// func BenchmarkTemplateParallelLarge(b *testing.B) { + +// tFail := &TestString{ +// Required: "", +// Len: "", +// Min: "", +// Max: "12345678901", +// MinMax: "", +// Lt: "0123456789", +// Lte: "01234567890", +// Gt: "1", +// Gte: "1", +// OmitEmpty: "12345678901", +// Sub: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "", +// }, +// Iface: &Impl{ +// F: "12", +// }, +// } + +// tSuccess := &TestString{ +// Required: "Required", +// Len: "length==10", +// Min: "min=1", +// Max: "1234567890", +// MinMax: "12345", +// Lt: "012345678", +// Lte: "0123456789", +// Gt: "01234567890", +// Gte: "0123456789", +// OmitEmpty: "", +// Sub: &SubTest{ +// Test: "1", +// }, +// SubIgnore: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "1", +// }, +// Iface: &Impl{ +// F: "123", +// }, +// } + +// b.RunParallel(func(pb *testing.PB) { +// for pb.Next() { +// validate.Struct(tSuccess) +// validate.Struct(tFail) +// } +// }) +// } diff --git a/examples_test.go b/examples_test.go index c5dd351..a2aca52 100644 --- a/examples_test.go +++ b/examples_test.go @@ -1,95 +1,89 @@ package validator_test -import ( - "fmt" - - "../validator" -) - -func ExampleValidate_new() { - validator.New("validate", validator.BakedInValidators) -} - -func ExampleValidate_addFunction() { - // This should be stored somewhere globally - var validate *validator.Validate - - validate = validator.New("validate", validator.BakedInValidators) - - fn := func(top interface{}, current interface{}, field interface{}, param string) bool { - return field.(string) == "hello" - } - - validate.AddFunction("valueishello", fn) - - message := "hello" - err := validate.Field(message, "valueishello") - fmt.Println(err) - //Output: - // -} - -func ExampleValidate_field() { - // This should be stored somewhere globally - var validate *validator.Validate - - validate = validator.New("validate", validator.BakedInValidators) - - i := 0 - err := validate.Field(i, "gt=1,lte=10") - fmt.Println(err.Field) - fmt.Println(err.Tag) - fmt.Println(err.Kind) // NOTE: Kind and Type can be different i.e. time Kind=struct and Type=time.Time - fmt.Println(err.Type) - fmt.Println(err.Param) - fmt.Println(err.Value) - //Output: - // - //gt - //int - //int - //1 - //0 -} - -func ExampleValidate_struct() { - // This should be stored somewhere globally - var validate *validator.Validate - - validate = validator.New("validate", validator.BakedInValidators) - - type ContactInformation struct { - Phone string `validate:"required"` - Street string `validate:"required"` - City string `validate:"required"` - } - - type User struct { - Name string `validate:"required,excludesall=!@#$%^&*()_+-=:;?/0x2C"` // 0x2C = comma (,) - Age int8 `validate:"required,gt=0,lt=150"` - Email string `validate:"email"` - ContactInformation []*ContactInformation - } - - contactInfo := &ContactInformation{ - Street: "26 Here Blvd.", - City: "Paradeso", - } - - user := &User{ - Name: "Joey Bloggs", - Age: 31, - Email: "joeybloggs@gmail.com", - ContactInformation: []*ContactInformation{contactInfo}, - } - - structError := validate.Struct(user) - for _, fieldError := range structError.Errors { - fmt.Println(fieldError.Field) // Phone - fmt.Println(fieldError.Tag) // required - //... and so forth - //Output: - //Phone - //required - } -} +// func ExampleValidate_new() { +// validator.New("validate", validator.BakedInValidators) +// } + +// func ExampleValidate_addFunction() { +// // This should be stored somewhere globally +// var validate *validator.Validate + +// validate = validator.New("validate", validator.BakedInValidators) + +// fn := func(top interface{}, current interface{}, field interface{}, param string) bool { +// return field.(string) == "hello" +// } + +// validate.AddFunction("valueishello", fn) + +// message := "hello" +// err := validate.Field(message, "valueishello") +// fmt.Println(err) +// //Output: +// // +// } + +// func ExampleValidate_field() { +// // This should be stored somewhere globally +// var validate *validator.Validate + +// validate = validator.New("validate", validator.BakedInValidators) + +// i := 0 +// err := validate.Field(i, "gt=1,lte=10") +// fmt.Println(err.Field) +// fmt.Println(err.Tag) +// fmt.Println(err.Kind) // NOTE: Kind and Type can be different i.e. time Kind=struct and Type=time.Time +// fmt.Println(err.Type) +// fmt.Println(err.Param) +// fmt.Println(err.Value) +// //Output: +// // +// //gt +// //int +// //int +// //1 +// //0 +// } + +// func ExampleValidate_struct() { +// // This should be stored somewhere globally +// var validate *validator.Validate + +// validate = validator.New("validate", validator.BakedInValidators) + +// type ContactInformation struct { +// Phone string `validate:"required"` +// Street string `validate:"required"` +// City string `validate:"required"` +// } + +// type User struct { +// Name string `validate:"required,excludesall=!@#$%^&*()_+-=:;?/0x2C"` // 0x2C = comma (,) +// Age int8 `validate:"required,gt=0,lt=150"` +// Email string `validate:"email"` +// ContactInformation []*ContactInformation +// } + +// contactInfo := &ContactInformation{ +// Street: "26 Here Blvd.", +// City: "Paradeso", +// } + +// user := &User{ +// Name: "Joey Bloggs", +// Age: 31, +// Email: "joeybloggs@gmail.com", +// ContactInformation: []*ContactInformation{contactInfo}, +// } + +// structError := validate.Struct(user) +// for _, fieldError := range structError.Errors { +// fmt.Println(fieldError.Field) // Phone +// fmt.Println(fieldError.Tag) // required +// //... and so forth +// //Output: +// //Phone +// //required +// } +// } diff --git a/old/validator_old.go b/old/validator_old.go new file mode 100644 index 0000000..ccd2a55 --- /dev/null +++ b/old/validator_old.go @@ -0,0 +1,989 @@ +/** + * Package validator + * + * MISC: + * - anonymous structs - they don't have names so expect the Struct name within StructErrors to be blank + * + */ + +package validator + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "strings" + "sync" + "time" + "unicode" +) + +const ( + utf8HexComma = "0x2C" + tagSeparator = "," + orSeparator = "|" + noValidationTag = "-" + tagKeySeparator = "=" + structOnlyTag = "structonly" + omitempty = "omitempty" + required = "required" + fieldErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag" + sliceErrMsg = "Field validation for \"%s\" failed at index \"%d\" with error(s): %s" + mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s" + structErrMsg = "Struct:%s\n" + diveTag = "dive" + arrayIndexFieldName = "%s[%d]" + mapIndexFieldName = "%s[%v]" +) + +var structPool *sync.Pool + +// returns new *StructErrors to the pool +func newStructErrors() interface{} { + return &StructErrors{ + Errors: map[string]*FieldError{}, + StructErrors: map[string]*StructErrors{}, + } +} + +type cachedTags struct { + keyVals [][]string + isOrVal bool +} + +type cachedField struct { + index int + name string + tags []*cachedTags + tag string + kind reflect.Kind + typ reflect.Type + isTime bool + isSliceOrArray bool + isMap bool + isTimeSubtype bool + sliceSubtype reflect.Type + mapSubtype reflect.Type + sliceSubKind reflect.Kind + mapSubKind reflect.Kind + dive bool + diveTag string +} + +type cachedStruct struct { + children int + name string + kind reflect.Kind + fields []*cachedField +} + +type structsCacheMap struct { + lock sync.RWMutex + m map[reflect.Type]*cachedStruct +} + +func (s *structsCacheMap) Get(key reflect.Type) (*cachedStruct, bool) { + s.lock.RLock() + defer s.lock.RUnlock() + value, ok := s.m[key] + return value, ok +} + +func (s *structsCacheMap) Set(key reflect.Type, value *cachedStruct) { + s.lock.Lock() + defer s.lock.Unlock() + s.m[key] = value +} + +var structCache = &structsCacheMap{m: map[reflect.Type]*cachedStruct{}} + +type fieldsCacheMap struct { + lock sync.RWMutex + m map[string][]*cachedTags +} + +func (s *fieldsCacheMap) Get(key string) ([]*cachedTags, bool) { + s.lock.RLock() + defer s.lock.RUnlock() + value, ok := s.m[key] + return value, ok +} + +func (s *fieldsCacheMap) Set(key string, value []*cachedTags) { + s.lock.Lock() + defer s.lock.Unlock() + s.m[key] = value +} + +var fieldsCache = &fieldsCacheMap{m: map[string][]*cachedTags{}} + +// FieldError contains a single field's validation error along +// with other properties that may be needed for error message creation +type FieldError struct { + Field string + Tag string + Kind reflect.Kind + Type reflect.Type + Param string + Value interface{} + IsPlaceholderErr bool + IsSliceOrArray bool + IsMap bool + SliceOrArrayErrs map[int]error // counld be FieldError, StructErrors + MapErrs map[interface{}]error // counld be FieldError, StructErrors +} + +// This is intended for use in development + debugging and not intended to be a production error message. +// it also allows FieldError to be used as an Error interface +func (e *FieldError) Error() string { + + if e.IsPlaceholderErr { + + buff := bytes.NewBufferString("") + + if e.IsSliceOrArray { + + for j, err := range e.SliceOrArrayErrs { + buff.WriteString("\n") + buff.WriteString(fmt.Sprintf(sliceErrMsg, e.Field, j, "\n"+err.Error())) + } + + } else if e.IsMap { + + for key, err := range e.MapErrs { + buff.WriteString(fmt.Sprintf(mapErrMsg, e.Field, key, "\n"+err.Error())) + } + } + + return strings.TrimSpace(buff.String()) + } + + return fmt.Sprintf(fieldErrMsg, e.Field, e.Tag) +} + +// Flatten flattens the FieldError hierarchical structure into a flat namespace style field name +// for those that want/need it. +// This is now needed because of the new dive functionality +func (e *FieldError) Flatten() map[string]*FieldError { + + errs := map[string]*FieldError{} + + if e.IsPlaceholderErr { + + if e.IsSliceOrArray { + for key, err := range e.SliceOrArrayErrs { + + fe, ok := err.(*FieldError) + + if ok { + + if flat := fe.Flatten(); flat != nil && len(flat) > 0 { + for k, v := range flat { + if fe.IsPlaceholderErr { + errs[fmt.Sprintf("[%#v]%s", key, k)] = v + } else { + errs[fmt.Sprintf("[%#v]", key)] = v + } + + } + } + } else { + + se := err.(*StructErrors) + + if flat := se.Flatten(); flat != nil && len(flat) > 0 { + for k, v := range flat { + errs[fmt.Sprintf("[%#v].%s.%s", key, se.Struct, k)] = v + } + } + } + } + } + + if e.IsMap { + for key, err := range e.MapErrs { + + fe, ok := err.(*FieldError) + + if ok { + + if flat := fe.Flatten(); flat != nil && len(flat) > 0 { + for k, v := range flat { + if fe.IsPlaceholderErr { + errs[fmt.Sprintf("[%#v]%s", key, k)] = v + } else { + errs[fmt.Sprintf("[%#v]", key)] = v + } + } + } + } else { + + se := err.(*StructErrors) + + if flat := se.Flatten(); flat != nil && len(flat) > 0 { + for k, v := range flat { + errs[fmt.Sprintf("[%#v].%s.%s", key, se.Struct, k)] = v + } + } + } + } + } + + return errs + } + + errs[e.Field] = e + + return errs +} + +// StructErrors is hierarchical list of field and struct validation errors +// for a non hierarchical representation please see the Flatten method for StructErrors +type StructErrors struct { + // Name of the Struct + Struct string + // Struct Field Errors + Errors map[string]*FieldError + // Struct Fields of type struct and their errors + // key = Field Name of current struct, but internally Struct will be the actual struct name unless anonymous struct, it will be blank + StructErrors map[string]*StructErrors +} + +// This is intended for use in development + debugging and not intended to be a production error message. +// it also allows StructErrors to be used as an Error interface +func (e *StructErrors) Error() string { + buff := bytes.NewBufferString(fmt.Sprintf(structErrMsg, e.Struct)) + + for _, err := range e.Errors { + buff.WriteString(err.Error()) + buff.WriteString("\n") + } + + for _, err := range e.StructErrors { + buff.WriteString(err.Error()) + } + + return strings.TrimSpace(buff.String()) +} + +// Flatten flattens the StructErrors hierarchical structure into a flat namespace style field name +// for those that want/need it +func (e *StructErrors) Flatten() map[string]*FieldError { + + if e == nil { + return nil + } + + errs := map[string]*FieldError{} + + for _, f := range e.Errors { + + if flat := f.Flatten(); flat != nil && len(flat) > 0 { + + for k, fe := range flat { + + if f.IsPlaceholderErr { + errs[f.Field+k] = fe + } else { + errs[k] = fe + } + } + } + } + + for key, val := range e.StructErrors { + + otherErrs := val.Flatten() + + for _, f2 := range otherErrs { + + f2.Field = fmt.Sprintf("%s.%s", key, f2.Field) + errs[f2.Field] = f2 + } + } + + return errs +} + +// Func accepts all values needed for file and cross field validation +// top = top level struct when validating by struct otherwise nil +// current = current level struct when validating by struct otherwise optional comparison value +// f = field value for validation +// param = parameter used in validation i.e. gt=0 param would be 0 +type Func func(top interface{}, current interface{}, f interface{}, param string) bool + +// Validate implements the Validate Struct +// NOTE: Fields within are not thread safe and that is on purpose +// Functions and Tags should all be predifined before use, so subscribe to the philosiphy +// or make it thread safe on your end +type Validate struct { + // tagName being used. + tagName string + // validateFuncs is a map of validation functions and the tag keys + validationFuncs map[string]Func +} + +// New creates a new Validate instance for use. +func New(tagName string, funcs map[string]Func) *Validate { + + structPool = &sync.Pool{New: newStructErrors} + + return &Validate{ + tagName: tagName, + validationFuncs: funcs, + } +} + +// SetTag sets tagName of the Validator to one of your choosing after creation +// perhaps to dodge a tag name conflict in a specific section of code +// NOTE: this method is not thread-safe +func (v *Validate) SetTag(tagName string) { + v.tagName = tagName +} + +// SetMaxStructPoolSize sets the struct pools max size. this may be usefull for fine grained +// performance tuning towards your application, however, the default should be fine for +// nearly all cases. only increase if you have a deeply nested struct structure. +// NOTE: this method is not thread-safe +// NOTE: this is only here to keep compatibility with v5, in v6 the method will be removed +func (v *Validate) SetMaxStructPoolSize(max int) { + structPool = &sync.Pool{New: newStructErrors} +} + +// AddFunction adds a validation Func to a Validate's map of validators denoted by the key +// NOTE: if the key already exists, it will get replaced. +// NOTE: this method is not thread-safe +func (v *Validate) AddFunction(key string, f Func) error { + + if len(key) == 0 { + return errors.New("Function Key cannot be empty") + } + + if f == nil { + return errors.New("Function cannot be empty") + } + + v.validationFuncs[key] = f + + return nil +} + +// Struct validates a struct, even it's nested structs, and returns a struct containing the errors +// NOTE: Nested Arrays, or Maps of structs do not get validated only the Array or Map itself; the reason is that there is no good +// way to represent or report which struct within the array has the error, besides can validate the struct prior to adding it to +// the Array or Map. +func (v *Validate) Struct(s interface{}) *StructErrors { + + return v.structRecursive(s, s, s) +} + +// structRecursive validates a struct recursivly and passes the top level and current struct around for use in validator functions and returns a struct containing the errors +func (v *Validate) structRecursive(top interface{}, current interface{}, s interface{}) *StructErrors { + + structValue := reflect.ValueOf(s) + + if structValue.Kind() == reflect.Ptr && !structValue.IsNil() { + return v.structRecursive(top, current, structValue.Elem().Interface()) + } + + if structValue.Kind() != reflect.Struct && structValue.Kind() != reflect.Interface { + panic("interface passed for validation is not a struct") + } + + structType := reflect.TypeOf(s) + + var structName string + var numFields int + var cs *cachedStruct + var isCached bool + + cs, isCached = structCache.Get(structType) + + if isCached { + structName = cs.name + numFields = cs.children + } else { + structName = structType.Name() + numFields = structValue.NumField() + cs = &cachedStruct{name: structName, children: numFields} + } + + validationErrors := structPool.Get().(*StructErrors) + validationErrors.Struct = structName + + for i := 0; i < numFields; i++ { + + var valueField reflect.Value + var cField *cachedField + var typeField reflect.StructField + + if isCached { + cField = cs.fields[i] + valueField = structValue.Field(cField.index) + + if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { + valueField = valueField.Elem() + } + } else { + valueField = structValue.Field(i) + + if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { + valueField = valueField.Elem() + } + + typeField = structType.Field(i) + + cField = &cachedField{index: i, tag: typeField.Tag.Get(v.tagName), isTime: (valueField.Type() == reflect.TypeOf(time.Time{}) || valueField.Type() == reflect.TypeOf(&time.Time{}))} + + if cField.tag == noValidationTag { + cs.children-- + continue + } + + // if no validation and not a struct (which may containt fields for validation) + if cField.tag == "" && ((valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface) || valueField.Type() == reflect.TypeOf(time.Time{})) { + cs.children-- + continue + } + + cField.name = typeField.Name + cField.kind = valueField.Kind() + cField.typ = valueField.Type() + } + + // this can happen if the first cache value was nil + // but the second actually has a value + if cField.kind == reflect.Ptr { + cField.kind = valueField.Kind() + } + + switch cField.kind { + + case reflect.Struct, reflect.Interface: + + if !unicode.IsUpper(rune(cField.name[0])) { + cs.children-- + continue + } + + if cField.isTime { + + if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { + validationErrors.Errors[fieldError.Field] = fieldError + // free up memory reference + fieldError = nil + } + + } else { + + if strings.Contains(cField.tag, structOnlyTag) { + cs.children-- + continue + } + + if (valueField.Kind() == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() { + + if strings.Contains(cField.tag, omitempty) { + goto CACHEFIELD + } + + tags := strings.Split(cField.tag, tagSeparator) + + if len(tags) > 0 { + + var param string + vals := strings.SplitN(tags[0], tagKeySeparator, 2) + + if len(vals) > 1 { + param = vals[1] + } + + validationErrors.Errors[cField.name] = &FieldError{ + Field: cField.name, + Tag: vals[0], + Param: param, + Value: valueField.Interface(), + Kind: valueField.Kind(), + Type: valueField.Type(), + } + + goto CACHEFIELD + } + } + + // if we get here, the field is interface and could be a struct or a field + // and we need to check the inner type and validate + if cField.kind == reflect.Interface { + + valueField = valueField.Elem() + + if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { + valueField = valueField.Elem() + } + + if valueField.Kind() == reflect.Struct { + goto VALIDATESTRUCT + } + + // sending nil for cField as it was type interface and could be anything + // each time and so must be calculated each time and can't be cached reliably + if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, nil); fieldError != nil { + validationErrors.Errors[fieldError.Field] = fieldError + // free up memory reference + fieldError = nil + } + + goto CACHEFIELD + } + + VALIDATESTRUCT: + if structErrors := v.structRecursive(top, valueField.Interface(), valueField.Interface()); structErrors != nil { + validationErrors.StructErrors[cField.name] = structErrors + // free up memory map no longer needed + structErrors = nil + } + } + + case reflect.Slice, reflect.Array: + cField.isSliceOrArray = true + cField.sliceSubtype = cField.typ.Elem() + cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{})) + cField.sliceSubKind = cField.sliceSubtype.Kind() + + if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { + validationErrors.Errors[fieldError.Field] = fieldError + // free up memory reference + fieldError = nil + } + + case reflect.Map: + cField.isMap = true + cField.mapSubtype = cField.typ.Elem() + cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{})) + cField.mapSubKind = cField.mapSubtype.Kind() + + if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { + validationErrors.Errors[fieldError.Field] = fieldError + // free up memory reference + fieldError = nil + } + + default: + if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { + validationErrors.Errors[fieldError.Field] = fieldError + // free up memory reference + fieldError = nil + } + } + + CACHEFIELD: + if !isCached { + cs.fields = append(cs.fields, cField) + } + } + + structCache.Set(structType, cs) + + if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 { + structPool.Put(validationErrors) + return nil + } + + return validationErrors +} + +// Field allows validation of a single field, still using tag style validation to check multiple errors +func (v *Validate) Field(f interface{}, tag string) *FieldError { + return v.FieldWithValue(nil, f, tag) +} + +// FieldWithValue allows validation of a single field, possibly even against another fields value, still using tag style validation to check multiple errors +func (v *Validate) FieldWithValue(val interface{}, f interface{}, tag string) *FieldError { + return v.fieldWithNameAndValue(nil, val, f, tag, "", true, nil) +} + +func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f interface{}, tag string, name string, isSingleField bool, cacheField *cachedField) *FieldError { + + var cField *cachedField + var isCached bool + var valueField reflect.Value + + // This is a double check if coming from validate.Struct but need to be here in case function is called directly + if tag == noValidationTag || tag == "" { + return nil + } + + if strings.Contains(tag, omitempty) && !hasValue(val, current, f, "") { + return nil + } + + valueField = reflect.ValueOf(f) + + if cacheField == nil { + + if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { + valueField = valueField.Elem() + f = valueField.Interface() + } + + cField = &cachedField{name: name, kind: valueField.Kind(), tag: tag, typ: valueField.Type()} + + switch cField.kind { + case reflect.Slice, reflect.Array: + isSingleField = false // cached tags mean nothing because it will be split up while diving + cField.isSliceOrArray = true + cField.sliceSubtype = cField.typ.Elem() + cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{})) + cField.sliceSubKind = cField.sliceSubtype.Kind() + case reflect.Map: + isSingleField = false // cached tags mean nothing because it will be split up while diving + cField.isMap = true + cField.mapSubtype = cField.typ.Elem() + cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{})) + cField.mapSubKind = cField.mapSubtype.Kind() + } + } else { + cField = cacheField + } + + switch cField.kind { + + case reflect.Struct, reflect.Interface, reflect.Invalid: + + if cField.typ != reflect.TypeOf(time.Time{}) { + panic("Invalid field passed to fieldWithNameAndValue") + } + } + + if len(cField.tags) == 0 { + + if isSingleField { + cField.tags, isCached = fieldsCache.Get(tag) + } + + if !isCached { + + for _, t := range strings.Split(tag, tagSeparator) { + + if t == diveTag { + + cField.dive = true + cField.diveTag = strings.TrimLeft(strings.SplitN(tag, diveTag, 2)[1], ",") + break + } + + orVals := strings.Split(t, orSeparator) + cTag := &cachedTags{isOrVal: len(orVals) > 1, keyVals: make([][]string, len(orVals))} + cField.tags = append(cField.tags, cTag) + + for i, val := range orVals { + vals := strings.SplitN(val, tagKeySeparator, 2) + + key := strings.TrimSpace(vals[0]) + + if len(key) == 0 { + panic(fmt.Sprintf("Invalid validation tag on field %s", name)) + } + + param := "" + if len(vals) > 1 { + param = strings.Replace(vals[1], utf8HexComma, ",", -1) + } + + cTag.keyVals[i] = []string{key, param} + } + } + + if isSingleField { + fieldsCache.Set(cField.tag, cField.tags) + } + } + } + + var fieldErr *FieldError + var err error + + for _, cTag := range cField.tags { + + if cTag.isOrVal { + + errTag := "" + + for _, val := range cTag.keyVals { + + fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, val[0], val[1], name) + + if err == nil { + return nil + } + + errTag += orSeparator + fieldErr.Tag + } + + errTag = strings.TrimLeft(errTag, orSeparator) + + fieldErr.Tag = errTag + fieldErr.Kind = cField.kind + fieldErr.Type = cField.typ + + return fieldErr + } + + if fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, cTag.keyVals[0][0], cTag.keyVals[0][1], name); err != nil { + + fieldErr.Kind = cField.kind + fieldErr.Type = cField.typ + + return fieldErr + } + } + + if cField.dive { + + if cField.isSliceOrArray { + + if errs := v.traverseSliceOrArray(val, current, valueField, cField); errs != nil && len(errs) > 0 { + + return &FieldError{ + Field: cField.name, + Kind: cField.kind, + Type: cField.typ, + Value: f, + IsPlaceholderErr: true, + IsSliceOrArray: true, + SliceOrArrayErrs: errs, + } + } + + } else if cField.isMap { + if errs := v.traverseMap(val, current, valueField, cField); errs != nil && len(errs) > 0 { + + return &FieldError{ + Field: cField.name, + Kind: cField.kind, + Type: cField.typ, + Value: f, + IsPlaceholderErr: true, + IsMap: true, + MapErrs: errs, + } + } + } else { + // throw error, if not a slice or map then should not have gotten here + panic("dive error! can't dive on a non slice or map") + } + } + + return nil +} + +func (v *Validate) traverseMap(val interface{}, current interface{}, valueField reflect.Value, cField *cachedField) map[interface{}]error { + + errs := map[interface{}]error{} + + for _, key := range valueField.MapKeys() { + + idxField := valueField.MapIndex(key) + + if cField.mapSubKind == reflect.Ptr && !idxField.IsNil() { + idxField = idxField.Elem() + cField.mapSubKind = idxField.Kind() + } + + switch cField.mapSubKind { + case reflect.Struct, reflect.Interface: + + if cField.isTimeSubtype { + + if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), false, nil); fieldError != nil { + errs[key.Interface()] = fieldError + } + + continue + } + + if (idxField.Kind() == reflect.Ptr || idxField.Kind() == reflect.Interface) && idxField.IsNil() { + + if strings.Contains(cField.diveTag, omitempty) { + continue + } + + tags := strings.Split(cField.diveTag, tagSeparator) + + if len(tags) > 0 { + + var param string + vals := strings.SplitN(tags[0], tagKeySeparator, 2) + + if len(vals) > 1 { + param = vals[1] + } + + errs[key.Interface()] = &FieldError{ + Field: fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), + Tag: vals[0], + Param: param, + Value: idxField.Interface(), + Kind: idxField.Kind(), + Type: cField.mapSubtype, + } + } + + continue + } + + // if we get here, the field is interface and could be a struct or a field + // and we need to check the inner type and validate + if idxField.Kind() == reflect.Interface { + + idxField = idxField.Elem() + + if idxField.Kind() == reflect.Ptr && !idxField.IsNil() { + idxField = idxField.Elem() + } + + if idxField.Kind() == reflect.Struct { + goto VALIDATESTRUCT + } + + // sending nil for cField as it was type interface and could be anything + // each time and so must be calculated each time and can't be cached reliably + if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), false, nil); fieldError != nil { + errs[key.Interface()] = fieldError + } + + continue + } + + VALIDATESTRUCT: + if structErrors := v.structRecursive(val, current, idxField.Interface()); structErrors != nil { + errs[key.Interface()] = structErrors + } + + default: + if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), false, nil); fieldError != nil { + errs[key.Interface()] = fieldError + } + } + } + + return errs +} + +func (v *Validate) traverseSliceOrArray(val interface{}, current interface{}, valueField reflect.Value, cField *cachedField) map[int]error { + + errs := map[int]error{} + + for i := 0; i < valueField.Len(); i++ { + + idxField := valueField.Index(i) + + if cField.sliceSubKind == reflect.Ptr && !idxField.IsNil() { + idxField = idxField.Elem() + cField.sliceSubKind = idxField.Kind() + } + + switch cField.sliceSubKind { + case reflect.Struct, reflect.Interface: + + if cField.isTimeSubtype { + + if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(arrayIndexFieldName, cField.name, i), false, nil); fieldError != nil { + errs[i] = fieldError + } + + continue + } + + if (idxField.Kind() == reflect.Ptr || idxField.Kind() == reflect.Interface) && idxField.IsNil() { + + if strings.Contains(cField.diveTag, omitempty) { + continue + } + + tags := strings.Split(cField.diveTag, tagSeparator) + + if len(tags) > 0 { + + var param string + vals := strings.SplitN(tags[0], tagKeySeparator, 2) + + if len(vals) > 1 { + param = vals[1] + } + + errs[i] = &FieldError{ + Field: fmt.Sprintf(arrayIndexFieldName, cField.name, i), + Tag: vals[0], + Param: param, + Value: idxField.Interface(), + Kind: idxField.Kind(), + Type: cField.sliceSubtype, + } + } + + continue + } + + // if we get here, the field is interface and could be a struct or a field + // and we need to check the inner type and validate + if idxField.Kind() == reflect.Interface { + + idxField = idxField.Elem() + + if idxField.Kind() == reflect.Ptr && !idxField.IsNil() { + idxField = idxField.Elem() + } + + if idxField.Kind() == reflect.Struct { + goto VALIDATESTRUCT + } + + // sending nil for cField as it was type interface and could be anything + // each time and so must be calculated each time and can't be cached reliably + if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(arrayIndexFieldName, cField.name, i), false, nil); fieldError != nil { + errs[i] = fieldError + } + + continue + } + + VALIDATESTRUCT: + if structErrors := v.structRecursive(val, current, idxField.Interface()); structErrors != nil { + errs[i] = structErrors + } + + default: + if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(arrayIndexFieldName, cField.name, i), false, nil); fieldError != nil { + errs[i] = fieldError + } + } + } + + return errs +} + +func (v *Validate) fieldWithNameAndSingleTag(val interface{}, current interface{}, f interface{}, key string, param string, name string) (*FieldError, error) { + + // OK to continue because we checked it's existance before getting into this loop + if key == omitempty { + return nil, nil + } + + valFunc, ok := v.validationFuncs[key] + if !ok { + panic(fmt.Sprintf("Undefined validation function on field %s", name)) + } + + if err := valFunc(val, current, f, param); err { + return nil, nil + } + + return &FieldError{ + Field: name, + Tag: key, + Value: f, + Param: param, + }, errors.New(key) +} diff --git a/validator.go b/validator.go index ccd2a55..1607d28 100644 --- a/validator.go +++ b/validator.go @@ -8,302 +8,19 @@ package validator -import ( - "bytes" - "errors" - "fmt" - "reflect" - "strings" - "sync" - "time" - "unicode" -) - -const ( - utf8HexComma = "0x2C" - tagSeparator = "," - orSeparator = "|" - noValidationTag = "-" - tagKeySeparator = "=" - structOnlyTag = "structonly" - omitempty = "omitempty" - required = "required" - fieldErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag" - sliceErrMsg = "Field validation for \"%s\" failed at index \"%d\" with error(s): %s" - mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s" - structErrMsg = "Struct:%s\n" - diveTag = "dive" - arrayIndexFieldName = "%s[%d]" - mapIndexFieldName = "%s[%v]" -) - -var structPool *sync.Pool - -// returns new *StructErrors to the pool -func newStructErrors() interface{} { - return &StructErrors{ - Errors: map[string]*FieldError{}, - StructErrors: map[string]*StructErrors{}, - } -} - -type cachedTags struct { - keyVals [][]string - isOrVal bool -} - -type cachedField struct { - index int - name string - tags []*cachedTags - tag string - kind reflect.Kind - typ reflect.Type - isTime bool - isSliceOrArray bool - isMap bool - isTimeSubtype bool - sliceSubtype reflect.Type - mapSubtype reflect.Type - sliceSubKind reflect.Kind - mapSubKind reflect.Kind - dive bool - diveTag string -} - -type cachedStruct struct { - children int - name string - kind reflect.Kind - fields []*cachedField -} - -type structsCacheMap struct { - lock sync.RWMutex - m map[reflect.Type]*cachedStruct -} - -func (s *structsCacheMap) Get(key reflect.Type) (*cachedStruct, bool) { - s.lock.RLock() - defer s.lock.RUnlock() - value, ok := s.m[key] - return value, ok -} - -func (s *structsCacheMap) Set(key reflect.Type, value *cachedStruct) { - s.lock.Lock() - defer s.lock.Unlock() - s.m[key] = value -} - -var structCache = &structsCacheMap{m: map[reflect.Type]*cachedStruct{}} - -type fieldsCacheMap struct { - lock sync.RWMutex - m map[string][]*cachedTags -} - -func (s *fieldsCacheMap) Get(key string) ([]*cachedTags, bool) { - s.lock.RLock() - defer s.lock.RUnlock() - value, ok := s.m[key] - return value, ok -} - -func (s *fieldsCacheMap) Set(key string, value []*cachedTags) { - s.lock.Lock() - defer s.lock.Unlock() - s.m[key] = value -} - -var fieldsCache = &fieldsCacheMap{m: map[string][]*cachedTags{}} - -// FieldError contains a single field's validation error along -// with other properties that may be needed for error message creation -type FieldError struct { - Field string - Tag string - Kind reflect.Kind - Type reflect.Type - Param string - Value interface{} - IsPlaceholderErr bool - IsSliceOrArray bool - IsMap bool - SliceOrArrayErrs map[int]error // counld be FieldError, StructErrors - MapErrs map[interface{}]error // counld be FieldError, StructErrors -} - -// This is intended for use in development + debugging and not intended to be a production error message. -// it also allows FieldError to be used as an Error interface -func (e *FieldError) Error() string { - - if e.IsPlaceholderErr { - - buff := bytes.NewBufferString("") - - if e.IsSliceOrArray { - - for j, err := range e.SliceOrArrayErrs { - buff.WriteString("\n") - buff.WriteString(fmt.Sprintf(sliceErrMsg, e.Field, j, "\n"+err.Error())) - } - - } else if e.IsMap { - - for key, err := range e.MapErrs { - buff.WriteString(fmt.Sprintf(mapErrMsg, e.Field, key, "\n"+err.Error())) - } - } - - return strings.TrimSpace(buff.String()) - } - - return fmt.Sprintf(fieldErrMsg, e.Field, e.Tag) -} - -// Flatten flattens the FieldError hierarchical structure into a flat namespace style field name -// for those that want/need it. -// This is now needed because of the new dive functionality -func (e *FieldError) Flatten() map[string]*FieldError { - - errs := map[string]*FieldError{} - - if e.IsPlaceholderErr { - - if e.IsSliceOrArray { - for key, err := range e.SliceOrArrayErrs { - - fe, ok := err.(*FieldError) - - if ok { - - if flat := fe.Flatten(); flat != nil && len(flat) > 0 { - for k, v := range flat { - if fe.IsPlaceholderErr { - errs[fmt.Sprintf("[%#v]%s", key, k)] = v - } else { - errs[fmt.Sprintf("[%#v]", key)] = v - } - - } - } - } else { - - se := err.(*StructErrors) - - if flat := se.Flatten(); flat != nil && len(flat) > 0 { - for k, v := range flat { - errs[fmt.Sprintf("[%#v].%s.%s", key, se.Struct, k)] = v - } - } - } - } - } - - if e.IsMap { - for key, err := range e.MapErrs { - - fe, ok := err.(*FieldError) - - if ok { - - if flat := fe.Flatten(); flat != nil && len(flat) > 0 { - for k, v := range flat { - if fe.IsPlaceholderErr { - errs[fmt.Sprintf("[%#v]%s", key, k)] = v - } else { - errs[fmt.Sprintf("[%#v]", key)] = v - } - } - } - } else { - - se := err.(*StructErrors) - - if flat := se.Flatten(); flat != nil && len(flat) > 0 { - for k, v := range flat { - errs[fmt.Sprintf("[%#v].%s.%s", key, se.Struct, k)] = v - } - } - } - } - } - - return errs - } - - errs[e.Field] = e - - return errs -} - -// StructErrors is hierarchical list of field and struct validation errors -// for a non hierarchical representation please see the Flatten method for StructErrors -type StructErrors struct { - // Name of the Struct - Struct string - // Struct Field Errors - Errors map[string]*FieldError - // Struct Fields of type struct and their errors - // key = Field Name of current struct, but internally Struct will be the actual struct name unless anonymous struct, it will be blank - StructErrors map[string]*StructErrors -} - -// This is intended for use in development + debugging and not intended to be a production error message. -// it also allows StructErrors to be used as an Error interface -func (e *StructErrors) Error() string { - buff := bytes.NewBufferString(fmt.Sprintf(structErrMsg, e.Struct)) - - for _, err := range e.Errors { - buff.WriteString(err.Error()) - buff.WriteString("\n") - } - - for _, err := range e.StructErrors { - buff.WriteString(err.Error()) - } - - return strings.TrimSpace(buff.String()) +// Validate implements the Validate Struct +// NOTE: Fields within are not thread safe and that is on purpose +// Functions and Tags should all be predifined before use, so subscribe to the philosiphy +// or make it thread safe on your end +type Validate struct { + config Config } -// Flatten flattens the StructErrors hierarchical structure into a flat namespace style field name -// for those that want/need it -func (e *StructErrors) Flatten() map[string]*FieldError { - - if e == nil { - return nil - } - - errs := map[string]*FieldError{} - - for _, f := range e.Errors { - - if flat := f.Flatten(); flat != nil && len(flat) > 0 { - - for k, fe := range flat { - - if f.IsPlaceholderErr { - errs[f.Field+k] = fe - } else { - errs[k] = fe - } - } - } - } - - for key, val := range e.StructErrors { - - otherErrs := val.Flatten() - - for _, f2 := range otherErrs { - - f2.Field = fmt.Sprintf("%s.%s", key, f2.Field) - errs[f2.Field] = f2 - } - } - - return errs +// Config contains the options that Validator with use +// passed to the New function +type Config struct { + TagName string + ValidationFuncs map[string]Func } // Func accepts all values needed for file and cross field validation @@ -313,677 +30,124 @@ func (e *StructErrors) Flatten() map[string]*FieldError { // param = parameter used in validation i.e. gt=0 param would be 0 type Func func(top interface{}, current interface{}, f interface{}, param string) bool -// Validate implements the Validate Struct -// NOTE: Fields within are not thread safe and that is on purpose -// Functions and Tags should all be predifined before use, so subscribe to the philosiphy -// or make it thread safe on your end -type Validate struct { - // tagName being used. - tagName string - // validateFuncs is a map of validation functions and the tag keys - validationFuncs map[string]Func +// FieldError contains a single field's validation error along +// with other properties that may be needed for error message creation +type FieldError struct { + Field string + // Tag string + // Kind reflect.Kind + // Type reflect.Type + // Param string + // Value interface{} + // IsPlaceholderErr bool + // IsSliceOrArray bool + // IsMap bool + // SliceOrArrayErrs map[int]error // counld be FieldError, StructErrors + // MapErrs map[interface{}]error // counld be FieldError, StructErrors } // New creates a new Validate instance for use. -func New(tagName string, funcs map[string]Func) *Validate { - - structPool = &sync.Pool{New: newStructErrors} - - return &Validate{ - tagName: tagName, - validationFuncs: funcs, - } -} +func New(config Config) *Validate { -// SetTag sets tagName of the Validator to one of your choosing after creation -// perhaps to dodge a tag name conflict in a specific section of code -// NOTE: this method is not thread-safe -func (v *Validate) SetTag(tagName string) { - v.tagName = tagName -} - -// SetMaxStructPoolSize sets the struct pools max size. this may be usefull for fine grained -// performance tuning towards your application, however, the default should be fine for -// nearly all cases. only increase if you have a deeply nested struct structure. -// NOTE: this method is not thread-safe -// NOTE: this is only here to keep compatibility with v5, in v6 the method will be removed -func (v *Validate) SetMaxStructPoolSize(max int) { - structPool = &sync.Pool{New: newStructErrors} -} - -// AddFunction adds a validation Func to a Validate's map of validators denoted by the key -// NOTE: if the key already exists, it will get replaced. -// NOTE: this method is not thread-safe -func (v *Validate) AddFunction(key string, f Func) error { - - if len(key) == 0 { - return errors.New("Function Key cannot be empty") - } - - if f == nil { - return errors.New("Function cannot be empty") - } - - v.validationFuncs[key] = f + // structPool = &sync.Pool{New: newStructErrors} - return nil + return &Validate{config: config} } // Struct validates a struct, even it's nested structs, and returns a struct containing the errors // NOTE: Nested Arrays, or Maps of structs do not get validated only the Array or Map itself; the reason is that there is no good // way to represent or report which struct within the array has the error, besides can validate the struct prior to adding it to // the Array or Map. -func (v *Validate) Struct(s interface{}) *StructErrors { - - return v.structRecursive(s, s, s) -} - -// structRecursive validates a struct recursivly and passes the top level and current struct around for use in validator functions and returns a struct containing the errors -func (v *Validate) structRecursive(top interface{}, current interface{}, s interface{}) *StructErrors { - - structValue := reflect.ValueOf(s) - - if structValue.Kind() == reflect.Ptr && !structValue.IsNil() { - return v.structRecursive(top, current, structValue.Elem().Interface()) - } - - if structValue.Kind() != reflect.Struct && structValue.Kind() != reflect.Interface { - panic("interface passed for validation is not a struct") - } - - structType := reflect.TypeOf(s) - - var structName string - var numFields int - var cs *cachedStruct - var isCached bool - - cs, isCached = structCache.Get(structType) - - if isCached { - structName = cs.name - numFields = cs.children - } else { - structName = structType.Name() - numFields = structValue.NumField() - cs = &cachedStruct{name: structName, children: numFields} - } - - validationErrors := structPool.Get().(*StructErrors) - validationErrors.Struct = structName - - for i := 0; i < numFields; i++ { - - var valueField reflect.Value - var cField *cachedField - var typeField reflect.StructField - - if isCached { - cField = cs.fields[i] - valueField = structValue.Field(cField.index) - - if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { - valueField = valueField.Elem() - } - } else { - valueField = structValue.Field(i) - - if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { - valueField = valueField.Elem() - } - - typeField = structType.Field(i) - - cField = &cachedField{index: i, tag: typeField.Tag.Get(v.tagName), isTime: (valueField.Type() == reflect.TypeOf(time.Time{}) || valueField.Type() == reflect.TypeOf(&time.Time{}))} - - if cField.tag == noValidationTag { - cs.children-- - continue - } - - // if no validation and not a struct (which may containt fields for validation) - if cField.tag == "" && ((valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface) || valueField.Type() == reflect.TypeOf(time.Time{})) { - cs.children-- - continue - } - - cField.name = typeField.Name - cField.kind = valueField.Kind() - cField.typ = valueField.Type() - } - - // this can happen if the first cache value was nil - // but the second actually has a value - if cField.kind == reflect.Ptr { - cField.kind = valueField.Kind() - } - - switch cField.kind { +func (v *Validate) Struct(s interface{}) map[string]*FieldError { - case reflect.Struct, reflect.Interface: - - if !unicode.IsUpper(rune(cField.name[0])) { - cs.children-- - continue - } - - if cField.isTime { - - if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { - validationErrors.Errors[fieldError.Field] = fieldError - // free up memory reference - fieldError = nil - } - - } else { - - if strings.Contains(cField.tag, structOnlyTag) { - cs.children-- - continue - } - - if (valueField.Kind() == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() { - - if strings.Contains(cField.tag, omitempty) { - goto CACHEFIELD - } - - tags := strings.Split(cField.tag, tagSeparator) - - if len(tags) > 0 { - - var param string - vals := strings.SplitN(tags[0], tagKeySeparator, 2) - - if len(vals) > 1 { - param = vals[1] - } - - validationErrors.Errors[cField.name] = &FieldError{ - Field: cField.name, - Tag: vals[0], - Param: param, - Value: valueField.Interface(), - Kind: valueField.Kind(), - Type: valueField.Type(), - } - - goto CACHEFIELD - } - } - - // if we get here, the field is interface and could be a struct or a field - // and we need to check the inner type and validate - if cField.kind == reflect.Interface { - - valueField = valueField.Elem() - - if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { - valueField = valueField.Elem() - } - - if valueField.Kind() == reflect.Struct { - goto VALIDATESTRUCT - } - - // sending nil for cField as it was type interface and could be anything - // each time and so must be calculated each time and can't be cached reliably - if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, nil); fieldError != nil { - validationErrors.Errors[fieldError.Field] = fieldError - // free up memory reference - fieldError = nil - } - - goto CACHEFIELD - } - - VALIDATESTRUCT: - if structErrors := v.structRecursive(top, valueField.Interface(), valueField.Interface()); structErrors != nil { - validationErrors.StructErrors[cField.name] = structErrors - // free up memory map no longer needed - structErrors = nil - } - } - - case reflect.Slice, reflect.Array: - cField.isSliceOrArray = true - cField.sliceSubtype = cField.typ.Elem() - cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{})) - cField.sliceSubKind = cField.sliceSubtype.Kind() - - if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { - validationErrors.Errors[fieldError.Field] = fieldError - // free up memory reference - fieldError = nil - } - - case reflect.Map: - cField.isMap = true - cField.mapSubtype = cField.typ.Elem() - cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{})) - cField.mapSubKind = cField.mapSubtype.Kind() - - if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { - validationErrors.Errors[fieldError.Field] = fieldError - // free up memory reference - fieldError = nil - } - - default: - if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil { - validationErrors.Errors[fieldError.Field] = fieldError - // free up memory reference - fieldError = nil - } - } - - CACHEFIELD: - if !isCached { - cs.fields = append(cs.fields, cField) - } - } - - structCache.Set(structType, cs) - - if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 { - structPool.Put(validationErrors) - return nil - } - - return validationErrors -} - -// Field allows validation of a single field, still using tag style validation to check multiple errors -func (v *Validate) Field(f interface{}, tag string) *FieldError { - return v.FieldWithValue(nil, f, tag) -} + // var err *FieldError + errs := map[string]*FieldError{} + // errchan := make(chan *FieldError) + // done := make(chan bool) + // wg := &sync.WaitGroup{} + + v.structRecursive(s, s, s, 0, errs) + + // LOOP: + // for { + // select { + // case err := <-errchan: + // errs[err.Field] = err + // // fmt.Println(err) + // case <-done: + // // fmt.Println("All Done") + // break LOOP + // } + // } -// FieldWithValue allows validation of a single field, possibly even against another fields value, still using tag style validation to check multiple errors -func (v *Validate) FieldWithValue(val interface{}, f interface{}, tag string) *FieldError { - return v.fieldWithNameAndValue(nil, val, f, tag, "", true, nil) + return errs } -func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f interface{}, tag string, name string, isSingleField bool, cacheField *cachedField) *FieldError { - - var cField *cachedField - var isCached bool - var valueField reflect.Value - - // This is a double check if coming from validate.Struct but need to be here in case function is called directly - if tag == noValidationTag || tag == "" { - return nil - } - - if strings.Contains(tag, omitempty) && !hasValue(val, current, f, "") { - return nil - } - - valueField = reflect.ValueOf(f) - - if cacheField == nil { - - if valueField.Kind() == reflect.Ptr && !valueField.IsNil() { - valueField = valueField.Elem() - f = valueField.Interface() - } - - cField = &cachedField{name: name, kind: valueField.Kind(), tag: tag, typ: valueField.Type()} - - switch cField.kind { - case reflect.Slice, reflect.Array: - isSingleField = false // cached tags mean nothing because it will be split up while diving - cField.isSliceOrArray = true - cField.sliceSubtype = cField.typ.Elem() - cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{})) - cField.sliceSubKind = cField.sliceSubtype.Kind() - case reflect.Map: - isSingleField = false // cached tags mean nothing because it will be split up while diving - cField.isMap = true - cField.mapSubtype = cField.typ.Elem() - cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{})) - cField.mapSubKind = cField.mapSubtype.Kind() - } - } else { - cField = cacheField - } - - switch cField.kind { - - case reflect.Struct, reflect.Interface, reflect.Invalid: - - if cField.typ != reflect.TypeOf(time.Time{}) { - panic("Invalid field passed to fieldWithNameAndValue") - } - } - - if len(cField.tags) == 0 { - - if isSingleField { - cField.tags, isCached = fieldsCache.Get(tag) - } - - if !isCached { - - for _, t := range strings.Split(tag, tagSeparator) { - - if t == diveTag { - - cField.dive = true - cField.diveTag = strings.TrimLeft(strings.SplitN(tag, diveTag, 2)[1], ",") - break - } - - orVals := strings.Split(t, orSeparator) - cTag := &cachedTags{isOrVal: len(orVals) > 1, keyVals: make([][]string, len(orVals))} - cField.tags = append(cField.tags, cTag) - - for i, val := range orVals { - vals := strings.SplitN(val, tagKeySeparator, 2) - - key := strings.TrimSpace(vals[0]) - - if len(key) == 0 { - panic(fmt.Sprintf("Invalid validation tag on field %s", name)) - } - - param := "" - if len(vals) > 1 { - param = strings.Replace(vals[1], utf8HexComma, ",", -1) - } - - cTag.keyVals[i] = []string{key, param} - } - } - - if isSingleField { - fieldsCache.Set(cField.tag, cField.tags) - } - } - } - - var fieldErr *FieldError - var err error - - for _, cTag := range cField.tags { - - if cTag.isOrVal { - - errTag := "" - - for _, val := range cTag.keyVals { +func (v *Validate) structRecursive(top interface{}, current interface{}, s interface{}, depth int, errs map[string]*FieldError) { - fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, val[0], val[1], name) + errs["Name"] = &FieldError{Field: "Name"} - if err == nil { - return nil - } - - errTag += orSeparator + fieldErr.Tag - } - - errTag = strings.TrimLeft(errTag, orSeparator) - - fieldErr.Tag = errTag - fieldErr.Kind = cField.kind - fieldErr.Type = cField.typ - - return fieldErr - } - - if fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, cTag.keyVals[0][0], cTag.keyVals[0][1], name); err != nil { - - fieldErr.Kind = cField.kind - fieldErr.Type = cField.typ - - return fieldErr - } - } - - if cField.dive { - - if cField.isSliceOrArray { - - if errs := v.traverseSliceOrArray(val, current, valueField, cField); errs != nil && len(errs) > 0 { - - return &FieldError{ - Field: cField.name, - Kind: cField.kind, - Type: cField.typ, - Value: f, - IsPlaceholderErr: true, - IsSliceOrArray: true, - SliceOrArrayErrs: errs, - } - } - - } else if cField.isMap { - if errs := v.traverseMap(val, current, valueField, cField); errs != nil && len(errs) > 0 { - - return &FieldError{ - Field: cField.name, - Kind: cField.kind, - Type: cField.typ, - Value: f, - IsPlaceholderErr: true, - IsMap: true, - MapErrs: errs, - } - } - } else { - // throw error, if not a slice or map then should not have gotten here - panic("dive error! can't dive on a non slice or map") - } + if depth < 3 { + // wg.Add(1) + v.structRecursive(s, s, s, depth+1, errs) } - return nil -} - -func (v *Validate) traverseMap(val interface{}, current interface{}, valueField reflect.Value, cField *cachedField) map[interface{}]error { - - errs := map[interface{}]error{} - - for _, key := range valueField.MapKeys() { - - idxField := valueField.MapIndex(key) - - if cField.mapSubKind == reflect.Ptr && !idxField.IsNil() { - idxField = idxField.Elem() - cField.mapSubKind = idxField.Kind() - } - - switch cField.mapSubKind { - case reflect.Struct, reflect.Interface: - - if cField.isTimeSubtype { - - if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), false, nil); fieldError != nil { - errs[key.Interface()] = fieldError - } - - continue - } - - if (idxField.Kind() == reflect.Ptr || idxField.Kind() == reflect.Interface) && idxField.IsNil() { - - if strings.Contains(cField.diveTag, omitempty) { - continue - } - - tags := strings.Split(cField.diveTag, tagSeparator) - - if len(tags) > 0 { - - var param string - vals := strings.SplitN(tags[0], tagKeySeparator, 2) - - if len(vals) > 1 { - param = vals[1] - } - - errs[key.Interface()] = &FieldError{ - Field: fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), - Tag: vals[0], - Param: param, - Value: idxField.Interface(), - Kind: idxField.Kind(), - Type: cField.mapSubtype, - } - } - - continue - } - - // if we get here, the field is interface and could be a struct or a field - // and we need to check the inner type and validate - if idxField.Kind() == reflect.Interface { - - idxField = idxField.Elem() - - if idxField.Kind() == reflect.Ptr && !idxField.IsNil() { - idxField = idxField.Elem() - } + // wg.Wait() - if idxField.Kind() == reflect.Struct { - goto VALIDATESTRUCT - } - - // sending nil for cField as it was type interface and could be anything - // each time and so must be calculated each time and can't be cached reliably - if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), false, nil); fieldError != nil { - errs[key.Interface()] = fieldError - } - - continue - } - - VALIDATESTRUCT: - if structErrors := v.structRecursive(val, current, idxField.Interface()); structErrors != nil { - errs[key.Interface()] = structErrors - } - - default: - if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(mapIndexFieldName, cField.name, key.Interface()), false, nil); fieldError != nil { - errs[key.Interface()] = fieldError - } - } - } - - return errs + // if depth == 0 { + // // wg.Wait() + // done <- true + // // return + // } else { + // // wg.Done() + // } } -func (v *Validate) traverseSliceOrArray(val interface{}, current interface{}, valueField reflect.Value, cField *cachedField) map[int]error { - - errs := map[int]error{} - - for i := 0; i < valueField.Len(); i++ { - - idxField := valueField.Index(i) - - if cField.sliceSubKind == reflect.Ptr && !idxField.IsNil() { - idxField = idxField.Elem() - cField.sliceSubKind = idxField.Kind() - } - - switch cField.sliceSubKind { - case reflect.Struct, reflect.Interface: - - if cField.isTimeSubtype { - - if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(arrayIndexFieldName, cField.name, i), false, nil); fieldError != nil { - errs[i] = fieldError - } - - continue - } - - if (idxField.Kind() == reflect.Ptr || idxField.Kind() == reflect.Interface) && idxField.IsNil() { - - if strings.Contains(cField.diveTag, omitempty) { - continue - } - - tags := strings.Split(cField.diveTag, tagSeparator) +// // Struct validates a struct, even it's nested structs, and returns a struct containing the errors +// // NOTE: Nested Arrays, or Maps of structs do not get validated only the Array or Map itself; the reason is that there is no good +// // way to represent or report which struct within the array has the error, besides can validate the struct prior to adding it to +// // the Array or Map. +// func (v *Validate) Struct(s interface{}) map[string]*FieldError { - if len(tags) > 0 { +// // var err *FieldError +// errs := map[string]*FieldError{} +// errchan := make(chan *FieldError) +// done := make(chan bool) +// // wg := &sync.WaitGroup{} - var param string - vals := strings.SplitN(tags[0], tagKeySeparator, 2) +// go v.structRecursive(s, s, s, 0, errchan, done) - if len(vals) > 1 { - param = vals[1] - } +// LOOP: +// for { +// select { +// case err := <-errchan: +// errs[err.Field] = err +// // fmt.Println(err) +// case <-done: +// // fmt.Println("All Done") +// break LOOP +// } +// } - errs[i] = &FieldError{ - Field: fmt.Sprintf(arrayIndexFieldName, cField.name, i), - Tag: vals[0], - Param: param, - Value: idxField.Interface(), - Kind: idxField.Kind(), - Type: cField.sliceSubtype, - } - } +// return errs +// } - continue - } +// func (v *Validate) structRecursive(top interface{}, current interface{}, s interface{}, depth int, errs chan *FieldError, done chan bool) { - // if we get here, the field is interface and could be a struct or a field - // and we need to check the inner type and validate - if idxField.Kind() == reflect.Interface { +// errs <- &FieldError{Field: "Name"} - idxField = idxField.Elem() +// if depth < 1 { +// // wg.Add(1) +// v.structRecursive(s, s, s, depth+1, errs, done) +// } - if idxField.Kind() == reflect.Ptr && !idxField.IsNil() { - idxField = idxField.Elem() - } +// // wg.Wait() - if idxField.Kind() == reflect.Struct { - goto VALIDATESTRUCT - } - - // sending nil for cField as it was type interface and could be anything - // each time and so must be calculated each time and can't be cached reliably - if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(arrayIndexFieldName, cField.name, i), false, nil); fieldError != nil { - errs[i] = fieldError - } - - continue - } - - VALIDATESTRUCT: - if structErrors := v.structRecursive(val, current, idxField.Interface()); structErrors != nil { - errs[i] = structErrors - } - - default: - if fieldError := v.fieldWithNameAndValue(val, current, idxField.Interface(), cField.diveTag, fmt.Sprintf(arrayIndexFieldName, cField.name, i), false, nil); fieldError != nil { - errs[i] = fieldError - } - } - } - - return errs -} - -func (v *Validate) fieldWithNameAndSingleTag(val interface{}, current interface{}, f interface{}, key string, param string, name string) (*FieldError, error) { - - // OK to continue because we checked it's existance before getting into this loop - if key == omitempty { - return nil, nil - } - - valFunc, ok := v.validationFuncs[key] - if !ok { - panic(fmt.Sprintf("Undefined validation function on field %s", name)) - } - - if err := valFunc(val, current, f, param); err { - return nil, nil - } - - return &FieldError{ - Field: name, - Tag: key, - Value: f, - Param: param, - }, errors.New(key) -} +// if depth == 0 { +// // wg.Wait() +// done <- true +// // return +// } else { +// // wg.Done() +// } +// } diff --git a/validator_test.go b/validator_test.go index 8bfff9b..63a11c7 100644 --- a/validator_test.go +++ b/validator_test.go @@ -6,7 +6,6 @@ import ( "reflect" "runtime" "testing" - "time" ) // NOTES: @@ -108,7 +107,7 @@ type TestSlice struct { OmitEmpty []int `validate:"omitempty,min=1,max=10"` } -var validate = New("validate", BakedInValidators) +var validate = New(Config{TagName: "validate", ValidationFuncs: BakedInValidators}) func IsEqual(t *testing.T, val1, val2 interface{}) bool { v1 := reflect.ValueOf(val1) @@ -203,3618 +202,3631 @@ func PanicMatchesSkip(t *testing.T, skip int, fn func(), matches string) { fn() } -func AssertStruct(t *testing.T, s *StructErrors, structFieldName string, expectedStructName string) *StructErrors { +func TestValidation(t *testing.T) { - val, ok := s.StructErrors[structFieldName] - EqualSkip(t, 2, ok, true) - NotEqualSkip(t, 2, val, nil) - EqualSkip(t, 2, val.Struct, expectedStructName) - - return val -} - -func AssertFieldError(t *testing.T, s *StructErrors, field string, expectedTag string) { - - val, ok := s.Errors[field] - EqualSkip(t, 2, ok, true) - NotEqualSkip(t, 2, val, nil) - EqualSkip(t, 2, val.Field, field) - EqualSkip(t, 2, val.Tag, expectedTag) -} - -func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, expectedTag string) { - - val, ok := s[field] - EqualSkip(t, 2, ok, true) - NotEqualSkip(t, 2, val, nil) - EqualSkip(t, 2, val.Field, field) - EqualSkip(t, 2, val.Tag, expectedTag) -} - -func TestBadKeyValidation(t *testing.T) { type Test struct { - Name string `validate:"required, "` - } - - tst := &Test{ - Name: "test", - } - - PanicMatches(t, func() { validate.Struct(tst) }, "Invalid validation tag on field Name") -} - -func TestFlattenValidation(t *testing.T) { - - type Inner struct { - Name string `validate:"required"` - } - - type TestMultiDimensionalStructsPtr struct { - Errs [][]*Inner `validate:"gt=0,dive,dive,required"` - } - - var errStructPtrArray [][]*Inner - - errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{"ok"}}) - - tmsp := &TestMultiDimensionalStructsPtr{ - Errs: errStructPtrArray, - } - - errs := validate.Struct(tmsp) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - // for full test coverage - fmt.Sprint(errs.Error()) - - fieldErr := errs.Errors["Errs"] - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, fieldErr.Field, "Errs") - Equal(t, len(fieldErr.SliceOrArrayErrs), 1) - - innerSlice1, ok := fieldErr.SliceOrArrayErrs[0].(*FieldError) - Equal(t, ok, true) - Equal(t, innerSlice1.IsPlaceholderErr, true) - Equal(t, innerSlice1.Field, "Errs[0]") - - flatFieldErr, ok := fieldErr.Flatten()["[0][1].Inner.Name"] - Equal(t, ok, true) - Equal(t, flatFieldErr.Field, "Name") - Equal(t, flatFieldErr.Tag, "required") - - structErrFlatten, ok := errs.Flatten()["Errs[0][1].Inner.Name"] - Equal(t, ok, true) - Equal(t, structErrFlatten.Field, "Name") - Equal(t, structErrFlatten.Tag, "required") - - errStructPtrArray = [][]*Inner{} - errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, nil, &Inner{"ok"}}) - - tmsp = &TestMultiDimensionalStructsPtr{ - Errs: errStructPtrArray, - } - - errs = validate.Struct(tmsp) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - // for full test coverage - fmt.Sprint(errs.Error()) - - fieldErr = errs.Errors["Errs"] - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, fieldErr.Field, "Errs") - Equal(t, len(fieldErr.SliceOrArrayErrs), 1) - - innerSlice1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) - Equal(t, ok, true) - Equal(t, innerSlice1.IsPlaceholderErr, true) - Equal(t, innerSlice1.Field, "Errs[0]") - - flatFieldErr, ok = fieldErr.Flatten()["[0][1]"] - Equal(t, ok, true) - Equal(t, flatFieldErr.Field, "Errs[0][1]") - Equal(t, flatFieldErr.Tag, "required") - - type TestMapStructPtr struct { - Errs map[int]*Inner `validate:"gt=0,dive,required"` - } - - mip := map[int]*Inner{0: &Inner{"ok"}, 3: &Inner{""}, 4: &Inner{"ok"}} - - msp := &TestMapStructPtr{ - Errs: mip, - } - - errs = validate.Struct(msp) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldError := errs.Errors["Errs"] - Equal(t, fieldError.IsPlaceholderErr, true) - Equal(t, fieldError.IsMap, true) - Equal(t, len(fieldError.MapErrs), 1) - - innerStructError, ok := fieldError.MapErrs[3].(*StructErrors) - Equal(t, ok, true) - Equal(t, innerStructError.Struct, "Inner") - Equal(t, len(innerStructError.Errors), 1) - - innerInnerFieldError, ok := innerStructError.Errors["Name"] - Equal(t, ok, true) - Equal(t, innerInnerFieldError.IsPlaceholderErr, false) - Equal(t, innerInnerFieldError.IsSliceOrArray, false) - Equal(t, innerInnerFieldError.Field, "Name") - Equal(t, innerInnerFieldError.Tag, "required") - - flatErrs, ok := errs.Flatten()["Errs[3].Inner.Name"] - Equal(t, ok, true) - Equal(t, flatErrs.Field, "Name") - Equal(t, flatErrs.Tag, "required") - - mip2 := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} - - msp2 := &TestMapStructPtr{ - Errs: mip2, - } - - errs = validate.Struct(msp2) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldError = errs.Errors["Errs"] - Equal(t, fieldError.IsPlaceholderErr, true) - Equal(t, fieldError.IsMap, true) - Equal(t, len(fieldError.MapErrs), 1) - - innerFieldError, ok := fieldError.MapErrs[3].(*FieldError) - Equal(t, ok, true) - Equal(t, innerFieldError.IsPlaceholderErr, false) - Equal(t, innerFieldError.IsSliceOrArray, false) - Equal(t, innerFieldError.Field, "Errs[3]") - Equal(t, innerFieldError.Tag, "required") - - flatErrs, ok = errs.Flatten()["Errs[3]"] - Equal(t, ok, true) - Equal(t, flatErrs.Field, "Errs[3]") - Equal(t, flatErrs.Tag, "required") - - type TestMapInnerArrayStruct struct { - Errs map[int][]string `validate:"gt=0,dive,dive,required"` + Name string } - mias := map[int][]string{0: []string{"ok"}, 3: []string{"ok", ""}, 4: []string{"ok"}} - - mia := &TestMapInnerArrayStruct{ - Errs: mias, - } + tst := &Test{Name: "Dean"} - errs = validate.Struct(mia) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) + errs := validate.Struct(tst) - flatErrs, ok = errs.Flatten()["Errs[3][1]"] - Equal(t, ok, true) - Equal(t, flatErrs.Field, "Errs[3][1]") - Equal(t, flatErrs.Tag, "required") + fmt.Println(errs) } -func TestInterfaceErrValidation(t *testing.T) { - - var v1 interface{} - var v2 interface{} - - v2 = 1 - v1 = v2 - - err := validate.Field(v1, "len=1") - Equal(t, err, nil) - err = validate.Field(v2, "len=1") - Equal(t, err, nil) - - type ExternalCMD struct { - Userid string `json:"userid"` - Action uint32 `json:"action"` - Data interface{} `json:"data,omitempty" validate:"required"` - } - - s := &ExternalCMD{ - Userid: "123456", - Action: 10000, - // Data: 1, - } - - errs := validate.Struct(s) - NotEqual(t, errs, nil) - Equal(t, errs.Errors["Data"].Field, "Data") - Equal(t, errs.Errors["Data"].Tag, "required") - - type ExternalCMD2 struct { - Userid string `json:"userid"` - Action uint32 `json:"action"` - Data interface{} `json:"data,omitempty" validate:"len=1"` - } - - s2 := &ExternalCMD2{ - Userid: "123456", - Action: 10000, - // Data: 1, - } - - errs = validate.Struct(s2) - NotEqual(t, errs, nil) - Equal(t, errs.Errors["Data"].Field, "Data") - Equal(t, errs.Errors["Data"].Tag, "len") - Equal(t, errs.Errors["Data"].Param, "1") - - s3 := &ExternalCMD2{ - Userid: "123456", - Action: 10000, - Data: 2, - } - - errs = validate.Struct(s3) - NotEqual(t, errs, nil) - Equal(t, errs.Errors["Data"].Field, "Data") - Equal(t, errs.Errors["Data"].Tag, "len") - Equal(t, errs.Errors["Data"].Param, "1") - - type Inner struct { - Name string `validate:"required"` - } - - inner := &Inner{ - Name: "", - } - - s4 := &ExternalCMD{ - Userid: "123456", - Action: 10000, - Data: inner, - } - - errs = validate.Struct(s4) - NotEqual(t, errs, nil) - Equal(t, errs.StructErrors["Data"].Struct, "Inner") - Equal(t, errs.StructErrors["Data"].Errors["Name"].Field, "Name") - Equal(t, errs.StructErrors["Data"].Errors["Name"].Tag, "required") +// func AssertStruct(t *testing.T, s *StructErrors, structFieldName string, expectedStructName string) *StructErrors { - type TestMapStructPtr struct { - Errs map[int]interface{} `validate:"gt=0,dive,len=2"` - } - - mip := map[int]interface{}{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} - - msp := &TestMapStructPtr{ - Errs: mip, - } - - errs = validate.Struct(msp) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldError := errs.Errors["Errs"] - Equal(t, fieldError.IsPlaceholderErr, true) - Equal(t, fieldError.IsMap, true) - Equal(t, len(fieldError.MapErrs), 1) - - innerFieldError, ok := fieldError.MapErrs[3].(*FieldError) - Equal(t, ok, true) - Equal(t, innerFieldError.IsPlaceholderErr, false) - Equal(t, innerFieldError.IsMap, false) - Equal(t, len(innerFieldError.MapErrs), 0) - Equal(t, innerFieldError.Field, "Errs[3]") - Equal(t, innerFieldError.Tag, "len") - - type TestMultiDimensionalStructs struct { - Errs [][]interface{} `validate:"gt=0,dive,dive,len=2"` - } - - var errStructArray [][]interface{} - - errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// val, ok := s.StructErrors[structFieldName] +// EqualSkip(t, 2, ok, true) +// NotEqualSkip(t, 2, val, nil) +// EqualSkip(t, 2, val.Struct, expectedStructName) - tms := &TestMultiDimensionalStructs{ - Errs: errStructArray, - } +// return val +// } - errs = validate.Struct(tms) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok := errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 2) - - sliceError1, ok := fieldErr.SliceOrArrayErrs[0].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceStructError1, ok := sliceError1.SliceOrArrayErrs[1].(*StructErrors) - Equal(t, ok, true) - Equal(t, len(innerSliceStructError1.Errors), 1) - - innerInnersliceError1 := innerSliceStructError1.Errors["Name"] - Equal(t, innerInnersliceError1.IsPlaceholderErr, false) - Equal(t, innerInnersliceError1.IsSliceOrArray, false) - Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) - - type TestMultiDimensionalStructsPtr2 struct { - Errs [][]*Inner `validate:"gt=0,dive,dive,len=2"` - } +// func AssertFieldError(t *testing.T, s *StructErrors, field string, expectedTag string) { - var errStructPtr2Array [][]*Inner +// val, ok := s.Errors[field] +// EqualSkip(t, 2, ok, true) +// NotEqualSkip(t, 2, val, nil) +// EqualSkip(t, 2, val.Field, field) +// EqualSkip(t, 2, val.Tag, expectedTag) +// } - errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) +// func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, expectedTag string) { - tmsp2 := &TestMultiDimensionalStructsPtr2{ - Errs: errStructPtr2Array, - } +// val, ok := s[field] +// EqualSkip(t, 2, ok, true) +// NotEqualSkip(t, 2, val, nil) +// EqualSkip(t, 2, val.Field, field) +// EqualSkip(t, 2, val.Tag, expectedTag) +// } - errs = validate.Struct(tmsp2) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 3) - - sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) - Equal(t, ok, true) - Equal(t, len(innerSliceStructError1.Errors), 1) - - innerSliceStructError2, ok := sliceError1.SliceOrArrayErrs[2].(*FieldError) - Equal(t, ok, true) - Equal(t, innerSliceStructError2.IsPlaceholderErr, false) - Equal(t, innerSliceStructError2.IsSliceOrArray, false) - Equal(t, len(innerSliceStructError2.SliceOrArrayErrs), 0) - Equal(t, innerSliceStructError2.Field, "Errs[2][2]") - - innerInnersliceError1 = innerSliceStructError1.Errors["Name"] - Equal(t, innerInnersliceError1.IsPlaceholderErr, false) - Equal(t, innerInnersliceError1.IsSliceOrArray, false) - Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) - - m := map[int]interface{}{0: "ok", 3: "", 4: "ok"} - - err = validate.Field(m, "len=3,dive,len=2") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, true) - Equal(t, err.IsMap, true) - Equal(t, len(err.MapErrs), 1) - - err = validate.Field(m, "len=2,dive,required") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, false) - Equal(t, err.IsMap, false) - Equal(t, len(err.MapErrs), 0) - - arr := []interface{}{"ok", "", "ok"} - - err = validate.Field(arr, "len=3,dive,len=2") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, true) - Equal(t, err.IsSliceOrArray, true) - Equal(t, len(err.SliceOrArrayErrs), 1) - - err = validate.Field(arr, "len=2,dive,required") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, false) - Equal(t, err.IsSliceOrArray, false) - Equal(t, len(err.SliceOrArrayErrs), 0) - - type MyStruct struct { - A, B string - C interface{} - } +// func TestBadKeyValidation(t *testing.T) { +// type Test struct { +// Name string `validate:"required, "` +// } - var a MyStruct +// tst := &Test{ +// Name: "test", +// } - a.A = "value" - a.C = "nu" +// PanicMatches(t, func() { validate.Struct(tst) }, "Invalid validation tag on field Name") +// } - errs = validate.Struct(a) - Equal(t, errs, nil) -} +// func TestFlattenValidation(t *testing.T) { -func TestMapDiveValidation(t *testing.T) { +// type Inner struct { +// Name string `validate:"required"` +// } - n := map[int]interface{}{0: nil} - err := validate.Field(n, "omitempty,required") +// type TestMultiDimensionalStructsPtr struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive,required"` +// } - m := map[int]string{0: "ok", 3: "", 4: "ok"} +// var errStructPtrArray [][]*Inner - err = validate.Field(m, "len=3,dive,required") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, true) - Equal(t, err.IsMap, true) - Equal(t, len(err.MapErrs), 1) +// errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{"ok"}}) - err = validate.Field(m, "len=2,dive,required") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, false) - Equal(t, err.IsMap, false) - Equal(t, len(err.MapErrs), 0) +// tmsp := &TestMultiDimensionalStructsPtr{ +// Errs: errStructPtrArray, +// } - type Inner struct { - Name string `validate:"required"` - } +// errs := validate.Struct(tmsp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) +// // for full test coverage +// fmt.Sprint(errs.Error()) - type TestMapStruct struct { - Errs map[int]Inner `validate:"gt=0,dive"` - } +// fieldErr := errs.Errors["Errs"] +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, fieldErr.Field, "Errs") +// Equal(t, len(fieldErr.SliceOrArrayErrs), 1) - mi := map[int]Inner{0: Inner{"ok"}, 3: Inner{""}, 4: Inner{"ok"}} +// innerSlice1, ok := fieldErr.SliceOrArrayErrs[0].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerSlice1.IsPlaceholderErr, true) +// Equal(t, innerSlice1.Field, "Errs[0]") - ms := &TestMapStruct{ - Errs: mi, - } +// flatFieldErr, ok := fieldErr.Flatten()["[0][1].Inner.Name"] +// Equal(t, ok, true) +// Equal(t, flatFieldErr.Field, "Name") +// Equal(t, flatFieldErr.Tag, "required") - errs := validate.Struct(ms) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - // for full test coverage - fmt.Sprint(errs.Error()) - - fieldError := errs.Errors["Errs"] - Equal(t, fieldError.IsPlaceholderErr, true) - Equal(t, fieldError.IsMap, true) - Equal(t, len(fieldError.MapErrs), 1) - - structErr, ok := fieldError.MapErrs[3].(*StructErrors) - Equal(t, ok, true) - Equal(t, len(structErr.Errors), 1) - - innerErr := structErr.Errors["Name"] - Equal(t, innerErr.IsPlaceholderErr, false) - Equal(t, innerErr.IsMap, false) - Equal(t, len(innerErr.MapErrs), 0) - Equal(t, innerErr.Field, "Name") - Equal(t, innerErr.Tag, "required") - - type TestMapTimeStruct struct { - Errs map[int]*time.Time `validate:"gt=0,dive,required"` - } +// structErrFlatten, ok := errs.Flatten()["Errs[0][1].Inner.Name"] +// Equal(t, ok, true) +// Equal(t, structErrFlatten.Field, "Name") +// Equal(t, structErrFlatten.Tag, "required") - t1 := time.Now().UTC() +// errStructPtrArray = [][]*Inner{} +// errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, nil, &Inner{"ok"}}) - mta := map[int]*time.Time{0: &t1, 3: nil, 4: nil} +// tmsp = &TestMultiDimensionalStructsPtr{ +// Errs: errStructPtrArray, +// } - mt := &TestMapTimeStruct{ - Errs: mta, - } +// errs = validate.Struct(tmsp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) +// // for full test coverage +// fmt.Sprint(errs.Error()) + +// fieldErr = errs.Errors["Errs"] +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, fieldErr.Field, "Errs") +// Equal(t, len(fieldErr.SliceOrArrayErrs), 1) + +// innerSlice1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerSlice1.IsPlaceholderErr, true) +// Equal(t, innerSlice1.Field, "Errs[0]") + +// flatFieldErr, ok = fieldErr.Flatten()["[0][1]"] +// Equal(t, ok, true) +// Equal(t, flatFieldErr.Field, "Errs[0][1]") +// Equal(t, flatFieldErr.Tag, "required") + +// type TestMapStructPtr struct { +// Errs map[int]*Inner `validate:"gt=0,dive,required"` +// } + +// mip := map[int]*Inner{0: &Inner{"ok"}, 3: &Inner{""}, 4: &Inner{"ok"}} + +// msp := &TestMapStructPtr{ +// Errs: mip, +// } + +// errs = validate.Struct(msp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldError := errs.Errors["Errs"] +// Equal(t, fieldError.IsPlaceholderErr, true) +// Equal(t, fieldError.IsMap, true) +// Equal(t, len(fieldError.MapErrs), 1) + +// innerStructError, ok := fieldError.MapErrs[3].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, innerStructError.Struct, "Inner") +// Equal(t, len(innerStructError.Errors), 1) + +// innerInnerFieldError, ok := innerStructError.Errors["Name"] +// Equal(t, ok, true) +// Equal(t, innerInnerFieldError.IsPlaceholderErr, false) +// Equal(t, innerInnerFieldError.IsSliceOrArray, false) +// Equal(t, innerInnerFieldError.Field, "Name") +// Equal(t, innerInnerFieldError.Tag, "required") + +// flatErrs, ok := errs.Flatten()["Errs[3].Inner.Name"] +// Equal(t, ok, true) +// Equal(t, flatErrs.Field, "Name") +// Equal(t, flatErrs.Tag, "required") + +// mip2 := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} + +// msp2 := &TestMapStructPtr{ +// Errs: mip2, +// } + +// errs = validate.Struct(msp2) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldError = errs.Errors["Errs"] +// Equal(t, fieldError.IsPlaceholderErr, true) +// Equal(t, fieldError.IsMap, true) +// Equal(t, len(fieldError.MapErrs), 1) + +// innerFieldError, ok := fieldError.MapErrs[3].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerFieldError.IsPlaceholderErr, false) +// Equal(t, innerFieldError.IsSliceOrArray, false) +// Equal(t, innerFieldError.Field, "Errs[3]") +// Equal(t, innerFieldError.Tag, "required") + +// flatErrs, ok = errs.Flatten()["Errs[3]"] +// Equal(t, ok, true) +// Equal(t, flatErrs.Field, "Errs[3]") +// Equal(t, flatErrs.Tag, "required") + +// type TestMapInnerArrayStruct struct { +// Errs map[int][]string `validate:"gt=0,dive,dive,required"` +// } + +// mias := map[int][]string{0: []string{"ok"}, 3: []string{"ok", ""}, 4: []string{"ok"}} + +// mia := &TestMapInnerArrayStruct{ +// Errs: mias, +// } + +// errs = validate.Struct(mia) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// flatErrs, ok = errs.Flatten()["Errs[3][1]"] +// Equal(t, ok, true) +// Equal(t, flatErrs.Field, "Errs[3][1]") +// Equal(t, flatErrs.Tag, "required") +// } + +// func TestInterfaceErrValidation(t *testing.T) { + +// var v1 interface{} +// var v2 interface{} + +// v2 = 1 +// v1 = v2 + +// err := validate.Field(v1, "len=1") +// Equal(t, err, nil) +// err = validate.Field(v2, "len=1") +// Equal(t, err, nil) + +// type ExternalCMD struct { +// Userid string `json:"userid"` +// Action uint32 `json:"action"` +// Data interface{} `json:"data,omitempty" validate:"required"` +// } + +// s := &ExternalCMD{ +// Userid: "123456", +// Action: 10000, +// // Data: 1, +// } + +// errs := validate.Struct(s) +// NotEqual(t, errs, nil) +// Equal(t, errs.Errors["Data"].Field, "Data") +// Equal(t, errs.Errors["Data"].Tag, "required") + +// type ExternalCMD2 struct { +// Userid string `json:"userid"` +// Action uint32 `json:"action"` +// Data interface{} `json:"data,omitempty" validate:"len=1"` +// } + +// s2 := &ExternalCMD2{ +// Userid: "123456", +// Action: 10000, +// // Data: 1, +// } + +// errs = validate.Struct(s2) +// NotEqual(t, errs, nil) +// Equal(t, errs.Errors["Data"].Field, "Data") +// Equal(t, errs.Errors["Data"].Tag, "len") +// Equal(t, errs.Errors["Data"].Param, "1") + +// s3 := &ExternalCMD2{ +// Userid: "123456", +// Action: 10000, +// Data: 2, +// } + +// errs = validate.Struct(s3) +// NotEqual(t, errs, nil) +// Equal(t, errs.Errors["Data"].Field, "Data") +// Equal(t, errs.Errors["Data"].Tag, "len") +// Equal(t, errs.Errors["Data"].Param, "1") + +// type Inner struct { +// Name string `validate:"required"` +// } + +// inner := &Inner{ +// Name: "", +// } + +// s4 := &ExternalCMD{ +// Userid: "123456", +// Action: 10000, +// Data: inner, +// } + +// errs = validate.Struct(s4) +// NotEqual(t, errs, nil) +// Equal(t, errs.StructErrors["Data"].Struct, "Inner") +// Equal(t, errs.StructErrors["Data"].Errors["Name"].Field, "Name") +// Equal(t, errs.StructErrors["Data"].Errors["Name"].Tag, "required") + +// type TestMapStructPtr struct { +// Errs map[int]interface{} `validate:"gt=0,dive,len=2"` +// } + +// mip := map[int]interface{}{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} + +// msp := &TestMapStructPtr{ +// Errs: mip, +// } + +// errs = validate.Struct(msp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldError := errs.Errors["Errs"] +// Equal(t, fieldError.IsPlaceholderErr, true) +// Equal(t, fieldError.IsMap, true) +// Equal(t, len(fieldError.MapErrs), 1) + +// innerFieldError, ok := fieldError.MapErrs[3].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerFieldError.IsPlaceholderErr, false) +// Equal(t, innerFieldError.IsMap, false) +// Equal(t, len(innerFieldError.MapErrs), 0) +// Equal(t, innerFieldError.Field, "Errs[3]") +// Equal(t, innerFieldError.Tag, "len") + +// type TestMultiDimensionalStructs struct { +// Errs [][]interface{} `validate:"gt=0,dive,dive,len=2"` +// } + +// var errStructArray [][]interface{} + +// errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructArray = append(errStructArray, []interface{}{&Inner{"ok"}, &Inner{""}, &Inner{""}}) + +// tms := &TestMultiDimensionalStructs{ +// Errs: errStructArray, +// } + +// errs = validate.Struct(tms) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok := errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 2) + +// sliceError1, ok := fieldErr.SliceOrArrayErrs[0].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceStructError1, ok := sliceError1.SliceOrArrayErrs[1].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, len(innerSliceStructError1.Errors), 1) + +// innerInnersliceError1 := innerSliceStructError1.Errors["Name"] +// Equal(t, innerInnersliceError1.IsPlaceholderErr, false) +// Equal(t, innerInnersliceError1.IsSliceOrArray, false) +// Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) + +// type TestMultiDimensionalStructsPtr2 struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive,len=2"` +// } + +// var errStructPtr2Array [][]*Inner + +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) + +// tmsp2 := &TestMultiDimensionalStructsPtr2{ +// Errs: errStructPtr2Array, +// } + +// errs = validate.Struct(tmsp2) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 3) + +// sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, len(innerSliceStructError1.Errors), 1) + +// innerSliceStructError2, ok := sliceError1.SliceOrArrayErrs[2].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerSliceStructError2.IsPlaceholderErr, false) +// Equal(t, innerSliceStructError2.IsSliceOrArray, false) +// Equal(t, len(innerSliceStructError2.SliceOrArrayErrs), 0) +// Equal(t, innerSliceStructError2.Field, "Errs[2][2]") + +// innerInnersliceError1 = innerSliceStructError1.Errors["Name"] +// Equal(t, innerInnersliceError1.IsPlaceholderErr, false) +// Equal(t, innerInnersliceError1.IsSliceOrArray, false) +// Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) + +// m := map[int]interface{}{0: "ok", 3: "", 4: "ok"} + +// err = validate.Field(m, "len=3,dive,len=2") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, true) +// Equal(t, err.IsMap, true) +// Equal(t, len(err.MapErrs), 1) + +// err = validate.Field(m, "len=2,dive,required") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, false) +// Equal(t, err.IsMap, false) +// Equal(t, len(err.MapErrs), 0) + +// arr := []interface{}{"ok", "", "ok"} + +// err = validate.Field(arr, "len=3,dive,len=2") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, true) +// Equal(t, err.IsSliceOrArray, true) +// Equal(t, len(err.SliceOrArrayErrs), 1) + +// err = validate.Field(arr, "len=2,dive,required") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, false) +// Equal(t, err.IsSliceOrArray, false) +// Equal(t, len(err.SliceOrArrayErrs), 0) + +// type MyStruct struct { +// A, B string +// C interface{} +// } + +// var a MyStruct + +// a.A = "value" +// a.C = "nu" + +// errs = validate.Struct(a) +// Equal(t, errs, nil) +// } + +// func TestMapDiveValidation(t *testing.T) { + +// n := map[int]interface{}{0: nil} +// err := validate.Field(n, "omitempty,required") + +// m := map[int]string{0: "ok", 3: "", 4: "ok"} + +// err = validate.Field(m, "len=3,dive,required") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, true) +// Equal(t, err.IsMap, true) +// Equal(t, len(err.MapErrs), 1) + +// err = validate.Field(m, "len=2,dive,required") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, false) +// Equal(t, err.IsMap, false) +// Equal(t, len(err.MapErrs), 0) + +// type Inner struct { +// Name string `validate:"required"` +// } + +// type TestMapStruct struct { +// Errs map[int]Inner `validate:"gt=0,dive"` +// } + +// mi := map[int]Inner{0: Inner{"ok"}, 3: Inner{""}, 4: Inner{"ok"}} + +// ms := &TestMapStruct{ +// Errs: mi, +// } + +// errs := validate.Struct(ms) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) +// // for full test coverage +// fmt.Sprint(errs.Error()) + +// fieldError := errs.Errors["Errs"] +// Equal(t, fieldError.IsPlaceholderErr, true) +// Equal(t, fieldError.IsMap, true) +// Equal(t, len(fieldError.MapErrs), 1) + +// structErr, ok := fieldError.MapErrs[3].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, len(structErr.Errors), 1) + +// innerErr := structErr.Errors["Name"] +// Equal(t, innerErr.IsPlaceholderErr, false) +// Equal(t, innerErr.IsMap, false) +// Equal(t, len(innerErr.MapErrs), 0) +// Equal(t, innerErr.Field, "Name") +// Equal(t, innerErr.Tag, "required") + +// type TestMapTimeStruct struct { +// Errs map[int]*time.Time `validate:"gt=0,dive,required"` +// } + +// t1 := time.Now().UTC() + +// mta := map[int]*time.Time{0: &t1, 3: nil, 4: nil} + +// mt := &TestMapTimeStruct{ +// Errs: mta, +// } + +// errs = validate.Struct(mt) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldError = errs.Errors["Errs"] +// Equal(t, fieldError.IsPlaceholderErr, true) +// Equal(t, fieldError.IsMap, true) +// Equal(t, len(fieldError.MapErrs), 2) + +// innerErr, ok = fieldError.MapErrs[3].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerErr.IsPlaceholderErr, false) +// Equal(t, innerErr.IsMap, false) +// Equal(t, len(innerErr.MapErrs), 0) +// Equal(t, innerErr.Field, "Errs[3]") +// Equal(t, innerErr.Tag, "required") + +// type TestMapStructPtr struct { +// Errs map[int]*Inner `validate:"gt=0,dive,required"` +// } + +// mip := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} + +// msp := &TestMapStructPtr{ +// Errs: mip, +// } + +// errs = validate.Struct(msp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldError = errs.Errors["Errs"] +// Equal(t, fieldError.IsPlaceholderErr, true) +// Equal(t, fieldError.IsMap, true) +// Equal(t, len(fieldError.MapErrs), 1) + +// innerFieldError, ok := fieldError.MapErrs[3].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerFieldError.IsPlaceholderErr, false) +// Equal(t, innerFieldError.IsMap, false) +// Equal(t, len(innerFieldError.MapErrs), 0) +// Equal(t, innerFieldError.Field, "Errs[3]") +// Equal(t, innerFieldError.Tag, "required") + +// type TestMapStructPtr2 struct { +// Errs map[int]*Inner `validate:"gt=0,dive,omitempty,required"` +// } + +// mip2 := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} + +// msp2 := &TestMapStructPtr2{ +// Errs: mip2, +// } + +// errs = validate.Struct(msp2) +// Equal(t, errs, nil) +// } + +// func TestArrayDiveValidation(t *testing.T) { + +// arr := []string{"ok", "", "ok"} + +// err := validate.Field(arr, "len=3,dive,required") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, true) +// Equal(t, err.IsSliceOrArray, true) +// Equal(t, len(err.SliceOrArrayErrs), 1) + +// // flat := err.Flatten() +// // fe, ok := flat["[1]"] +// // Equal(t, ok, true) +// // Equal(t, fe.Tag, "required") + +// err = validate.Field(arr, "len=2,dive,required") +// NotEqual(t, err, nil) +// Equal(t, err.IsPlaceholderErr, false) +// Equal(t, err.IsSliceOrArray, false) +// Equal(t, len(err.SliceOrArrayErrs), 0) + +// type BadDive struct { +// Name string `validate:"dive"` +// } + +// bd := &BadDive{ +// Name: "TEST", +// } + +// PanicMatches(t, func() { validate.Struct(bd) }, "dive error! can't dive on a non slice or map") + +// type Test struct { +// Errs []string `validate:"gt=0,dive,required"` +// } + +// test := &Test{ +// Errs: []string{"ok", "", "ok"}, +// } + +// errs := validate.Struct(test) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// // flat = errs.Flatten() +// // me, ok := flat["Errs[1]"] +// // Equal(t, ok, true) +// // Equal(t, me.Field, "Errs[1]") +// // Equal(t, me.Tag, "required") + +// fieldErr, ok := errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 1) + +// innerErr, ok := fieldErr.SliceOrArrayErrs[1].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerErr.Tag, required) +// Equal(t, innerErr.IsPlaceholderErr, false) +// Equal(t, innerErr.Field, "Errs[1]") + +// test = &Test{ +// Errs: []string{"ok", "ok", ""}, +// } + +// errs = validate.Struct(test) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 1) + +// innerErr, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerErr.Tag, required) +// Equal(t, innerErr.IsPlaceholderErr, false) +// Equal(t, innerErr.Field, "Errs[2]") + +// type TestMultiDimensional struct { +// Errs [][]string `validate:"gt=0,dive,dive,required"` +// } + +// var errArray [][]string + +// errArray = append(errArray, []string{"ok", "", ""}) +// errArray = append(errArray, []string{"ok", "", ""}) + +// tm := &TestMultiDimensional{ +// Errs: errArray, +// } + +// errs = validate.Struct(tm) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 2) + +// sliceError1, ok := fieldErr.SliceOrArrayErrs[0].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) +// Equal(t, sliceError1.Field, "Errs[0]") + +// innerSliceError1, ok := sliceError1.SliceOrArrayErrs[1].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerSliceError1.IsPlaceholderErr, false) +// Equal(t, innerSliceError1.Tag, required) +// Equal(t, innerSliceError1.IsSliceOrArray, false) +// Equal(t, len(innerSliceError1.SliceOrArrayErrs), 0) +// Equal(t, innerSliceError1.Field, "Errs[0][1]") + +// type Inner struct { +// Name string `validate:"required"` +// } + +// type TestMultiDimensionalStructs struct { +// Errs [][]Inner `validate:"gt=0,dive,dive"` +// } + +// var errStructArray [][]Inner + +// errStructArray = append(errStructArray, []Inner{Inner{"ok"}, Inner{""}, Inner{""}}) +// errStructArray = append(errStructArray, []Inner{Inner{"ok"}, Inner{""}, Inner{""}}) + +// tms := &TestMultiDimensionalStructs{ +// Errs: errStructArray, +// } + +// errs = validate.Struct(tms) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 2) + +// sliceError1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceStructError1, ok := sliceError1.SliceOrArrayErrs[1].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, len(innerSliceStructError1.Errors), 1) + +// innerInnersliceError1 := innerSliceStructError1.Errors["Name"] +// Equal(t, innerInnersliceError1.IsPlaceholderErr, false) +// Equal(t, innerInnersliceError1.IsSliceOrArray, false) +// Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) + +// type TestMultiDimensionalStructsPtr struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive"` +// } + +// var errStructPtrArray [][]*Inner + +// errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) + +// tmsp := &TestMultiDimensionalStructsPtr{ +// Errs: errStructPtrArray, +// } + +// errs = validate.Struct(tmsp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) +// // for full test coverage +// fmt.Sprint(errs.Error()) + +// // flat := errs.Flatten() +// // // fmt.Println(errs) +// // fmt.Println(flat) +// // expect Errs[0][1].Inner.Name +// // me, ok := flat["Errs[1]"] +// // Equal(t, ok, true) +// // Equal(t, me.Field, "Errs[1]") +// // Equal(t, me.Tag, "required") + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 3) + +// // flat := fieldErr.Flatten() +// // fmt.Println(errs) +// // fmt.Println(flat) + +// sliceError1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, len(innerSliceStructError1.Errors), 1) + +// innerInnersliceError1 = innerSliceStructError1.Errors["Name"] +// Equal(t, innerInnersliceError1.IsPlaceholderErr, false) +// Equal(t, innerInnersliceError1.IsSliceOrArray, false) +// Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) + +// type TestMultiDimensionalStructsPtr2 struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive,required"` +// } + +// var errStructPtr2Array [][]*Inner + +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) + +// tmsp2 := &TestMultiDimensionalStructsPtr2{ +// Errs: errStructPtr2Array, +// } + +// errs = validate.Struct(tmsp2) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 3) + +// sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, len(innerSliceStructError1.Errors), 1) + +// innerSliceStructError2, ok := sliceError1.SliceOrArrayErrs[2].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerSliceStructError2.IsPlaceholderErr, false) +// Equal(t, innerSliceStructError2.IsSliceOrArray, false) +// Equal(t, len(innerSliceStructError2.SliceOrArrayErrs), 0) +// Equal(t, innerSliceStructError2.Field, "Errs[2][2]") + +// innerInnersliceError1 = innerSliceStructError1.Errors["Name"] +// Equal(t, innerInnersliceError1.IsPlaceholderErr, false) +// Equal(t, innerInnersliceError1.IsSliceOrArray, false) +// Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) + +// type TestMultiDimensionalStructsPtr3 struct { +// Errs [][]*Inner `validate:"gt=0,dive,dive,omitempty"` +// } + +// var errStructPtr3Array [][]*Inner + +// errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) +// errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) + +// tmsp3 := &TestMultiDimensionalStructsPtr3{ +// Errs: errStructPtr3Array, +// } + +// errs = validate.Struct(tmsp3) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 3) + +// sliceError1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) +// Equal(t, ok, true) +// Equal(t, len(innerSliceStructError1.Errors), 1) + +// innerInnersliceError1 = innerSliceStructError1.Errors["Name"] +// Equal(t, innerInnersliceError1.IsPlaceholderErr, false) +// Equal(t, innerInnersliceError1.IsSliceOrArray, false) +// Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) + +// type TestMultiDimensionalTimeTime struct { +// Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` +// } + +// var errTimePtr3Array [][]*time.Time + +// t1 := time.Now().UTC() +// t2 := time.Now().UTC() +// t3 := time.Now().UTC().Add(time.Hour * 24) + +// errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, &t3}) +// errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, nil}) +// errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, nil, nil}) + +// tmtp3 := &TestMultiDimensionalTimeTime{ +// Errs: errTimePtr3Array, +// } + +// errs = validate.Struct(tmtp3) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 2) + +// sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceError1, ok = sliceError1.SliceOrArrayErrs[1].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerSliceError1.IsPlaceholderErr, false) +// Equal(t, innerSliceError1.IsSliceOrArray, false) +// Equal(t, len(innerSliceError1.SliceOrArrayErrs), 0) +// Equal(t, innerSliceError1.Field, "Errs[2][1]") +// Equal(t, innerSliceError1.Tag, required) + +// type TestMultiDimensionalTimeTime2 struct { +// Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` +// } + +// var errTimeArray [][]*time.Time + +// t1 = time.Now().UTC() +// t2 = time.Now().UTC() +// t3 = time.Now().UTC().Add(time.Hour * 24) + +// errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, &t3}) +// errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, nil}) +// errTimeArray = append(errTimeArray, []*time.Time{&t1, nil, nil}) + +// tmtp := &TestMultiDimensionalTimeTime2{ +// Errs: errTimeArray, +// } + +// errs = validate.Struct(tmtp) +// NotEqual(t, errs, nil) +// Equal(t, len(errs.Errors), 1) + +// fieldErr, ok = errs.Errors["Errs"] +// Equal(t, ok, true) +// Equal(t, fieldErr.IsPlaceholderErr, true) +// Equal(t, fieldErr.IsSliceOrArray, true) +// Equal(t, len(fieldErr.SliceOrArrayErrs), 2) + +// sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) +// Equal(t, ok, true) +// Equal(t, sliceError1.IsPlaceholderErr, true) +// Equal(t, sliceError1.IsSliceOrArray, true) +// Equal(t, len(sliceError1.SliceOrArrayErrs), 2) + +// innerSliceError1, ok = sliceError1.SliceOrArrayErrs[1].(*FieldError) +// Equal(t, ok, true) +// Equal(t, innerSliceError1.IsPlaceholderErr, false) +// Equal(t, innerSliceError1.IsSliceOrArray, false) +// Equal(t, len(innerSliceError1.SliceOrArrayErrs), 0) +// Equal(t, innerSliceError1.Field, "Errs[2][1]") +// Equal(t, innerSliceError1.Tag, required) +// } + +// func TestNilStructPointerValidation(t *testing.T) { +// type Inner struct { +// Data string +// } + +// type Outer struct { +// Inner *Inner `validate:"omitempty"` +// } + +// inner := &Inner{ +// Data: "test", +// } + +// outer := &Outer{ +// Inner: inner, +// } + +// errs := validate.Struct(outer) +// Equal(t, errs, nil) + +// outer = &Outer{ +// Inner: nil, +// } + +// errs = validate.Struct(outer) +// Equal(t, errs, nil) + +// type Inner2 struct { +// Data string +// } + +// type Outer2 struct { +// Inner2 *Inner2 `validate:"required"` +// } + +// inner2 := &Inner2{ +// Data: "test", +// } + +// outer2 := &Outer2{ +// Inner2: inner2, +// } + +// errs = validate.Struct(outer2) +// Equal(t, errs, nil) + +// outer2 = &Outer2{ +// Inner2: nil, +// } + +// errs = validate.Struct(outer2) +// NotEqual(t, errs, nil) + +// type Inner3 struct { +// Data string +// } + +// type Outer3 struct { +// Inner3 *Inner3 +// } + +// inner3 := &Inner3{ +// Data: "test", +// } + +// outer3 := &Outer3{ +// Inner3: inner3, +// } + +// errs = validate.Struct(outer3) +// Equal(t, errs, nil) + +// type Inner4 struct { +// Data string +// } + +// type Outer4 struct { +// Inner4 *Inner4 `validate:"-"` +// } + +// inner4 := &Inner4{ +// Data: "test", +// } + +// outer4 := &Outer4{ +// Inner4: inner4, +// } + +// errs = validate.Struct(outer4) +// Equal(t, errs, nil) +// } + +// func TestSSNValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"00-90-8787", false}, +// {"66690-76", false}, +// {"191 60 2869", true}, +// {"191-60-2869", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "ssn") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d SSN failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ssn") { +// t.Fatalf("Index: %d SSN failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestLongitudeValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"-180.000", true}, +// {"180.1", false}, +// {"+73.234", true}, +// {"+382.3811", false}, +// {"23.11111111", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "longitude") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d Longitude failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "longitude") { +// t.Fatalf("Index: %d Longitude failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestLatitudeValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"-90.000", true}, +// {"+90", true}, +// {"47.1231231", true}, +// {"+99.9", false}, +// {"108", false}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "latitude") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d Latitude failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "latitude") { +// t.Fatalf("Index: %d Latitude failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestDataURIValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, +// {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, +// {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, +// {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + +// "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + +// "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + +// "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + +// "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + +// "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, +// {"data:image/png;base64,12345", false}, +// {"", false}, +// {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "datauri") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d DataURI failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "datauri") { +// t.Fatalf("Index: %d DataURI failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestMultibyteValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", true}, +// {"abc", false}, +// {"123", false}, +// {"<>@;.-=", false}, +// {"ひらがな・カタカナ、.漢字", true}, +// {"あいうえお foobar", true}, +// {"test@example.com", true}, +// {"test@example.com", true}, +// {"1234abcDExyz", true}, +// {"カタカナ", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "multibyte") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d Multibyte failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "multibyte") { +// t.Fatalf("Index: %d Multibyte failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestPrintableASCIIValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", true}, +// {"foobar", false}, +// {"xyz098", false}, +// {"123456", false}, +// {"カタカナ", false}, +// {"foobar", true}, +// {"0987654321", true}, +// {"test@example.com", true}, +// {"1234abcDEF", true}, +// {"newline\n", false}, +// {"\x19test\x7F", false}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "printascii") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "printascii") { +// t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestASCIIValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", true}, +// {"foobar", false}, +// {"xyz098", false}, +// {"123456", false}, +// {"カタカナ", false}, +// {"foobar", true}, +// {"0987654321", true}, +// {"test@example.com", true}, +// {"1234abcDEF", true}, +// {"", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "ascii") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d ASCII failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ascii") { +// t.Fatalf("Index: %d ASCII failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestUUID5Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ + +// {"", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"9c858901-8a57-4791-81fe-4c455b099bc9", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"987fbc97-4bed-5078-af07-9141ba07c9f3", true}, +// {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "uuid5") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d UUID5 failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid5") { +// t.Fatalf("Index: %d UUID5 failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestUUID4Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false}, +// {"934859", false}, +// {"57b73598-8764-4ad0-a76a-679bb6640eb1", true}, +// {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "uuid4") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d UUID4 failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid4") { +// t.Fatalf("Index: %d UUID4 failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestUUID3Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"412452646", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "uuid3") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d UUID3 failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid3") { +// t.Fatalf("Index: %d UUID3 failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestUUIDValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, +// {"a987fbc94bed3078cf079141ba07c9f3", false}, +// {"934859", false}, +// {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, +// {"aaaaaaaa-1111-1111-aaag-111111111111", false}, +// {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "uuid") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d UUID failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid") { +// t.Fatalf("Index: %d UUID failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestISBNValidation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"foo", false}, +// {"3836221195", true}, +// {"1-61729-085-8", true}, +// {"3 423 21412 0", true}, +// {"3 401 01319 X", true}, +// {"9784873113685", true}, +// {"978-4-87311-368-5", true}, +// {"978 3401013190", true}, +// {"978-3-8362-2119-1", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "isbn") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d ISBN failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn") { +// t.Fatalf("Index: %d ISBN failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestISBN13Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"foo", false}, +// {"3-8362-2119-5", false}, +// {"01234567890ab", false}, +// {"978 3 8362 2119 0", false}, +// {"9784873113685", true}, +// {"978-4-87311-368-5", true}, +// {"978 3401013190", true}, +// {"978-3-8362-2119-1", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "isbn13") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d ISBN13 failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn13") { +// t.Fatalf("Index: %d ISBN13 failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestISBN10Validation(t *testing.T) { +// tests := []struct { +// param string +// expected bool +// }{ +// {"", false}, +// {"foo", false}, +// {"3423214121", false}, +// {"978-3836221191", false}, +// {"3-423-21412-1", false}, +// {"3 423 21412 1", false}, +// {"3836221195", true}, +// {"1-61729-085-8", true}, +// {"3 423 21412 0", true}, +// {"3 401 01319 X", true}, +// } + +// for i, test := range tests { + +// err := validate.Field(test.param, "isbn10") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d ISBN10 failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn10") { +// t.Fatalf("Index: %d ISBN10 failed Error: %s", i, err) +// } +// } +// } +// } + +// func TestExcludesRuneValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"excludesrune=☻"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "a☺b☻c☹d", Tag: "excludesrune=☻", ExpectedNil: false}, +// {Value: "abcd", Tag: "excludesrune=☻", ExpectedNil: true}, +// } + +// for i, s := range tests { +// err := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, err) +// } + +// errs := validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestExcludesAllValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"excludesall=@!{}[]"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "excludesall=@!{}[]", ExpectedNil: false}, +// {Value: "abcdefg", Tag: "excludesall=@!{}[]", ExpectedNil: true}, +// } + +// for i, s := range tests { +// err := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, err) +// } + +// errs := validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } + +// username := "joeybloggs " + +// err := validate.Field(username, "excludesall=@ ") +// NotEqual(t, err, nil) + +// excluded := "," + +// err = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C?") +// NotEqual(t, err, nil) + +// excluded = "=" + +// err = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C=?") +// NotEqual(t, err, nil) +// } + +// func TestExcludesValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"excludes=@"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "excludes=@", ExpectedNil: false}, +// {Value: "abcdq!jfk", Tag: "excludes=@", ExpectedNil: true}, +// } + +// for i, s := range tests { +// err := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, err) +// } + +// errs := validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestContainsRuneValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"containsrune=☻"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "a☺b☻c☹d", Tag: "containsrune=☻", ExpectedNil: true}, +// {Value: "abcd", Tag: "containsrune=☻", ExpectedNil: false}, +// } + +// for i, s := range tests { +// err := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, err) +// } - errs = validate.Struct(mt) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldError = errs.Errors["Errs"] - Equal(t, fieldError.IsPlaceholderErr, true) - Equal(t, fieldError.IsMap, true) - Equal(t, len(fieldError.MapErrs), 2) - - innerErr, ok = fieldError.MapErrs[3].(*FieldError) - Equal(t, ok, true) - Equal(t, innerErr.IsPlaceholderErr, false) - Equal(t, innerErr.IsMap, false) - Equal(t, len(innerErr.MapErrs), 0) - Equal(t, innerErr.Field, "Errs[3]") - Equal(t, innerErr.Tag, "required") - - type TestMapStructPtr struct { - Errs map[int]*Inner `validate:"gt=0,dive,required"` - } +// errs := validate.Struct(s) - mip := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestContainsAnyValidation(t *testing.T) { + +// tests := []struct { +// Value string `validate:"containsany=@!{}[]"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "containsany=@!{}[]", ExpectedNil: true}, +// {Value: "abcdefg", Tag: "containsany=@!{}[]", ExpectedNil: false}, +// } + +// for i, s := range tests { +// err := validate.Field(s.Value, s.Tag) - msp := &TestMapStructPtr{ - Errs: mip, - } +// if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, err) +// } - errs = validate.Struct(msp) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldError = errs.Errors["Errs"] - Equal(t, fieldError.IsPlaceholderErr, true) - Equal(t, fieldError.IsMap, true) - Equal(t, len(fieldError.MapErrs), 1) - - innerFieldError, ok := fieldError.MapErrs[3].(*FieldError) - Equal(t, ok, true) - Equal(t, innerFieldError.IsPlaceholderErr, false) - Equal(t, innerFieldError.IsMap, false) - Equal(t, len(innerFieldError.MapErrs), 0) - Equal(t, innerFieldError.Field, "Errs[3]") - Equal(t, innerFieldError.Tag, "required") - - type TestMapStructPtr2 struct { - Errs map[int]*Inner `validate:"gt=0,dive,omitempty,required"` - } +// errs := validate.Struct(s) - mip2 := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}} +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } - msp2 := &TestMapStructPtr2{ - Errs: mip2, - } +// func TestContainsValidation(t *testing.T) { - errs = validate.Struct(msp2) - Equal(t, errs, nil) -} +// tests := []struct { +// Value string `validate:"contains=@"` +// Tag string +// ExpectedNil bool +// }{ +// {Value: "abcd@!jfk", Tag: "contains=@", ExpectedNil: true}, +// {Value: "abcdq!jfk", Tag: "contains=@", ExpectedNil: false}, +// } -func TestArrayDiveValidation(t *testing.T) { +// for i, s := range tests { +// err := validate.Field(s.Value, s.Tag) + +// if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, err) +// } + +// errs := validate.Struct(s) + +// if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { +// t.Fatalf("Index: %d failed Error: %s", i, errs) +// } +// } +// } + +// func TestIsNeFieldValidation(t *testing.T) { + +// var j uint64 +// var k float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} +// now := time.Now().UTC() + +// var j2 uint64 +// var k2 float64 +// s2 := "abcdef" +// i2 := 3 +// j2 = 2 +// k2 = 1.5434456 +// arr2 := []string{"test", "test2"} +// arr3 := []string{"test"} +// now2 := now - arr := []string{"ok", "", "ok"} +// err := validate.FieldWithValue(s, s2, "nefield") +// Equal(t, err, nil) + +// err = validate.FieldWithValue(i2, i, "nefield") +// Equal(t, err, nil) + +// err = validate.FieldWithValue(j2, j, "nefield") +// Equal(t, err, nil) + +// err = validate.FieldWithValue(k2, k, "nefield") +// Equal(t, err, nil) + +// err = validate.FieldWithValue(arr2, arr, "nefield") +// Equal(t, err, nil) + +// err = validate.FieldWithValue(now2, now, "nefield") +// NotEqual(t, err, nil) + +// err = validate.FieldWithValue(arr3, arr, "nefield") +// NotEqual(t, err, nil) + +// type Test struct { +// Start *time.Time `validate:"nefield=End"` +// End *time.Time +// } + +// sv := &Test{ +// Start: &now, +// End: &now, +// } + +// errs := validate.Struct(sv) +// NotEqual(t, errs, nil) - err := validate.Field(arr, "len=3,dive,required") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, true) - Equal(t, err.IsSliceOrArray, true) - Equal(t, len(err.SliceOrArrayErrs), 1) +// now3 := time.Now().UTC() - // flat := err.Flatten() - // fe, ok := flat["[1]"] - // Equal(t, ok, true) - // Equal(t, fe.Tag, "required") +// sv = &Test{ +// Start: &now, +// End: &now3, +// } - err = validate.Field(arr, "len=2,dive,required") - NotEqual(t, err, nil) - Equal(t, err.IsPlaceholderErr, false) - Equal(t, err.IsSliceOrArray, false) - Equal(t, len(err.SliceOrArrayErrs), 0) +// errs = validate.Struct(sv) +// Equal(t, errs, nil) - type BadDive struct { - Name string `validate:"dive"` - } +// channel := make(chan string) + +// PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "nefield") }, "struct not passed for cross validation") +// PanicMatches(t, func() { validate.FieldWithValue(5, channel, "nefield") }, "Bad field type chan string") +// PanicMatches(t, func() { validate.FieldWithValue(5, now, "nefield") }, "Bad Top Level field type") - bd := &BadDive{ - Name: "TEST", - } +// type Test2 struct { +// Start *time.Time `validate:"nefield=NonExistantField"` +// End *time.Time +// } - PanicMatches(t, func() { validate.Struct(bd) }, "dive error! can't dive on a non slice or map") +// sv2 := &Test2{ +// Start: &now, +// End: &now, +// } - type Test struct { - Errs []string `validate:"gt=0,dive,required"` - } +// PanicMatches(t, func() { validate.Struct(sv2) }, "Field \"NonExistantField\" not found in struct") +// } - test := &Test{ - Errs: []string{"ok", "", "ok"}, - } +// func TestIsNeValidation(t *testing.T) { - errs := validate.Struct(test) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - // flat = errs.Flatten() - // me, ok := flat["Errs[1]"] - // Equal(t, ok, true) - // Equal(t, me.Field, "Errs[1]") - // Equal(t, me.Tag, "required") - - fieldErr, ok := errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 1) - - innerErr, ok := fieldErr.SliceOrArrayErrs[1].(*FieldError) - Equal(t, ok, true) - Equal(t, innerErr.Tag, required) - Equal(t, innerErr.IsPlaceholderErr, false) - Equal(t, innerErr.Field, "Errs[1]") - - test = &Test{ - Errs: []string{"ok", "ok", ""}, - } +// var j uint64 +// var k float64 +// s := "abcdef" +// i := 3 +// j = 2 +// k = 1.5434 +// arr := []string{"test"} +// now := time.Now().UTC() - errs = validate.Struct(test) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) +// err := validate.Field(s, "ne=abcd") +// Equal(t, err, nil) - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 1) +// err = validate.Field(i, "ne=1") +// Equal(t, err, nil) - innerErr, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) - Equal(t, ok, true) - Equal(t, innerErr.Tag, required) - Equal(t, innerErr.IsPlaceholderErr, false) - Equal(t, innerErr.Field, "Errs[2]") +// err = validate.Field(j, "ne=1") +// Equal(t, err, nil) - type TestMultiDimensional struct { - Errs [][]string `validate:"gt=0,dive,dive,required"` - } +// err = validate.Field(k, "ne=1.543") +// Equal(t, err, nil) - var errArray [][]string +// err = validate.Field(arr, "ne=2") +// Equal(t, err, nil) - errArray = append(errArray, []string{"ok", "", ""}) - errArray = append(errArray, []string{"ok", "", ""}) +// err = validate.Field(arr, "ne=1") +// NotEqual(t, err, nil) - tm := &TestMultiDimensional{ - Errs: errArray, - } +// PanicMatches(t, func() { validate.Field(now, "ne=now") }, "Bad field type time.Time") +// } - errs = validate.Struct(tm) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 2) - - sliceError1, ok := fieldErr.SliceOrArrayErrs[0].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - Equal(t, sliceError1.Field, "Errs[0]") - - innerSliceError1, ok := sliceError1.SliceOrArrayErrs[1].(*FieldError) - Equal(t, ok, true) - Equal(t, innerSliceError1.IsPlaceholderErr, false) - Equal(t, innerSliceError1.Tag, required) - Equal(t, innerSliceError1.IsSliceOrArray, false) - Equal(t, len(innerSliceError1.SliceOrArrayErrs), 0) - Equal(t, innerSliceError1.Field, "Errs[0][1]") - - type Inner struct { - Name string `validate:"required"` - } +// func TestIsEqFieldValidation(t *testing.T) { - type TestMultiDimensionalStructs struct { - Errs [][]Inner `validate:"gt=0,dive,dive"` - } +// var j uint64 +// var k float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} +// now := time.Now().UTC() - var errStructArray [][]Inner +// var j2 uint64 +// var k2 float64 +// s2 := "abcd" +// i2 := 1 +// j2 = 1 +// k2 = 1.543 +// arr2 := []string{"test"} +// arr3 := []string{"test", "test2"} +// now2 := now - errStructArray = append(errStructArray, []Inner{Inner{"ok"}, Inner{""}, Inner{""}}) - errStructArray = append(errStructArray, []Inner{Inner{"ok"}, Inner{""}, Inner{""}}) +// err := validate.FieldWithValue(s, s2, "eqfield") +// Equal(t, err, nil) - tms := &TestMultiDimensionalStructs{ - Errs: errStructArray, - } +// err = validate.FieldWithValue(i2, i, "eqfield") +// Equal(t, err, nil) - errs = validate.Struct(tms) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 2) - - sliceError1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceStructError1, ok := sliceError1.SliceOrArrayErrs[1].(*StructErrors) - Equal(t, ok, true) - Equal(t, len(innerSliceStructError1.Errors), 1) - - innerInnersliceError1 := innerSliceStructError1.Errors["Name"] - Equal(t, innerInnersliceError1.IsPlaceholderErr, false) - Equal(t, innerInnersliceError1.IsSliceOrArray, false) - Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) - - type TestMultiDimensionalStructsPtr struct { - Errs [][]*Inner `validate:"gt=0,dive,dive"` - } +// err = validate.FieldWithValue(j2, j, "eqfield") +// Equal(t, err, nil) - var errStructPtrArray [][]*Inner +// err = validate.FieldWithValue(k2, k, "eqfield") +// Equal(t, err, nil) - errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) +// err = validate.FieldWithValue(arr2, arr, "eqfield") +// Equal(t, err, nil) - tmsp := &TestMultiDimensionalStructsPtr{ - Errs: errStructPtrArray, - } +// err = validate.FieldWithValue(now2, now, "eqfield") +// Equal(t, err, nil) - errs = validate.Struct(tmsp) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - // for full test coverage - fmt.Sprint(errs.Error()) - - // flat := errs.Flatten() - // // fmt.Println(errs) - // fmt.Println(flat) - // expect Errs[0][1].Inner.Name - // me, ok := flat["Errs[1]"] - // Equal(t, ok, true) - // Equal(t, me.Field, "Errs[1]") - // Equal(t, me.Tag, "required") - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 3) - - // flat := fieldErr.Flatten() - // fmt.Println(errs) - // fmt.Println(flat) - - sliceError1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) - Equal(t, ok, true) - Equal(t, len(innerSliceStructError1.Errors), 1) - - innerInnersliceError1 = innerSliceStructError1.Errors["Name"] - Equal(t, innerInnersliceError1.IsPlaceholderErr, false) - Equal(t, innerInnersliceError1.IsSliceOrArray, false) - Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) - - type TestMultiDimensionalStructsPtr2 struct { - Errs [][]*Inner `validate:"gt=0,dive,dive,required"` - } +// err = validate.FieldWithValue(arr3, arr, "eqfield") +// NotEqual(t, err, nil) - var errStructPtr2Array [][]*Inner +// type Test struct { +// Start *time.Time `validate:"eqfield=End"` +// End *time.Time +// } - errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) +// sv := &Test{ +// Start: &now, +// End: &now, +// } - tmsp2 := &TestMultiDimensionalStructsPtr2{ - Errs: errStructPtr2Array, - } +// errs := validate.Struct(sv) +// Equal(t, errs, nil) - errs = validate.Struct(tmsp2) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 3) - - sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) - Equal(t, ok, true) - Equal(t, len(innerSliceStructError1.Errors), 1) - - innerSliceStructError2, ok := sliceError1.SliceOrArrayErrs[2].(*FieldError) - Equal(t, ok, true) - Equal(t, innerSliceStructError2.IsPlaceholderErr, false) - Equal(t, innerSliceStructError2.IsSliceOrArray, false) - Equal(t, len(innerSliceStructError2.SliceOrArrayErrs), 0) - Equal(t, innerSliceStructError2.Field, "Errs[2][2]") - - innerInnersliceError1 = innerSliceStructError1.Errors["Name"] - Equal(t, innerInnersliceError1.IsPlaceholderErr, false) - Equal(t, innerInnersliceError1.IsSliceOrArray, false) - Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) - - type TestMultiDimensionalStructsPtr3 struct { - Errs [][]*Inner `validate:"gt=0,dive,dive,omitempty"` - } +// now3 := time.Now().UTC() - var errStructPtr3Array [][]*Inner +// sv = &Test{ +// Start: &now, +// End: &now3, +// } - errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}}) - errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil}) +// errs = validate.Struct(sv) +// NotEqual(t, errs, nil) - tmsp3 := &TestMultiDimensionalStructsPtr3{ - Errs: errStructPtr3Array, - } +// channel := make(chan string) - errs = validate.Struct(tmsp3) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 3) - - sliceError1, ok = fieldErr.SliceOrArrayErrs[0].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceStructError1, ok = sliceError1.SliceOrArrayErrs[1].(*StructErrors) - Equal(t, ok, true) - Equal(t, len(innerSliceStructError1.Errors), 1) - - innerInnersliceError1 = innerSliceStructError1.Errors["Name"] - Equal(t, innerInnersliceError1.IsPlaceholderErr, false) - Equal(t, innerInnersliceError1.IsSliceOrArray, false) - Equal(t, len(innerInnersliceError1.SliceOrArrayErrs), 0) - - type TestMultiDimensionalTimeTime struct { - Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` - } +// PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "eqfield") }, "struct not passed for cross validation") +// PanicMatches(t, func() { validate.FieldWithValue(5, channel, "eqfield") }, "Bad field type chan string") +// PanicMatches(t, func() { validate.FieldWithValue(5, now, "eqfield") }, "Bad Top Level field type") - var errTimePtr3Array [][]*time.Time +// type Test2 struct { +// Start *time.Time `validate:"eqfield=NonExistantField"` +// End *time.Time +// } - t1 := time.Now().UTC() - t2 := time.Now().UTC() - t3 := time.Now().UTC().Add(time.Hour * 24) +// sv2 := &Test2{ +// Start: &now, +// End: &now, +// } - errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, &t3}) - errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, &t2, nil}) - errTimePtr3Array = append(errTimePtr3Array, []*time.Time{&t1, nil, nil}) +// PanicMatches(t, func() { validate.Struct(sv2) }, "Field \"NonExistantField\" not found in struct") +// } - tmtp3 := &TestMultiDimensionalTimeTime{ - Errs: errTimePtr3Array, - } +// func TestIsEqValidation(t *testing.T) { - errs = validate.Struct(tmtp3) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 2) - - sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceError1, ok = sliceError1.SliceOrArrayErrs[1].(*FieldError) - Equal(t, ok, true) - Equal(t, innerSliceError1.IsPlaceholderErr, false) - Equal(t, innerSliceError1.IsSliceOrArray, false) - Equal(t, len(innerSliceError1.SliceOrArrayErrs), 0) - Equal(t, innerSliceError1.Field, "Errs[2][1]") - Equal(t, innerSliceError1.Tag, required) - - type TestMultiDimensionalTimeTime2 struct { - Errs [][]*time.Time `validate:"gt=0,dive,dive,required"` - } +// var j uint64 +// var k float64 +// s := "abcd" +// i := 1 +// j = 1 +// k = 1.543 +// arr := []string{"test"} +// now := time.Now().UTC() - var errTimeArray [][]*time.Time +// err := validate.Field(s, "eq=abcd") +// Equal(t, err, nil) - t1 = time.Now().UTC() - t2 = time.Now().UTC() - t3 = time.Now().UTC().Add(time.Hour * 24) +// err = validate.Field(i, "eq=1") +// Equal(t, err, nil) - errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, &t3}) - errTimeArray = append(errTimeArray, []*time.Time{&t1, &t2, nil}) - errTimeArray = append(errTimeArray, []*time.Time{&t1, nil, nil}) +// err = validate.Field(j, "eq=1") +// Equal(t, err, nil) - tmtp := &TestMultiDimensionalTimeTime2{ - Errs: errTimeArray, - } +// err = validate.Field(k, "eq=1.543") +// Equal(t, err, nil) - errs = validate.Struct(tmtp) - NotEqual(t, errs, nil) - Equal(t, len(errs.Errors), 1) - - fieldErr, ok = errs.Errors["Errs"] - Equal(t, ok, true) - Equal(t, fieldErr.IsPlaceholderErr, true) - Equal(t, fieldErr.IsSliceOrArray, true) - Equal(t, len(fieldErr.SliceOrArrayErrs), 2) - - sliceError1, ok = fieldErr.SliceOrArrayErrs[2].(*FieldError) - Equal(t, ok, true) - Equal(t, sliceError1.IsPlaceholderErr, true) - Equal(t, sliceError1.IsSliceOrArray, true) - Equal(t, len(sliceError1.SliceOrArrayErrs), 2) - - innerSliceError1, ok = sliceError1.SliceOrArrayErrs[1].(*FieldError) - Equal(t, ok, true) - Equal(t, innerSliceError1.IsPlaceholderErr, false) - Equal(t, innerSliceError1.IsSliceOrArray, false) - Equal(t, len(innerSliceError1.SliceOrArrayErrs), 0) - Equal(t, innerSliceError1.Field, "Errs[2][1]") - Equal(t, innerSliceError1.Tag, required) -} +// err = validate.Field(arr, "eq=1") +// Equal(t, err, nil) -func TestNilStructPointerValidation(t *testing.T) { - type Inner struct { - Data string - } +// err = validate.Field(arr, "eq=2") +// NotEqual(t, err, nil) - type Outer struct { - Inner *Inner `validate:"omitempty"` - } +// PanicMatches(t, func() { validate.Field(now, "eq=now") }, "Bad field type time.Time") +// } - inner := &Inner{ - Data: "test", - } +// func TestBase64Validation(t *testing.T) { - outer := &Outer{ - Inner: inner, - } +// s := "dW5pY29ybg==" - errs := validate.Struct(outer) - Equal(t, errs, nil) +// err := validate.Field(s, "base64") +// Equal(t, err, nil) - outer = &Outer{ - Inner: nil, - } +// s = "dGhpIGlzIGEgdGVzdCBiYXNlNjQ=" +// err = validate.Field(s, "base64") +// Equal(t, err, nil) - errs = validate.Struct(outer) - Equal(t, errs, nil) +// s = "" +// err = validate.Field(s, "base64") +// NotEqual(t, err, nil) - type Inner2 struct { - Data string - } +// s = "dW5pY29ybg== foo bar" +// err = validate.Field(s, "base64") +// NotEqual(t, err, nil) +// } - type Outer2 struct { - Inner2 *Inner2 `validate:"required"` - } +// func TestStructOnlyValidation(t *testing.T) { - inner2 := &Inner2{ - Data: "test", - } +// type Inner struct { +// Test string `validate:"len=5"` +// } - outer2 := &Outer2{ - Inner2: inner2, - } +// type Outer struct { +// InnerStruct *Inner `validate:"required,structonly"` +// } - errs = validate.Struct(outer2) - Equal(t, errs, nil) +// outer := &Outer{ +// InnerStruct: nil, +// } - outer2 = &Outer2{ - Inner2: nil, - } +// errs := validate.Struct(outer) +// NotEqual(t, errs, nil) - errs = validate.Struct(outer2) - NotEqual(t, errs, nil) +// inner := &Inner{ +// Test: "1234", +// } - type Inner3 struct { - Data string - } +// outer = &Outer{ +// InnerStruct: inner, +// } - type Outer3 struct { - Inner3 *Inner3 - } +// errs = validate.Struct(outer) +// Equal(t, errs, nil) +// } - inner3 := &Inner3{ - Data: "test", - } +// func TestGtField(t *testing.T) { - outer3 := &Outer3{ - Inner3: inner3, - } +// type TimeTest struct { +// Start *time.Time `validate:"required,gt"` +// End *time.Time `validate:"required,gt,gtfield=Start"` +// } - errs = validate.Struct(outer3) - Equal(t, errs, nil) +// now := time.Now() +// start := now.Add(time.Hour * 24) +// end := start.Add(time.Hour * 24) - type Inner4 struct { - Data string - } +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } - type Outer4 struct { - Inner4 *Inner4 `validate:"-"` - } +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) - inner4 := &Inner4{ - Data: "test", - } +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } - outer4 := &Outer4{ - Inner4: inner4, - } +// errs2 := validate.Struct(timeTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "End", "gtfield") - errs = validate.Struct(outer4) - Equal(t, errs, nil) -} +// err3 := validate.FieldWithValue(&start, &end, "gtfield") +// Equal(t, err3, nil) -func TestSSNValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"00-90-8787", false}, - {"66690-76", false}, - {"191 60 2869", true}, - {"191-60-2869", true}, - } +// err3 = validate.FieldWithValue(&end, &start, "gtfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtfield") - for i, test := range tests { +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,gtfield=Val1"` +// } - err := validate.Field(test.param, "ssn") +// intTest := &IntTest{ +// Val1: 1, +// Val2: 5, +// } - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d SSN failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ssn") { - t.Fatalf("Index: %d SSN failed Error: %s", i, err) - } - } - } -} +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) -func TestLongitudeValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"-180.000", true}, - {"180.1", false}, - {"+73.234", true}, - {"+382.3811", false}, - {"23.11111111", true}, - } +// intTest = &IntTest{ +// Val1: 5, +// Val2: 1, +// } - for i, test := range tests { +// errs2 = validate.Struct(intTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "gtfield") - err := validate.Field(test.param, "longitude") +// err3 = validate.FieldWithValue(int(1), int(5), "gtfield") +// Equal(t, err3, nil) - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d Longitude failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "longitude") { - t.Fatalf("Index: %d Longitude failed Error: %s", i, err) - } - } - } -} +// err3 = validate.FieldWithValue(int(5), int(1), "gtfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtfield") -func TestLatitudeValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"-90.000", true}, - {"+90", true}, - {"47.1231231", true}, - {"+99.9", false}, - {"108", false}, - } +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,gtfield=Val1"` +// } - for i, test := range tests { +// uIntTest := &UIntTest{ +// Val1: 1, +// Val2: 5, +// } - err := validate.Field(test.param, "latitude") +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d Latitude failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "latitude") { - t.Fatalf("Index: %d Latitude failed Error: %s", i, err) - } - } - } -} +// uIntTest = &UIntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs2 = validate.Struct(uIntTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "gtfield") + +// err3 = validate.FieldWithValue(uint(1), uint(5), "gtfield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(uint(5), uint(1), "gtfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtfield") + +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,gtfield=Val1"` +// } + +// floatTest := &FloatTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) + +// floatTest = &FloatTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs2 = validate.Struct(floatTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "gtfield") + +// err3 = validate.FieldWithValue(float32(1), float32(5), "gtfield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(float32(5), float32(1), "gtfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtfield") + +// PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "gtfield") }, "struct not passed for cross validation") +// PanicMatches(t, func() { validate.FieldWithValue(5, "T", "gtfield") }, "Bad field type string") +// PanicMatches(t, func() { validate.FieldWithValue(5, start, "gtfield") }, "Bad Top Level field type") + +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,gtfield=NonExistantField"` +// } + +// timeTest2 := &TimeTest2{ +// Start: &start, +// End: &end, +// } + +// PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") +// } + +// func TestLtField(t *testing.T) { + +// type TimeTest struct { +// Start *time.Time `validate:"required,lt,ltfield=End"` +// End *time.Time `validate:"required,lt"` +// } + +// now := time.Now() +// start := now.Add(time.Hour * 24 * -1 * 2) +// end := start.Add(time.Hour * 24) + +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } + +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) + +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } + +// errs2 := validate.Struct(timeTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Start", "ltfield") + +// err3 := validate.FieldWithValue(&end, &start, "ltfield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(&start, &end, "ltfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltfield") + +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,ltfield=Val1"` +// } + +// intTest := &IntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) + +// intTest = &IntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs2 = validate.Struct(intTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "ltfield") + +// err3 = validate.FieldWithValue(int(5), int(1), "ltfield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(int(1), int(5), "ltfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltfield") -func TestDataURIValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, - {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, - {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, - {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + - "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + - "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + - "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + - "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + - "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, - {"data:image/png;base64,12345", false}, - {"", false}, - {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, - } +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,ltfield=Val1"` +// } + +// uIntTest := &UIntTest{ +// Val1: 5, +// Val2: 1, +// } - for i, test := range tests { +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) + +// uIntTest = &UIntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs2 = validate.Struct(uIntTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "ltfield") + +// err3 = validate.FieldWithValue(uint(5), uint(1), "ltfield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(uint(1), uint(5), "ltfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltfield") + +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,ltfield=Val1"` +// } + +// floatTest := &FloatTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) + +// floatTest = &FloatTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs2 = validate.Struct(floatTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "ltfield") + +// err3 = validate.FieldWithValue(float32(5), float32(1), "ltfield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(float32(1), float32(5), "ltfield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltfield") + +// PanicMatches(t, func() { validate.FieldWithValue(nil, 5, "ltfield") }, "struct not passed for cross validation") +// PanicMatches(t, func() { validate.FieldWithValue(1, "T", "ltfield") }, "Bad field type string") +// PanicMatches(t, func() { validate.FieldWithValue(1, end, "ltfield") }, "Bad Top Level field type") + +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,ltfield=NonExistantField"` +// } + +// timeTest2 := &TimeTest2{ +// Start: &end, +// End: &start, +// } + +// PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") +// } + +// func TestLteField(t *testing.T) { + +// type TimeTest struct { +// Start *time.Time `validate:"required,lte,ltefield=End"` +// End *time.Time `validate:"required,lte"` +// } + +// now := time.Now() +// start := now.Add(time.Hour * 24 * -1 * 2) +// end := start.Add(time.Hour * 24) + +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } + +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) + +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } + +// errs2 := validate.Struct(timeTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Start", "ltefield") + +// err3 := validate.FieldWithValue(&end, &start, "ltefield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(&start, &end, "ltefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltefield") + +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,ltefield=Val1"` +// } + +// intTest := &IntTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) + +// intTest = &IntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs2 = validate.Struct(intTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "ltefield") + +// err3 = validate.FieldWithValue(int(5), int(1), "ltefield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(int(1), int(5), "ltefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltefield") - err := validate.Field(test.param, "datauri") +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,ltefield=Val1"` +// } + +// uIntTest := &UIntTest{ +// Val1: 5, +// Val2: 1, +// } - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d DataURI failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "datauri") { - t.Fatalf("Index: %d DataURI failed Error: %s", i, err) - } - } - } -} +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) + +// uIntTest = &UIntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs2 = validate.Struct(uIntTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "ltefield") + +// err3 = validate.FieldWithValue(uint(5), uint(1), "ltefield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(uint(1), uint(5), "ltefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltefield") + +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,ltefield=Val1"` +// } + +// floatTest := &FloatTest{ +// Val1: 5, +// Val2: 1, +// } + +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) + +// floatTest = &FloatTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs2 = validate.Struct(floatTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "ltefield") + +// err3 = validate.FieldWithValue(float32(5), float32(1), "ltefield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(float32(1), float32(5), "ltefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "ltefield") + +// PanicMatches(t, func() { validate.FieldWithValue(nil, 5, "ltefield") }, "struct not passed for cross validation") +// PanicMatches(t, func() { validate.FieldWithValue(1, "T", "ltefield") }, "Bad field type string") +// PanicMatches(t, func() { validate.FieldWithValue(1, end, "ltefield") }, "Bad Top Level field type") + +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,ltefield=NonExistantField"` +// } + +// timeTest2 := &TimeTest2{ +// Start: &end, +// End: &start, +// } + +// PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") +// } + +// func TestGteField(t *testing.T) { + +// type TimeTest struct { +// Start *time.Time `validate:"required,gte"` +// End *time.Time `validate:"required,gte,gtefield=Start"` +// } + +// now := time.Now() +// start := now.Add(time.Hour * 24) +// end := start.Add(time.Hour * 24) + +// timeTest := &TimeTest{ +// Start: &start, +// End: &end, +// } + +// errs := validate.Struct(timeTest) +// Equal(t, errs, nil) + +// timeTest = &TimeTest{ +// Start: &end, +// End: &start, +// } + +// errs2 := validate.Struct(timeTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "End", "gtefield") + +// err3 := validate.FieldWithValue(&start, &end, "gtefield") +// Equal(t, err3, nil) + +// err3 = validate.FieldWithValue(&end, &start, "gtefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtefield") + +// type IntTest struct { +// Val1 int `validate:"required"` +// Val2 int `validate:"required,gtefield=Val1"` +// } + +// intTest := &IntTest{ +// Val1: 1, +// Val2: 5, +// } + +// errs = validate.Struct(intTest) +// Equal(t, errs, nil) -func TestMultibyteValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", true}, - {"abc", false}, - {"123", false}, - {"<>@;.-=", false}, - {"ひらがな・カタカナ、.漢字", true}, - {"あいうえお foobar", true}, - {"test@example.com", true}, - {"test@example.com", true}, - {"1234abcDExyz", true}, - {"カタカナ", true}, - } +// intTest = &IntTest{ +// Val1: 5, +// Val2: 1, +// } - for i, test := range tests { +// errs2 = validate.Struct(intTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "gtefield") - err := validate.Field(test.param, "multibyte") +// err3 = validate.FieldWithValue(int(1), int(5), "gtefield") +// Equal(t, err3, nil) - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d Multibyte failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "multibyte") { - t.Fatalf("Index: %d Multibyte failed Error: %s", i, err) - } - } - } -} +// err3 = validate.FieldWithValue(int(5), int(1), "gtefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtefield") -func TestPrintableASCIIValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", true}, - {"foobar", false}, - {"xyz098", false}, - {"123456", false}, - {"カタカナ", false}, - {"foobar", true}, - {"0987654321", true}, - {"test@example.com", true}, - {"1234abcDEF", true}, - {"newline\n", false}, - {"\x19test\x7F", false}, - } +// type UIntTest struct { +// Val1 uint `validate:"required"` +// Val2 uint `validate:"required,gtefield=Val1"` +// } - for i, test := range tests { +// uIntTest := &UIntTest{ +// Val1: 1, +// Val2: 5, +// } - err := validate.Field(test.param, "printascii") +// errs = validate.Struct(uIntTest) +// Equal(t, errs, nil) - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "printascii") { - t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, err) - } - } - } -} +// uIntTest = &UIntTest{ +// Val1: 5, +// Val2: 1, +// } -func TestASCIIValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", true}, - {"foobar", false}, - {"xyz098", false}, - {"123456", false}, - {"カタカナ", false}, - {"foobar", true}, - {"0987654321", true}, - {"test@example.com", true}, - {"1234abcDEF", true}, - {"", true}, - } +// errs2 = validate.Struct(uIntTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "gtefield") - for i, test := range tests { +// err3 = validate.FieldWithValue(uint(1), uint(5), "gtefield") +// Equal(t, err3, nil) - err := validate.Field(test.param, "ascii") +// err3 = validate.FieldWithValue(uint(5), uint(1), "gtefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtefield") - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d ASCII failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "ascii") { - t.Fatalf("Index: %d ASCII failed Error: %s", i, err) - } - } - } -} +// type FloatTest struct { +// Val1 float64 `validate:"required"` +// Val2 float64 `validate:"required,gtefield=Val1"` +// } -func TestUUID5Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - - {"", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"9c858901-8a57-4791-81fe-4c455b099bc9", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"987fbc97-4bed-5078-af07-9141ba07c9f3", true}, - {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true}, - } +// floatTest := &FloatTest{ +// Val1: 1, +// Val2: 5, +// } - for i, test := range tests { +// errs = validate.Struct(floatTest) +// Equal(t, errs, nil) - err := validate.Field(test.param, "uuid5") +// floatTest = &FloatTest{ +// Val1: 5, +// Val2: 1, +// } - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d UUID5 failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid5") { - t.Fatalf("Index: %d UUID5 failed Error: %s", i, err) - } - } - } -} +// errs2 = validate.Struct(floatTest).Flatten() +// NotEqual(t, errs2, nil) +// AssertMapFieldError(t, errs2, "Val2", "gtefield") -func TestUUID4Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false}, - {"934859", false}, - {"57b73598-8764-4ad0-a76a-679bb6640eb1", true}, - {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true}, - } +// err3 = validate.FieldWithValue(float32(1), float32(5), "gtefield") +// Equal(t, err3, nil) - for i, test := range tests { +// err3 = validate.FieldWithValue(float32(5), float32(1), "gtefield") +// NotEqual(t, err3, nil) +// Equal(t, err3.Tag, "gtefield") - err := validate.Field(test.param, "uuid4") +// PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "gtefield") }, "struct not passed for cross validation") +// PanicMatches(t, func() { validate.FieldWithValue(5, "T", "gtefield") }, "Bad field type string") +// PanicMatches(t, func() { validate.FieldWithValue(5, start, "gtefield") }, "Bad Top Level field type") - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d UUID4 failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid4") { - t.Fatalf("Index: %d UUID4 failed Error: %s", i, err) - } - } - } -} +// type TimeTest2 struct { +// Start *time.Time `validate:"required"` +// End *time.Time `validate:"required,gtefield=NonExistantField"` +// } -func TestUUID3Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"412452646", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, - } +// timeTest2 := &TimeTest2{ +// Start: &start, +// End: &end, +// } - for i, test := range tests { +// PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") +// } - err := validate.Field(test.param, "uuid3") +// func TestValidateByTagAndValue(t *testing.T) { - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d UUID3 failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid3") { - t.Fatalf("Index: %d UUID3 failed Error: %s", i, err) - } - } - } -} +// val := "test" +// field := "test" +// err := validate.FieldWithValue(val, field, "required") +// Equal(t, err, nil) -func TestUUIDValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, - {"a987fbc94bed3078cf079141ba07c9f3", false}, - {"934859", false}, - {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, - {"aaaaaaaa-1111-1111-aaag-111111111111", false}, - {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, - } +// fn := func(val interface{}, current interface{}, field interface{}, param string) bool { - for i, test := range tests { +// return current.(string) == field.(string) +// } - err := validate.Field(test.param, "uuid") +// validate.AddFunction("isequaltestfunc", fn) - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d UUID failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uuid") { - t.Fatalf("Index: %d UUID failed Error: %s", i, err) - } - } - } -} +// err = validate.FieldWithValue(val, field, "isequaltestfunc") +// Equal(t, err, nil) -func TestISBNValidation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"foo", false}, - {"3836221195", true}, - {"1-61729-085-8", true}, - {"3 423 21412 0", true}, - {"3 401 01319 X", true}, - {"9784873113685", true}, - {"978-4-87311-368-5", true}, - {"978 3401013190", true}, - {"978-3-8362-2119-1", true}, - } +// val = "unequal" - for i, test := range tests { +// err = validate.FieldWithValue(val, field, "isequaltestfunc") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "isequaltestfunc") +// } - err := validate.Field(test.param, "isbn") +// func TestAddFunctions(t *testing.T) { - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d ISBN failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn") { - t.Fatalf("Index: %d ISBN failed Error: %s", i, err) - } - } - } -} +// fn := func(val interface{}, current interface{}, field interface{}, param string) bool { -func TestISBN13Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"foo", false}, - {"3-8362-2119-5", false}, - {"01234567890ab", false}, - {"978 3 8362 2119 0", false}, - {"9784873113685", true}, - {"978-4-87311-368-5", true}, - {"978 3401013190", true}, - {"978-3-8362-2119-1", true}, - } +// return true +// } - for i, test := range tests { +// validate := New("validateme", BakedInValidators) - err := validate.Field(test.param, "isbn13") +// err := validate.AddFunction("new", fn) +// Equal(t, err, nil) - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d ISBN13 failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn13") { - t.Fatalf("Index: %d ISBN13 failed Error: %s", i, err) - } - } - } -} +// err = validate.AddFunction("", fn) +// NotEqual(t, err, nil) -func TestISBN10Validation(t *testing.T) { - tests := []struct { - param string - expected bool - }{ - {"", false}, - {"foo", false}, - {"3423214121", false}, - {"978-3836221191", false}, - {"3-423-21412-1", false}, - {"3 423 21412 1", false}, - {"3836221195", true}, - {"1-61729-085-8", true}, - {"3 423 21412 0", true}, - {"3 401 01319 X", true}, - } +// validate.AddFunction("new", nil) +// NotEqual(t, err, nil) - for i, test := range tests { +// err = validate.AddFunction("new", fn) +// Equal(t, err, nil) +// } - err := validate.Field(test.param, "isbn10") +// func TestChangeTag(t *testing.T) { - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d ISBN10 failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "isbn10") { - t.Fatalf("Index: %d ISBN10 failed Error: %s", i, err) - } - } - } -} +// validate := New("validateme", BakedInValidators) +// validate.SetTag("val") -func TestExcludesRuneValidation(t *testing.T) { +// type Test struct { +// Name string `val:"len=4"` +// } +// s := &Test{ +// Name: "TEST", +// } - tests := []struct { - Value string `validate:"excludesrune=☻"` - Tag string - ExpectedNil bool - }{ - {Value: "a☺b☻c☹d", Tag: "excludesrune=☻", ExpectedNil: false}, - {Value: "abcd", Tag: "excludesrune=☻", ExpectedNil: true}, - } +// err := validate.Struct(s) +// Equal(t, err, nil) +// } - for i, s := range tests { - err := validate.Field(s.Value, s.Tag) +// func TestUnexposedStruct(t *testing.T) { - if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { - t.Fatalf("Index: %d failed Error: %s", i, err) - } +// type Test struct { +// Name string +// unexposed struct { +// A string `validate:"required"` +// } +// } - errs := validate.Struct(s) +// s := &Test{ +// Name: "TEST", +// } - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} +// err := validate.Struct(s) +// Equal(t, err, nil) +// } -func TestExcludesAllValidation(t *testing.T) { +// func TestBadParams(t *testing.T) { - tests := []struct { - Value string `validate:"excludesall=@!{}[]"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "excludesall=@!{}[]", ExpectedNil: false}, - {Value: "abcdefg", Tag: "excludesall=@!{}[]", ExpectedNil: true}, - } +// i := 1 +// err := validate.Field(i, "-") +// Equal(t, err, nil) - for i, s := range tests { - err := validate.Field(s.Value, s.Tag) +// PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") +// PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") - if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { - t.Fatalf("Index: %d failed Error: %s", i, err) - } +// var ui uint = 1 +// PanicMatches(t, func() { validate.Field(ui, "len=a") }, "strconv.ParseUint: parsing \"a\": invalid syntax") - errs := validate.Struct(s) +// f := 1.23 +// PanicMatches(t, func() { validate.Field(f, "len=a") }, "strconv.ParseFloat: parsing \"a\": invalid syntax") +// } - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } +// func TestLength(t *testing.T) { - username := "joeybloggs " +// i := true +// PanicMatches(t, func() { validate.Field(i, "len") }, "Bad field type bool") +// } - err := validate.Field(username, "excludesall=@ ") - NotEqual(t, err, nil) +// func TestIsGt(t *testing.T) { - excluded := "," +// myMap := map[string]string{} +// err := validate.Field(myMap, "gt=0") +// NotEqual(t, err, nil) - err = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C?") - NotEqual(t, err, nil) +// f := 1.23 +// err = validate.Field(f, "gt=5") +// NotEqual(t, err, nil) - excluded = "=" +// var ui uint = 5 +// err = validate.Field(ui, "gt=10") +// NotEqual(t, err, nil) - err = validate.Field(excluded, "excludesall=!@#$%^&*()_+.0x2C=?") - NotEqual(t, err, nil) -} +// i := true +// PanicMatches(t, func() { validate.Field(i, "gt") }, "Bad field type bool") -func TestExcludesValidation(t *testing.T) { +// tm := time.Now().UTC() +// tm = tm.Add(time.Hour * 24) - tests := []struct { - Value string `validate:"excludes=@"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "excludes=@", ExpectedNil: false}, - {Value: "abcdq!jfk", Tag: "excludes=@", ExpectedNil: true}, - } +// err = validate.Field(tm, "gt") +// Equal(t, err, nil) - for i, s := range tests { - err := validate.Field(s.Value, s.Tag) +// t2 := time.Now().UTC() - if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { - t.Fatalf("Index: %d failed Error: %s", i, err) - } +// err = validate.Field(t2, "gt") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "gt") - errs := validate.Struct(s) +// type Test struct { +// Now *time.Time `validate:"gt"` +// } +// s := &Test{ +// Now: &tm, +// } - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} +// errs := validate.Struct(s) +// Equal(t, errs, nil) -func TestContainsRuneValidation(t *testing.T) { +// s = &Test{ +// Now: &t2, +// } - tests := []struct { - Value string `validate:"containsrune=☻"` - Tag string - ExpectedNil bool - }{ - {Value: "a☺b☻c☹d", Tag: "containsrune=☻", ExpectedNil: true}, - {Value: "abcd", Tag: "containsrune=☻", ExpectedNil: false}, - } +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// } - for i, s := range tests { - err := validate.Field(s.Value, s.Tag) +// func TestIsGte(t *testing.T) { - if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { - t.Fatalf("Index: %d failed Error: %s", i, err) - } +// i := true +// PanicMatches(t, func() { validate.Field(i, "gte") }, "Bad field type bool") - errs := validate.Struct(s) +// t1 := time.Now().UTC() +// t1 = t1.Add(time.Hour * 24) - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} +// err := validate.Field(t1, "gte") +// Equal(t, err, nil) -func TestContainsAnyValidation(t *testing.T) { +// t2 := time.Now().UTC() - tests := []struct { - Value string `validate:"containsany=@!{}[]"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "containsany=@!{}[]", ExpectedNil: true}, - {Value: "abcdefg", Tag: "containsany=@!{}[]", ExpectedNil: false}, - } +// err = validate.Field(t2, "gte") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "gte") +// Equal(t, err.Type, reflect.TypeOf(time.Time{})) - for i, s := range tests { - err := validate.Field(s.Value, s.Tag) +// type Test struct { +// Now *time.Time `validate:"gte"` +// } +// s := &Test{ +// Now: &t1, +// } - if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { - t.Fatalf("Index: %d failed Error: %s", i, err) - } +// errs := validate.Struct(s) +// Equal(t, errs, nil) - errs := validate.Struct(s) +// s = &Test{ +// Now: &t2, +// } - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// } -func TestContainsValidation(t *testing.T) { +// func TestIsLt(t *testing.T) { - tests := []struct { - Value string `validate:"contains=@"` - Tag string - ExpectedNil bool - }{ - {Value: "abcd@!jfk", Tag: "contains=@", ExpectedNil: true}, - {Value: "abcdq!jfk", Tag: "contains=@", ExpectedNil: false}, - } +// myMap := map[string]string{} +// err := validate.Field(myMap, "lt=0") +// NotEqual(t, err, nil) - for i, s := range tests { - err := validate.Field(s.Value, s.Tag) +// f := 1.23 +// err = validate.Field(f, "lt=0") +// NotEqual(t, err, nil) - if (s.ExpectedNil && err != nil) || (!s.ExpectedNil && err == nil) { - t.Fatalf("Index: %d failed Error: %s", i, err) - } +// var ui uint = 5 +// err = validate.Field(ui, "lt=0") +// NotEqual(t, err, nil) - errs := validate.Struct(s) +// i := true +// PanicMatches(t, func() { validate.Field(i, "lt") }, "Bad field type bool") - if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) { - t.Fatalf("Index: %d failed Error: %s", i, errs) - } - } -} +// t1 := time.Now().UTC() + +// err = validate.Field(t1, "lt") +// Equal(t, err, nil) + +// t2 := time.Now().UTC() +// t2 = t2.Add(time.Hour * 24) + +// err = validate.Field(t2, "lt") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "lt") + +// type Test struct { +// Now *time.Time `validate:"lt"` +// } + +// s := &Test{ +// Now: &t1, +// } + +// errs := validate.Struct(s) +// Equal(t, errs, nil) + +// s = &Test{ +// Now: &t2, +// } + +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// } + +// func TestIsLte(t *testing.T) { + +// i := true +// PanicMatches(t, func() { validate.Field(i, "lte") }, "Bad field type bool") + +// t1 := time.Now().UTC() + +// err := validate.Field(t1, "lte") +// Equal(t, err, nil) + +// t2 := time.Now().UTC() +// t2 = t2.Add(time.Hour * 24) + +// err = validate.Field(t2, "lte") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "lte") + +// type Test struct { +// Now *time.Time `validate:"lte"` +// } + +// s := &Test{ +// Now: &t1, +// } + +// errs := validate.Struct(s) +// Equal(t, errs, nil) + +// s = &Test{ +// Now: &t2, +// } + +// errs = validate.Struct(s) +// NotEqual(t, errs, nil) +// } + +// func TestUrl(t *testing.T) { + +// var tests = []struct { +// param string +// expected bool +// }{ +// {"http://foo.bar#com", true}, +// {"http://foobar.com", true}, +// {"https://foobar.com", true}, +// {"foobar.com", false}, +// {"http://foobar.coffee/", true}, +// {"http://foobar.中文网/", true}, +// {"http://foobar.org/", true}, +// {"http://foobar.org:8080/", true}, +// {"ftp://foobar.ru/", true}, +// {"http://user:pass@www.foobar.com/", true}, +// {"http://127.0.0.1/", true}, +// {"http://duckduckgo.com/?q=%2F", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com/?foo=bar#baz=qux", true}, +// {"http://foobar.com?foo=bar", true}, +// {"http://www.xn--froschgrn-x9a.net/", true}, +// {"", false}, +// {"xyz://foobar.com", true}, +// {"invalid.", false}, +// {".com", false}, +// {"rtmp://foobar.com", true}, +// {"http://www.foo_bar.com/", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com#baz=qux", true}, +// {"http://foobar.com/t$-_.+!*\\'(),", true}, +// {"http://www.foobar.com/~foobar", true}, +// {"http://www.-foobar.com/", true}, +// {"http://www.foo---bar.com/", true}, +// {"mailto:someone@example.com", true}, +// {"irc://irc.server.org/channel", true}, +// {"irc://#channel@network", true}, +// {"/abs/test/dir", false}, +// {"./rel/test/dir", false}, +// } +// for i, test := range tests { + +// err := validate.Field(test.param, "url") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d URL failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "url") { +// t.Fatalf("Index: %d URL failed Error: %s", i, err) +// } +// } +// } + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "url") }, "Bad field type int") +// } + +// func TestUri(t *testing.T) { + +// var tests = []struct { +// param string +// expected bool +// }{ +// {"http://foo.bar#com", true}, +// {"http://foobar.com", true}, +// {"https://foobar.com", true}, +// {"foobar.com", false}, +// {"http://foobar.coffee/", true}, +// {"http://foobar.中文网/", true}, +// {"http://foobar.org/", true}, +// {"http://foobar.org:8080/", true}, +// {"ftp://foobar.ru/", true}, +// {"http://user:pass@www.foobar.com/", true}, +// {"http://127.0.0.1/", true}, +// {"http://duckduckgo.com/?q=%2F", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com/?foo=bar#baz=qux", true}, +// {"http://foobar.com?foo=bar", true}, +// {"http://www.xn--froschgrn-x9a.net/", true}, +// {"", false}, +// {"xyz://foobar.com", true}, +// {"invalid.", false}, +// {".com", false}, +// {"rtmp://foobar.com", true}, +// {"http://www.foo_bar.com/", true}, +// {"http://localhost:3000/", true}, +// {"http://foobar.com#baz=qux", true}, +// {"http://foobar.com/t$-_.+!*\\'(),", true}, +// {"http://www.foobar.com/~foobar", true}, +// {"http://www.-foobar.com/", true}, +// {"http://www.foo---bar.com/", true}, +// {"mailto:someone@example.com", true}, +// {"irc://irc.server.org/channel", true}, +// {"irc://#channel@network", true}, +// {"/abs/test/dir", true}, +// {"./rel/test/dir", false}, +// } +// for i, test := range tests { + +// err := validate.Field(test.param, "uri") + +// if test.expected == true { +// if !IsEqual(t, err, nil) { +// t.Fatalf("Index: %d URI failed Error: %s", i, err) +// } +// } else { +// if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uri") { +// t.Fatalf("Index: %d URI failed Error: %s", i, err) +// } +// } +// } + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "uri") }, "Bad field type int") +// } + +// func TestOrTag(t *testing.T) { +// s := "rgba(0,31,255,0.5)" +// err := validate.Field(s, "rgb|rgba") +// Equal(t, err, nil) + +// s = "rgba(0,31,255,0.5)" +// err = validate.Field(s, "rgb|rgba|len=18") +// Equal(t, err, nil) + +// s = "this ain't right" +// err = validate.Field(s, "rgb|rgba") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgb|rgba") + +// s = "this ain't right" +// err = validate.Field(s, "rgb|rgba|len=10") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgb|rgba|len") + +// s = "this is right" +// err = validate.Field(s, "rgb|rgba|len=13") +// Equal(t, err, nil) + +// s = "" +// err = validate.Field(s, "omitempty,rgb|rgba") +// Equal(t, err, nil) +// } + +// func TestHsla(t *testing.T) { + +// s := "hsla(360,100%,100%,1)" +// err := validate.Field(s, "hsla") +// Equal(t, err, nil) + +// s = "hsla(360,100%,100%,0.5)" +// err = validate.Field(s, "hsla") +// Equal(t, err, nil) + +// s = "hsla(0,0%,0%, 0)" +// err = validate.Field(s, "hsla") +// Equal(t, err, nil) + +// s = "hsl(361,100%,50%,1)" +// err = validate.Field(s, "hsla") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsla") + +// s = "hsl(361,100%,50%)" +// err = validate.Field(s, "hsla") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsla") + +// s = "hsla(361,100%,50%)" +// err = validate.Field(s, "hsla") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsla") + +// s = "hsla(360,101%,50%)" +// err = validate.Field(s, "hsla") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsla") + +// s = "hsla(360,100%,101%)" +// err = validate.Field(s, "hsla") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsla") + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "hsla") }, "interface conversion: interface is int, not string") +// } + +// func TestHsl(t *testing.T) { + +// s := "hsl(360,100%,50%)" +// err := validate.Field(s, "hsl") +// Equal(t, err, nil) + +// s = "hsl(0,0%,0%)" +// err = validate.Field(s, "hsl") +// Equal(t, err, nil) + +// s = "hsl(361,100%,50%)" +// err = validate.Field(s, "hsl") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsl") + +// s = "hsl(361,101%,50%)" +// err = validate.Field(s, "hsl") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsl") + +// s = "hsl(361,100%,101%)" +// err = validate.Field(s, "hsl") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsl") + +// s = "hsl(-10,100%,100%)" +// err = validate.Field(s, "hsl") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hsl") + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "hsl") }, "interface conversion: interface is int, not string") +// } + +// func TestRgba(t *testing.T) { + +// s := "rgba(0,31,255,0.5)" +// err := validate.Field(s, "rgba") +// Equal(t, err, nil) + +// s = "rgba(0,31,255,0.12)" +// err = validate.Field(s, "rgba") +// Equal(t, err, nil) + +// s = "rgba(12%,55%,100%,0.12)" +// err = validate.Field(s, "rgba") +// Equal(t, err, nil) + +// s = "rgba( 0, 31, 255, 0.5)" +// err = validate.Field(s, "rgba") +// Equal(t, err, nil) + +// s = "rgba(12%,55,100%,0.12)" +// err = validate.Field(s, "rgba") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgba") + +// s = "rgb(0, 31, 255)" +// err = validate.Field(s, "rgba") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgba") + +// s = "rgb(1,349,275,0.5)" +// err = validate.Field(s, "rgba") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgba") + +// s = "rgb(01,31,255,0.5)" +// err = validate.Field(s, "rgba") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgba") + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "rgba") }, "interface conversion: interface is int, not string") +// } + +// func TestRgb(t *testing.T) { + +// s := "rgb(0,31,255)" +// err := validate.Field(s, "rgb") +// Equal(t, err, nil) + +// s = "rgb(0, 31, 255)" +// err = validate.Field(s, "rgb") +// Equal(t, err, nil) + +// s = "rgb(10%, 50%, 100%)" +// err = validate.Field(s, "rgb") +// Equal(t, err, nil) + +// s = "rgb(10%, 50%, 55)" +// err = validate.Field(s, "rgb") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgb") + +// s = "rgb(1,349,275)" +// err = validate.Field(s, "rgb") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgb") + +// s = "rgb(01,31,255)" +// err = validate.Field(s, "rgb") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgb") + +// s = "rgba(0,31,255)" +// err = validate.Field(s, "rgb") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "rgb") + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "rgb") }, "interface conversion: interface is int, not string") +// } + +// func TestEmail(t *testing.T) { + +// s := "test@mail.com" +// err := validate.Field(s, "email") +// Equal(t, err, nil) + +// s = "" +// err = validate.Field(s, "email") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "email") + +// s = "test@email" +// err = validate.Field(s, "email") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "email") + +// s = "test@email." +// err = validate.Field(s, "email") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "email") + +// s = "@email.com" +// err = validate.Field(s, "email") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "email") + +// i := true +// PanicMatches(t, func() { validate.Field(i, "email") }, "interface conversion: interface is bool, not string") +// } + +// func TestHexColor(t *testing.T) { + +// s := "#fff" +// err := validate.Field(s, "hexcolor") +// Equal(t, err, nil) + +// s = "#c2c2c2" +// err = validate.Field(s, "hexcolor") +// Equal(t, err, nil) + +// s = "fff" +// err = validate.Field(s, "hexcolor") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hexcolor") + +// s = "fffFF" +// err = validate.Field(s, "hexcolor") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hexcolor") + +// i := true +// PanicMatches(t, func() { validate.Field(i, "hexcolor") }, "interface conversion: interface is bool, not string") +// } + +// func TestHexadecimal(t *testing.T) { + +// s := "ff0044" +// err := validate.Field(s, "hexadecimal") +// Equal(t, err, nil) + +// s = "abcdefg" +// err = validate.Field(s, "hexadecimal") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "hexadecimal") + +// i := true +// PanicMatches(t, func() { validate.Field(i, "hexadecimal") }, "interface conversion: interface is bool, not string") +// } + +// func TestNumber(t *testing.T) { + +// s := "1" +// err := validate.Field(s, "number") +// Equal(t, err, nil) + +// s = "+1" +// err = validate.Field(s, "number") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "number") + +// s = "-1" +// err = validate.Field(s, "number") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "number") -func TestIsNeFieldValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - now := time.Now().UTC() - - var j2 uint64 - var k2 float64 - s2 := "abcdef" - i2 := 3 - j2 = 2 - k2 = 1.5434456 - arr2 := []string{"test", "test2"} - arr3 := []string{"test"} - now2 := now - - err := validate.FieldWithValue(s, s2, "nefield") - Equal(t, err, nil) - - err = validate.FieldWithValue(i2, i, "nefield") - Equal(t, err, nil) - - err = validate.FieldWithValue(j2, j, "nefield") - Equal(t, err, nil) - - err = validate.FieldWithValue(k2, k, "nefield") - Equal(t, err, nil) - - err = validate.FieldWithValue(arr2, arr, "nefield") - Equal(t, err, nil) - - err = validate.FieldWithValue(now2, now, "nefield") - NotEqual(t, err, nil) - - err = validate.FieldWithValue(arr3, arr, "nefield") - NotEqual(t, err, nil) - - type Test struct { - Start *time.Time `validate:"nefield=End"` - End *time.Time - } - - sv := &Test{ - Start: &now, - End: &now, - } - - errs := validate.Struct(sv) - NotEqual(t, errs, nil) - - now3 := time.Now().UTC() - - sv = &Test{ - Start: &now, - End: &now3, - } - - errs = validate.Struct(sv) - Equal(t, errs, nil) - - channel := make(chan string) - - PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "nefield") }, "struct not passed for cross validation") - PanicMatches(t, func() { validate.FieldWithValue(5, channel, "nefield") }, "Bad field type chan string") - PanicMatches(t, func() { validate.FieldWithValue(5, now, "nefield") }, "Bad Top Level field type") - - type Test2 struct { - Start *time.Time `validate:"nefield=NonExistantField"` - End *time.Time - } - - sv2 := &Test2{ - Start: &now, - End: &now, - } - - PanicMatches(t, func() { validate.Struct(sv2) }, "Field \"NonExistantField\" not found in struct") -} - -func TestIsNeValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcdef" - i := 3 - j = 2 - k = 1.5434 - arr := []string{"test"} - now := time.Now().UTC() - - err := validate.Field(s, "ne=abcd") - Equal(t, err, nil) - - err = validate.Field(i, "ne=1") - Equal(t, err, nil) - - err = validate.Field(j, "ne=1") - Equal(t, err, nil) - - err = validate.Field(k, "ne=1.543") - Equal(t, err, nil) - - err = validate.Field(arr, "ne=2") - Equal(t, err, nil) - - err = validate.Field(arr, "ne=1") - NotEqual(t, err, nil) - - PanicMatches(t, func() { validate.Field(now, "ne=now") }, "Bad field type time.Time") -} - -func TestIsEqFieldValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - now := time.Now().UTC() - - var j2 uint64 - var k2 float64 - s2 := "abcd" - i2 := 1 - j2 = 1 - k2 = 1.543 - arr2 := []string{"test"} - arr3 := []string{"test", "test2"} - now2 := now - - err := validate.FieldWithValue(s, s2, "eqfield") - Equal(t, err, nil) - - err = validate.FieldWithValue(i2, i, "eqfield") - Equal(t, err, nil) - - err = validate.FieldWithValue(j2, j, "eqfield") - Equal(t, err, nil) - - err = validate.FieldWithValue(k2, k, "eqfield") - Equal(t, err, nil) - - err = validate.FieldWithValue(arr2, arr, "eqfield") - Equal(t, err, nil) - - err = validate.FieldWithValue(now2, now, "eqfield") - Equal(t, err, nil) - - err = validate.FieldWithValue(arr3, arr, "eqfield") - NotEqual(t, err, nil) - - type Test struct { - Start *time.Time `validate:"eqfield=End"` - End *time.Time - } - - sv := &Test{ - Start: &now, - End: &now, - } - - errs := validate.Struct(sv) - Equal(t, errs, nil) - - now3 := time.Now().UTC() - - sv = &Test{ - Start: &now, - End: &now3, - } - - errs = validate.Struct(sv) - NotEqual(t, errs, nil) - - channel := make(chan string) - - PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "eqfield") }, "struct not passed for cross validation") - PanicMatches(t, func() { validate.FieldWithValue(5, channel, "eqfield") }, "Bad field type chan string") - PanicMatches(t, func() { validate.FieldWithValue(5, now, "eqfield") }, "Bad Top Level field type") - - type Test2 struct { - Start *time.Time `validate:"eqfield=NonExistantField"` - End *time.Time - } - - sv2 := &Test2{ - Start: &now, - End: &now, - } - - PanicMatches(t, func() { validate.Struct(sv2) }, "Field \"NonExistantField\" not found in struct") -} - -func TestIsEqValidation(t *testing.T) { - - var j uint64 - var k float64 - s := "abcd" - i := 1 - j = 1 - k = 1.543 - arr := []string{"test"} - now := time.Now().UTC() - - err := validate.Field(s, "eq=abcd") - Equal(t, err, nil) - - err = validate.Field(i, "eq=1") - Equal(t, err, nil) - - err = validate.Field(j, "eq=1") - Equal(t, err, nil) - - err = validate.Field(k, "eq=1.543") - Equal(t, err, nil) - - err = validate.Field(arr, "eq=1") - Equal(t, err, nil) - - err = validate.Field(arr, "eq=2") - NotEqual(t, err, nil) - - PanicMatches(t, func() { validate.Field(now, "eq=now") }, "Bad field type time.Time") -} - -func TestBase64Validation(t *testing.T) { - - s := "dW5pY29ybg==" - - err := validate.Field(s, "base64") - Equal(t, err, nil) - - s = "dGhpIGlzIGEgdGVzdCBiYXNlNjQ=" - err = validate.Field(s, "base64") - Equal(t, err, nil) - - s = "" - err = validate.Field(s, "base64") - NotEqual(t, err, nil) - - s = "dW5pY29ybg== foo bar" - err = validate.Field(s, "base64") - NotEqual(t, err, nil) -} - -func TestStructOnlyValidation(t *testing.T) { - - type Inner struct { - Test string `validate:"len=5"` - } - - type Outer struct { - InnerStruct *Inner `validate:"required,structonly"` - } - - outer := &Outer{ - InnerStruct: nil, - } - - errs := validate.Struct(outer) - NotEqual(t, errs, nil) - - inner := &Inner{ - Test: "1234", - } - - outer = &Outer{ - InnerStruct: inner, - } - - errs = validate.Struct(outer) - Equal(t, errs, nil) -} - -func TestGtField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,gt"` - End *time.Time `validate:"required,gt,gtfield=Start"` - } - - now := time.Now() - start := now.Add(time.Hour * 24) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs2 := validate.Struct(timeTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "End", "gtfield") - - err3 := validate.FieldWithValue(&start, &end, "gtfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(&end, &start, "gtfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtfield") - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,gtfield=Val1"` - } - - intTest := &IntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 5, - Val2: 1, - } - - errs2 = validate.Struct(intTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "gtfield") - - err3 = validate.FieldWithValue(int(1), int(5), "gtfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(int(5), int(1), "gtfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtfield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,gtfield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs2 = validate.Struct(uIntTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "gtfield") - - err3 = validate.FieldWithValue(uint(1), uint(5), "gtfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(uint(5), uint(1), "gtfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtfield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,gtfield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs2 = validate.Struct(floatTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "gtfield") - - err3 = validate.FieldWithValue(float32(1), float32(5), "gtfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(float32(5), float32(1), "gtfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtfield") - - PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "gtfield") }, "struct not passed for cross validation") - PanicMatches(t, func() { validate.FieldWithValue(5, "T", "gtfield") }, "Bad field type string") - PanicMatches(t, func() { validate.FieldWithValue(5, start, "gtfield") }, "Bad Top Level field type") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,gtfield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &start, - End: &end, - } - - PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") -} - -func TestLtField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,lt,ltfield=End"` - End *time.Time `validate:"required,lt"` - } - - now := time.Now() - start := now.Add(time.Hour * 24 * -1 * 2) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs2 := validate.Struct(timeTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Start", "ltfield") - - err3 := validate.FieldWithValue(&end, &start, "ltfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(&start, &end, "ltfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltfield") - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,ltfield=Val1"` - } - - intTest := &IntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 1, - Val2: 5, - } - - errs2 = validate.Struct(intTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "ltfield") - - err3 = validate.FieldWithValue(int(5), int(1), "ltfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(int(1), int(5), "ltfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltfield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,ltfield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs2 = validate.Struct(uIntTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "ltfield") - - err3 = validate.FieldWithValue(uint(5), uint(1), "ltfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(uint(1), uint(5), "ltfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltfield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,ltfield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs2 = validate.Struct(floatTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "ltfield") - - err3 = validate.FieldWithValue(float32(5), float32(1), "ltfield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(float32(1), float32(5), "ltfield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltfield") - - PanicMatches(t, func() { validate.FieldWithValue(nil, 5, "ltfield") }, "struct not passed for cross validation") - PanicMatches(t, func() { validate.FieldWithValue(1, "T", "ltfield") }, "Bad field type string") - PanicMatches(t, func() { validate.FieldWithValue(1, end, "ltfield") }, "Bad Top Level field type") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,ltfield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &end, - End: &start, - } - - PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") -} - -func TestLteField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,lte,ltefield=End"` - End *time.Time `validate:"required,lte"` - } - - now := time.Now() - start := now.Add(time.Hour * 24 * -1 * 2) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs2 := validate.Struct(timeTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Start", "ltefield") - - err3 := validate.FieldWithValue(&end, &start, "ltefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(&start, &end, "ltefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltefield") - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,ltefield=Val1"` - } - - intTest := &IntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 1, - Val2: 5, - } - - errs2 = validate.Struct(intTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "ltefield") - - err3 = validate.FieldWithValue(int(5), int(1), "ltefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(int(1), int(5), "ltefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltefield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,ltefield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs2 = validate.Struct(uIntTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "ltefield") - - err3 = validate.FieldWithValue(uint(5), uint(1), "ltefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(uint(1), uint(5), "ltefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltefield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,ltefield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs2 = validate.Struct(floatTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "ltefield") - - err3 = validate.FieldWithValue(float32(5), float32(1), "ltefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(float32(1), float32(5), "ltefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "ltefield") - - PanicMatches(t, func() { validate.FieldWithValue(nil, 5, "ltefield") }, "struct not passed for cross validation") - PanicMatches(t, func() { validate.FieldWithValue(1, "T", "ltefield") }, "Bad field type string") - PanicMatches(t, func() { validate.FieldWithValue(1, end, "ltefield") }, "Bad Top Level field type") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,ltefield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &end, - End: &start, - } - - PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") -} - -func TestGteField(t *testing.T) { - - type TimeTest struct { - Start *time.Time `validate:"required,gte"` - End *time.Time `validate:"required,gte,gtefield=Start"` - } - - now := time.Now() - start := now.Add(time.Hour * 24) - end := start.Add(time.Hour * 24) - - timeTest := &TimeTest{ - Start: &start, - End: &end, - } - - errs := validate.Struct(timeTest) - Equal(t, errs, nil) - - timeTest = &TimeTest{ - Start: &end, - End: &start, - } - - errs2 := validate.Struct(timeTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "End", "gtefield") - - err3 := validate.FieldWithValue(&start, &end, "gtefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(&end, &start, "gtefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtefield") - - type IntTest struct { - Val1 int `validate:"required"` - Val2 int `validate:"required,gtefield=Val1"` - } - - intTest := &IntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(intTest) - Equal(t, errs, nil) - - intTest = &IntTest{ - Val1: 5, - Val2: 1, - } - - errs2 = validate.Struct(intTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "gtefield") - - err3 = validate.FieldWithValue(int(1), int(5), "gtefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(int(5), int(1), "gtefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtefield") - - type UIntTest struct { - Val1 uint `validate:"required"` - Val2 uint `validate:"required,gtefield=Val1"` - } - - uIntTest := &UIntTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(uIntTest) - Equal(t, errs, nil) - - uIntTest = &UIntTest{ - Val1: 5, - Val2: 1, - } - - errs2 = validate.Struct(uIntTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "gtefield") - - err3 = validate.FieldWithValue(uint(1), uint(5), "gtefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(uint(5), uint(1), "gtefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtefield") - - type FloatTest struct { - Val1 float64 `validate:"required"` - Val2 float64 `validate:"required,gtefield=Val1"` - } - - floatTest := &FloatTest{ - Val1: 1, - Val2: 5, - } - - errs = validate.Struct(floatTest) - Equal(t, errs, nil) - - floatTest = &FloatTest{ - Val1: 5, - Val2: 1, - } - - errs2 = validate.Struct(floatTest).Flatten() - NotEqual(t, errs2, nil) - AssertMapFieldError(t, errs2, "Val2", "gtefield") - - err3 = validate.FieldWithValue(float32(1), float32(5), "gtefield") - Equal(t, err3, nil) - - err3 = validate.FieldWithValue(float32(5), float32(1), "gtefield") - NotEqual(t, err3, nil) - Equal(t, err3.Tag, "gtefield") - - PanicMatches(t, func() { validate.FieldWithValue(nil, 1, "gtefield") }, "struct not passed for cross validation") - PanicMatches(t, func() { validate.FieldWithValue(5, "T", "gtefield") }, "Bad field type string") - PanicMatches(t, func() { validate.FieldWithValue(5, start, "gtefield") }, "Bad Top Level field type") - - type TimeTest2 struct { - Start *time.Time `validate:"required"` - End *time.Time `validate:"required,gtefield=NonExistantField"` - } - - timeTest2 := &TimeTest2{ - Start: &start, - End: &end, - } - - PanicMatches(t, func() { validate.Struct(timeTest2) }, "Field \"NonExistantField\" not found in struct") -} - -func TestValidateByTagAndValue(t *testing.T) { - - val := "test" - field := "test" - err := validate.FieldWithValue(val, field, "required") - Equal(t, err, nil) - - fn := func(val interface{}, current interface{}, field interface{}, param string) bool { - - return current.(string) == field.(string) - } - - validate.AddFunction("isequaltestfunc", fn) - - err = validate.FieldWithValue(val, field, "isequaltestfunc") - Equal(t, err, nil) - - val = "unequal" - - err = validate.FieldWithValue(val, field, "isequaltestfunc") - NotEqual(t, err, nil) - Equal(t, err.Tag, "isequaltestfunc") -} - -func TestAddFunctions(t *testing.T) { - - fn := func(val interface{}, current interface{}, field interface{}, param string) bool { - - return true - } - - validate := New("validateme", BakedInValidators) - - err := validate.AddFunction("new", fn) - Equal(t, err, nil) - - err = validate.AddFunction("", fn) - NotEqual(t, err, nil) - - validate.AddFunction("new", nil) - NotEqual(t, err, nil) - - err = validate.AddFunction("new", fn) - Equal(t, err, nil) -} - -func TestChangeTag(t *testing.T) { - - validate := New("validateme", BakedInValidators) - validate.SetTag("val") - - type Test struct { - Name string `val:"len=4"` - } - s := &Test{ - Name: "TEST", - } - - err := validate.Struct(s) - Equal(t, err, nil) -} - -func TestUnexposedStruct(t *testing.T) { - - type Test struct { - Name string - unexposed struct { - A string `validate:"required"` - } - } - - s := &Test{ - Name: "TEST", - } - - err := validate.Struct(s) - Equal(t, err, nil) -} - -func TestBadParams(t *testing.T) { - - i := 1 - err := validate.Field(i, "-") - Equal(t, err, nil) - - PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") - PanicMatches(t, func() { validate.Field(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax") - - var ui uint = 1 - PanicMatches(t, func() { validate.Field(ui, "len=a") }, "strconv.ParseUint: parsing \"a\": invalid syntax") - - f := 1.23 - PanicMatches(t, func() { validate.Field(f, "len=a") }, "strconv.ParseFloat: parsing \"a\": invalid syntax") -} - -func TestLength(t *testing.T) { - - i := true - PanicMatches(t, func() { validate.Field(i, "len") }, "Bad field type bool") -} - -func TestIsGt(t *testing.T) { - - myMap := map[string]string{} - err := validate.Field(myMap, "gt=0") - NotEqual(t, err, nil) - - f := 1.23 - err = validate.Field(f, "gt=5") - NotEqual(t, err, nil) - - var ui uint = 5 - err = validate.Field(ui, "gt=10") - NotEqual(t, err, nil) - - i := true - PanicMatches(t, func() { validate.Field(i, "gt") }, "Bad field type bool") - - tm := time.Now().UTC() - tm = tm.Add(time.Hour * 24) - - err = validate.Field(tm, "gt") - Equal(t, err, nil) - - t2 := time.Now().UTC() - - err = validate.Field(t2, "gt") - NotEqual(t, err, nil) - Equal(t, err.Tag, "gt") - - type Test struct { - Now *time.Time `validate:"gt"` - } - s := &Test{ - Now: &tm, - } - - errs := validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) -} - -func TestIsGte(t *testing.T) { - - i := true - PanicMatches(t, func() { validate.Field(i, "gte") }, "Bad field type bool") - - t1 := time.Now().UTC() - t1 = t1.Add(time.Hour * 24) - - err := validate.Field(t1, "gte") - Equal(t, err, nil) - - t2 := time.Now().UTC() - - err = validate.Field(t2, "gte") - NotEqual(t, err, nil) - Equal(t, err.Tag, "gte") - Equal(t, err.Type, reflect.TypeOf(time.Time{})) - - type Test struct { - Now *time.Time `validate:"gte"` - } - s := &Test{ - Now: &t1, - } - - errs := validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) -} - -func TestIsLt(t *testing.T) { - - myMap := map[string]string{} - err := validate.Field(myMap, "lt=0") - NotEqual(t, err, nil) - - f := 1.23 - err = validate.Field(f, "lt=0") - NotEqual(t, err, nil) - - var ui uint = 5 - err = validate.Field(ui, "lt=0") - NotEqual(t, err, nil) - - i := true - PanicMatches(t, func() { validate.Field(i, "lt") }, "Bad field type bool") - - t1 := time.Now().UTC() - - err = validate.Field(t1, "lt") - Equal(t, err, nil) - - t2 := time.Now().UTC() - t2 = t2.Add(time.Hour * 24) - - err = validate.Field(t2, "lt") - NotEqual(t, err, nil) - Equal(t, err.Tag, "lt") - - type Test struct { - Now *time.Time `validate:"lt"` - } - - s := &Test{ - Now: &t1, - } - - errs := validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) -} - -func TestIsLte(t *testing.T) { - - i := true - PanicMatches(t, func() { validate.Field(i, "lte") }, "Bad field type bool") - - t1 := time.Now().UTC() - - err := validate.Field(t1, "lte") - Equal(t, err, nil) - - t2 := time.Now().UTC() - t2 = t2.Add(time.Hour * 24) - - err = validate.Field(t2, "lte") - NotEqual(t, err, nil) - Equal(t, err.Tag, "lte") - - type Test struct { - Now *time.Time `validate:"lte"` - } - - s := &Test{ - Now: &t1, - } - - errs := validate.Struct(s) - Equal(t, errs, nil) - - s = &Test{ - Now: &t2, - } - - errs = validate.Struct(s) - NotEqual(t, errs, nil) -} - -func TestUrl(t *testing.T) { - - var tests = []struct { - param string - expected bool - }{ - {"http://foo.bar#com", true}, - {"http://foobar.com", true}, - {"https://foobar.com", true}, - {"foobar.com", false}, - {"http://foobar.coffee/", true}, - {"http://foobar.中文网/", true}, - {"http://foobar.org/", true}, - {"http://foobar.org:8080/", true}, - {"ftp://foobar.ru/", true}, - {"http://user:pass@www.foobar.com/", true}, - {"http://127.0.0.1/", true}, - {"http://duckduckgo.com/?q=%2F", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com/?foo=bar#baz=qux", true}, - {"http://foobar.com?foo=bar", true}, - {"http://www.xn--froschgrn-x9a.net/", true}, - {"", false}, - {"xyz://foobar.com", true}, - {"invalid.", false}, - {".com", false}, - {"rtmp://foobar.com", true}, - {"http://www.foo_bar.com/", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com#baz=qux", true}, - {"http://foobar.com/t$-_.+!*\\'(),", true}, - {"http://www.foobar.com/~foobar", true}, - {"http://www.-foobar.com/", true}, - {"http://www.foo---bar.com/", true}, - {"mailto:someone@example.com", true}, - {"irc://irc.server.org/channel", true}, - {"irc://#channel@network", true}, - {"/abs/test/dir", false}, - {"./rel/test/dir", false}, - } - for i, test := range tests { - - err := validate.Field(test.param, "url") - - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d URL failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "url") { - t.Fatalf("Index: %d URL failed Error: %s", i, err) - } - } - } - - i := 1 - PanicMatches(t, func() { validate.Field(i, "url") }, "Bad field type int") -} - -func TestUri(t *testing.T) { - - var tests = []struct { - param string - expected bool - }{ - {"http://foo.bar#com", true}, - {"http://foobar.com", true}, - {"https://foobar.com", true}, - {"foobar.com", false}, - {"http://foobar.coffee/", true}, - {"http://foobar.中文网/", true}, - {"http://foobar.org/", true}, - {"http://foobar.org:8080/", true}, - {"ftp://foobar.ru/", true}, - {"http://user:pass@www.foobar.com/", true}, - {"http://127.0.0.1/", true}, - {"http://duckduckgo.com/?q=%2F", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com/?foo=bar#baz=qux", true}, - {"http://foobar.com?foo=bar", true}, - {"http://www.xn--froschgrn-x9a.net/", true}, - {"", false}, - {"xyz://foobar.com", true}, - {"invalid.", false}, - {".com", false}, - {"rtmp://foobar.com", true}, - {"http://www.foo_bar.com/", true}, - {"http://localhost:3000/", true}, - {"http://foobar.com#baz=qux", true}, - {"http://foobar.com/t$-_.+!*\\'(),", true}, - {"http://www.foobar.com/~foobar", true}, - {"http://www.-foobar.com/", true}, - {"http://www.foo---bar.com/", true}, - {"mailto:someone@example.com", true}, - {"irc://irc.server.org/channel", true}, - {"irc://#channel@network", true}, - {"/abs/test/dir", true}, - {"./rel/test/dir", false}, - } - for i, test := range tests { - - err := validate.Field(test.param, "uri") - - if test.expected == true { - if !IsEqual(t, err, nil) { - t.Fatalf("Index: %d URI failed Error: %s", i, err) - } - } else { - if IsEqual(t, err, nil) || !IsEqual(t, err.Tag, "uri") { - t.Fatalf("Index: %d URI failed Error: %s", i, err) - } - } - } - - i := 1 - PanicMatches(t, func() { validate.Field(i, "uri") }, "Bad field type int") -} - -func TestOrTag(t *testing.T) { - s := "rgba(0,31,255,0.5)" - err := validate.Field(s, "rgb|rgba") - Equal(t, err, nil) - - s = "rgba(0,31,255,0.5)" - err = validate.Field(s, "rgb|rgba|len=18") - Equal(t, err, nil) - - s = "this ain't right" - err = validate.Field(s, "rgb|rgba") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgb|rgba") - - s = "this ain't right" - err = validate.Field(s, "rgb|rgba|len=10") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgb|rgba|len") - - s = "this is right" - err = validate.Field(s, "rgb|rgba|len=13") - Equal(t, err, nil) - - s = "" - err = validate.Field(s, "omitempty,rgb|rgba") - Equal(t, err, nil) -} - -func TestHsla(t *testing.T) { - - s := "hsla(360,100%,100%,1)" - err := validate.Field(s, "hsla") - Equal(t, err, nil) - - s = "hsla(360,100%,100%,0.5)" - err = validate.Field(s, "hsla") - Equal(t, err, nil) - - s = "hsla(0,0%,0%, 0)" - err = validate.Field(s, "hsla") - Equal(t, err, nil) - - s = "hsl(361,100%,50%,1)" - err = validate.Field(s, "hsla") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsla") - - s = "hsl(361,100%,50%)" - err = validate.Field(s, "hsla") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsla") - - s = "hsla(361,100%,50%)" - err = validate.Field(s, "hsla") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsla") - - s = "hsla(360,101%,50%)" - err = validate.Field(s, "hsla") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsla") - - s = "hsla(360,100%,101%)" - err = validate.Field(s, "hsla") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsla") - - i := 1 - PanicMatches(t, func() { validate.Field(i, "hsla") }, "interface conversion: interface is int, not string") -} - -func TestHsl(t *testing.T) { - - s := "hsl(360,100%,50%)" - err := validate.Field(s, "hsl") - Equal(t, err, nil) - - s = "hsl(0,0%,0%)" - err = validate.Field(s, "hsl") - Equal(t, err, nil) - - s = "hsl(361,100%,50%)" - err = validate.Field(s, "hsl") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsl") - - s = "hsl(361,101%,50%)" - err = validate.Field(s, "hsl") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsl") - - s = "hsl(361,100%,101%)" - err = validate.Field(s, "hsl") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsl") - - s = "hsl(-10,100%,100%)" - err = validate.Field(s, "hsl") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hsl") - - i := 1 - PanicMatches(t, func() { validate.Field(i, "hsl") }, "interface conversion: interface is int, not string") -} - -func TestRgba(t *testing.T) { - - s := "rgba(0,31,255,0.5)" - err := validate.Field(s, "rgba") - Equal(t, err, nil) - - s = "rgba(0,31,255,0.12)" - err = validate.Field(s, "rgba") - Equal(t, err, nil) - - s = "rgba(12%,55%,100%,0.12)" - err = validate.Field(s, "rgba") - Equal(t, err, nil) - - s = "rgba( 0, 31, 255, 0.5)" - err = validate.Field(s, "rgba") - Equal(t, err, nil) - - s = "rgba(12%,55,100%,0.12)" - err = validate.Field(s, "rgba") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgba") - - s = "rgb(0, 31, 255)" - err = validate.Field(s, "rgba") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgba") - - s = "rgb(1,349,275,0.5)" - err = validate.Field(s, "rgba") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgba") - - s = "rgb(01,31,255,0.5)" - err = validate.Field(s, "rgba") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgba") - - i := 1 - PanicMatches(t, func() { validate.Field(i, "rgba") }, "interface conversion: interface is int, not string") -} - -func TestRgb(t *testing.T) { - - s := "rgb(0,31,255)" - err := validate.Field(s, "rgb") - Equal(t, err, nil) - - s = "rgb(0, 31, 255)" - err = validate.Field(s, "rgb") - Equal(t, err, nil) - - s = "rgb(10%, 50%, 100%)" - err = validate.Field(s, "rgb") - Equal(t, err, nil) - - s = "rgb(10%, 50%, 55)" - err = validate.Field(s, "rgb") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgb") - - s = "rgb(1,349,275)" - err = validate.Field(s, "rgb") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgb") - - s = "rgb(01,31,255)" - err = validate.Field(s, "rgb") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgb") - - s = "rgba(0,31,255)" - err = validate.Field(s, "rgb") - NotEqual(t, err, nil) - Equal(t, err.Tag, "rgb") - - i := 1 - PanicMatches(t, func() { validate.Field(i, "rgb") }, "interface conversion: interface is int, not string") -} - -func TestEmail(t *testing.T) { - - s := "test@mail.com" - err := validate.Field(s, "email") - Equal(t, err, nil) - - s = "" - err = validate.Field(s, "email") - NotEqual(t, err, nil) - Equal(t, err.Tag, "email") - - s = "test@email" - err = validate.Field(s, "email") - NotEqual(t, err, nil) - Equal(t, err.Tag, "email") - - s = "test@email." - err = validate.Field(s, "email") - NotEqual(t, err, nil) - Equal(t, err.Tag, "email") - - s = "@email.com" - err = validate.Field(s, "email") - NotEqual(t, err, nil) - Equal(t, err.Tag, "email") - - i := true - PanicMatches(t, func() { validate.Field(i, "email") }, "interface conversion: interface is bool, not string") -} - -func TestHexColor(t *testing.T) { - - s := "#fff" - err := validate.Field(s, "hexcolor") - Equal(t, err, nil) - - s = "#c2c2c2" - err = validate.Field(s, "hexcolor") - Equal(t, err, nil) - - s = "fff" - err = validate.Field(s, "hexcolor") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hexcolor") - - s = "fffFF" - err = validate.Field(s, "hexcolor") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hexcolor") - - i := true - PanicMatches(t, func() { validate.Field(i, "hexcolor") }, "interface conversion: interface is bool, not string") -} - -func TestHexadecimal(t *testing.T) { - - s := "ff0044" - err := validate.Field(s, "hexadecimal") - Equal(t, err, nil) - - s = "abcdefg" - err = validate.Field(s, "hexadecimal") - NotEqual(t, err, nil) - Equal(t, err.Tag, "hexadecimal") - - i := true - PanicMatches(t, func() { validate.Field(i, "hexadecimal") }, "interface conversion: interface is bool, not string") -} - -func TestNumber(t *testing.T) { - - s := "1" - err := validate.Field(s, "number") - Equal(t, err, nil) - - s = "+1" - err = validate.Field(s, "number") - NotEqual(t, err, nil) - Equal(t, err.Tag, "number") - - s = "-1" - err = validate.Field(s, "number") - NotEqual(t, err, nil) - Equal(t, err.Tag, "number") - - s = "1.12" - err = validate.Field(s, "number") - NotEqual(t, err, nil) - Equal(t, err.Tag, "number") - - s = "+1.12" - err = validate.Field(s, "number") - NotEqual(t, err, nil) - Equal(t, err.Tag, "number") - - s = "-1.12" - err = validate.Field(s, "number") - NotEqual(t, err, nil) - Equal(t, err.Tag, "number") - - s = "1." - err = validate.Field(s, "number") - NotEqual(t, err, nil) - Equal(t, err.Tag, "number") - - s = "1.o" - err = validate.Field(s, "number") - NotEqual(t, err, nil) - Equal(t, err.Tag, "number") - - i := 1 - PanicMatches(t, func() { validate.Field(i, "number") }, "interface conversion: interface is int, not string") -} - -func TestNumeric(t *testing.T) { - - s := "1" - err := validate.Field(s, "numeric") - Equal(t, err, nil) - - s = "+1" - err = validate.Field(s, "numeric") - Equal(t, err, nil) - - s = "-1" - err = validate.Field(s, "numeric") - Equal(t, err, nil) - - s = "1.12" - err = validate.Field(s, "numeric") - Equal(t, err, nil) - - s = "+1.12" - err = validate.Field(s, "numeric") - Equal(t, err, nil) - - s = "-1.12" - err = validate.Field(s, "numeric") - Equal(t, err, nil) - - s = "1." - err = validate.Field(s, "numeric") - NotEqual(t, err, nil) - Equal(t, err.Tag, "numeric") - - s = "1.o" - err = validate.Field(s, "numeric") - NotEqual(t, err, nil) - Equal(t, err.Tag, "numeric") - - i := 1 - PanicMatches(t, func() { validate.Field(i, "numeric") }, "interface conversion: interface is int, not string") -} - -func TestAlphaNumeric(t *testing.T) { - - s := "abcd123" - err := validate.Field(s, "alphanum") - Equal(t, err, nil) - - s = "abc!23" - err = validate.Field(s, "alphanum") - NotEqual(t, err, nil) - Equal(t, err.Tag, "alphanum") - - PanicMatches(t, func() { validate.Field(1, "alphanum") }, "interface conversion: interface is int, not string") -} - -func TestAlpha(t *testing.T) { - - s := "abcd" - err := validate.Field(s, "alpha") - Equal(t, err, nil) - - s = "abc1" - err = validate.Field(s, "alpha") - NotEqual(t, err, nil) - Equal(t, err.Tag, "alpha") - - PanicMatches(t, func() { validate.Field(1, "alpha") }, "interface conversion: interface is int, not string") -} - -func TestFlattening(t *testing.T) { - - tSuccess := &TestString{ - Required: "Required", - Len: "length==10", - Min: "min=1", - Max: "1234567890", - MinMax: "12345", - Lt: "012345678", - Lte: "0123456789", - Gt: "01234567890", - Gte: "0123456789", - OmitEmpty: "", - Sub: &SubTest{ - Test: "1", - }, - SubIgnore: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "1", - }, - Iface: &Impl{ - F: "123", - }, - } - - err1 := validate.Struct(tSuccess).Flatten() - Equal(t, len(err1), 0) - - tFail := &TestString{ - Required: "", - Len: "", - Min: "", - Max: "12345678901", - MinMax: "", - OmitEmpty: "12345678901", - Sub: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "", - }, - Iface: &Impl{ - F: "12", - }, - } - - err2 := validate.Struct(tFail).Flatten() - - // Assert Top Level - NotEqual(t, err2, nil) - - // Assert Fields - AssertMapFieldError(t, err2, "Len", "len") - AssertMapFieldError(t, err2, "Gt", "gt") - AssertMapFieldError(t, err2, "Gte", "gte") - - // Assert Struct Field - AssertMapFieldError(t, err2, "Sub.Test", "required") - - // Assert Anonymous Struct Field - AssertMapFieldError(t, err2, "Anonymous.A", "required") - - // Assert Interface Field - AssertMapFieldError(t, err2, "Iface.F", "len") -} - -func TestStructStringValidation(t *testing.T) { - - validate.SetMaxStructPoolSize(11) - - tSuccess := &TestString{ - Required: "Required", - Len: "length==10", - Min: "min=1", - Max: "1234567890", - MinMax: "12345", - Lt: "012345678", - Lte: "0123456789", - Gt: "01234567890", - Gte: "0123456789", - OmitEmpty: "", - Sub: &SubTest{ - Test: "1", - }, - SubIgnore: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "1", - }, - Iface: &Impl{ - F: "123", - }, - } - - err := validate.Struct(tSuccess) - Equal(t, err, nil) - - tFail := &TestString{ - Required: "", - Len: "", - Min: "", - Max: "12345678901", - MinMax: "", - Lt: "0123456789", - Lte: "01234567890", - Gt: "1", - Gte: "1", - OmitEmpty: "12345678901", - Sub: &SubTest{ - Test: "", - }, - Anonymous: struct { - A string `validate:"required"` - }{ - A: "", - }, - Iface: &Impl{ - F: "12", - }, - } - - err = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, err, nil) - Equal(t, err.Struct, "TestString") - Equal(t, len(err.Errors), 10) - Equal(t, len(err.StructErrors), 3) - - // Assert Fields - AssertFieldError(t, err, "Required", "required") - AssertFieldError(t, err, "Len", "len") - AssertFieldError(t, err, "Min", "min") - AssertFieldError(t, err, "Max", "max") - AssertFieldError(t, err, "MinMax", "min") - AssertFieldError(t, err, "Gt", "gt") - AssertFieldError(t, err, "Gte", "gte") - AssertFieldError(t, err, "OmitEmpty", "max") - - // Assert Anonymous embedded struct - AssertStruct(t, err, "Anonymous", "") - - // Assert SubTest embedded struct - val := AssertStruct(t, err, "Sub", "SubTest") - Equal(t, len(val.Errors), 1) - Equal(t, len(val.StructErrors), 0) - - AssertFieldError(t, val, "Test", "required") - - errors := err.Error() - NotEqual(t, errors, nil) -} - -func TestStructInt32Validation(t *testing.T) { - - tSuccess := &TestInt32{ - Required: 1, - Len: 10, - Min: 1, - Max: 10, - MinMax: 5, - Lt: 9, - Lte: 10, - Gt: 11, - Gte: 10, - OmitEmpty: 0, - } - - err := validate.Struct(tSuccess) - Equal(t, err, nil) - - tFail := &TestInt32{ - Required: 0, - Len: 11, - Min: -1, - Max: 11, - MinMax: -1, - Lt: 10, - Lte: 11, - Gt: 10, - Gte: 9, - OmitEmpty: 11, - } - - err = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, err, nil) - Equal(t, err.Struct, "TestInt32") - Equal(t, len(err.Errors), 10) - Equal(t, len(err.StructErrors), 0) - - // Assert Fields - AssertFieldError(t, err, "Required", "required") - AssertFieldError(t, err, "Len", "len") - AssertFieldError(t, err, "Min", "min") - AssertFieldError(t, err, "Max", "max") - AssertFieldError(t, err, "MinMax", "min") - AssertFieldError(t, err, "Lt", "lt") - AssertFieldError(t, err, "Lte", "lte") - AssertFieldError(t, err, "Gt", "gt") - AssertFieldError(t, err, "Gte", "gte") - AssertFieldError(t, err, "OmitEmpty", "max") -} - -func TestStructUint64Validation(t *testing.T) { - - tSuccess := &TestUint64{ - Required: 1, - Len: 10, - Min: 1, - Max: 10, - MinMax: 5, - OmitEmpty: 0, - } - - err := validate.Struct(tSuccess) - Equal(t, err, nil) - - tFail := &TestUint64{ - Required: 0, - Len: 11, - Min: 0, - Max: 11, - MinMax: 0, - OmitEmpty: 11, - } - - err = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, err, nil) - Equal(t, err.Struct, "TestUint64") - Equal(t, len(err.Errors), 6) - Equal(t, len(err.StructErrors), 0) - - // Assert Fields - AssertFieldError(t, err, "Required", "required") - AssertFieldError(t, err, "Len", "len") - AssertFieldError(t, err, "Min", "min") - AssertFieldError(t, err, "Max", "max") - AssertFieldError(t, err, "MinMax", "min") - AssertFieldError(t, err, "OmitEmpty", "max") -} - -func TestStructFloat64Validation(t *testing.T) { - - tSuccess := &TestFloat64{ - Required: 1, - Len: 10, - Min: 1, - Max: 10, - MinMax: 5, - OmitEmpty: 0, - } - - err := validate.Struct(tSuccess) - Equal(t, err, nil) - - tFail := &TestFloat64{ - Required: 0, - Len: 11, - Min: 0, - Max: 11, - MinMax: 0, - OmitEmpty: 11, - } - - err = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, err, nil) - Equal(t, err.Struct, "TestFloat64") - Equal(t, len(err.Errors), 6) - Equal(t, len(err.StructErrors), 0) - - // Assert Fields - AssertFieldError(t, err, "Required", "required") - AssertFieldError(t, err, "Len", "len") - AssertFieldError(t, err, "Min", "min") - AssertFieldError(t, err, "Max", "max") - AssertFieldError(t, err, "MinMax", "min") - AssertFieldError(t, err, "OmitEmpty", "max") -} - -func TestStructSliceValidation(t *testing.T) { - - tSuccess := &TestSlice{ - Required: []int{1}, - Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, - Min: []int{1, 2}, - Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, - MinMax: []int{1, 2, 3, 4, 5}, - OmitEmpty: []int{}, - } - - err := validate.Struct(tSuccess) - Equal(t, err, nil) - - tFail := &TestSlice{ - Required: []int{}, - Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, - Min: []int{}, - Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, - MinMax: []int{}, - OmitEmpty: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, - } - - err = validate.Struct(tFail) - - // Assert Top Level - NotEqual(t, err, nil) - Equal(t, err.Struct, "TestSlice") - Equal(t, len(err.Errors), 6) - Equal(t, len(err.StructErrors), 0) - - // Assert Fields - AssertFieldError(t, err, "Required", "required") - AssertFieldError(t, err, "Len", "len") - AssertFieldError(t, err, "Min", "min") - AssertFieldError(t, err, "Max", "max") - AssertFieldError(t, err, "MinMax", "min") - AssertFieldError(t, err, "OmitEmpty", "max") -} - -func TestInvalidStruct(t *testing.T) { - s := &SubTest{ - Test: "1", - } - - PanicMatches(t, func() { validate.Struct(s.Test) }, "interface passed for validation is not a struct") -} - -func TestInvalidField(t *testing.T) { - s := &SubTest{ - Test: "1", - } - - PanicMatches(t, func() { validate.Field(s, "required") }, "Invalid field passed to fieldWithNameAndValue") -} - -func TestInvalidTagField(t *testing.T) { - s := &SubTest{ - Test: "1", - } - - PanicMatches(t, func() { validate.Field(s.Test, "") }, fmt.Sprintf("Invalid validation tag on field %s", "")) -} - -func TestInvalidValidatorFunction(t *testing.T) { - s := &SubTest{ - Test: "1", - } - - PanicMatches(t, func() { validate.Field(s.Test, "zzxxBadFunction") }, fmt.Sprintf("Undefined validation function on field %s", "")) -} - -func TestPoolObjectMaxSizeValidation(t *testing.T) { - // this will ensure that the pool objects are let go - // when the pool is saturated - validate.SetMaxStructPoolSize(0) - - tSuccess := &TestSlice{ - Required: []int{1}, - Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, - Min: []int{1, 2}, - Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, - MinMax: []int{1, 2, 3, 4, 5}, - OmitEmpty: []int{}, - } - - for i := 0; i < 2; i++ { - err := validate.Struct(tSuccess) - Equal(t, err, nil) - } -} +// s = "1.12" +// err = validate.Field(s, "number") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "number") + +// s = "+1.12" +// err = validate.Field(s, "number") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "number") + +// s = "-1.12" +// err = validate.Field(s, "number") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "number") + +// s = "1." +// err = validate.Field(s, "number") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "number") + +// s = "1.o" +// err = validate.Field(s, "number") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "number") + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "number") }, "interface conversion: interface is int, not string") +// } + +// func TestNumeric(t *testing.T) { + +// s := "1" +// err := validate.Field(s, "numeric") +// Equal(t, err, nil) + +// s = "+1" +// err = validate.Field(s, "numeric") +// Equal(t, err, nil) + +// s = "-1" +// err = validate.Field(s, "numeric") +// Equal(t, err, nil) + +// s = "1.12" +// err = validate.Field(s, "numeric") +// Equal(t, err, nil) + +// s = "+1.12" +// err = validate.Field(s, "numeric") +// Equal(t, err, nil) + +// s = "-1.12" +// err = validate.Field(s, "numeric") +// Equal(t, err, nil) + +// s = "1." +// err = validate.Field(s, "numeric") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "numeric") + +// s = "1.o" +// err = validate.Field(s, "numeric") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "numeric") + +// i := 1 +// PanicMatches(t, func() { validate.Field(i, "numeric") }, "interface conversion: interface is int, not string") +// } + +// func TestAlphaNumeric(t *testing.T) { + +// s := "abcd123" +// err := validate.Field(s, "alphanum") +// Equal(t, err, nil) + +// s = "abc!23" +// err = validate.Field(s, "alphanum") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "alphanum") + +// PanicMatches(t, func() { validate.Field(1, "alphanum") }, "interface conversion: interface is int, not string") +// } + +// func TestAlpha(t *testing.T) { + +// s := "abcd" +// err := validate.Field(s, "alpha") +// Equal(t, err, nil) + +// s = "abc1" +// err = validate.Field(s, "alpha") +// NotEqual(t, err, nil) +// Equal(t, err.Tag, "alpha") + +// PanicMatches(t, func() { validate.Field(1, "alpha") }, "interface conversion: interface is int, not string") +// } + +// func TestFlattening(t *testing.T) { + +// tSuccess := &TestString{ +// Required: "Required", +// Len: "length==10", +// Min: "min=1", +// Max: "1234567890", +// MinMax: "12345", +// Lt: "012345678", +// Lte: "0123456789", +// Gt: "01234567890", +// Gte: "0123456789", +// OmitEmpty: "", +// Sub: &SubTest{ +// Test: "1", +// }, +// SubIgnore: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "1", +// }, +// Iface: &Impl{ +// F: "123", +// }, +// } + +// err1 := validate.Struct(tSuccess).Flatten() +// Equal(t, len(err1), 0) + +// tFail := &TestString{ +// Required: "", +// Len: "", +// Min: "", +// Max: "12345678901", +// MinMax: "", +// OmitEmpty: "12345678901", +// Sub: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "", +// }, +// Iface: &Impl{ +// F: "12", +// }, +// } + +// err2 := validate.Struct(tFail).Flatten() + +// // Assert Top Level +// NotEqual(t, err2, nil) + +// // Assert Fields +// AssertMapFieldError(t, err2, "Len", "len") +// AssertMapFieldError(t, err2, "Gt", "gt") +// AssertMapFieldError(t, err2, "Gte", "gte") + +// // Assert Struct Field +// AssertMapFieldError(t, err2, "Sub.Test", "required") + +// // Assert Anonymous Struct Field +// AssertMapFieldError(t, err2, "Anonymous.A", "required") + +// // Assert Interface Field +// AssertMapFieldError(t, err2, "Iface.F", "len") +// } + +// func TestStructStringValidation(t *testing.T) { + +// validate.SetMaxStructPoolSize(11) + +// tSuccess := &TestString{ +// Required: "Required", +// Len: "length==10", +// Min: "min=1", +// Max: "1234567890", +// MinMax: "12345", +// Lt: "012345678", +// Lte: "0123456789", +// Gt: "01234567890", +// Gte: "0123456789", +// OmitEmpty: "", +// Sub: &SubTest{ +// Test: "1", +// }, +// SubIgnore: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "1", +// }, +// Iface: &Impl{ +// F: "123", +// }, +// } + +// err := validate.Struct(tSuccess) +// Equal(t, err, nil) + +// tFail := &TestString{ +// Required: "", +// Len: "", +// Min: "", +// Max: "12345678901", +// MinMax: "", +// Lt: "0123456789", +// Lte: "01234567890", +// Gt: "1", +// Gte: "1", +// OmitEmpty: "12345678901", +// Sub: &SubTest{ +// Test: "", +// }, +// Anonymous: struct { +// A string `validate:"required"` +// }{ +// A: "", +// }, +// Iface: &Impl{ +// F: "12", +// }, +// } + +// err = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, err, nil) +// Equal(t, err.Struct, "TestString") +// Equal(t, len(err.Errors), 10) +// Equal(t, len(err.StructErrors), 3) + +// // Assert Fields +// AssertFieldError(t, err, "Required", "required") +// AssertFieldError(t, err, "Len", "len") +// AssertFieldError(t, err, "Min", "min") +// AssertFieldError(t, err, "Max", "max") +// AssertFieldError(t, err, "MinMax", "min") +// AssertFieldError(t, err, "Gt", "gt") +// AssertFieldError(t, err, "Gte", "gte") +// AssertFieldError(t, err, "OmitEmpty", "max") + +// // Assert Anonymous embedded struct +// AssertStruct(t, err, "Anonymous", "") + +// // Assert SubTest embedded struct +// val := AssertStruct(t, err, "Sub", "SubTest") +// Equal(t, len(val.Errors), 1) +// Equal(t, len(val.StructErrors), 0) + +// AssertFieldError(t, val, "Test", "required") + +// errors := err.Error() +// NotEqual(t, errors, nil) +// } + +// func TestStructInt32Validation(t *testing.T) { + +// tSuccess := &TestInt32{ +// Required: 1, +// Len: 10, +// Min: 1, +// Max: 10, +// MinMax: 5, +// Lt: 9, +// Lte: 10, +// Gt: 11, +// Gte: 10, +// OmitEmpty: 0, +// } + +// err := validate.Struct(tSuccess) +// Equal(t, err, nil) + +// tFail := &TestInt32{ +// Required: 0, +// Len: 11, +// Min: -1, +// Max: 11, +// MinMax: -1, +// Lt: 10, +// Lte: 11, +// Gt: 10, +// Gte: 9, +// OmitEmpty: 11, +// } + +// err = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, err, nil) +// Equal(t, err.Struct, "TestInt32") +// Equal(t, len(err.Errors), 10) +// Equal(t, len(err.StructErrors), 0) + +// // Assert Fields +// AssertFieldError(t, err, "Required", "required") +// AssertFieldError(t, err, "Len", "len") +// AssertFieldError(t, err, "Min", "min") +// AssertFieldError(t, err, "Max", "max") +// AssertFieldError(t, err, "MinMax", "min") +// AssertFieldError(t, err, "Lt", "lt") +// AssertFieldError(t, err, "Lte", "lte") +// AssertFieldError(t, err, "Gt", "gt") +// AssertFieldError(t, err, "Gte", "gte") +// AssertFieldError(t, err, "OmitEmpty", "max") +// } + +// func TestStructUint64Validation(t *testing.T) { + +// tSuccess := &TestUint64{ +// Required: 1, +// Len: 10, +// Min: 1, +// Max: 10, +// MinMax: 5, +// OmitEmpty: 0, +// } + +// err := validate.Struct(tSuccess) +// Equal(t, err, nil) + +// tFail := &TestUint64{ +// Required: 0, +// Len: 11, +// Min: 0, +// Max: 11, +// MinMax: 0, +// OmitEmpty: 11, +// } + +// err = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, err, nil) +// Equal(t, err.Struct, "TestUint64") +// Equal(t, len(err.Errors), 6) +// Equal(t, len(err.StructErrors), 0) + +// // Assert Fields +// AssertFieldError(t, err, "Required", "required") +// AssertFieldError(t, err, "Len", "len") +// AssertFieldError(t, err, "Min", "min") +// AssertFieldError(t, err, "Max", "max") +// AssertFieldError(t, err, "MinMax", "min") +// AssertFieldError(t, err, "OmitEmpty", "max") +// } + +// func TestStructFloat64Validation(t *testing.T) { + +// tSuccess := &TestFloat64{ +// Required: 1, +// Len: 10, +// Min: 1, +// Max: 10, +// MinMax: 5, +// OmitEmpty: 0, +// } + +// err := validate.Struct(tSuccess) +// Equal(t, err, nil) + +// tFail := &TestFloat64{ +// Required: 0, +// Len: 11, +// Min: 0, +// Max: 11, +// MinMax: 0, +// OmitEmpty: 11, +// } + +// err = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, err, nil) +// Equal(t, err.Struct, "TestFloat64") +// Equal(t, len(err.Errors), 6) +// Equal(t, len(err.StructErrors), 0) + +// // Assert Fields +// AssertFieldError(t, err, "Required", "required") +// AssertFieldError(t, err, "Len", "len") +// AssertFieldError(t, err, "Min", "min") +// AssertFieldError(t, err, "Max", "max") +// AssertFieldError(t, err, "MinMax", "min") +// AssertFieldError(t, err, "OmitEmpty", "max") +// } + +// func TestStructSliceValidation(t *testing.T) { + +// tSuccess := &TestSlice{ +// Required: []int{1}, +// Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, +// Min: []int{1, 2}, +// Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, +// MinMax: []int{1, 2, 3, 4, 5}, +// OmitEmpty: []int{}, +// } + +// err := validate.Struct(tSuccess) +// Equal(t, err, nil) + +// tFail := &TestSlice{ +// Required: []int{}, +// Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, +// Min: []int{}, +// Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, +// MinMax: []int{}, +// OmitEmpty: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}, +// } + +// err = validate.Struct(tFail) + +// // Assert Top Level +// NotEqual(t, err, nil) +// Equal(t, err.Struct, "TestSlice") +// Equal(t, len(err.Errors), 6) +// Equal(t, len(err.StructErrors), 0) + +// // Assert Fields +// AssertFieldError(t, err, "Required", "required") +// AssertFieldError(t, err, "Len", "len") +// AssertFieldError(t, err, "Min", "min") +// AssertFieldError(t, err, "Max", "max") +// AssertFieldError(t, err, "MinMax", "min") +// AssertFieldError(t, err, "OmitEmpty", "max") +// } + +// func TestInvalidStruct(t *testing.T) { +// s := &SubTest{ +// Test: "1", +// } + +// PanicMatches(t, func() { validate.Struct(s.Test) }, "interface passed for validation is not a struct") +// } + +// func TestInvalidField(t *testing.T) { +// s := &SubTest{ +// Test: "1", +// } + +// PanicMatches(t, func() { validate.Field(s, "required") }, "Invalid field passed to fieldWithNameAndValue") +// } + +// func TestInvalidTagField(t *testing.T) { +// s := &SubTest{ +// Test: "1", +// } + +// PanicMatches(t, func() { validate.Field(s.Test, "") }, fmt.Sprintf("Invalid validation tag on field %s", "")) +// } + +// func TestInvalidValidatorFunction(t *testing.T) { +// s := &SubTest{ +// Test: "1", +// } + +// PanicMatches(t, func() { validate.Field(s.Test, "zzxxBadFunction") }, fmt.Sprintf("Undefined validation function on field %s", "")) +// } + +// func TestPoolObjectMaxSizeValidation(t *testing.T) { +// // this will ensure that the pool objects are let go +// // when the pool is saturated +// validate.SetMaxStructPoolSize(0) + +// tSuccess := &TestSlice{ +// Required: []int{1}, +// Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, +// Min: []int{1, 2}, +// Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, +// MinMax: []int{1, 2, 3, 4, 5}, +// OmitEmpty: []int{}, +// } + +// for i := 0; i < 2; i++ { +// err := validate.Struct(tSuccess) +// Equal(t, err, nil) +// } +// }