💯Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
validator/validator_test.go

9199 lines
229 KiB

package validator
import (
8 years ago
"bytes"
"context"
"database/sql"
"database/sql/driver"
"encoding/base64"
"encoding/json"
"fmt"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
5 years ago
. "github.com/go-playground/assert/v2"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/fr"
"github.com/go-playground/locales/nl"
ut "github.com/go-playground/universal-translator"
)
// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
//
// go test -cpuprofile cpu.out
// ./validator.test -test.bench=. -test.cpuprofile=cpu.prof
// go tool pprof validator.test cpu.prof
//
//
// go test -memprofile mem.out
type I interface {
Foo() string
}
type Impl struct {
F string `validate:"len=3"`
}
func (i *Impl) Foo() string {
return i.F
}
type SubTest struct {
Test string `validate:"required"`
}
type TestInterface struct {
Iface I
}
type TestString struct {
BlankTag string `validate:""`
Required string `validate:"required"`
Len string `validate:"len=10"`
Min string `validate:"min=1"`
Max string `validate:"max=10"`
MinMax string `validate:"min=1,max=10"`
Lt string `validate:"lt=10"`
Lte string `validate:"lte=10"`
Gt string `validate:"gt=10"`
Gte string `validate:"gte=10"`
OmitEmpty string `validate:"omitempty,min=1,max=10"`
Sub *SubTest
SubIgnore *SubTest `validate:"-"`
Anonymous struct {
A string `validate:"required"`
}
Iface I
}
type TestUint64 struct {
Required uint64 `validate:"required"`
Len uint64 `validate:"len=10"`
Min uint64 `validate:"min=1"`
Max uint64 `validate:"max=10"`
MinMax uint64 `validate:"min=1,max=10"`
OmitEmpty uint64 `validate:"omitempty,min=1,max=10"`
}
type TestFloat64 struct {
Required float64 `validate:"required"`
Len float64 `validate:"len=10"`
Min float64 `validate:"min=1"`
Max float64 `validate:"max=10"`
MinMax float64 `validate:"min=1,max=10"`
Lte float64 `validate:"lte=10"`
OmitEmpty float64 `validate:"omitempty,min=1,max=10"`
}
type TestSlice struct {
Required []int `validate:"required"`
Len []int `validate:"len=10"`
Min []int `validate:"min=1"`
Max []int `validate:"max=10"`
MinMax []int `validate:"min=1,max=10"`
OmitEmpty []int `validate:"omitempty,min=1,max=10"`
}
8 years ago
func AssertError(t *testing.T, err error, nsKey, structNsKey, field, structField, expectedTag string) {
errs := err.(ValidationErrors)
8 years ago
found := false
var fe FieldError
for i := 0; i < len(errs); i++ {
8 years ago
if errs[i].Namespace() == nsKey && errs[i].StructNamespace() == structNsKey {
8 years ago
found = true
fe = errs[i]
break
}
}
EqualSkip(t, 2, found, true)
NotEqualSkip(t, 2, fe, nil)
EqualSkip(t, 2, fe.Field(), field)
8 years ago
EqualSkip(t, 2, fe.StructField(), structField)
8 years ago
EqualSkip(t, 2, fe.Tag(), expectedTag)
}
func AssertDeepError(t *testing.T, err error, nsKey, structNsKey, field, structField, expectedTag, actualTag string) {
errs := err.(ValidationErrors)
found := false
var fe FieldError
for i := 0; i < len(errs); i++ {
if errs[i].Namespace() == nsKey && errs[i].StructNamespace() == structNsKey && errs[i].Tag() == expectedTag && errs[i].ActualTag() == actualTag {
found = true
fe = errs[i]
break
}
}
EqualSkip(t, 2, found, true)
NotEqualSkip(t, 2, fe, nil)
EqualSkip(t, 2, fe.Field(), field)
EqualSkip(t, 2, fe.StructField(), structField)
}
8 years ago
func getError(err error, nsKey, structNsKey string) FieldError {
errs := err.(ValidationErrors)
var fe FieldError
for i := 0; i < len(errs); i++ {
8 years ago
if errs[i].Namespace() == nsKey && errs[i].StructNamespace() == structNsKey {
fe = errs[i]
break
}
}
return fe
}
type valuer struct {
Name string
}
func (v valuer) Value() (driver.Value, error) {
if v.Name == "errorme" {
panic("SQL Driver Valuer error: some kind of error")
// return nil, errors.New("some kind of error")
}
if len(v.Name) == 0 {
return nil, nil
}
return v.Name, nil
}
type MadeUpCustomType struct {
FirstName string
LastName string
}
func ValidateCustomType(field reflect.Value) interface{} {
if cust, ok := field.Interface().(MadeUpCustomType); ok {
if len(cust.FirstName) == 0 || len(cust.LastName) == 0 {
return ""
}
return cust.FirstName + " " + cust.LastName
}
return ""
}
func OverrideIntTypeForSomeReason(field reflect.Value) interface{} {
if i, ok := field.Interface().(int); ok {
if i == 1 {
return "1"
}
if i == 2 {
return "12"
}
}
return ""
}
type CustomMadeUpStruct struct {
MadeUp MadeUpCustomType `validate:"required"`
OverriddenInt int `validate:"gt=1"`
}
func ValidateValuerType(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(driver.Valuer); ok {
val, err := valuer.Value()
if err != nil {
// handle the error how you want
return nil
}
return val
}
return nil
}
type TestPartial struct {
NoTag string
BlankTag string `validate:""`
Required string `validate:"required"`
SubSlice []*SubTest `validate:"required,dive"`
Sub *SubTest
SubIgnore *SubTest `validate:"-"`
Anonymous struct {
A string `validate:"required"`
ASubSlice []*SubTest `validate:"required,dive"`
SubAnonStruct []struct {
Test string `validate:"required"`
OtherTest string `validate:"required"`
} `validate:"required,dive"`
}
}
type TestStruct struct {
String string `validate:"required" json:"StringVal"`
}
8 years ago
func StructValidationTestStructSuccess(sl StructLevel) {
8 years ago
st := sl.Current().Interface().(TestStruct)
if st.String != "good value" {
sl.ReportError(st.String, "StringVal", "String", "badvalueteststruct", "good value")
}
}
8 years ago
func StructValidationTestStruct(sl StructLevel) {
8 years ago
st := sl.Current().Interface().(TestStruct)
if st.String != "bad value" {
sl.ReportError(st.String, "StringVal", "String", "badvalueteststruct", "bad value")
}
}
8 years ago
func StructValidationNoTestStructCustomName(sl StructLevel) {
8 years ago
st := sl.Current().Interface().(TestStruct)
8 years ago
if st.String != "bad value" {
sl.ReportError(st.String, "String", "", "badvalueteststruct", "bad value")
8 years ago
}
}
8 years ago
func StructValidationTestStructInvalid(sl StructLevel) {
8 years ago
st := sl.Current().Interface().(TestStruct)
8 years ago
if st.String != "bad value" {
sl.ReportError(nil, "StringVal", "String", "badvalueteststruct", "bad value")
8 years ago
}
}
8 years ago
func StructValidationTestStructReturnValidationErrors(sl StructLevel) {
8 years ago
s := sl.Current().Interface().(TestStructReturnValidationErrors)
8 years ago
errs := sl.Validator().Struct(s.Inner1.Inner2)
if errs == nil {
return
}
8 years ago
sl.ReportValidationErrors("Inner1.", "Inner1.", errs.(ValidationErrors))
}
8 years ago
func StructValidationTestStructReturnValidationErrors2(sl StructLevel) {
8 years ago
s := sl.Current().Interface().(TestStructReturnValidationErrors)
8 years ago
errs := sl.Validator().Struct(s.Inner1.Inner2)
if errs == nil {
return
}
8 years ago
sl.ReportValidationErrors("Inner1JSON.", "Inner1.", errs.(ValidationErrors))
}
8 years ago
type TestStructReturnValidationErrorsInner2 struct {
String string `validate:"required" json:"JSONString"`
}
8 years ago
type TestStructReturnValidationErrorsInner1 struct {
Inner2 *TestStructReturnValidationErrorsInner2
}
8 years ago
type TestStructReturnValidationErrors struct {
Inner1 *TestStructReturnValidationErrorsInner1 `json:"Inner1JSON"`
}
type StructLevelInvalidErr struct {
Value string
}
func StructLevelInvalidError(sl StructLevel) {
top := sl.Top().Interface().(StructLevelInvalidErr)
s := sl.Current().Interface().(StructLevelInvalidErr)
if top.Value == s.Value {
sl.ReportError(nil, "Value", "Value", "required", "")
}
}
func TestStructLevelInvalidError(t *testing.T) {
validate := New()
validate.RegisterStructValidation(StructLevelInvalidError, StructLevelInvalidErr{})
var test StructLevelInvalidErr
err := validate.Struct(test)
NotEqual(t, err, nil)
errs, ok := err.(ValidationErrors)
Equal(t, ok, true)
fe := errs[0]
Equal(t, fe.Field(), "Value")
Equal(t, fe.StructField(), "Value")
Equal(t, fe.Namespace(), "StructLevelInvalidErr.Value")
Equal(t, fe.StructNamespace(), "StructLevelInvalidErr.Value")
Equal(t, fe.Tag(), "required")
Equal(t, fe.ActualTag(), "required")
Equal(t, fe.Kind(), reflect.Invalid)
Equal(t, fe.Type(), reflect.TypeOf(nil))
}
func TestNameNamespace(t *testing.T) {
type Inner2Namespace struct {
String []string `validate:"dive,required" json:"JSONString"`
}
type Inner1Namespace struct {
Inner2 *Inner2Namespace `json:"Inner2JSON"`
}
type Namespace struct {
Inner1 *Inner1Namespace `json:"Inner1JSON"`
}
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
i2 := &Inner2Namespace{String: []string{"ok", "ok", "ok"}}
i1 := &Inner1Namespace{Inner2: i2}
ns := &Namespace{Inner1: i1}
errs := validate.Struct(ns)
Equal(t, errs, nil)
i2.String[1] = ""
errs = validate.Struct(ns)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 1)
8 years ago
AssertError(t, errs, "Namespace.Inner1JSON.Inner2JSON.JSONString[1]", "Namespace.Inner1.Inner2.String[1]", "JSONString[1]", "String[1]", "required")
8 years ago
fe := getError(ve, "Namespace.Inner1JSON.Inner2JSON.JSONString[1]", "Namespace.Inner1.Inner2.String[1]")
NotEqual(t, fe, nil)
Equal(t, fe.Field(), "JSONString[1]")
Equal(t, fe.StructField(), "String[1]")
Equal(t, fe.Namespace(), "Namespace.Inner1JSON.Inner2JSON.JSONString[1]")
Equal(t, fe.StructNamespace(), "Namespace.Inner1.Inner2.String[1]")
}
8 years ago
func TestAnonymous(t *testing.T) {
8 years ago
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
8 years ago
8 years ago
if name == "-" {
return ""
}
8 years ago
8 years ago
return name
})
8 years ago
8 years ago
type Test struct {
Anonymous struct {
A string `validate:"required" json:"EH"`
}
AnonymousB struct {
B string `validate:"required" json:"BEE"`
}
anonymousC struct {
c string `validate:"required"`
}
}
8 years ago
8 years ago
tst := &Test{
Anonymous: struct {
A string `validate:"required" json:"EH"`
}{
A: "1",
},
AnonymousB: struct {
B string `validate:"required" json:"BEE"`
}{
B: "",
},
anonymousC: struct {
c string `validate:"required"`
}{
c: "",
},
}
8 years ago
5 years ago
Equal(t, tst.anonymousC.c, "")
8 years ago
err := validate.Struct(tst)
NotEqual(t, err, nil)
8 years ago
8 years ago
errs := err.(ValidationErrors)
8 years ago
8 years ago
Equal(t, len(errs), 1)
AssertError(t, errs, "Test.AnonymousB.BEE", "Test.AnonymousB.B", "BEE", "B", "required")
8 years ago
8 years ago
fe := getError(errs, "Test.AnonymousB.BEE", "Test.AnonymousB.B")
NotEqual(t, fe, nil)
Equal(t, fe.Field(), "BEE")
Equal(t, fe.StructField(), "B")
8 years ago
8 years ago
s := struct {
c string `validate:"required"`
}{
c: "",
}
8 years ago
8 years ago
err = validate.Struct(s)
Equal(t, err, nil)
}
8 years ago
8 years ago
func TestAnonymousSameStructDifferentTags(t *testing.T) {
8 years ago
8 years ago
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
8 years ago
8 years ago
if name == "-" {
return ""
}
8 years ago
8 years ago
return name
})
8 years ago
8 years ago
type Test struct {
A interface{}
}
8 years ago
8 years ago
tst := &Test{
A: struct {
A string `validate:"required"`
}{
A: "",
},
}
8 years ago
8 years ago
err := validate.Struct(tst)
NotEqual(t, err, nil)
8 years ago
8 years ago
errs := err.(ValidationErrors)
8 years ago
8 years ago
Equal(t, len(errs), 1)
AssertError(t, errs, "Test.A.A", "Test.A.A", "A", "A", "required")
8 years ago
8 years ago
tst = &Test{
A: struct {
A string `validate:"omitempty,required"`
}{
A: "",
},
}
8 years ago
8 years ago
err = validate.Struct(tst)
Equal(t, err, nil)
}
8 years ago
8 years ago
func TestStructLevelReturnValidationErrors(t *testing.T) {
8 years ago
8 years ago
validate := New()
validate.RegisterStructValidation(StructValidationTestStructReturnValidationErrors, TestStructReturnValidationErrors{})
8 years ago
8 years ago
inner2 := &TestStructReturnValidationErrorsInner2{
String: "I'm HERE",
}
8 years ago
inner1 := &TestStructReturnValidationErrorsInner1{
Inner2: inner2,
}
8 years ago
val := &TestStructReturnValidationErrors{
Inner1: inner1,
}
8 years ago
errs := validate.Struct(val)
Equal(t, errs, nil)
8 years ago
inner2.String = ""
8 years ago
errs = validate.Struct(val)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 2)
AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.Inner2.String", "TestStructReturnValidationErrors.Inner1.Inner2.String", "String", "String", "required")
// this is an extra error reported from struct validation
AssertError(t, errs, "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String", "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String", "String", "String", "required")
}
8 years ago
func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) {
8 years ago
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
8 years ago
if name == "-" {
return ""
}
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
return name
})
validate.RegisterStructValidation(StructValidationTestStructReturnValidationErrors2, TestStructReturnValidationErrors{})
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
inner2 := &TestStructReturnValidationErrorsInner2{
String: "I'm HERE",
}
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
inner1 := &TestStructReturnValidationErrorsInner1{
Inner2: inner2,
}
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
val := &TestStructReturnValidationErrors{
Inner1: inner1,
}
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
errs := validate.Struct(val)
Equal(t, errs, nil)
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
inner2.String = ""
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
errs = validate.Struct(val)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 2)
AssertError(t, errs, "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString", "TestStructReturnValidationErrors.Inner1.Inner2.String", "JSONString", "String", "required")
// this is an extra error reported from struct validation, it's a badly formatted one, but on purpose
AssertError(t, errs, "TestStructReturnValidationErrors.Inner1JSON.TestStructReturnValidationErrorsInner2.JSONString", "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String", "JSONString", "String", "required")
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
fe := getError(errs, "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString", "TestStructReturnValidationErrors.Inner1.Inner2.String")
NotEqual(t, fe, nil)
final touches + README updates fresh test of old vs new benchmarks ```go benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 155 118 -23.87% BenchmarkFieldFailure-8 777 758 -2.45% BenchmarkFieldDiveSuccess-8 2813 2471 -12.16% BenchmarkFieldDiveFailure-8 3544 3172 -10.50% BenchmarkFieldCustomTypeSuccess-8 328 300 -8.54% BenchmarkFieldCustomTypeFailure-8 748 775 +3.61% BenchmarkFieldOrTagSuccess-8 1169 1122 -4.02% BenchmarkFieldOrTagFailure-8 1205 1167 -3.15% BenchmarkStructLevelValidationSuccess-8 670 548 -18.21% BenchmarkStructLevelValidationFailure-8 1380 558 -59.57% BenchmarkStructSimpleCustomTypeSuccess-8 889 623 -29.92% BenchmarkStructSimpleCustomTypeFailure-8 1536 1381 -10.09% BenchmarkStructPartialSuccess-8 1194 1036 -13.23% BenchmarkStructPartialFailure-8 1869 1734 -7.22% BenchmarkStructExceptSuccess-8 949 888 -6.43% BenchmarkStructExceptFailure-8 1181 1036 -12.28% BenchmarkStructSimpleCrossFieldSuccess-8 948 773 -18.46% BenchmarkStructSimpleCrossFieldFailure-8 1708 1487 -12.94% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1608 1261 -21.58% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2320 2055 -11.42% BenchmarkStructSimpleSuccess-8 833 519 -37.70% BenchmarkStructSimpleFailure-8 1612 1429 -11.35% BenchmarkStructSimpleSuccessParallel-8 239 146 -38.91% BenchmarkStructSimpleFailureParallel-8 664 551 -17.02% BenchmarkStructComplexSuccess-8 5025 3269 -34.95% BenchmarkStructComplexFailure-8 10166 8436 -17.02% BenchmarkStructComplexSuccessParallel-8 1591 1024 -35.64% BenchmarkStructComplexFailureParallel-8 4306 3536 -17.88% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 27 28 +3.70% BenchmarkFieldDiveFailure-8 31 32 +3.23% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 6 +0.00% BenchmarkStructLevelValidationSuccess-8 6 5 -16.67% BenchmarkStructLevelValidationFailure-8 11 5 -54.55% BenchmarkStructSimpleCustomTypeSuccess-8 5 3 -40.00% BenchmarkStructSimpleCustomTypeFailure-8 11 9 -18.18% BenchmarkStructPartialSuccess-8 10 9 -10.00% BenchmarkStructPartialFailure-8 15 14 -6.67% BenchmarkStructExceptSuccess-8 7 7 +0.00% BenchmarkStructExceptFailure-8 10 9 -10.00% BenchmarkStructSimpleCrossFieldSuccess-8 6 4 -33.33% BenchmarkStructSimpleCrossFieldFailure-8 11 9 -18.18% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 10 7 -30.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 15 12 -20.00% BenchmarkStructSimpleSuccess-8 3 1 -66.67% BenchmarkStructSimpleFailure-8 11 9 -18.18% BenchmarkStructSimpleSuccessParallel-8 3 1 -66.67% BenchmarkStructSimpleFailureParallel-8 11 9 -18.18% BenchmarkStructComplexSuccess-8 32 15 -53.12% BenchmarkStructComplexFailure-8 77 60 -22.08% BenchmarkStructComplexSuccessParallel-8 32 15 -53.12% BenchmarkStructComplexFailureParallel-8 77 60 -22.08% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 432 +0.00% BenchmarkFieldDiveSuccess-8 384 464 +20.83% BenchmarkFieldDiveFailure-8 816 896 +9.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 432 +0.00% BenchmarkFieldOrTagSuccess-8 4 4 +0.00% BenchmarkFieldOrTagFailure-8 448 448 +0.00% BenchmarkStructLevelValidationSuccess-8 168 160 -4.76% BenchmarkStructLevelValidationFailure-8 632 160 -74.68% BenchmarkStructSimpleCustomTypeSuccess-8 56 36 -35.71% BenchmarkStructSimpleCustomTypeFailure-8 656 640 -2.44% BenchmarkStructPartialSuccess-8 352 272 -22.73% BenchmarkStructPartialFailure-8 808 730 -9.65% BenchmarkStructExceptSuccess-8 314 250 -20.38% BenchmarkStructExceptFailure-8 352 272 -22.73% BenchmarkStructSimpleCrossFieldSuccess-8 96 80 -16.67% BenchmarkStructSimpleCrossFieldFailure-8 552 536 -2.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 136 112 -17.65% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 600 576 -4.00% BenchmarkStructSimpleSuccess-8 24 4 -83.33% BenchmarkStructSimpleFailure-8 656 640 -2.44% BenchmarkStructSimpleSuccessParallel-8 24 4 -83.33% BenchmarkStructSimpleFailureParallel-8 656 640 -2.44% BenchmarkStructComplexSuccess-8 392 244 -37.76% BenchmarkStructComplexFailure-8 3745 3609 -3.63% BenchmarkStructComplexSuccessParallel-8 392 244 -37.76% BenchmarkStructComplexFailureParallel-8 3745 3609 -3.63% ```
8 years ago
8 years ago
// check for proper JSON namespace
Equal(t, fe.Field(), "JSONString")
Equal(t, fe.StructField(), "String")
Equal(t, fe.Namespace(), "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString")
Equal(t, fe.StructNamespace(), "TestStructReturnValidationErrors.Inner1.Inner2.String")
8 years ago
fe = getError(errs, "TestStructReturnValidationErrors.Inner1JSON.TestStructReturnValidationErrorsInner2.JSONString", "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String")
NotEqual(t, fe, nil)
8 years ago
// check for proper JSON namespace
Equal(t, fe.Field(), "JSONString")
Equal(t, fe.StructField(), "String")
Equal(t, fe.Namespace(), "TestStructReturnValidationErrors.Inner1JSON.TestStructReturnValidationErrorsInner2.JSONString")
Equal(t, fe.StructNamespace(), "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String")
}
8 years ago
func TestStructLevelValidations(t *testing.T) {
8 years ago
v1 := New()
v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{})
8 years ago
tst := &TestStruct{
String: "good value",
}
8 years ago
errs := v1.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct")
8 years ago
v2 := New()
v2.RegisterStructValidation(StructValidationNoTestStructCustomName, TestStruct{})
8 years ago
errs = v2.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestStruct.String", "TestStruct.String", "String", "String", "badvalueteststruct")
8 years ago
v3 := New()
v3.RegisterStructValidation(StructValidationTestStructInvalid, TestStruct{})
8 years ago
errs = v3.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct")
8 years ago
v4 := New()
v4.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{})
8 years ago
errs = v4.Struct(tst)
Equal(t, errs, nil)
}
8 years ago
func TestAliasTags(t *testing.T) {
8 years ago
validate := New()
validate.RegisterAlias("iscoloralias", "hexcolor|rgb|rgba|hsl|hsla")
8 years ago
s := "rgb(255,255,255)"
errs := validate.Var(s, "iscoloralias")
Equal(t, errs, nil)
8 years ago
s = ""
errs = validate.Var(s, "omitempty,iscoloralias")
Equal(t, errs, nil)
8 years ago
s = "rgb(255,255,0)"
errs = validate.Var(s, "iscoloralias,len=5")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "len")
8 years ago
8 years ago
type Test struct {
Color string `validate:"iscoloralias"`
}
8 years ago
8 years ago
tst := &Test{
Color: "#000",
}
8 years ago
8 years ago
errs = validate.Struct(tst)
Equal(t, errs, nil)
8 years ago
8 years ago
tst.Color = "cfvre"
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.Color", "Test.Color", "Color", "Color", "iscoloralias")
8 years ago
8 years ago
fe := getError(errs, "Test.Color", "Test.Color")
NotEqual(t, fe, nil)
Equal(t, fe.ActualTag(), "hexcolor|rgb|rgba|hsl|hsla")
validate.RegisterAlias("req", "required,dive,iscoloralias")
arr := []string{"val1", "#fff", "#000"}
errs = validate.Var(arr, "req")
NotEqual(t, errs, nil)
AssertError(t, errs, "[0]", "[0]", "[0]", "[0]", "iscoloralias")
PanicMatches(t, func() { validate.RegisterAlias("exists!", "gt=5,lt=10") }, "Alias 'exists!' either contains restricted characters or is the same as a restricted tag needed for normal operation")
}
8 years ago
func TestNilValidator(t *testing.T) {
type TestStruct struct {
Test string `validate:"required"`
}
ts := TestStruct{}
var val *Validate
fn := func(fl FieldLevel) bool {
return fl.Parent().String() == fl.Field().String()
}
PanicMatches(t, func() { val.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) }, "runtime error: invalid memory address or nil pointer dereference")
5 years ago
PanicMatches(t, func() { _ = val.RegisterValidation("something", fn) }, "runtime error: invalid memory address or nil pointer dereference")
PanicMatches(t, func() { _ = val.Var(ts.Test, "required") }, "runtime error: invalid memory address or nil pointer dereference")
PanicMatches(t, func() { _ = val.VarWithValue("test", ts.Test, "required") }, "runtime error: invalid memory address or nil pointer dereference")
PanicMatches(t, func() { _ = val.Struct(ts) }, "runtime error: invalid memory address or nil pointer dereference")
PanicMatches(t, func() { _ = val.StructExcept(ts, "Test") }, "runtime error: invalid memory address or nil pointer dereference")
PanicMatches(t, func() { _ = val.StructPartial(ts, "Test") }, "runtime error: invalid memory address or nil pointer dereference")
}
func TestStructPartial(t *testing.T) {
p1 := []string{
"NoTag",
"Required",
}
p2 := []string{
"SubSlice[0].Test",
"Sub",
"SubIgnore",
"Anonymous.A",
}
p3 := []string{
"SubTest.Test",
}
p4 := []string{
"A",
}
tPartial := &TestPartial{
NoTag: "NoTag",
Required: "Required",
SubSlice: []*SubTest{
{
Test: "Required",
},
{
Test: "Required",
},
},
Sub: &SubTest{
Test: "1",
},
SubIgnore: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
ASubSlice []*SubTest `validate:"required,dive"`
SubAnonStruct []struct {
Test string `validate:"required"`
OtherTest string `validate:"required"`
} `validate:"required,dive"`
}{
A: "1",
ASubSlice: []*SubTest{
{
Test: "Required",
},
{
Test: "Required",
},
},
SubAnonStruct: []struct {
Test string `validate:"required"`
OtherTest string `validate:"required"`
}{
{"Required", "RequiredOther"},
{"Required", "RequiredOther"},
},
},
}
validate := New()
// the following should all return no errors as everything is valid in
// the default state
errs := validate.StructPartialCtx(context.Background(), tPartial, p1...)
Equal(t, errs, nil)
errs = validate.StructPartial(tPartial, p2...)
Equal(t, errs, nil)
// this isn't really a robust test, but is ment to illustrate the ANON CASE below
errs = validate.StructPartial(tPartial.SubSlice[0], p3...)
Equal(t, errs, nil)
errs = validate.StructExceptCtx(context.Background(), tPartial, p1...)
Equal(t, errs, nil)
errs = validate.StructExcept(tPartial, p2...)
Equal(t, errs, nil)
// mod tParial for required feild and re-test making sure invalid fields are NOT required:
tPartial.Required = ""
errs = validate.StructExcept(tPartial, p1...)
Equal(t, errs, nil)
errs = validate.StructPartial(tPartial, p2...)
Equal(t, errs, nil)
// inversion and retesting Partial to generate failures:
errs = validate.StructPartial(tPartial, p1...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Required", "TestPartial.Required", "Required", "Required", "required")
errs = validate.StructExcept(tPartial, p2...)
AssertError(t, errs, "TestPartial.Required", "TestPartial.Required", "Required", "Required", "required")
// reset Required field, and set nested struct
tPartial.Required = "Required"
tPartial.Anonymous.A = ""
// will pass as unset feilds is not going to be tested
errs = validate.StructPartial(tPartial, p1...)
Equal(t, errs, nil)
errs = validate.StructExcept(tPartial, p2...)
Equal(t, errs, nil)
// ANON CASE the response here is strange, it clearly does what it is being told to
errs = validate.StructExcept(tPartial.Anonymous, p4...)
Equal(t, errs, nil)
// will fail as unset feild is tested
errs = validate.StructPartial(tPartial, p2...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Anonymous.A", "TestPartial.Anonymous.A", "A", "A", "required")
errs = validate.StructExcept(tPartial, p1...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Anonymous.A", "TestPartial.Anonymous.A", "A", "A", "required")
// reset nested struct and unset struct in slice
tPartial.Anonymous.A = "Required"
tPartial.SubSlice[0].Test = ""
// these will pass as unset item is NOT tested
errs = validate.StructPartial(tPartial, p1...)
Equal(t, errs, nil)
errs = validate.StructExcept(tPartial, p2...)
Equal(t, errs, nil)
// these will fail as unset item IS tested
errs = validate.StructExcept(tPartial, p1...)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required")
Equal(t, len(errs.(ValidationErrors)), 1)
errs = validate.StructPartial(tPartial, p2...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required")
Equal(t, len(errs.(ValidationErrors)), 1)
// Unset second slice member concurrently to test dive behavior:
tPartial.SubSlice[1].Test = ""
errs = validate.StructPartial(tPartial, p1...)
Equal(t, errs, nil)
// NOTE: When specifying nested items, it is still the users responsibility
// to specify the dive tag, the library does not override this.
errs = validate.StructExcept(tPartial, p2...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required")
errs = validate.StructExcept(tPartial, p1...)
Equal(t, len(errs.(ValidationErrors)), 2)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required")
AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required")
errs = validate.StructPartial(tPartial, p2...)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required")
// reset struct in slice, and unset struct in slice in unset posistion
tPartial.SubSlice[0].Test = "Required"
// these will pass as the unset item is NOT tested
errs = validate.StructPartial(tPartial, p1...)
Equal(t, errs, nil)
errs = validate.StructPartial(tPartial, p2...)
Equal(t, errs, nil)
// testing for missing item by exception, yes it dives and fails
errs = validate.StructExcept(tPartial, p1...)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required")
errs = validate.StructExcept(tPartial, p2...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.SubSlice[1].Test", "TestPartial.SubSlice[1].Test", "Test", "Test", "required")
tPartial.SubSlice[1].Test = "Required"
tPartial.Anonymous.SubAnonStruct[0].Test = ""
// these will pass as the unset item is NOT tested
errs = validate.StructPartial(tPartial, p1...)
Equal(t, errs, nil)
errs = validate.StructPartial(tPartial, p2...)
Equal(t, errs, nil)
errs = validate.StructExcept(tPartial, p1...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "Test", "required")
errs = validate.StructExcept(tPartial, p2...)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "Test", "required")
}
func TestCrossStructLteFieldValidation(t *testing.T) {
type Inner struct {
CreatedAt *time.Time
String string
Int int
Uint uint
Float float64
Array []string
}
type Test struct {
Inner *Inner
CreatedAt *time.Time `validate:"ltecsfield=Inner.CreatedAt"`
String string `validate:"ltecsfield=Inner.String"`
Int int `validate:"ltecsfield=Inner.Int"`
Uint uint `validate:"ltecsfield=Inner.Uint"`
Float float64 `validate:"ltecsfield=Inner.Float"`
Array []string `validate:"ltecsfield=Inner.Array"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * 5)
inner := &Inner{
CreatedAt: &then,
String: "abcd",
Int: 13,
Uint: 13,
Float: 1.13,
Array: []string{"val1", "val2"},
}
test := &Test{
Inner: inner,
CreatedAt: &now,
String: "abc",
Int: 12,
Uint: 12,
Float: 1.12,
Array: []string{"val1"},
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test.CreatedAt = &then
test.String = "abcd"
test.Int = 13
test.Uint = 13
test.Float = 1.13
test.Array = []string{"val1", "val2"}
errs = validate.Struct(test)
Equal(t, errs, nil)
after := now.Add(time.Hour * 10)
test.CreatedAt = &after
test.String = "abce"
test.Int = 14
test.Uint = 14
test.Float = 1.14
test.Array = []string{"val1", "val2", "val3"}
errs = validate.Struct(test)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltecsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltecsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltecsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltecsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltecsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltecsfield")
errs = validate.VarWithValueCtx(context.Background(), 1, "", "ltecsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltecsfield")
// this test is for the WARNING about unforeseen validation issues.
errs = validate.VarWithValue(test, now, "ltecsfield")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 6)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltecsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltecsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltecsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltecsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltecsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltecsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"ltecsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltecsfield")
}
func TestCrossStructLtFieldValidation(t *testing.T) {
type Inner struct {
CreatedAt *time.Time
String string
Int int
Uint uint
Float float64
Array []string
}
type Test struct {
Inner *Inner
CreatedAt *time.Time `validate:"ltcsfield=Inner.CreatedAt"`
String string `validate:"ltcsfield=Inner.String"`
Int int `validate:"ltcsfield=Inner.Int"`
Uint uint `validate:"ltcsfield=Inner.Uint"`
Float float64 `validate:"ltcsfield=Inner.Float"`
Array []string `validate:"ltcsfield=Inner.Array"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * 5)
inner := &Inner{
CreatedAt: &then,
String: "abcd",
Int: 13,
Uint: 13,
Float: 1.13,
Array: []string{"val1", "val2"},
}
test := &Test{
Inner: inner,
CreatedAt: &now,
String: "abc",
Int: 12,
Uint: 12,
Float: 1.12,
Array: []string{"val1"},
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test.CreatedAt = &then
test.String = "abcd"
test.Int = 13
test.Uint = 13
test.Float = 1.13
test.Array = []string{"val1", "val2"}
errs = validate.Struct(test)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltcsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltcsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltcsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltcsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltcsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltcsfield")
errs = validate.VarWithValue(1, "", "ltcsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltcsfield")
// this test is for the WARNING about unforeseen validation issues.
errs = validate.VarWithValue(test, now, "ltcsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "ltcsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "ltcsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "ltcsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "ltcsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "ltcsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "ltcsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"ltcsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltcsfield")
}
func TestCrossStructGteFieldValidation(t *testing.T) {
type Inner struct {
CreatedAt *time.Time
String string
Int int
Uint uint
Float float64
Array []string
}
type Test struct {
Inner *Inner
CreatedAt *time.Time `validate:"gtecsfield=Inner.CreatedAt"`
String string `validate:"gtecsfield=Inner.String"`
Int int `validate:"gtecsfield=Inner.Int"`
Uint uint `validate:"gtecsfield=Inner.Uint"`
Float float64 `validate:"gtecsfield=Inner.Float"`
Array []string `validate:"gtecsfield=Inner.Array"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * -5)
inner := &Inner{
CreatedAt: &then,
String: "abcd",
Int: 13,
Uint: 13,
Float: 1.13,
Array: []string{"val1", "val2"},
}
test := &Test{
Inner: inner,
CreatedAt: &now,
String: "abcde",
Int: 14,
Uint: 14,
Float: 1.14,
Array: []string{"val1", "val2", "val3"},
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test.CreatedAt = &then
test.String = "abcd"
test.Int = 13
test.Uint = 13
test.Float = 1.13
test.Array = []string{"val1", "val2"}
errs = validate.Struct(test)
Equal(t, errs, nil)
before := now.Add(time.Hour * -10)
test.CreatedAt = &before
test.String = "abc"
test.Int = 12
test.Uint = 12
test.Float = 1.12
test.Array = []string{"val1"}
errs = validate.Struct(test)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtecsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtecsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtecsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtecsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtecsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtecsfield")
errs = validate.VarWithValue(1, "", "gtecsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtecsfield")
// this test is for the WARNING about unforeseen validation issues.
errs = validate.VarWithValue(test, now, "gtecsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtecsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtecsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtecsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtecsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtecsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtecsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"gtecsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtecsfield")
}
func TestCrossStructGtFieldValidation(t *testing.T) {
type Inner struct {
CreatedAt *time.Time
String string
Int int
Uint uint
Float float64
Array []string
}
type Test struct {
Inner *Inner
CreatedAt *time.Time `validate:"gtcsfield=Inner.CreatedAt"`
String string `validate:"gtcsfield=Inner.String"`
Int int `validate:"gtcsfield=Inner.Int"`
Uint uint `validate:"gtcsfield=Inner.Uint"`
Float float64 `validate:"gtcsfield=Inner.Float"`
Array []string `validate:"gtcsfield=Inner.Array"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * -5)
inner := &Inner{
CreatedAt: &then,
String: "abcd",
Int: 13,
Uint: 13,
Float: 1.13,
Array: []string{"val1", "val2"},
}
test := &Test{
Inner: inner,
CreatedAt: &now,
String: "abcde",
Int: 14,
Uint: 14,
Float: 1.14,
Array: []string{"val1", "val2", "val3"},
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test.CreatedAt = &then
test.String = "abcd"
test.Int = 13
test.Uint = 13
test.Float = 1.13
test.Array = []string{"val1", "val2"}
errs = validate.Struct(test)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtcsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtcsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtcsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtcsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtcsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtcsfield")
errs = validate.VarWithValue(1, "", "gtcsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtcsfield")
// this test is for the WARNING about unforeseen validation issues.
errs = validate.VarWithValue(test, now, "gtcsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "gtcsfield")
AssertError(t, errs, "Test.String", "Test.String", "String", "String", "gtcsfield")
AssertError(t, errs, "Test.Int", "Test.Int", "Int", "Int", "gtcsfield")
AssertError(t, errs, "Test.Uint", "Test.Uint", "Uint", "Uint", "gtcsfield")
AssertError(t, errs, "Test.Float", "Test.Float", "Float", "Float", "gtcsfield")
AssertError(t, errs, "Test.Array", "Test.Array", "Array", "Array", "gtcsfield")
type Other struct {
Value string
}
type Test2 struct {
Value Other
Time time.Time `validate:"gtcsfield=Value"`
}
tst := Test2{
Value: Other{Value: "StringVal"},
Time: then,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtcsfield")
}
func TestCrossStructNeFieldValidation(t *testing.T) {
type Inner struct {
CreatedAt *time.Time
}
type Test struct {
Inner *Inner
CreatedAt *time.Time `validate:"necsfield=Inner.CreatedAt"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * 5)
inner := &Inner{
CreatedAt: &then,
}
test := &Test{
Inner: inner,
CreatedAt: &now,
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test.CreatedAt = &then
errs = validate.Struct(test)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "necsfield")
var j uint64
var k float64
var j2 uint64
var k2 float64
s := "abcd"
i := 1
j = 1
k = 1.543
arr := []string{"test"}
s2 := "abcd"
i2 := 1
j2 = 1
k2 = 1.543
arr2 := []string{"test"}
arr3 := []string{"test", "test2"}
now2 := now
errs = validate.VarWithValue(s, s2, "necsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "necsfield")
errs = validate.VarWithValue(i2, i, "necsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "necsfield")
errs = validate.VarWithValue(j2, j, "necsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "necsfield")
errs = validate.VarWithValue(k2, k, "necsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "necsfield")
errs = validate.VarWithValue(arr2, arr, "necsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "necsfield")
errs = validate.VarWithValue(now2, now, "necsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "necsfield")
errs = validate.VarWithValue(arr3, arr, "necsfield")
Equal(t, errs, nil)
type SInner struct {
Name string
}
type TStruct struct {
Inner *SInner
CreatedAt *time.Time `validate:"necsfield=Inner"`
}
sinner := &SInner{
Name: "NAME",
}
test2 := &TStruct{
Inner: sinner,
CreatedAt: &now,
}
errs = validate.Struct(test2)
Equal(t, errs, nil)
test2.Inner = nil
errs = validate.Struct(test2)
Equal(t, errs, nil)
errs = validate.VarWithValue(nil, 1, "necsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "necsfield")
}
func TestCrossStructEqFieldValidation(t *testing.T) {
type Inner struct {
CreatedAt *time.Time
}
type Test struct {
Inner *Inner
CreatedAt *time.Time `validate:"eqcsfield=Inner.CreatedAt"`
}
now := time.Now().UTC()
inner := &Inner{
CreatedAt: &now,
}
test := &Test{
Inner: inner,
CreatedAt: &now,
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
newTime := time.Now().UTC()
test.CreatedAt = &newTime
errs = validate.Struct(test)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.CreatedAt", "Test.CreatedAt", "CreatedAt", "CreatedAt", "eqcsfield")
var j uint64
var k float64
s := "abcd"
i := 1
j = 1
k = 1.543
arr := []string{"test"}
var j2 uint64
var k2 float64
s2 := "abcd"
i2 := 1
j2 = 1
k2 = 1.543
arr2 := []string{"test"}
arr3 := []string{"test", "test2"}
now2 := now
errs = validate.VarWithValue(s, s2, "eqcsfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(i2, i, "eqcsfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(j2, j, "eqcsfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(k2, k, "eqcsfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(arr2, arr, "eqcsfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(now2, now, "eqcsfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(arr3, arr, "eqcsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "eqcsfield")
type SInner struct {
Name string
}
type TStruct struct {
Inner *SInner
CreatedAt *time.Time `validate:"eqcsfield=Inner"`
}
sinner := &SInner{
Name: "NAME",
}
test2 := &TStruct{
Inner: sinner,
CreatedAt: &now,
}
errs = validate.Struct(test2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TStruct.CreatedAt", "TStruct.CreatedAt", "CreatedAt", "CreatedAt", "eqcsfield")
test2.Inner = nil
errs = validate.Struct(test2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TStruct.CreatedAt", "TStruct.CreatedAt", "CreatedAt", "CreatedAt", "eqcsfield")
errs = validate.VarWithValue(nil, 1, "eqcsfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "eqcsfield")
}
func TestCrossNamespaceFieldValidation(t *testing.T) {
type SliceStruct struct {
Name string
}
type Inner struct {
CreatedAt *time.Time
Slice []string
SliceStructs []*SliceStruct
SliceSlice [][]string
SliceSliceStruct [][]*SliceStruct
SliceMap []map[string]string
Map map[string]string
MapMap map[string]map[string]string
MapStructs map[string]*SliceStruct
MapMapStruct map[string]map[string]*SliceStruct
MapSlice map[string][]string
MapInt map[int]string
MapInt8 map[int8]string
MapInt16 map[int16]string
MapInt32 map[int32]string
MapInt64 map[int64]string
MapUint map[uint]string
MapUint8 map[uint8]string
MapUint16 map[uint16]string
MapUint32 map[uint32]string
MapUint64 map[uint64]string
MapFloat32 map[float32]string
MapFloat64 map[float64]string
MapBool map[bool]string
}
type Test struct {
Inner *Inner
CreatedAt *time.Time
}
now := time.Now()
inner := &Inner{
CreatedAt: &now,
Slice: []string{"val1", "val2", "val3"},
SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}},
SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}},
SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}},
SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}},
Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"},
MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}},
MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}},
MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}},
MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}},
MapInt: map[int]string{1: "val1", 2: "val2", 3: "val3"},
MapInt8: map[int8]string{1: "val1", 2: "val2", 3: "val3"},
MapInt16: map[int16]string{1: "val1", 2: "val2", 3: "val3"},
MapInt32: map[int32]string{1: "val1", 2: "val2", 3: "val3"},
MapInt64: map[int64]string{1: "val1", 2: "val2", 3: "val3"},
MapUint: map[uint]string{1: "val1", 2: "val2", 3: "val3"},
MapUint8: map[uint8]string{1: "val1", 2: "val2", 3: "val3"},
MapUint16: map[uint16]string{1: "val1", 2: "val2", 3: "val3"},
MapUint32: map[uint32]string{1: "val1", 2: "val2", 3: "val3"},
MapUint64: map[uint64]string{1: "val1", 2: "val2", 3: "val3"},
MapFloat32: map[float32]string{1.01: "val1", 2.02: "val2", 3.03: "val3"},
MapFloat64: map[float64]string{1.01: "val1", 2.02: "val2", 3.03: "val3"},
MapBool: map[bool]string{true: "val1", false: "val2"},
}
test := &Test{
Inner: inner,
CreatedAt: &now,
}
val := reflect.ValueOf(test)
vd := New()
v := &validate{
v: vd,
}
5 years ago
current, kind, _, ok := v.getStructFieldOKInternal(val, "Inner.CreatedAt")
Equal(t, ok, true)
Equal(t, kind, reflect.Struct)
tm, ok := current.Interface().(time.Time)
Equal(t, ok, true)
Equal(t, tm, now)
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.Slice[1]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, _, _, ok = v.getStructFieldOKInternal(val, "Inner.CrazyNonExistantField")
Equal(t, ok, false)
5 years ago
current, _, _, ok = v.getStructFieldOKInternal(val, "Inner.Slice[101]")
Equal(t, ok, false)
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.Map[key3]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val3")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapMap[key2][key2-1]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapStructs[key2].Name")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "name2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapMapStruct[key3][key3-1].Name")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "name3")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceSlice[2][0]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "7")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceSliceStruct[2][1].Name")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "name8")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceMap[1][key5]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val5")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapSlice[key3][2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "9")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt8[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt16[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt32[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapInt64[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint8[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint16[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint32[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapUint64[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapFloat32[3.03]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val3")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapFloat64[2.02]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val2")
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.MapBool[true]")
Equal(t, ok, true)
Equal(t, kind, reflect.String)
Equal(t, current.String(), "val1")
inner = &Inner{
CreatedAt: &now,
Slice: []string{"val1", "val2", "val3"},
SliceStructs: []*SliceStruct{{Name: "name1"}, {Name: "name2"}, nil},
SliceSlice: [][]string{{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}},
SliceSliceStruct: [][]*SliceStruct{{{Name: "name1"}, {Name: "name2"}, {Name: "name3"}}, {{Name: "name4"}, {Name: "name5"}, {Name: "name6"}}, {{Name: "name7"}, {Name: "name8"}, {Name: "name9"}}},
SliceMap: []map[string]string{{"key1": "val1", "key2": "val2", "key3": "val3"}, {"key4": "val4", "key5": "val5", "key6": "val6"}},
Map: map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"},
MapStructs: map[string]*SliceStruct{"key1": {Name: "name1"}, "key2": {Name: "name2"}, "key3": {Name: "name3"}},
MapMap: map[string]map[string]string{"key1": {"key1-1": "val1"}, "key2": {"key2-1": "val2"}, "key3": {"key3-1": "val3"}},
MapMapStruct: map[string]map[string]*SliceStruct{"key1": {"key1-1": {Name: "name1"}}, "key2": {"key2-1": {Name: "name2"}}, "key3": {"key3-1": {Name: "name3"}}},
MapSlice: map[string][]string{"key1": {"1", "2", "3"}, "key2": {"4", "5", "6"}, "key3": {"7", "8", "9"}},
}
test = &Test{
Inner: inner,
CreatedAt: nil,
}
val = reflect.ValueOf(test)
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceStructs[2]")
Equal(t, ok, true)
Equal(t, kind, reflect.Ptr)
Equal(t, current.String(), "<*validator.SliceStruct Value>")
Equal(t, current.IsNil(), true)
5 years ago
current, kind, _, ok = v.getStructFieldOKInternal(val, "Inner.SliceStructs[2].Name")
Equal(t, ok, false)
Equal(t, kind, reflect.Ptr)
Equal(t, current.String(), "<*validator.SliceStruct Value>")
Equal(t, current.IsNil(), true)
PanicMatches(t, func() { v.getStructFieldOKInternal(reflect.ValueOf(1), "crazyinput") }, "Invalid field namespace")
}
func TestExistsValidation(t *testing.T) {
jsonText := "{ \"truthiness2\": true }"
type Thing struct {
Truthiness *bool `json:"truthiness" validate:"required"`
}
var ting Thing
err := json.Unmarshal([]byte(jsonText), &ting)
Equal(t, err, nil)
NotEqual(t, ting, nil)
Equal(t, ting.Truthiness, nil)
validate := New()
errs := validate.Struct(ting)
NotEqual(t, errs, nil)
AssertError(t, errs, "Thing.Truthiness", "Thing.Truthiness", "Truthiness", "Truthiness", "required")
jsonText = "{ \"truthiness\": true }"
err = json.Unmarshal([]byte(jsonText), &ting)
Equal(t, err, nil)
NotEqual(t, ting, nil)
Equal(t, ting.Truthiness, true)
errs = validate.Struct(ting)
Equal(t, errs, nil)
}
func TestSQLValue2Validation(t *testing.T) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{})
validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1)
val := valuer{
Name: "",
}
errs := validate.Var(val, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
val.Name = "Valid Name"
errs = validate.VarCtx(context.Background(), val, "required")
Equal(t, errs, nil)
val.Name = "errorme"
5 years ago
PanicMatches(t, func() { _ = validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error")
myVal := valuer{
Name: "",
}
errs = validate.Var(myVal, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
cust := MadeUpCustomType{
FirstName: "Joey",
LastName: "Bloggs",
}
c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2}
errs = validate.Struct(c)
Equal(t, errs, nil)
c.MadeUp.FirstName = ""
c.OverriddenInt = 1
errs = validate.Struct(c)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 2)
AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "CustomMadeUpStruct.MadeUp", "MadeUp", "MadeUp", "required")
AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "OverriddenInt", "gt")
}
func TestSQLValueValidation(t *testing.T) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*driver.Valuer)(nil), valuer{})
validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{})
validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1)
val := valuer{
Name: "",
}
errs := validate.Var(val, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
val.Name = "Valid Name"
errs = validate.Var(val, "required")
Equal(t, errs, nil)
val.Name = "errorme"
PanicMatches(t, func() { errs = validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error")
myVal := valuer{
Name: "",
}
errs = validate.Var(myVal, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
cust := MadeUpCustomType{
FirstName: "Joey",
LastName: "Bloggs",
}
c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2}
errs = validate.Struct(c)
Equal(t, errs, nil)
c.MadeUp.FirstName = ""
c.OverriddenInt = 1
errs = validate.Struct(c)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 2)
AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "CustomMadeUpStruct.MadeUp", "MadeUp", "MadeUp", "required")
AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "OverriddenInt", "gt")
}
func TestMACValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"3D:F2:C9:A6:B3:4F", true},
{"3D-F2-C9-A6-B3:4F", false},
{"123", false},
{"", false},
{"abacaba", false},
{"00:25:96:FF:FE:12:34:56", true},
{"0025:96FF:FE12:3456", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "mac")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d mac failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d mac failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "mac" {
t.Fatalf("Index: %d mac failed Error: %s", i, errs)
}
}
}
}
}
func TestIPValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{"10.0.0.1", true},
{"172.16.0.1", true},
{"192.168.0.1", true},
{"192.168.255.254", true},
{"192.168.255.256", false},
{"172.16.255.254", true},
{"172.16.256.255", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", true},
{"2001:cdba:0:0:0:0:3257:9652", true},
{"2001:cdba::3257:9652", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ip")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ip failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ip failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ip" {
t.Fatalf("Index: %d ip failed Error: %s", i, errs)
}
}
}
}
}
func TestIPv6Validation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"10.0.0.1", false},
{"172.16.0.1", false},
{"192.168.0.1", false},
{"192.168.255.254", false},
{"192.168.255.256", false},
{"172.16.255.254", false},
{"172.16.256.255", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", true},
{"2001:cdba:0:0:0:0:3257:9652", true},
{"2001:cdba::3257:9652", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ipv6")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ipv6" {
t.Fatalf("Index: %d ipv6 failed Error: %s", i, errs)
}
}
}
}
}
func TestIPv4Validation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"10.0.0.1", true},
{"172.16.0.1", true},
{"192.168.0.1", true},
{"192.168.255.254", true},
{"192.168.255.256", false},
{"172.16.255.254", true},
{"172.16.256.255", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ipv4")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ipv4" {
t.Fatalf("Index: %d ipv4 failed Error: %s", i, errs)
}
}
}
}
}
func TestCIDRValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"10.0.0.0/0", true},
{"10.0.0.1/8", true},
{"172.16.0.1/16", true},
{"192.168.0.1/24", true},
{"192.168.255.254/24", true},
{"192.168.255.254/48", false},
{"192.168.255.256/24", false},
{"172.16.255.254/16", true},
{"172.16.256.255/16", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652/64", true},
{"2001:cdba:0000:0000:0000:0000:3257:9652/256", false},
{"2001:cdba:0:0:0:0:3257:9652/32", true},
{"2001:cdba::3257:9652/16", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "cidr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d cidr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d cidr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "cidr" {
t.Fatalf("Index: %d cidr failed Error: %s", i, errs)
}
}
}
}
}
func TestCIDRv6Validation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"10.0.0.0/0", false},
{"10.0.0.1/8", false},
{"172.16.0.1/16", false},
{"192.168.0.1/24", false},
{"192.168.255.254/24", false},
{"192.168.255.254/48", false},
{"192.168.255.256/24", false},
{"172.16.255.254/16", false},
{"172.16.256.255/16", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652/64", true},
{"2001:cdba:0000:0000:0000:0000:3257:9652/256", false},
{"2001:cdba:0:0:0:0:3257:9652/32", true},
{"2001:cdba::3257:9652/16", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "cidrv6")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "cidrv6" {
t.Fatalf("Index: %d cidrv6 failed Error: %s", i, errs)
}
}
}
}
}
func TestCIDRv4Validation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"10.0.0.0/0", true},
{"10.0.0.1/8", true},
{"172.16.0.1/16", true},
{"192.168.0.1/24", true},
{"192.168.255.254/24", true},
{"192.168.255.254/48", false},
{"192.168.255.256/24", false},
{"172.16.255.254/16", true},
{"172.16.256.255/16", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652/64", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652/256", false},
{"2001:cdba:0:0:0:0:3257:9652/32", false},
{"2001:cdba::3257:9652/16", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "cidrv4")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "cidrv4" {
t.Fatalf("Index: %d cidrv4 failed Error: %s", i, errs)
}
}
}
}
}
func TestTCPAddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{":80", false},
{"127.0.0.1:80", true},
{"[::1]:80", true},
{"256.0.0.0:1", false},
{"[::1]", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "tcp_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "tcp_addr" {
t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestTCP6AddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{":80", false},
{"127.0.0.1:80", false},
{"[::1]:80", true},
{"256.0.0.0:1", false},
{"[::1]", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "tcp6_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "tcp6_addr" {
t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestTCP4AddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{":80", false},
{"127.0.0.1:80", true},
{"[::1]:80", false}, // https://github.com/golang/go/issues/14037
{"256.0.0.0:1", false},
{"[::1]", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "tcp4_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Log(test.param, IsEqual(errs, nil))
t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "tcp4_addr" {
t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestUDPAddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{":80", false},
{"127.0.0.1:80", true},
{"[::1]:80", true},
{"256.0.0.0:1", false},
{"[::1]", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "udp_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "udp_addr" {
t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestUDP6AddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{":80", false},
{"127.0.0.1:80", false},
{"[::1]:80", true},
{"256.0.0.0:1", false},
{"[::1]", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "udp6_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "udp6_addr" {
t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestUDP4AddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{":80", false},
{"127.0.0.1:80", true},
{"[::1]:80", false}, // https://github.com/golang/go/issues/14037
{"256.0.0.0:1", false},
{"[::1]", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "udp4_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Log(test.param, IsEqual(errs, nil))
t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "udp4_addr" {
t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestIPAddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{"127.0.0.1", true},
{"127.0.0.1:80", false},
{"::1", true},
{"256.0.0.0", false},
{"localhost", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ip_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ip_addr" {
t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestIP6AddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{"127.0.0.1", false}, // https://github.com/golang/go/issues/14037
{"127.0.0.1:80", false},
{"::1", true},
{"0:0:0:0:0:0:0:1", true},
{"256.0.0.0", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ip6_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ip6_addr" {
t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestIP4AddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{"127.0.0.1", true},
{"127.0.0.1:80", false},
{"::1", false}, // https://github.com/golang/go/issues/14037
{"256.0.0.0", false},
{"localhost", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ip4_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Log(test.param, IsEqual(errs, nil))
t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ip4_addr" {
t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestUnixAddrValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", true},
{"v.sock", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "unix_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Log(test.param, IsEqual(errs, nil))
t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "unix_addr" {
t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs)
}
}
}
}
}
func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) {
validate := New()
var m map[string]string
errs := validate.Var(m, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
m = map[string]string{}
errs = validate.Var(m, "required")
Equal(t, errs, nil)
var arr [5]string
errs = validate.Var(arr, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
arr[0] = "ok"
errs = validate.Var(arr, "required")
Equal(t, errs, nil)
var s []string
errs = validate.Var(s, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
s = []string{}
errs = validate.Var(s, "required")
Equal(t, errs, nil)
var c chan string
errs = validate.Var(c, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
c = make(chan string)
errs = validate.Var(c, "required")
Equal(t, errs, nil)
var tst *int
errs = validate.Var(tst, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
one := 1
tst = &one
errs = validate.Var(tst, "required")
Equal(t, errs, nil)
var iface interface{}
errs = validate.Var(iface, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
errs = validate.Var(iface, "omitempty,required")
Equal(t, errs, nil)
errs = validate.Var(iface, "")
Equal(t, errs, nil)
errs = validate.VarWithValue(nil, iface, "")
Equal(t, errs, nil)
var f func(string)
errs = validate.Var(f, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "required")
f = func(name string) {}
errs = validate.Var(f, "required")
Equal(t, errs, nil)
}
func TestDatePtrValidationIssueValidation(t *testing.T) {
type Test struct {
LastViewed *time.Time
Reminder *time.Time
}
test := &Test{}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
}
func TestCommaAndPipeObfuscationValidation(t *testing.T) {
s := "My Name Is, |joeybloggs|"
validate := New()
errs := validate.Var(s, "excludesall=0x2C")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "excludesall")
errs = validate.Var(s, "excludesall=0x7C")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "excludesall")
}
func TestBadKeyValidation(t *testing.T) {
type Test struct {
Name string `validate:"required, "`
}
tst := &Test{
Name: "test",
}
validate := New()
5 years ago
PanicMatches(t, func() { _ = validate.Struct(tst) }, "Undefined validation function ' ' on field 'Name'")
type Test2 struct {
Name string `validate:"required,,len=2"`
}
tst2 := &Test2{
Name: "test",
}
5 years ago
PanicMatches(t, func() { _ = validate.Struct(tst2) }, "Invalid validation tag on field 'Name'")
}
func TestInterfaceErrValidation(t *testing.T) {
var v2 interface{} = 1
var v1 interface{} = v2
validate := New()
errs := validate.Var(v1, "len=1")
Equal(t, errs, nil)
errs = validate.Var(v2, "len=1")
Equal(t, errs, 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, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "ExternalCMD.Data", "ExternalCMD.Data", "Data", "Data", "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, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "ExternalCMD2.Data", "ExternalCMD2.Data", "Data", "Data", "len")
s3 := &ExternalCMD2{
Userid: "123456",
Action: 10000,
Data: 2,
}
errs = validate.Struct(s3)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "ExternalCMD2.Data", "ExternalCMD2.Data", "Data", "Data", "len")
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, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "ExternalCMD.Data.Name", "ExternalCMD.Data.Name", "Name", "Name", "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.(ValidationErrors)), 1)
AssertError(t, errs, "TestMapStructPtr.Errs[3]", "TestMapStructPtr.Errs[3]", "Errs[3]", "Errs[3]", "len")
type TestMultiDimensionalStructs struct {
Errs [][]interface{} `validate:"gt=0,dive,dive"`
}
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.(ValidationErrors)), 4)
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "Name", "required")
type TestMultiDimensionalStructsPtr2 struct {
Errs [][]*Inner `validate:"gt=0,dive,dive,required"`
}
var errStructPtr2Array [][]*Inner
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil})
tmsp2 := &TestMultiDimensionalStructsPtr2{
Errs: errStructPtr2Array,
}
errs = validate.Struct(tmsp2)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 6)
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "required")
m := map[int]interface{}{0: "ok", 3: "", 4: "ok"}
errs = validate.Var(m, "len=3,dive,len=2")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "[3]", "[3]", "[3]", "[3]", "len")
errs = validate.Var(m, "len=2,dive,required")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "", "", "", "", "len")
arr := []interface{}{"ok", "", "ok"}
errs = validate.Var(arr, "len=3,dive,len=2")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "[1]", "[1]", "[1]", "[1]", "len")
errs = validate.Var(arr, "len=2,dive,required")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "", "", "", "", "len")
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) {
validate := New()
n := map[int]interface{}{0: nil}
errs := validate.Var(n, "omitempty,required")
Equal(t, errs, nil)
m := map[int]string{0: "ok", 3: "", 4: "ok"}
errs = validate.Var(m, "len=3,dive,required")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "[3]", "[3]", "[3]", "[3]", "required")
errs = validate.Var(m, "len=2,dive,required")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "", "", "", "", "len")
type Inner struct {
Name string `validate:"required"`
}
type TestMapStruct struct {
Errs map[int]Inner `validate:"gt=0,dive"`
}
mi := map[int]Inner{0: {"ok"}, 3: {""}, 4: {"ok"}}
ms := &TestMapStruct{
Errs: mi,
}
errs = validate.Struct(ms)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "TestMapStruct.Errs[3].Name", "TestMapStruct.Errs[3].Name", "Name", "Name", "required")
// for full test coverage
s := fmt.Sprint(errs.Error())
NotEqual(t, s, "")
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.(ValidationErrors)), 2)
AssertError(t, errs, "TestMapTimeStruct.Errs[3]", "TestMapTimeStruct.Errs[3]", "Errs[3]", "Errs[3]", "required")
AssertError(t, errs, "TestMapTimeStruct.Errs[4]", "TestMapTimeStruct.Errs[4]", "Errs[4]", "Errs[4]", "required")
type TestMapStructPtr struct {
Errs map[int]*Inner `validate:"gt=0,dive,required"`
}
mip := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}}
msp := &TestMapStructPtr{
Errs: mip,
}
errs = validate.Struct(msp)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "TestMapStructPtr.Errs[3]", "TestMapStructPtr.Errs[3]", "Errs[3]", "Errs[3]", "required")
type TestMapStructPtr2 struct {
Errs map[int]*Inner `validate:"gt=0,dive,omitempty,required"`
}
mip2 := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}}
msp2 := &TestMapStructPtr2{
Errs: mip2,
}
errs = validate.Struct(msp2)
Equal(t, errs, nil)
v2 := New()
v2.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type MapDiveJSONTest struct {
Map map[string]string `validate:"required,gte=1,dive,gte=1" json:"MyName"`
}
mdjt := &MapDiveJSONTest{
Map: map[string]string{
"Key1": "Value1",
"Key2": "",
},
}
err := v2.Struct(mdjt)
NotEqual(t, err, nil)
errs = err.(ValidationErrors)
fe := getError(errs, "MapDiveJSONTest.MyName[Key2]", "MapDiveJSONTest.Map[Key2]")
NotEqual(t, fe, nil)
Equal(t, fe.Tag(), "gte")
Equal(t, fe.ActualTag(), "gte")
Equal(t, fe.Field(), "MyName[Key2]")
Equal(t, fe.StructField(), "Map[Key2]")
}
func TestArrayDiveValidation(t *testing.T) {
validate := New()
arr := []string{"ok", "", "ok"}
errs := validate.Var(arr, "len=3,dive,required")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "[1]", "[1]", "[1]", "[1]", "required")
errs = validate.Var(arr, "len=2,dive,required")
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "", "", "", "", "len")
type BadDive struct {
Name string `validate:"dive"`
}
bd := &BadDive{
Name: "TEST",
}
5 years ago
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.(ValidationErrors)), 1)
AssertError(t, errs, "Test.Errs[1]", "Test.Errs[1]", "Errs[1]", "Errs[1]", "required")
test = &Test{
Errs: []string{"ok", "ok", ""},
}
errs = validate.Struct(test)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "Test.Errs[2]", "Test.Errs[2]", "Errs[2]", "Errs[2]", "required")
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.(ValidationErrors)), 4)
AssertError(t, errs, "TestMultiDimensional.Errs[0][1]", "TestMultiDimensional.Errs[0][1]", "Errs[0][1]", "Errs[0][1]", "required")
AssertError(t, errs, "TestMultiDimensional.Errs[0][2]", "TestMultiDimensional.Errs[0][2]", "Errs[0][2]", "Errs[0][2]", "required")
AssertError(t, errs, "TestMultiDimensional.Errs[1][1]", "TestMultiDimensional.Errs[1][1]", "Errs[1][1]", "Errs[1][1]", "required")
AssertError(t, errs, "TestMultiDimensional.Errs[1][2]", "TestMultiDimensional.Errs[1][2]", "Errs[1][2]", "Errs[1][2]", "required")
type Inner struct {
Name string `validate:"required"`
}
type TestMultiDimensionalStructs struct {
Errs [][]Inner `validate:"gt=0,dive,dive"`
}
var errStructArray [][]Inner
errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}})
errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}})
tms := &TestMultiDimensionalStructs{
Errs: errStructArray,
}
errs = validate.Struct(tms)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 4)
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][1].Name", "TestMultiDimensionalStructs.Errs[0][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[0][2].Name", "TestMultiDimensionalStructs.Errs[0][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][1].Name", "TestMultiDimensionalStructs.Errs[1][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructs.Errs[1][2].Name", "TestMultiDimensionalStructs.Errs[1][2].Name", "Name", "Name", "required")
type TestMultiDimensionalStructsPtr struct {
Errs [][]*Inner `validate:"gt=0,dive,dive"`
}
var errStructPtrArray [][]*Inner
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}})
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}})
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, nil})
tmsp := &TestMultiDimensionalStructsPtr{
Errs: errStructPtrArray,
}
errs = validate.Struct(tmsp)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 5)
AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][1].Name", "TestMultiDimensionalStructsPtr.Errs[0][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[0][2].Name", "TestMultiDimensionalStructsPtr.Errs[0][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][1].Name", "TestMultiDimensionalStructsPtr.Errs[1][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[1][2].Name", "TestMultiDimensionalStructsPtr.Errs[1][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr.Errs[2][1].Name", "TestMultiDimensionalStructsPtr.Errs[2][1].Name", "Name", "Name", "required")
// for full test coverage
s := fmt.Sprint(errs.Error())
NotEqual(t, s, "")
type TestMultiDimensionalStructsPtr2 struct {
Errs [][]*Inner `validate:"gt=0,dive,dive,required"`
}
var errStructPtr2Array [][]*Inner
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil})
tmsp2 := &TestMultiDimensionalStructsPtr2{
Errs: errStructPtr2Array,
}
errs = validate.Struct(tmsp2)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 6)
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "TestMultiDimensionalStructsPtr2.Errs[0][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "TestMultiDimensionalStructsPtr2.Errs[0][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "TestMultiDimensionalStructsPtr2.Errs[1][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "TestMultiDimensionalStructsPtr2.Errs[1][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "TestMultiDimensionalStructsPtr2.Errs[2][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr2.Errs[2][2]", "TestMultiDimensionalStructsPtr2.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "required")
type TestMultiDimensionalStructsPtr3 struct {
Errs [][]*Inner `validate:"gt=0,dive,dive,omitempty"`
}
var errStructPtr3Array [][]*Inner
errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, nil})
tmsp3 := &TestMultiDimensionalStructsPtr3{
Errs: errStructPtr3Array,
}
errs = validate.Struct(tmsp3)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 5)
AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][1].Name", "TestMultiDimensionalStructsPtr3.Errs[0][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[0][2].Name", "TestMultiDimensionalStructsPtr3.Errs[0][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][1].Name", "TestMultiDimensionalStructsPtr3.Errs[1][1].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[1][2].Name", "TestMultiDimensionalStructsPtr3.Errs[1][2].Name", "Name", "Name", "required")
AssertError(t, errs, "TestMultiDimensionalStructsPtr3.Errs[2][1].Name", "TestMultiDimensionalStructsPtr3.Errs[2][1].Name", "Name", "Name", "required")
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.(ValidationErrors)), 3)
AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[1][2]", "TestMultiDimensionalTimeTime.Errs[1][2]", "Errs[1][2]", "Errs[1][2]", "required")
AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][1]", "TestMultiDimensionalTimeTime.Errs[2][1]", "Errs[2][1]", "Errs[2][1]", "required")
AssertError(t, errs, "TestMultiDimensionalTimeTime.Errs[2][2]", "TestMultiDimensionalTimeTime.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "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.(ValidationErrors)), 3)
AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[1][2]", "TestMultiDimensionalTimeTime2.Errs[1][2]", "Errs[1][2]", "Errs[1][2]", "required")
AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][1]", "TestMultiDimensionalTimeTime2.Errs[2][1]", "Errs[2][1]", "Errs[2][1]", "required")
AssertError(t, errs, "TestMultiDimensionalTimeTime2.Errs[2][2]", "TestMultiDimensionalTimeTime2.Errs[2][2]", "Errs[2][2]", "Errs[2][2]", "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,
}
validate := New()
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)
AssertError(t, errs, "Outer2.Inner2", "Outer2.Inner2", "Inner2", "Inner2", "required")
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ssn")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d SSN failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d SSN failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ssn" {
t.Fatalf("Index: %d Latitude failed Error: %s", i, errs)
}
}
}
}
}
func TestLongitudeValidation(t *testing.T) {
tests := []struct {
param interface{}
expected bool
}{
{"", false},
{"-180.000", true},
{"180.1", false},
{"+73.234", true},
{"+382.3811", false},
{"23.11111111", true},
{uint(180), true},
{float32(-180.0), true},
{-180, true},
{180.1, false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "longitude")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d Longitude failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d Longitude failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "longitude" {
t.Fatalf("Index: %d Longitude failed Error: %s", i, errs)
}
}
}
}
5 years ago
PanicMatches(t, func() { _ = validate.Var(true, "longitude") }, "Bad field type bool")
}
func TestLatitudeValidation(t *testing.T) {
tests := []struct {
param interface{}
expected bool
}{
{"", false},
{"-90.000", true},
{"+90", true},
{"47.1231231", true},
{"+99.9", false},
{"108", false},
{uint(90), true},
{float32(-90.0), true},
{-90, true},
{90.1, false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "latitude")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d Latitude failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d Latitude failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "latitude" {
t.Fatalf("Index: %d Latitude failed Error: %s", i, errs)
}
}
}
}
5 years ago
PanicMatches(t, func() { _ = validate.Var(true, "latitude") }, "Bad field type bool")
}
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},
{"data:image/jpeg;key=value;base64,UEsDBBQAAAAI", true},
{"data:image/jpeg;key=value,UEsDBBQAAAAI", true},
{"data:;base64;sdfgsdfgsdfasdfa=s,UEsDBBQAAAAI", true},
{"data:,UEsDBBQAAAAI", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "datauri")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d DataURI failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d DataURI failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "datauri" {
t.Fatalf("Index: %d DataURI failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "multibyte")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "multibyte" {
t.Fatalf("Index: %d Multibyte failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "printascii")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "printascii" {
t.Fatalf("Index: %d Printable ASCII failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "ascii")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ASCII failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ASCII failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "ascii" {
t.Fatalf("Index: %d ASCII failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid5")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid5" {
t.Fatalf("Index: %d UUID5 failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid4")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid4" {
t.Fatalf("Index: %d UUID4 failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid3")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid3" {
t.Fatalf("Index: %d UUID3 failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid" {
t.Fatalf("Index: %d UUID failed Error: %s", i, errs)
}
}
}
}
}
6 years ago
func TestUUID5RFC4122Validation(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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid5_rfc4122")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID5RFC4122 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID5RFC4122 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid5_rfc4122" {
t.Fatalf("Index: %d UUID5RFC4122 failed Error: %s", i, errs)
}
}
}
}
}
func TestUUID4RFC4122Validation(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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid4_rfc4122")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID4RFC4122 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID4RFC4122 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid4_rfc4122" {
t.Fatalf("Index: %d UUID4RFC4122 failed Error: %s", i, errs)
}
}
}
}
}
func TestUUID3RFC4122Validation(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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid3_rfc4122")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID3RFC4122 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUID3RFC4122 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid3_rfc4122" {
t.Fatalf("Index: %d UUID3RFC4122 failed Error: %s", i, errs)
}
}
}
}
}
func TestUUIDRFC4122Validation(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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uuid_rfc4122")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d UUIDRFC4122 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d UUIDRFC4122 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uuid_rfc4122" {
t.Fatalf("Index: %d UUIDRFC4122 failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "isbn")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ISBN failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ISBN failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "isbn" {
t.Fatalf("Index: %d ISBN failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "isbn13")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "isbn13" {
t.Fatalf("Index: %d ISBN13 failed Error: %s", i, errs)
}
}
}
}
}
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 := New()
for i, test := range tests {
errs := validate.Var(test.param, "isbn10")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "isbn10" {
t.Fatalf("Index: %d ISBN10 failed Error: %s", i, errs)
}
}
}
}
}
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},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
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},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
errs = validate.Struct(s)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
}
username := "joeybloggs "
errs := validate.Var(username, "excludesall=@ ")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "excludesall")
excluded := ","
errs = validate.Var(excluded, "excludesall=!@#$%^&*()_+.0x2C?")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "excludesall")
excluded = "="
errs = validate.Var(excluded, "excludesall=!@#$%^&*()_+.0x2C=?")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "excludesall")
}
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},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
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},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
errs = validate.Struct(s)
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},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
errs = validate.Struct(s)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
}
}
func TestContainsValidation(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},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
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) {
validate := New()
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
errs := validate.VarWithValue(s, s2, "nefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(i2, i, "nefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(j2, j, "nefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(k2, k, "nefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(arr2, arr, "nefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(now2, now, "nefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "nefield")
errs = validate.VarWithValue(arr3, arr, "nefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "nefield")
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)
AssertError(t, errs, "Test.Start", "Test.Start", "Start", "Start", "nefield")
now3 := time.Now().UTC()
sv = &Test{
Start: &now,
End: &now3,
}
errs = validate.Struct(sv)
Equal(t, errs, nil)
errs = validate.VarWithValue(nil, 1, "nefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "nefield")
errs = validate.VarWithValue(sv, now, "nefield")
Equal(t, errs, nil)
type Test2 struct {
Start *time.Time `validate:"nefield=NonExistantField"`
End *time.Time
}
sv2 := &Test2{
Start: &now,
End: &now,
}
errs = validate.Struct(sv2)
Equal(t, errs, nil)
type Other struct {
Value string
}
type Test3 struct {
Value Other
Time time.Time `validate:"nefield=Value"`
}
tst := Test3{
Value: Other{Value: "StringVal"},
Time: now,
}
errs = validate.Struct(tst)
Equal(t, errs, nil)
}
func TestIsNeValidation(t *testing.T) {
validate := New()
var j uint64
var k float64
s := "abcdef"
i := 3
j = 2
k = 1.5434
arr := []string{"test"}
now := time.Now().UTC()
errs := validate.Var(s, "ne=abcd")
Equal(t, errs, nil)
errs = validate.Var(i, "ne=1")
Equal(t, errs, nil)
errs = validate.Var(j, "ne=1")
Equal(t, errs, nil)
errs = validate.Var(k, "ne=1.543")
Equal(t, errs, nil)
errs = validate.Var(arr, "ne=2")
Equal(t, errs, nil)
errs = validate.Var(arr, "ne=1")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ne")
5 years ago
PanicMatches(t, func() { _ = validate.Var(now, "ne=now") }, "Bad field type time.Time")
}
func TestIsEqFieldValidation(t *testing.T) {
validate := New()
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
errs := validate.VarWithValue(s, s2, "eqfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(i2, i, "eqfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(j2, j, "eqfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(k2, k, "eqfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(arr2, arr, "eqfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(now2, now, "eqfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(arr3, arr, "eqfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "eqfield")
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)
AssertError(t, errs, "Test.Start", "Test.Start", "Start", "Start", "eqfield")
errs = validate.VarWithValue(nil, 1, "eqfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "eqfield")
channel := make(chan string)
errs = validate.VarWithValue(5, channel, "eqfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "eqfield")
errs = validate.VarWithValue(5, now, "eqfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "eqfield")
type Test2 struct {
Start *time.Time `validate:"eqfield=NonExistantField"`
End *time.Time
}
sv2 := &Test2{
Start: &now,
End: &now,
}
errs = validate.Struct(sv2)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test2.Start", "Test2.Start", "Start", "Start", "eqfield")
type Inner struct {
Name string
}
type TStruct struct {
Inner *Inner
CreatedAt *time.Time `validate:"eqfield=Inner"`
}
inner := &Inner{
Name: "NAME",
}
test := &TStruct{
Inner: inner,
CreatedAt: &now,
}
errs = validate.Struct(test)
NotEqual(t, errs, nil)
AssertError(t, errs, "TStruct.CreatedAt", "TStruct.CreatedAt", "CreatedAt", "CreatedAt", "eqfield")
}
func TestIsEqValidation(t *testing.T) {
validate := New()
var j uint64
var k float64
s := "abcd"
i := 1
j = 1
k = 1.543
arr := []string{"test"}
now := time.Now().UTC()
errs := validate.Var(s, "eq=abcd")
Equal(t, errs, nil)
errs = validate.Var(i, "eq=1")
Equal(t, errs, nil)
errs = validate.Var(j, "eq=1")
Equal(t, errs, nil)
errs = validate.Var(k, "eq=1.543")
Equal(t, errs, nil)
errs = validate.Var(arr, "eq=1")
Equal(t, errs, nil)
errs = validate.Var(arr, "eq=2")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "eq")
5 years ago
PanicMatches(t, func() { _ = validate.Var(now, "eq=now") }, "Bad field type time.Time")
}
func TestOneOfValidation(t *testing.T) {
validate := New()
passSpecs := []struct {
f interface{}
t string
}{
{f: "red", t: "oneof=red green"},
{f: "green", t: "oneof=red green"},
{f: "red green", t: "oneof='red green' blue"},
{f: "blue", t: "oneof='red green' blue"},
{f: 5, t: "oneof=5 6"},
{f: 6, t: "oneof=5 6"},
{f: int8(6), t: "oneof=5 6"},
{f: int16(6), t: "oneof=5 6"},
{f: int32(6), t: "oneof=5 6"},
{f: int64(6), t: "oneof=5 6"},
{f: uint(6), t: "oneof=5 6"},
{f: uint8(6), t: "oneof=5 6"},
{f: uint16(6), t: "oneof=5 6"},
{f: uint32(6), t: "oneof=5 6"},
{f: uint64(6), t: "oneof=5 6"},
}
for _, spec := range passSpecs {
t.Logf("%#v", spec)
errs := validate.Var(spec.f, spec.t)
Equal(t, errs, nil)
}
failSpecs := []struct {
f interface{}
t string
}{
{f: "", t: "oneof=red green"},
{f: "yellow", t: "oneof=red green"},
{f: "green", t: "oneof='red green' blue"},
{f: 5, t: "oneof=red green"},
{f: 6, t: "oneof=red green"},
{f: 6, t: "oneof=7"},
{f: uint(6), t: "oneof=7"},
{f: int8(5), t: "oneof=red green"},
{f: int16(5), t: "oneof=red green"},
{f: int32(5), t: "oneof=red green"},
{f: int64(5), t: "oneof=red green"},
{f: uint(5), t: "oneof=red green"},
{f: uint8(5), t: "oneof=red green"},
{f: uint16(5), t: "oneof=red green"},
{f: uint32(5), t: "oneof=red green"},
{f: uint64(5), t: "oneof=red green"},
}
for _, spec := range failSpecs {
t.Logf("%#v", spec)
errs := validate.Var(spec.f, spec.t)
AssertError(t, errs, "", "", "", "", "oneof")
}
PanicMatches(t, func() {
5 years ago
_ = validate.Var(3.14, "oneof=red green")
}, "Bad field type float64")
}
func TestBase64Validation(t *testing.T) {
validate := New()
s := "dW5pY29ybg=="
errs := validate.Var(s, "base64")
Equal(t, errs, nil)
s = "dGhpIGlzIGEgdGVzdCBiYXNlNjQ="
errs = validate.Var(s, "base64")
Equal(t, errs, nil)
s = ""
errs = validate.Var(s, "base64")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "base64")
s = "dW5pY29ybg== foo bar"
errs = validate.Var(s, "base64")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "base64")
}
func TestBase64URLValidation(t *testing.T) {
validate := New()
testCases := []struct {
decoded, encoded string
success bool
}{
// empty string, although a valid base64 string, should fail
{"", "", false},
// invalid length
{"", "a", false},
// base64 with padding
{"f", "Zg==", true},
{"fo", "Zm8=", true},
// base64 without padding
{"foo", "Zm9v", true},
{"", "Zg", false},
{"", "Zm8", false},
// base64 URL safe encoding with invalid, special characters '+' and '/'
{"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+", false},
{"\x14\xfb\x9c\x03\xf9\x73", "FPucA/lz", false},
// base64 URL safe encoding with valid, special characters '-' and '_'
{"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l-", true},
{"\x14\xfb\x9c\x03\xf9\x73", "FPucA_lz", true},
// non base64 characters
{"", "@mc=", false},
{"", "Zm 9", false},
}
for _, tc := range testCases {
err := validate.Var(tc.encoded, "base64url")
if tc.success {
Equal(t, err, nil)
// make sure encoded value is decoded back to the expected value
d, innerErr := base64.URLEncoding.DecodeString(tc.encoded)
Equal(t, innerErr, nil)
Equal(t, tc.decoded, string(d))
} else {
NotEqual(t, err, nil)
if len(tc.encoded) > 0 {
// make sure that indeed the encoded value was faulty
_, err := base64.URLEncoding.DecodeString(tc.encoded)
NotEqual(t, err, nil)
}
}
}
}
func TestFileValidation(t *testing.T) {
validate := New()
tests := []struct {
title string
param string
expected bool
}{
{"empty path", "", false},
{"regular file", filepath.Join("testdata", "a.go"), true},
{"missing file", filepath.Join("testdata", "no.go"), false},
{"directory, not a file", "testdata", false},
}
for _, test := range tests {
errs := validate.Var(test.param, "file")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Test: '%s' failed Error: %s", test.title, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Test: '%s' failed Error: %s", test.title, errs)
}
}
}
PanicMatches(t, func() {
5 years ago
_ = validate.Var(6, "file")
}, "Bad field type int")
}
func TestEthereumAddressValidation(t *testing.T) {
validate := New()
tests := []struct {
param string
expected bool
}{
{"", false},
{"0x02F9AE5f22EA3fA88F05780B30385bEC", false},
{"123f681646d4a755815f9cb19e1acc8565a0c2ac", false},
{"0x02F9AE5f22EA3fA88F05780B30385bECFacbf130", true},
{"0x123f681646d4a755815f9cb19e1acc8565a0c2ac", true},
}
for i, test := range tests {
errs := validate.Var(test.param, "eth_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d eth_addr failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d eth_addr failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "eth_addr" {
t.Fatalf("Index: %d Latitude failed Error: %s", i, errs)
}
}
}
}
}
func TestBitcoinAddressValidation(t *testing.T) {
validate := New()
tests := []struct {
param string
expected bool
}{
{"", false},
{"x", false},
{"0x02F9AE5f22EA3fA88F05780B30385bEC", false},
{"1A1zP1ePQGefi2DMPTifTL5SLmv7DivfNa", false},
{"1P9RQEr2XeE3PEb44ZE35sfZRRW1JH8Uqx", false},
{"3P14159I73E4gFr7JterCCQh9QjiTjiZrG", false},
{"3P141597f3E4gFr7JterCCQh9QjiTjiZrG", false},
{"37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y", false},
{"dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv", false},
{"MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S", false},
{"rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf", false},
{"4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq", false},
{"7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb", false},
{"17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs", false},
{"KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3", false},
{"7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th", false},
{"cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va", false},
{"gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk", false},
{"emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs", false},
{"7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo", false},
{"1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso", false},
{"31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq", false},
{"DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN", false},
{"2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i", false},
{"7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos", false},
{"1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu", false},
{"2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb", false},
{"8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ", false},
{"163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ", false},
{"2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu", false},
{"461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU", false},
{"2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs", false},
{"cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn", false},
{"gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj", false},
{"nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny", false},
{"L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc", false},
{"7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ ", false},
{"2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP", false},
{"dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw", false},
{"HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX", false},
{"4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB", false},
{"31uEbMgunupShBVTewXjtqbBv5MndwfXhb", false},
{"175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W", false},
{"Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ", false},
{"Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs", false},
{"6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ", false},
{"giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4", false},
{"cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK", false},
{"37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig", false},
{"EsYbG4tWWWY45G31nox838qNdzksbPySWc", false},
{"nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT", false},
{"cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx", false},
{"1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde", false},
{"2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU", false},
{"ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf", false},
{"Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd", false},
{"2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED", false},
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", true},
{"1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", true},
{"1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", true},
{"1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", true},
{"1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", true},
{"19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", true},
{"13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", true},
{"1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2", true},
{"3P14159f73E4gFr7JterCCQh9QjiTjiZrG", true},
{"3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", true},
{"3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", true},
{"3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", true},
{"33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", true},
{"3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", true},
{"37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", true},
{"3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", true},
{"12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP", true},
{"12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y", true},
{"1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs", true},
{"1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez", true},
{"116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd", true},
{"3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt", true},
}
for i, test := range tests {
errs := validate.Var(test.param, "btc_addr")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d btc_addr failed with Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d btc_addr failed with Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "btc_addr" {
t.Fatalf("Index: %d Latitude failed with Error: %s", i, errs)
}
}
}
}
}
func TestBitcoinBech32AddressValidation(t *testing.T) {
validate := New()
tests := []struct {
param string
expected bool
}{
{"", false},
{"bc1rw5uspcuh", false},
{"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", false},
{"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", false},
{"qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", false},
{"bc1rw5uspcuh", false},
{"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", false},
{"BC1QW508d6QEJxTDG4y5R3ZArVARY0C5XW7KV8F3T4", false},
{"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", false},
{"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", false},
{"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", false},
{"bc1pw508d6qejxtdg4y5r3zarqfsj6c3", false},
{"bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", false},
{"bc1gmk9yu", false},
{"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", false},
{"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", true},
{"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", true},
{"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", true},
{"BC1SW50QA3JX3S", true},
{"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", true},
}
for i, test := range tests {
errs := validate.Var(test.param, "btc_addr_bech32")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d btc_addr_bech32 failed with Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d btc_addr_bech32 failed with Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "btc_addr_bech32" {
t.Fatalf("Index: %d Latitude failed with Error: %s", i, errs)
}
}
}
}
}
func TestNoStructLevelValidation(t *testing.T) {
type Inner struct {
Test string `validate:"len=5"`
}
type Outer struct {
InnerStruct *Inner `validate:"required,nostructlevel"`
}
outer := &Outer{
InnerStruct: nil,
}
validate := New()
errs := validate.Struct(outer)
NotEqual(t, errs, nil)
AssertError(t, errs, "Outer.InnerStruct", "Outer.InnerStruct", "InnerStruct", "InnerStruct", "required")
inner := &Inner{
Test: "1234",
}
outer = &Outer{
InnerStruct: inner,
}
errs = validate.Struct(outer)
Equal(t, errs, 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,
}
validate := New()
errs := validate.Struct(outer)
NotEqual(t, errs, nil)
AssertError(t, errs, "Outer.InnerStruct", "Outer.InnerStruct", "InnerStruct", "InnerStruct", "required")
inner := &Inner{
Test: "1234",
}
outer = &Outer{
InnerStruct: inner,
}
errs = validate.Struct(outer)
Equal(t, errs, nil)
// Address houses a users address information
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
type User struct {
FirstName string `json:"fname"`
LastName string `json:"lname"`
Age uint8 `validate:"gte=0,lte=130"`
Number string `validate:"required,e164"`
Email string `validate:"required,email"`
FavouriteColor string `validate:"hexcolor|rgb|rgba"`
Addresses []*Address `validate:"required"` // a person can have a home and cottage...
Address Address `validate:"structonly"` // a person can have a home and cottage...
}
address := &Address{
Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
City: "Unknown",
}
user := &User{
FirstName: "",
LastName: "",
Age: 45,
Number: "+1123456789",
Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000",
Addresses: []*Address{address},
Address: Address{
// Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
City: "Unknown",
},
}
errs = validate.Struct(user)
Equal(t, errs, nil)
}
func TestGtField(t *testing.T) {
validate := New()
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,
}
errs = validate.Struct(timeTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest.End", "TimeTest.End", "End", "End", "gtfield")
errs = validate.VarWithValue(&end, &start, "gtfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(&start, &end, "gtfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtfield")
errs = validate.VarWithValue(&end, &start, "gtfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(&timeTest, &end, "gtfield")
NotEqual(t, errs, nil)
errs = validate.VarWithValue("test bigger", "test", "gtfield")
Equal(t, errs, nil)
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,
}
errs = validate.Struct(intTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "gtfield")
errs = validate.VarWithValue(int(5), int(1), "gtfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(int(1), int(5), "gtfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(uIntTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "gtfield")
errs = validate.VarWithValue(uint(5), uint(1), "gtfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(uint(1), uint(5), "gtfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(floatTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "gtfield")
errs = validate.VarWithValue(float32(5), float32(1), "gtfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(float32(1), float32(5), "gtfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtfield")
errs = validate.VarWithValue(nil, 1, "gtfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtfield")
errs = validate.VarWithValue(5, "T", "gtfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtfield")
errs = validate.VarWithValue(5, start, "gtfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtfield")
type TimeTest2 struct {
Start *time.Time `validate:"required"`
End *time.Time `validate:"required,gtfield=NonExistantField"`
}
timeTest2 := &TimeTest2{
Start: &start,
End: &end,
}
errs = validate.Struct(timeTest2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "gtfield")
type Other struct {
Value string
}
type Test struct {
Value Other
Time time.Time `validate:"gtfield=Value"`
}
tst := Test{
Value: Other{Value: "StringVal"},
Time: end,
}
errs = validate.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.Time", "Test.Time", "Time", "Time", "gtfield")
}
func TestLtField(t *testing.T) {
validate := New()
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,
}
errs = validate.Struct(timeTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest.Start", "TimeTest.Start", "Start", "Start", "ltfield")
errs = validate.VarWithValue(&start, &end, "ltfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(&end, &start, "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltfield")
errs = validate.VarWithValue(&end, timeTest, "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltfield")
errs = validate.VarWithValue("tes", "test", "ltfield")
Equal(t, errs, nil)
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,
}
errs = validate.Struct(intTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "ltfield")
errs = validate.VarWithValue(int(1), int(5), "ltfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(int(5), int(1), "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(uIntTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "ltfield")
errs = validate.VarWithValue(uint(1), uint(5), "ltfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(uint(5), uint(1), "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(floatTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "ltfield")
errs = validate.VarWithValue(float32(1), float32(5), "ltfield")
Equal(t, errs, nil)
errs = validate.VarWithValue(float32(5), float32(1), "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltfield")
errs = validate.VarWithValue(nil, 5, "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltfield")
errs = validate.VarWithValue(1, "T", "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltfield")
errs = validate.VarWithValue(1, end, "ltfield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltfield")
type TimeTest2 struct {
Start *time.Time `validate:"required"`
End *time.Time `validate:"required,ltfield=NonExistantField"`
}
timeTest2 := &TimeTest2{
Start: &end,
End: &start,
}
errs = validate.Struct(timeTest2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "ltfield")
}
func TestFieldContains(t *testing.T) {
validate := New()
type StringTest struct {
Foo string `validate:"fieldcontains=Bar"`
Bar string
}
stringTest := &StringTest{
Foo: "foobar",
Bar: "bar",
}
errs := validate.Struct(stringTest)
Equal(t, errs, nil)
stringTest = &StringTest{
Foo: "foo",
Bar: "bar",
}
errs = validate.Struct(stringTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "StringTest.Foo", "StringTest.Foo", "Foo", "Foo", "fieldcontains")
errs = validate.VarWithValue("foo", "bar", "fieldcontains")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "fieldcontains")
errs = validate.VarWithValue("bar", "foobarfoo", "fieldcontains")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "fieldcontains")
errs = validate.VarWithValue("foobarfoo", "bar", "fieldcontains")
Equal(t, errs, nil)
type StringTestMissingField struct {
Foo string `validate:"fieldcontains=Bar"`
}
stringTestMissingField := &StringTestMissingField{
Foo: "foo",
}
errs = validate.Struct(stringTestMissingField)
NotEqual(t, errs, nil)
AssertError(t, errs, "StringTestMissingField.Foo", "StringTestMissingField.Foo", "Foo", "Foo", "fieldcontains")
}
func TestFieldExcludes(t *testing.T) {
validate := New()
type StringTest struct {
Foo string `validate:"fieldexcludes=Bar"`
Bar string
}
stringTest := &StringTest{
Foo: "foobar",
Bar: "bar",
}
errs := validate.Struct(stringTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "StringTest.Foo", "StringTest.Foo", "Foo", "Foo", "fieldexcludes")
stringTest = &StringTest{
Foo: "foo",
Bar: "bar",
}
errs = validate.Struct(stringTest)
Equal(t, errs, nil)
errs = validate.VarWithValue("foo", "bar", "fieldexcludes")
Equal(t, errs, nil)
errs = validate.VarWithValue("bar", "foobarfoo", "fieldexcludes")
Equal(t, errs, nil)
errs = validate.VarWithValue("foobarfoo", "bar", "fieldexcludes")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "fieldexcludes")
type StringTestMissingField struct {
Foo string `validate:"fieldexcludes=Bar"`
}
stringTestMissingField := &StringTestMissingField{
Foo: "foo",
}
errs = validate.Struct(stringTestMissingField)
Equal(t, errs, nil)
}
func TestContainsAndExcludes(t *testing.T) {
validate := New()
type ImpossibleStringTest struct {
Foo string `validate:"fieldcontains=Bar"`
Bar string `validate:"fieldexcludes=Foo"`
}
impossibleStringTest := &ImpossibleStringTest{
Foo: "foo",
Bar: "bar",
}
errs := validate.Struct(impossibleStringTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "ImpossibleStringTest.Foo", "ImpossibleStringTest.Foo", "Foo", "Foo", "fieldcontains")
impossibleStringTest = &ImpossibleStringTest{
Foo: "bar",
Bar: "foo",
}
errs = validate.Struct(impossibleStringTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "ImpossibleStringTest.Foo", "ImpossibleStringTest.Foo", "Foo", "Foo", "fieldcontains")
}
func TestLteField(t *testing.T) {
validate := New()
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,
}
errs = validate.Struct(timeTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest.Start", "TimeTest.Start", "Start", "Start", "ltefield")
errs = validate.VarWithValue(&start, &end, "ltefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(&end, &start, "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltefield")
errs = validate.VarWithValue(&end, timeTest, "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltefield")
errs = validate.VarWithValue("tes", "test", "ltefield")
Equal(t, errs, nil)
errs = validate.VarWithValue("test", "test", "ltefield")
Equal(t, errs, nil)
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,
}
errs = validate.Struct(intTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "ltefield")
errs = validate.VarWithValue(int(1), int(5), "ltefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(int(5), int(1), "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(uIntTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "ltefield")
errs = validate.VarWithValue(uint(1), uint(5), "ltefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(uint(5), uint(1), "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(floatTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "ltefield")
errs = validate.VarWithValue(float32(1), float32(5), "ltefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(float32(5), float32(1), "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltefield")
errs = validate.VarWithValue(nil, 5, "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltefield")
errs = validate.VarWithValue(1, "T", "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltefield")
errs = validate.VarWithValue(1, end, "ltefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "ltefield")
type TimeTest2 struct {
Start *time.Time `validate:"required"`
End *time.Time `validate:"required,ltefield=NonExistantField"`
}
timeTest2 := &TimeTest2{
Start: &end,
End: &start,
}
errs = validate.Struct(timeTest2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "ltefield")
}
func TestGteField(t *testing.T) {
validate := New()
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,
}
errs = validate.Struct(timeTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest.End", "TimeTest.End", "End", "End", "gtefield")
errs = validate.VarWithValue(&end, &start, "gtefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(&start, &end, "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtefield")
errs = validate.VarWithValue(&start, timeTest, "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtefield")
errs = validate.VarWithValue("test", "test", "gtefield")
Equal(t, errs, nil)
errs = validate.VarWithValue("test bigger", "test", "gtefield")
Equal(t, errs, nil)
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,
}
errs = validate.Struct(intTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "IntTest.Val2", "IntTest.Val2", "Val2", "Val2", "gtefield")
errs = validate.VarWithValue(int(5), int(1), "gtefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(int(1), int(5), "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(uIntTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "UIntTest.Val2", "UIntTest.Val2", "Val2", "Val2", "gtefield")
errs = validate.VarWithValue(uint(5), uint(1), "gtefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(uint(1), uint(5), "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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,
}
errs = validate.Struct(floatTest)
NotEqual(t, errs, nil)
AssertError(t, errs, "FloatTest.Val2", "FloatTest.Val2", "Val2", "Val2", "gtefield")
errs = validate.VarWithValue(float32(5), float32(1), "gtefield")
Equal(t, errs, nil)
errs = validate.VarWithValue(float32(1), float32(5), "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtefield")
errs = validate.VarWithValue(nil, 1, "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtefield")
errs = validate.VarWithValue(5, "T", "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtefield")
errs = validate.VarWithValue(5, start, "gtefield")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gtefield")
type TimeTest2 struct {
Start *time.Time `validate:"required"`
End *time.Time `validate:"required,gtefield=NonExistantField"`
}
timeTest2 := &TimeTest2{
Start: &start,
End: &end,
}
errs = validate.Struct(timeTest2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "gtefield")
}
func TestValidateByTagAndValue(t *testing.T) {
validate := New()
val := "test"
field := "test"
errs := validate.VarWithValue(val, field, "required")
Equal(t, errs, nil)
fn := func(fl FieldLevel) bool {
return fl.Parent().String() == fl.Field().String()
}
5 years ago
errs = validate.RegisterValidation("isequaltestfunc", fn)
Equal(t, errs, nil)
errs = validate.VarWithValue(val, field, "isequaltestfunc")
Equal(t, errs, nil)
val = "unequal"
errs = validate.VarWithValue(val, field, "isequaltestfunc")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "isequaltestfunc")
}
func TestAddFunctions(t *testing.T) {
fn := func(fl FieldLevel) bool {
return true
}
fnCtx := func(ctx context.Context, fl FieldLevel) bool {
return true
}
validate := New()
errs := validate.RegisterValidation("new", fn)
Equal(t, errs, nil)
errs = validate.RegisterValidation("", fn)
NotEqual(t, errs, nil)
5 years ago
errs = validate.RegisterValidation("new", nil)
NotEqual(t, errs, nil)
errs = validate.RegisterValidation("new", fn)
Equal(t, errs, nil)
errs = validate.RegisterValidationCtx("new", fnCtx)
Equal(t, errs, nil)
5 years ago
PanicMatches(t, func() { _ = validate.RegisterValidation("dive", fn) }, "Tag 'dive' either contains restricted characters or is the same as a restricted tag needed for normal operation")
}
func TestChangeTag(t *testing.T) {
validate := New()
validate.SetTagName("val")
type Test struct {
Name string `val:"len=4"`
}
s := &Test{
Name: "TEST",
}
errs := validate.Struct(s)
Equal(t, errs, nil)
s.Name = ""
errs = validate.Struct(s)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.Name", "Test.Name", "Name", "Name", "len")
}
func TestUnexposedStruct(t *testing.T) {
validate := New()
type Test struct {
Name string
unexposed struct {
A string `validate:"required"`
}
}
s := &Test{
Name: "TEST",
}
5 years ago
Equal(t, s.unexposed.A, "")
errs := validate.Struct(s)
Equal(t, errs, nil)
}
func TestBadParams(t *testing.T) {
validate := New()
i := 1
errs := validate.Var(i, "-")
Equal(t, errs, nil)
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax")
PanicMatches(t, func() { _ = validate.Var(i, "len=a") }, "strconv.ParseInt: parsing \"a\": invalid syntax")
var ui uint = 1
5 years ago
PanicMatches(t, func() { _ = validate.Var(ui, "len=a") }, "strconv.ParseUint: parsing \"a\": invalid syntax")
f := 1.23
5 years ago
PanicMatches(t, func() { _ = validate.Var(f, "len=a") }, "strconv.ParseFloat: parsing \"a\": invalid syntax")
}
func TestLength(t *testing.T) {
validate := New()
i := true
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, "len") }, "Bad field type bool")
}
func TestIsGt(t *testing.T) {
validate := New()
myMap := map[string]string{}
errs := validate.Var(myMap, "gt=0")
NotEqual(t, errs, nil)
f := 1.23
errs = validate.Var(f, "gt=5")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gt")
var ui uint = 5
errs = validate.Var(ui, "gt=10")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gt")
i := true
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, "gt") }, "Bad field type bool")
tm := time.Now().UTC()
tm = tm.Add(time.Hour * 24)
errs = validate.Var(tm, "gt")
Equal(t, errs, nil)
t2 := time.Now().UTC().Add(-time.Hour)
errs = validate.Var(t2, "gt")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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)
AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "gt")
}
func TestIsGte(t *testing.T) {
validate := New()
i := true
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, "gte") }, "Bad field type bool")
t1 := time.Now().UTC()
t1 = t1.Add(time.Hour * 24)
errs := validate.Var(t1, "gte")
Equal(t, errs, nil)
t2 := time.Now().UTC().Add(-time.Hour)
errs = validate.Var(t2, "gte")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "gte")
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)
AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "gte")
}
func TestIsLt(t *testing.T) {
validate := New()
myMap := map[string]string{}
errs := validate.Var(myMap, "lt=0")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "lt")
f := 1.23
errs = validate.Var(f, "lt=0")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "lt")
var ui uint = 5
errs = validate.Var(ui, "lt=0")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "lt")
i := true
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, "lt") }, "Bad field type bool")
t1 := time.Now().UTC().Add(-time.Hour)
errs = validate.Var(t1, "lt")
Equal(t, errs, nil)
t2 := time.Now().UTC()
t2 = t2.Add(time.Hour * 24)
errs = validate.Var(t2, "lt")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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)
AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "lt")
}
func TestIsLte(t *testing.T) {
validate := New()
i := true
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, "lte") }, "Bad field type bool")
t1 := time.Now().UTC().Add(-time.Hour)
errs := validate.Var(t1, "lte")
Equal(t, errs, nil)
t2 := time.Now().UTC()
t2 = t2.Add(time.Hour * 24)
errs = validate.Var(t2, "lte")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "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 TestUrnRFC2141(t *testing.T) {
var tests = []struct {
param string
expected bool
}{
{"urn:a:b", true},
{"urn:a::", true},
{"urn:a:-", true},
{"URN:simple:simple", true},
{"urn:urna:simple", true},
{"urn:burnout:nss", true},
{"urn:burn:nss", true},
{"urn:urnurnurn:x", true},
{"urn:abcdefghilmnopqrstuvzabcdefghilm:x", true},
{"URN:123:x", true},
{"URN:abcd-:x", true},
{"URN:abcd-abcd:x", true},
{"urn:urnx:urn", true},
{"urn:ciao:a:b:c", true},
{"urn:aaa:x:y:", true},
{"urn:ciao:-", true},
{"urn:colon:::::nss", true},
{"urn:ciao:@!=%2C(xyz)+a,b.*@g=$_'", true},
{"URN:hexes:%25", true},
{"URN:x:abc%1Dz%2F%3az", true},
{"URN:foo:a123,456", true},
{"urn:foo:a123,456", true},
{"urn:FOO:a123,456", true},
{"urn:foo:A123,456", true},
{"urn:foo:a123%2C456", true},
{"URN:FOO:a123%2c456", true},
{"URN:FOO:ABC%FFabc123%2c456", true},
{"URN:FOO:ABC%FFabc123%2C456%9A", true},
{"urn:ietf:params:scim:schemas:core:2.0:User", true},
{"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:meta.lastModified", true},
{"URN:-xxx:x", false},
{"urn::colon:nss", false},
{"urn:abcdefghilmnopqrstuvzabcdefghilmn:specificstring", false},
{"URN:a!?:x", false},
{"URN:#,:x", false},
{"urn:urn:NSS", false},
{"urn:URN:NSS", false},
{"urn:white space:NSS", false},
{"urn:concat:no spaces", false},
{"urn:a:%", false},
{"urn:", false},
}
tag := "urn_rfc2141"
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, tag)
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d URN failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d URN failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != tag {
t.Fatalf("Index: %d URN failed Error: %s", i, errs)
}
}
}
}
i := 1
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, tag) }, "Bad field type int")
}
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", 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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "url")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d URL failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d URL failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "url" {
t.Fatalf("Index: %d URL failed Error: %s", i, errs)
}
}
}
}
i := 1
5 years ago
PanicMatches(t, func() { _ = validate.Var(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},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uri")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d URI failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d URI failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uri" {
t.Fatalf("Index: %d URI failed Error: %s", i, errs)
}
}
}
}
i := 1
5 years ago
PanicMatches(t, func() { _ = validate.Var(i, "uri") }, "Bad field type int")
}
func TestOrTag(t *testing.T) {
validate := New()
s := "rgba(0,31,255,0.5)"
errs := validate.Var(s, "rgb|rgba")
Equal(t, errs, nil)
s = "rgba(0,31,255,0.5)"
errs = validate.Var(s, "rgb|rgba|len=18")
Equal(t, errs, nil)
s = "this ain't right"
errs = validate.Var(s, "rgb|rgba")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgb|rgba")
s = "this ain't right"
errs = validate.Var(s, "rgb|rgba|len=10")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgb|rgba|len=10")
s = "this is right"
errs = validate.Var(s, "rgb|rgba|len=13")
Equal(t, errs, nil)
s = ""
errs = validate.Var(s, "omitempty,rgb|rgba")
Equal(t, errs, nil)
s = "green"
errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") //should fail on first validation block
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 1)
Equal(t, ve[0].Tag(), "eq=|eq=blue")
s = "this is right, but a blank or isn't"
5 years ago
PanicMatches(t, func() { _ = validate.Var(s, "rgb||len=13") }, "Invalid validation tag on field ''")
PanicMatches(t, func() { _ = validate.Var(s, "rgb|rgbaa|len=13") }, "Undefined validation function 'rgbaa' on field ''")
v2 := New()
v2.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type Colors struct {
Fav string `validate:"rgb|rgba" json:"fc"`
}
c := Colors{Fav: "this ain't right"}
err := v2.Struct(c)
NotEqual(t, err, nil)
errs = err.(ValidationErrors)
fe := getError(errs, "Colors.fc", "Colors.Fav")
NotEqual(t, fe, nil)
}
func TestHsla(t *testing.T) {
validate := New()
s := "hsla(360,100%,100%,1)"
errs := validate.Var(s, "hsla")
Equal(t, errs, nil)
s = "hsla(360,100%,100%,0.5)"
errs = validate.Var(s, "hsla")
Equal(t, errs, nil)
s = "hsla(0,0%,0%, 0)"
errs = validate.Var(s, "hsla")
Equal(t, errs, nil)
s = "hsl(361,100%,50%,1)"
errs = validate.Var(s, "hsla")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsla")
s = "hsl(361,100%,50%)"
errs = validate.Var(s, "hsla")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsla")
s = "hsla(361,100%,50%)"
errs = validate.Var(s, "hsla")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsla")
s = "hsla(360,101%,50%)"
errs = validate.Var(s, "hsla")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsla")
s = "hsla(360,100%,101%)"
errs = validate.Var(s, "hsla")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsla")
i := 1
5 years ago
errs = validate.Var(i, "hsla")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsla")
}
func TestHsl(t *testing.T) {
validate := New()
s := "hsl(360,100%,50%)"
errs := validate.Var(s, "hsl")
Equal(t, errs, nil)
s = "hsl(0,0%,0%)"
errs = validate.Var(s, "hsl")
Equal(t, errs, nil)
s = "hsl(361,100%,50%)"
errs = validate.Var(s, "hsl")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsl")
s = "hsl(361,101%,50%)"
errs = validate.Var(s, "hsl")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsl")
s = "hsl(361,100%,101%)"
errs = validate.Var(s, "hsl")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsl")
s = "hsl(-10,100%,100%)"
errs = validate.Var(s, "hsl")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsl")
i := 1
errs = validate.Var(i, "hsl")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hsl")
}
func TestRgba(t *testing.T) {
validate := New()
s := "rgba(0,31,255,0.5)"
errs := validate.Var(s, "rgba")
Equal(t, errs, nil)
s = "rgba(0,31,255,0.12)"
errs = validate.Var(s, "rgba")
Equal(t, errs, nil)
s = "rgba(12%,55%,100%,0.12)"
errs = validate.Var(s, "rgba")
Equal(t, errs, nil)
s = "rgba( 0, 31, 255, 0.5)"
errs = validate.Var(s, "rgba")
Equal(t, errs, nil)
s = "rgba(12%,55,100%,0.12)"
errs = validate.Var(s, "rgba")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgba")
s = "rgb(0, 31, 255)"
errs = validate.Var(s, "rgba")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgba")
s = "rgb(1,349,275,0.5)"
errs = validate.Var(s, "rgba")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgba")
s = "rgb(01,31,255,0.5)"
errs = validate.Var(s, "rgba")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgba")
i := 1
errs = validate.Var(i, "rgba")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgba")
}
func TestRgb(t *testing.T) {
validate := New()
s := "rgb(0,31,255)"
errs := validate.Var(s, "rgb")
Equal(t, errs, nil)
s = "rgb(0, 31, 255)"
errs = validate.Var(s, "rgb")
Equal(t, errs, nil)
s = "rgb(10%, 50%, 100%)"
errs = validate.Var(s, "rgb")
Equal(t, errs, nil)
s = "rgb(10%, 50%, 55)"
errs = validate.Var(s, "rgb")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgb")
s = "rgb(1,349,275)"
errs = validate.Var(s, "rgb")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgb")
s = "rgb(01,31,255)"
errs = validate.Var(s, "rgb")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgb")
s = "rgba(0,31,255)"
errs = validate.Var(s, "rgb")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgb")
i := 1
errs = validate.Var(i, "rgb")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "rgb")
}
func TestEmail(t *testing.T) {
validate := New()
s := "test@mail.com"
errs := validate.Var(s, "email")
Equal(t, errs, nil)
s = "Dörte@Sörensen.example.com"
errs = validate.Var(s, "email")
Equal(t, errs, nil)
s = "θσερ@εχαμπλε.ψομ"
errs = validate.Var(s, "email")
Equal(t, errs, nil)
s = "юзер@екзампл.ком"
errs = validate.Var(s, "email")
Equal(t, errs, nil)
s = "उपयगकर@उदहरण.कम"
errs = validate.Var(s, "email")
Equal(t, errs, nil)
s = "用户@例子.广告"
errs = validate.Var(s, "email")
Equal(t, errs, nil)
s = "mail@domain_with_underscores.org"
errs = validate.Var(s, "email")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "email")
s = ""
errs = validate.Var(s, "email")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "email")
s = "test@email"
errs = validate.Var(s, "email")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "email")
s = "test@email."
errs = validate.Var(s, "email")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "email")
s = "@email.com"
errs = validate.Var(s, "email")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "email")
6 years ago
s = `"test test"@email.com`
errs = validate.Var(s, "email")
Equal(t, errs, nil)
s = `"@email.com`
errs = validate.Var(s, "email")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "email")
i := true
errs = validate.Var(i, "email")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "email")
}
func TestHexColor(t *testing.T) {
validate := New()
s := "#fff"
errs := validate.Var(s, "hexcolor")
Equal(t, errs, nil)
s = "#c2c2c2"
errs = validate.Var(s, "hexcolor")
Equal(t, errs, nil)
s = "fff"
errs = validate.Var(s, "hexcolor")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hexcolor")
s = "fffFF"
errs = validate.Var(s, "hexcolor")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hexcolor")
i := true
errs = validate.Var(i, "hexcolor")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hexcolor")
}
func TestHexadecimal(t *testing.T) {
validate := New()
s := "ff0044"
errs := validate.Var(s, "hexadecimal")
Equal(t, errs, nil)
s = "abcdefg"
errs = validate.Var(s, "hexadecimal")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hexadecimal")
i := true
errs = validate.Var(i, "hexadecimal")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "hexadecimal")
}
func TestNumber(t *testing.T) {
validate := New()
s := "1"
errs := validate.Var(s, "number")
Equal(t, errs, nil)
s = "+1"
errs = validate.Var(s, "number")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "number")
s = "-1"
errs = validate.Var(s, "number")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "number")
s = "1.12"
errs = validate.Var(s, "number")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "number")
s = "+1.12"
errs = validate.Var(s, "number")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "number")
s = "-1.12"
errs = validate.Var(s, "number")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "number")
s = "1."
errs = validate.Var(s, "number")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "number")
s = "1.o"
errs = validate.Var(s, "number")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "number")
i := 1
errs = validate.Var(i, "number")
Equal(t, errs, nil)
}
func TestNumeric(t *testing.T) {
validate := New()
s := "1"
errs := validate.Var(s, "numeric")
Equal(t, errs, nil)
s = "+1"
errs = validate.Var(s, "numeric")
Equal(t, errs, nil)
s = "-1"
errs = validate.Var(s, "numeric")
Equal(t, errs, nil)
s = "1.12"
errs = validate.Var(s, "numeric")
Equal(t, errs, nil)
s = "+1.12"
errs = validate.Var(s, "numeric")
Equal(t, errs, nil)
s = "-1.12"
errs = validate.Var(s, "numeric")
Equal(t, errs, nil)
s = "1."
errs = validate.Var(s, "numeric")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "numeric")
s = "1.o"
errs = validate.Var(s, "numeric")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "numeric")
i := 1
errs = validate.Var(i, "numeric")
Equal(t, errs, nil)
}
func TestAlphaNumeric(t *testing.T) {
validate := New()
s := "abcd123"
errs := validate.Var(s, "alphanum")
Equal(t, errs, nil)
s = "abc!23"
errs = validate.Var(s, "alphanum")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "alphanum")
errs = validate.Var(1, "alphanum")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "alphanum")
}
func TestAlpha(t *testing.T) {
validate := New()
s := "abcd"
errs := validate.Var(s, "alpha")
Equal(t, errs, nil)
s = "abc®"
errs = validate.Var(s, "alpha")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "alpha")
s = "abc÷"
errs = validate.Var(s, "alpha")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "alpha")
s = "abc1"
errs = validate.Var(s, "alpha")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "alpha")
s = "this is a test string"
errs = validate.Var(s, "alpha")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "alpha")
errs = validate.Var(1, "alpha")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "", "", "alpha")
}
func TestStructStringValidation(t *testing.T) {
validate := New()
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",
},
}
errs := validate.Struct(tSuccess)
Equal(t, errs, 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",
},
}
errs = validate.Struct(tFail)
// Assert Top Level
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 13)
// Assert Fields
AssertError(t, errs, "TestString.Required", "TestString.Required", "Required", "Required", "required")
AssertError(t, errs, "TestString.Len", "TestString.Len", "Len", "Len", "len")
AssertError(t, errs, "TestString.Min", "TestString.Min", "Min", "Min", "min")
AssertError(t, errs, "TestString.Max", "TestString.Max", "Max", "Max", "max")
AssertError(t, errs, "TestString.MinMax", "TestString.MinMax", "MinMax", "MinMax", "min")
AssertError(t, errs, "TestString.Lt", "TestString.Lt", "Lt", "Lt", "lt")
AssertError(t, errs, "TestString.Lte", "TestString.Lte", "Lte", "Lte", "lte")
AssertError(t, errs, "TestString.Gt", "TestString.Gt", "Gt", "Gt", "gt")
AssertError(t, errs, "TestString.Gte", "TestString.Gte", "Gte", "Gte", "gte")
AssertError(t, errs, "TestString.OmitEmpty", "TestString.OmitEmpty", "OmitEmpty", "OmitEmpty", "max")
// Nested Struct Field Errs
AssertError(t, errs, "TestString.Anonymous.A", "TestString.Anonymous.A", "A", "A", "required")
AssertError(t, errs, "TestString.Sub.Test", "TestString.Sub.Test", "Test", "Test", "required")
AssertError(t, errs, "TestString.Iface.F", "TestString.Iface.F", "F", "F", "len")
}
8 years ago
func TestStructInt32Validation(t *testing.T) {
8 years ago
type TestInt32 struct {
Required int `validate:"required"`
Len int `validate:"len=10"`
Min int `validate:"min=1"`
Max int `validate:"max=10"`
MinMax int `validate:"min=1,max=10"`
Lt int `validate:"lt=10"`
Lte int `validate:"lte=10"`
Gt int `validate:"gt=10"`
Gte int `validate:"gte=10"`
OmitEmpty int `validate:"omitempty,min=1,max=10"`
}
tSuccess := &TestInt32{
Required: 1,
Len: 10,
Min: 1,
Max: 10,
MinMax: 5,
Lt: 9,
Lte: 10,
Gt: 11,
Gte: 10,
OmitEmpty: 0,
}
8 years ago
validate := New()
errs := validate.Struct(tSuccess)
Equal(t, errs, nil)
tFail := &TestInt32{
Required: 0,
Len: 11,
Min: -1,
Max: 11,
MinMax: -1,
Lt: 10,
Lte: 11,
Gt: 10,
Gte: 9,
OmitEmpty: 11,
}
errs = validate.Struct(tFail)
// Assert Top Level
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 10)
// Assert Fields
8 years ago
AssertError(t, errs, "TestInt32.Required", "TestInt32.Required", "Required", "Required", "required")
AssertError(t, errs, "TestInt32.Len", "TestInt32.Len", "Len", "Len", "len")
AssertError(t, errs, "TestInt32.Min", "TestInt32.Min", "Min", "Min", "min")
AssertError(t, errs, "TestInt32.Max", "TestInt32.Max", "Max", "Max", "max")
AssertError(t, errs, "TestInt32.MinMax", "TestInt32.MinMax", "MinMax", "MinMax", "min")
AssertError(t, errs, "TestInt32.Lt", "TestInt32.Lt", "Lt", "Lt", "lt")
AssertError(t, errs, "TestInt32.Lte", "TestInt32.Lte", "Lte", "Lte", "lte")
AssertError(t, errs, "TestInt32.Gt", "TestInt32.Gt", "Gt", "Gt", "gt")
AssertError(t, errs, "TestInt32.Gte", "TestInt32.Gte", "Gte", "Gte", "gte")
AssertError(t, errs, "TestInt32.OmitEmpty", "TestInt32.OmitEmpty", "OmitEmpty", "OmitEmpty", "max")
}
func TestStructUint64Validation(t *testing.T) {
validate := New()
tSuccess := &TestUint64{
Required: 1,
Len: 10,
Min: 1,
Max: 10,
MinMax: 5,
OmitEmpty: 0,
}
errs := validate.Struct(tSuccess)
Equal(t, errs, nil)
tFail := &TestUint64{
Required: 0,
Len: 11,
Min: 0,
Max: 11,
MinMax: 0,
OmitEmpty: 11,
}
errs = validate.Struct(tFail)
// Assert Top Level
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 6)
// Assert Fields
AssertError(t, errs, "TestUint64.Required", "TestUint64.Required", "Required", "Required", "required")
AssertError(t, errs, "TestUint64.Len", "TestUint64.Len", "Len", "Len", "len")
AssertError(t, errs, "TestUint64.Min", "TestUint64.Min", "Min", "Min", "min")
AssertError(t, errs, "TestUint64.Max", "TestUint64.Max", "Max", "Max", "max")
AssertError(t, errs, "TestUint64.MinMax", "TestUint64.MinMax", "MinMax", "MinMax", "min")
AssertError(t, errs, "TestUint64.OmitEmpty", "TestUint64.OmitEmpty", "OmitEmpty", "OmitEmpty", "max")
}
func TestStructFloat64Validation(t *testing.T) {
validate := New()
tSuccess := &TestFloat64{
Required: 1,
Len: 10,
Min: 1,
Max: 10,
MinMax: 5,
OmitEmpty: 0,
}
errs := validate.Struct(tSuccess)
Equal(t, errs, nil)
tFail := &TestFloat64{
Required: 0,
Len: 11,
Min: 0,
Max: 11,
MinMax: 0,
OmitEmpty: 11,
}
errs = validate.Struct(tFail)
// Assert Top Level
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 6)
// Assert Fields
AssertError(t, errs, "TestFloat64.Required", "TestFloat64.Required", "Required", "Required", "required")
AssertError(t, errs, "TestFloat64.Len", "TestFloat64.Len", "Len", "Len", "len")
AssertError(t, errs, "TestFloat64.Min", "TestFloat64.Min", "Min", "Min", "min")
AssertError(t, errs, "TestFloat64.Max", "TestFloat64.Max", "Max", "Max", "max")
AssertError(t, errs, "TestFloat64.MinMax", "TestFloat64.MinMax", "MinMax", "MinMax", "min")
AssertError(t, errs, "TestFloat64.OmitEmpty", "TestFloat64.OmitEmpty", "OmitEmpty", "OmitEmpty", "max")
}
func TestStructSliceValidation(t *testing.T) {
validate := New()
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: nil,
}
errs := validate.Struct(tSuccess)
Equal(t, errs, nil)
tFail := &TestSlice{
Required: nil,
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},
}
errs = validate.Struct(tFail)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 6)
// Assert Field Errors
AssertError(t, errs, "TestSlice.Required", "TestSlice.Required", "Required", "Required", "required")
AssertError(t, errs, "TestSlice.Len", "TestSlice.Len", "Len", "Len", "len")
AssertError(t, errs, "TestSlice.Min", "TestSlice.Min", "Min", "Min", "min")
AssertError(t, errs, "TestSlice.Max", "TestSlice.Max", "Max", "Max", "max")
AssertError(t, errs, "TestSlice.MinMax", "TestSlice.MinMax", "MinMax", "MinMax", "min")
AssertError(t, errs, "TestSlice.OmitEmpty", "TestSlice.OmitEmpty", "OmitEmpty", "OmitEmpty", "max")
fe := getError(errs, "TestSlice.Len", "TestSlice.Len")
NotEqual(t, fe, nil)
Equal(t, fe.Field(), "Len")
Equal(t, fe.StructField(), "Len")
Equal(t, fe.Namespace(), "TestSlice.Len")
Equal(t, fe.StructNamespace(), "TestSlice.Len")
Equal(t, fe.Tag(), "len")
Equal(t, fe.ActualTag(), "len")
Equal(t, fe.Param(), "10")
Equal(t, fe.Kind(), reflect.Slice)
Equal(t, fe.Type(), reflect.TypeOf([]int{}))
_, ok := fe.Value().([]int)
Equal(t, ok, true)
}
func TestInvalidStruct(t *testing.T) {
validate := New()
s := &SubTest{
Test: "1",
}
err := validate.Struct(s.Test)
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil string)")
err = validate.Struct(nil)
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil)")
err = validate.StructPartial(nil, "SubTest.Test")
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil)")
err = validate.StructExcept(nil, "SubTest.Test")
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil)")
}
func TestInvalidValidatorFunction(t *testing.T) {
validate := New()
s := &SubTest{
Test: "1",
}
5 years ago
PanicMatches(t, func() { _ = validate.Var(s.Test, "zzxxBadFunction") }, "Undefined validation function 'zzxxBadFunction' on field ''")
}
func TestCustomFieldName(t *testing.T) {
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("schema"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type A struct {
B string `schema:"b" validate:"required"`
C string `schema:"c" validate:"required"`
D []bool `schema:"d" validate:"required"`
E string `schema:"-" validate:"required"`
}
a := &A{}
err := validate.Struct(a)
NotEqual(t, err, nil)
errs := err.(ValidationErrors)
Equal(t, len(errs), 4)
Equal(t, getError(errs, "A.b", "A.B").Field(), "b")
Equal(t, getError(errs, "A.c", "A.C").Field(), "c")
Equal(t, getError(errs, "A.d", "A.D").Field(), "d")
Equal(t, getError(errs, "A.E", "A.E").Field(), "E")
v2 := New()
err = v2.Struct(a)
NotEqual(t, err, nil)
errs = err.(ValidationErrors)
Equal(t, len(errs), 4)
Equal(t, getError(errs, "A.B", "A.B").Field(), "B")
Equal(t, getError(errs, "A.C", "A.C").Field(), "C")
Equal(t, getError(errs, "A.D", "A.D").Field(), "D")
Equal(t, getError(errs, "A.E", "A.E").Field(), "E")
}
func TestMutipleRecursiveExtractStructCache(t *testing.T) {
validate := New()
type Recursive struct {
Field *string `validate:"required,len=5,ne=string"`
}
var test Recursive
current := reflect.ValueOf(test)
name := "Recursive"
proceed := make(chan struct{})
sc := validate.extractStructCache(current, name)
ptr := fmt.Sprintf("%p", sc)
for i := 0; i < 100; i++ {
go func() {
<-proceed
sc := validate.extractStructCache(current, name)
Equal(t, ptr, fmt.Sprintf("%p", sc))
}()
}
close(proceed)
}
// Thanks @robbrockbank, see https://github.com/go-playground/validator/issues/249
func TestPointerAndOmitEmpty(t *testing.T) {
validate := New()
type Test struct {
MyInt *int `validate:"omitempty,gte=2,lte=255"`
}
val1 := 0
val2 := 256
t1 := Test{MyInt: &val1} // This should fail validation on gte because value is 0
t2 := Test{MyInt: &val2} // This should fail validate on lte because value is 256
t3 := Test{MyInt: nil} // This should succeed validation because pointer is nil
errs := validate.Struct(t1)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.MyInt", "Test.MyInt", "MyInt", "MyInt", "gte")
errs = validate.Struct(t2)
NotEqual(t, errs, nil)
AssertError(t, errs, "Test.MyInt", "Test.MyInt", "MyInt", "MyInt", "lte")
errs = validate.Struct(t3)
Equal(t, errs, nil)
type TestIface struct {
MyInt interface{} `validate:"omitempty,gte=2,lte=255"`
}
ti1 := TestIface{MyInt: &val1} // This should fail validation on gte because value is 0
ti2 := TestIface{MyInt: &val2} // This should fail validate on lte because value is 256
ti3 := TestIface{MyInt: nil} // This should succeed validation because pointer is nil
errs = validate.Struct(ti1)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestIface.MyInt", "TestIface.MyInt", "MyInt", "MyInt", "gte")
errs = validate.Struct(ti2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestIface.MyInt", "TestIface.MyInt", "MyInt", "MyInt", "lte")
errs = validate.Struct(ti3)
Equal(t, errs, nil)
}
func TestRequired(t *testing.T) {
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type Test struct {
Value interface{} `validate:"required"`
}
var test Test
err := validate.Struct(test)
NotEqual(t, err, nil)
AssertError(t, err.(ValidationErrors), "Test.Value", "Test.Value", "Value", "Value", "required")
}
func TestBoolEqual(t *testing.T) {
validate := New()
type Test struct {
Value bool `validate:"eq=true"`
}
var test Test
err := validate.Struct(test)
NotEqual(t, err, nil)
AssertError(t, err.(ValidationErrors), "Test.Value", "Test.Value", "Value", "Value", "eq")
test.Value = true
err = validate.Struct(test)
Equal(t, err, nil)
}
func TestTranslations(t *testing.T) {
en := en.New()
uni := ut.New(en, en, fr.New())
trans, _ := uni.GetTranslator("en")
fr, _ := uni.GetTranslator("fr")
validate := New()
err := validate.RegisterTranslation("required", trans,
func(ut ut.Translator) (err error) {
// using this stype because multiple translation may have to be added for the full translation
if err = ut.Add("required", "{0} is a required field", false); err != nil {
return
}
return
}, func(ut ut.Translator, fe FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field())
if err != nil {
fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError))
return fe.(*fieldError).Error()
}
return t
})
Equal(t, err, nil)
err = validate.RegisterTranslation("required", fr,
func(ut ut.Translator) (err error) {
// using this stype because multiple translation may have to be added for the full translation
if err = ut.Add("required", "{0} est un champ obligatoire", false); err != nil {
return
}
return
}, func(ut ut.Translator, fe FieldError) string {
t, transErr := ut.T(fe.Tag(), fe.Field())
if transErr != nil {
fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError))
return fe.(*fieldError).Error()
}
return t
})
Equal(t, err, nil)
type Test struct {
Value interface{} `validate:"required"`
}
var test Test
err = validate.Struct(test)
NotEqual(t, err, nil)
errs := err.(ValidationErrors)
Equal(t, len(errs), 1)
fe := errs[0]
Equal(t, fe.Tag(), "required")
Equal(t, fe.Namespace(), "Test.Value")
Equal(t, fe.Translate(trans), fmt.Sprintf("%s is a required field", fe.Field()))
Equal(t, fe.Translate(fr), fmt.Sprintf("%s est un champ obligatoire", fe.Field()))
nl := nl.New()
uni2 := ut.New(nl, nl)
trans2, _ := uni2.GetTranslator("nl")
Equal(t, fe.Translate(trans2), "Key: 'Test.Value' Error:Field validation for 'Value' failed on the 'required' tag")
terrs := errs.Translate(trans)
Equal(t, len(terrs), 1)
v, ok := terrs["Test.Value"]
Equal(t, ok, true)
Equal(t, v, fmt.Sprintf("%s is a required field", fe.Field()))
terrs = errs.Translate(fr)
Equal(t, len(terrs), 1)
v, ok = terrs["Test.Value"]
Equal(t, ok, true)
Equal(t, v, fmt.Sprintf("%s est un champ obligatoire", fe.Field()))
type Test2 struct {
Value string `validate:"gt=1"`
}
var t2 Test2
err = validate.Struct(t2)
NotEqual(t, err, nil)
errs = err.(ValidationErrors)
Equal(t, len(errs), 1)
fe = errs[0]
Equal(t, fe.Tag(), "gt")
Equal(t, fe.Namespace(), "Test2.Value")
Equal(t, fe.Translate(trans), "Key: 'Test2.Value' Error:Field validation for 'Value' failed on the 'gt' tag")
}
func TestTranslationErrors(t *testing.T) {
en := en.New()
uni := ut.New(en, en, fr.New())
trans, _ := uni.GetTranslator("en")
5 years ago
err := trans.Add("required", "{0} is a required field", false) // using translator outside of validator also
Equal(t, err, nil)
validate := New()
5 years ago
err = validate.RegisterTranslation("required", trans,
func(ut ut.Translator) (err error) {
// using this stype because multiple translation may have to be added for the full translation
if err = ut.Add("required", "{0} is a required field", false); err != nil {
return
}
return
}, func(ut ut.Translator, fe FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field())
if err != nil {
fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError))
return fe.(*fieldError).Error()
}
return t
})
NotEqual(t, err, nil)
Equal(t, err.Error(), "error: conflicting key 'required' rule 'Unknown' with text '{0} is a required field' for locale 'en', value being ignored")
}
8 years ago
func TestStructFiltered(t *testing.T) {
p1 := func(ns []byte) bool {
if bytes.HasSuffix(ns, []byte("NoTag")) || bytes.HasSuffix(ns, []byte("Required")) {
return false
}
return true
}
p2 := func(ns []byte) bool {
if bytes.HasSuffix(ns, []byte("SubSlice[0].Test")) ||
bytes.HasSuffix(ns, []byte("SubSlice[0]")) ||
bytes.HasSuffix(ns, []byte("SubSlice")) ||
bytes.HasSuffix(ns, []byte("Sub")) ||
bytes.HasSuffix(ns, []byte("SubIgnore")) ||
bytes.HasSuffix(ns, []byte("Anonymous")) ||
bytes.HasSuffix(ns, []byte("Anonymous.A")) {
return false
}
return true
}
p3 := func(ns []byte) bool {
return !bytes.HasSuffix(ns, []byte("SubTest.Test"))
8 years ago
}
// p4 := []string{
// "A",
// }
tPartial := &TestPartial{
NoTag: "NoTag",
Required: "Required",
SubSlice: []*SubTest{
{
Test: "Required",
},
{
Test: "Required",
},
},
Sub: &SubTest{
Test: "1",
},
SubIgnore: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
ASubSlice []*SubTest `validate:"required,dive"`
SubAnonStruct []struct {
Test string `validate:"required"`
OtherTest string `validate:"required"`
} `validate:"required,dive"`
}{
A: "1",
ASubSlice: []*SubTest{
{
Test: "Required",
},
{
Test: "Required",
},
},
SubAnonStruct: []struct {
Test string `validate:"required"`
OtherTest string `validate:"required"`
}{
{"Required", "RequiredOther"},
{"Required", "RequiredOther"},
},
},
}
validate := New()
// the following should all return no errors as everything is valid in
// the default state
errs := validate.StructFilteredCtx(context.Background(), tPartial, p1)
8 years ago
Equal(t, errs, nil)
errs = validate.StructFiltered(tPartial, p2)
Equal(t, errs, nil)
// this isn't really a robust test, but is ment to illustrate the ANON CASE below
errs = validate.StructFiltered(tPartial.SubSlice[0], p3)
Equal(t, errs, nil)
// mod tParial for required feild and re-test making sure invalid fields are NOT required:
tPartial.Required = ""
// inversion and retesting Partial to generate failures:
errs = validate.StructFiltered(tPartial, p1)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Required", "TestPartial.Required", "Required", "Required", "required")
// reset Required field, and set nested struct
tPartial.Required = "Required"
tPartial.Anonymous.A = ""
// will pass as unset feilds is not going to be tested
errs = validate.StructFiltered(tPartial, p1)
Equal(t, errs, nil)
// will fail as unset feild is tested
errs = validate.StructFiltered(tPartial, p2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.Anonymous.A", "TestPartial.Anonymous.A", "A", "A", "required")
// reset nested struct and unset struct in slice
tPartial.Anonymous.A = "Required"
tPartial.SubSlice[0].Test = ""
// these will pass as unset item is NOT tested
errs = validate.StructFiltered(tPartial, p1)
Equal(t, errs, nil)
errs = validate.StructFiltered(tPartial, p2)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required")
Equal(t, len(errs.(ValidationErrors)), 1)
// Unset second slice member concurrently to test dive behavior:
tPartial.SubSlice[1].Test = ""
errs = validate.StructFiltered(tPartial, p1)
Equal(t, errs, nil)
errs = validate.StructFiltered(tPartial, p2)
NotEqual(t, errs, nil)
Equal(t, len(errs.(ValidationErrors)), 1)
AssertError(t, errs, "TestPartial.SubSlice[0].Test", "TestPartial.SubSlice[0].Test", "Test", "Test", "required")
// reset struct in slice, and unset struct in slice in unset posistion
tPartial.SubSlice[0].Test = "Required"
// these will pass as the unset item is NOT tested
errs = validate.StructFiltered(tPartial, p1)
Equal(t, errs, nil)
errs = validate.StructFiltered(tPartial, p2)
Equal(t, errs, nil)
tPartial.SubSlice[1].Test = "Required"
tPartial.Anonymous.SubAnonStruct[0].Test = ""
// these will pass as the unset item is NOT tested
errs = validate.StructFiltered(tPartial, p1)
Equal(t, errs, nil)
errs = validate.StructFiltered(tPartial, p2)
Equal(t, errs, nil)
dt := time.Now()
err := validate.StructFiltered(&dt, func(ns []byte) bool { return true })
NotEqual(t, err, nil)
Equal(t, err.Error(), "validator: (nil *time.Time)")
}
func TestRequiredPtr(t *testing.T) {
type Test struct {
Bool *bool `validate:"required"`
}
validate := New()
f := false
test := Test{
Bool: &f,
}
err := validate.Struct(test)
Equal(t, err, nil)
tr := true
test.Bool = &tr
err = validate.Struct(test)
Equal(t, err, nil)
test.Bool = nil
err = validate.Struct(test)
NotEqual(t, err, nil)
errs, ok := err.(ValidationErrors)
Equal(t, ok, true)
Equal(t, len(errs), 1)
AssertError(t, errs, "Test.Bool", "Test.Bool", "Bool", "Bool", "required")
type Test2 struct {
Bool bool `validate:"required"`
}
var test2 Test2
err = validate.Struct(test2)
NotEqual(t, err, nil)
errs, ok = err.(ValidationErrors)
Equal(t, ok, true)
Equal(t, len(errs), 1)
AssertError(t, errs, "Test2.Bool", "Test2.Bool", "Bool", "Bool", "required")
test2.Bool = true
err = validate.Struct(test2)
Equal(t, err, nil)
type Test3 struct {
Arr []string `validate:"required"`
}
var test3 Test3
err = validate.Struct(test3)
NotEqual(t, err, nil)
errs, ok = err.(ValidationErrors)
Equal(t, ok, true)
Equal(t, len(errs), 1)
AssertError(t, errs, "Test3.Arr", "Test3.Arr", "Arr", "Arr", "required")
test3.Arr = make([]string, 0)
err = validate.Struct(test3)
Equal(t, err, nil)
type Test4 struct {
Arr *[]string `validate:"required"` // I know I know pointer to array, just making sure validation works as expected...
}
var test4 Test4
err = validate.Struct(test4)
NotEqual(t, err, nil)
errs, ok = err.(ValidationErrors)
Equal(t, ok, true)
Equal(t, len(errs), 1)
AssertError(t, errs, "Test4.Arr", "Test4.Arr", "Arr", "Arr", "required")
arr := make([]string, 0)
test4.Arr = &arr
err = validate.Struct(test4)
Equal(t, err, nil)
}
func TestAlphaUnicodeValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{"abc", true},
{"this is a test string", false},
{"这是一个测试字符串", true},
{"123", false},
{"<>@;.-=", false},
{"ひらがな・カタカナ、.漢字", false},
{"あいうえおfoobar", true},
{"test@example.com", false},
{"1234abcDE", false},
{"カタカナ", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "alphaunicode")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d Alpha Unicode failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d Alpha Unicode failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "alphaunicode" {
t.Fatalf("Index: %d Alpha Unicode failed Error: %s", i, errs)
}
}
}
}
}
func TestAlphanumericUnicodeValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"", false},
{"abc", true},
{"this is a test string", false},
{"这是一个测试字符串", true},
{"\u0031\u0032\u0033", true}, // unicode 5
{"123", true},
{"<>@;.-=", false},
{"ひらがな・カタカナ、.漢字", false},
{"あいうえおfoobar", true},
{"test@example.com", false},
{"1234abcDE", true},
{"カタカナ", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "alphanumunicode")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d Alphanum Unicode failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d Alphanum Unicode failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "alphanumunicode" {
t.Fatalf("Index: %d Alphanum Unicode failed Error: %s", i, errs)
}
}
}
}
}
func TestArrayStructNamespace(t *testing.T) {
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type child struct {
Name string `json:"name" validate:"required"`
}
var input struct {
Children []child `json:"children" validate:"required,gt=0,dive"`
}
input.Children = []child{{"ok"}, {""}}
errs := validate.Struct(input)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 1)
AssertError(t, errs, "children[1].name", "Children[1].Name", "name", "Name", "required")
}
func TestMapStructNamespace(t *testing.T) {
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type child struct {
Name string `json:"name" validate:"required"`
}
var input struct {
Children map[int]child `json:"children" validate:"required,gt=0,dive"`
}
input.Children = map[int]child{
0: {Name: "ok"},
1: {Name: ""},
}
errs := validate.Struct(input)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 1)
AssertError(t, errs, "children[1].name", "Children[1].Name", "name", "Name", "required")
}
func TestFieldLevelName(t *testing.T) {
type Test struct {
String string `validate:"custom1" json:"json1"`
Array []string `validate:"dive,custom2" json:"json2"`
Map map[string]string `validate:"dive,custom3" json:"json3"`
Array2 []string `validate:"custom4" json:"json4"`
Map2 map[string]string `validate:"custom5" json:"json5"`
}
var res1, res2, res3, res4, res5, alt1, alt2, alt3, alt4, alt5 string
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
5 years ago
err := validate.RegisterValidation("custom1", func(fl FieldLevel) bool {
res1 = fl.FieldName()
alt1 = fl.StructFieldName()
return true
})
5 years ago
Equal(t, err, nil)
err = validate.RegisterValidation("custom2", func(fl FieldLevel) bool {
res2 = fl.FieldName()
alt2 = fl.StructFieldName()
return true
})
5 years ago
Equal(t, err, nil)
err = validate.RegisterValidation("custom3", func(fl FieldLevel) bool {
res3 = fl.FieldName()
alt3 = fl.StructFieldName()
return true
})
5 years ago
Equal(t, err, nil)
err = validate.RegisterValidation("custom4", func(fl FieldLevel) bool {
res4 = fl.FieldName()
alt4 = fl.StructFieldName()
return true
})
5 years ago
Equal(t, err, nil)
err = validate.RegisterValidation("custom5", func(fl FieldLevel) bool {
res5 = fl.FieldName()
alt5 = fl.StructFieldName()
return true
})
5 years ago
Equal(t, err, nil)
test := Test{
String: "test",
Array: []string{"1"},
Map: map[string]string{"test": "test"},
}
errs := validate.Struct(test)
Equal(t, errs, nil)
Equal(t, res1, "json1")
Equal(t, alt1, "String")
Equal(t, res2, "json2[0]")
Equal(t, alt2, "Array[0]")
Equal(t, res3, "json3[test]")
Equal(t, alt3, "Map[test]")
Equal(t, res4, "json4")
Equal(t, alt4, "Array2")
Equal(t, res5, "json5")
Equal(t, alt5, "Map2")
}
func TestValidateStructRegisterCtx(t *testing.T) {
var ctxVal string
fnCtx := func(ctx context.Context, fl FieldLevel) bool {
ctxVal = ctx.Value(&ctxVal).(string)
return true
}
var ctxSlVal string
slFn := func(ctx context.Context, sl StructLevel) {
ctxSlVal = ctx.Value(&ctxSlVal).(string)
}
type Test struct {
Field string `validate:"val"`
}
var tst Test
validate := New()
5 years ago
err := validate.RegisterValidationCtx("val", fnCtx)
Equal(t, err, nil)
validate.RegisterStructValidationCtx(slFn, Test{})
ctx := context.WithValue(context.Background(), &ctxVal, "testval")
ctx = context.WithValue(ctx, &ctxSlVal, "slVal")
errs := validate.StructCtx(ctx, tst)
Equal(t, errs, nil)
Equal(t, ctxVal, "testval")
Equal(t, ctxSlVal, "slVal")
}
func TestHostnameRFC952Validation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"test.example.com", true},
{"example.com", true},
{"example24.com", true},
{"test.example24.com", true},
{"test24.example24.com", true},
{"example", true},
{"EXAMPLE", true},
{"1.foo.com", false},
{"test.example.com.", false},
{"example.com.", false},
{"example24.com.", false},
{"test.example24.com.", false},
{"test24.example24.com.", false},
{"example.", false},
{"192.168.0.1", false},
{"email@example.com", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "hostname")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "hostname" {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
}
}
}
}
func TestHostnameRFC1123Validation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"test.example.com", true},
{"example.com", true},
{"example24.com", true},
{"test.example24.com", true},
{"test24.example24.com", true},
{"example", true},
{"1.foo.com", true},
{"test.example.com.", false},
{"example.com.", false},
{"example24.com.", false},
{"test.example24.com.", false},
{"test24.example24.com.", false},
{"example.", false},
{"192.168.0.1", true},
{"email@example.com", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "hostname_rfc1123")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Hostname: %v failed Error: %v", test, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Hostname: %v failed Error: %v", test, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "hostname_rfc1123" {
t.Fatalf("Hostname: %v failed Error: %v", i, errs)
}
}
}
}
}
func TestHostnameRFC1123AliasValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"test.example.com", true},
{"example.com", true},
{"example24.com", true},
{"test.example24.com", true},
{"test24.example24.com", true},
{"example", true},
{"1.foo.com", true},
{"test.example.com.", false},
{"example.com.", false},
{"example24.com.", false},
{"test.example24.com.", false},
{"test24.example24.com.", false},
{"example.", false},
{"192.168.0.1", true},
{"email@example.com", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false},
}
validate := New()
validate.RegisterAlias("hostname", "hostname_rfc1123")
for i, test := range tests {
errs := validate.Var(test.param, "hostname")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "hostname" {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs)
}
}
}
}
}
func TestFQDNValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"test.example.com", true},
{"example.com", true},
{"example24.com", true},
{"test.example24.com", true},
{"test24.example24.com", true},
{"test.example.com.", true},
{"example.com.", true},
{"example24.com.", true},
{"test.example24.com.", true},
{"test24.example24.com.", true},
{"24.example24.com", true},
{"test.24.example.com", true},
{"test24.example24.com..", false},
{"example", false},
{"192.168.0.1", false},
{"email@example.com", false},
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false},
{"", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "fqdn")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d fqdn failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d fqdn failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "fqdn" {
t.Fatalf("Index: %d fqdn failed Error: %v", i, errs)
}
}
}
}
}
func TestIsDefault(t *testing.T) {
validate := New()
type Inner struct {
String string `validate:"isdefault"`
}
type Test struct {
String string `validate:"isdefault"`
Inner *Inner `validate:"isdefault"`
}
var tt Test
errs := validate.Struct(tt)
Equal(t, errs, nil)
tt.Inner = &Inner{String: ""}
errs = validate.Struct(tt)
NotEqual(t, errs, nil)
fe := errs.(ValidationErrors)[0]
Equal(t, fe.Field(), "Inner")
Equal(t, fe.Namespace(), "Test.Inner")
Equal(t, fe.Tag(), "isdefault")
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type Inner2 struct {
String string `validate:"isdefault"`
}
type Test2 struct {
Inner Inner2 `validate:"isdefault" json:"inner"`
}
var t2 Test2
errs = validate.Struct(t2)
Equal(t, errs, nil)
t2.Inner.String = "Changed"
errs = validate.Struct(t2)
NotEqual(t, errs, nil)
fe = errs.(ValidationErrors)[0]
Equal(t, fe.Field(), "inner")
Equal(t, fe.Namespace(), "Test2.inner")
Equal(t, fe.Tag(), "isdefault")
}
func TestUniqueValidation(t *testing.T) {
tests := []struct {
param interface{}
expected bool
}{
// Arrays
{[2]string{"a", "b"}, true},
{[2]int{1, 2}, true},
{[2]float64{1, 2}, true},
{[2]interface{}{"a", "b"}, true},
{[2]interface{}{"a", 1}, true},
{[2]float64{1, 1}, false},
{[2]int{1, 1}, false},
{[2]string{"a", "a"}, false},
{[2]interface{}{"a", "a"}, false},
{[4]interface{}{"a", 1, "b", 1}, false},
// Slices
{[]string{"a", "b"}, true},
{[]int{1, 2}, true},
{[]float64{1, 2}, true},
{[]interface{}{"a", "b"}, true},
{[]interface{}{"a", 1}, true},
{[]float64{1, 1}, false},
{[]int{1, 1}, false},
{[]string{"a", "a"}, false},
{[]interface{}{"a", "a"}, false},
{[]interface{}{"a", 1, "b", 1}, false},
// Maps
{map[string]string{"one": "a", "two": "b"}, true},
{map[string]int{"one": 1, "two": 2}, true},
{map[string]float64{"one": 1, "two": 2}, true},
{map[string]interface{}{"one": "a", "two": "b"}, true},
{map[string]interface{}{"one": "a", "two": 1}, true},
{map[string]float64{"one": 1, "two": 1}, false},
{map[string]int{"one": 1, "two": 1}, false},
{map[string]string{"one": "a", "two": "a"}, false},
{map[string]interface{}{"one": "a", "two": "a"}, false},
{map[string]interface{}{"one": "a", "two": 1, "three": "b", "four": 1}, false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "unique")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "unique" {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
}
}
}
5 years ago
PanicMatches(t, func() { _ = validate.Var(1.0, "unique") }, "Bad field type float64")
}
func TestUniqueValidationStructSlice(t *testing.T) {
testStructs := []struct {
A string
B string
}{
{A: "one", B: "two"},
{A: "one", B: "three"},
}
tests := []struct {
target interface{}
param string
expected bool
}{
{testStructs, "unique", true},
{testStructs, "unique=A", false},
{testStructs, "unique=B", true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.target, test.param)
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "unique" {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
}
}
}
PanicMatches(t, func() { validate.Var(testStructs, "unique=C") }, "Bad field name C")
}
func TestHTMLValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"<html>", true},
{"<script>", true},
{"<stillworks>", true},
{"</html", false},
{"</script>", true},
{"<//script>", false},
{"<123nonsense>", false},
{"test", false},
{"&example", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "html")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d html failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d html failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "html" {
t.Fatalf("Index: %d html failed Error: %v", i, errs)
}
}
}
}
}
func TestHTMLEncodedValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"&#x3c;", true},
{"&#xaf;", true},
{"&#x00;", true},
{"&#xf0;", true},
{"&#x3c", true},
{"&#xaf", true},
{"&#x00", true},
{"&#xf0", true},
{"&#ab", true},
{"&lt;", true},
{"&gt;", true},
{"&quot;", true},
{"&amp;", true},
{"#x0a", false},
{"&x00", false},
{"&#x1z", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "html_encoded")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d html_encoded failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d html_enocded failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "html_encoded" {
t.Fatalf("Index: %d html_encoded failed Error: %v", i, errs)
}
}
}
}
}
func TestURLEncodedValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"%20", true},
{"%af", true},
{"%ff", true},
{"<%az", false},
{"%test%", false},
{"a%b", false},
{"1%2", false},
{"%%a%%", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "url_encoded")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d url_encoded failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d url_enocded failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "url_encoded" {
t.Fatalf("Index: %d url_encoded failed Error: %v", i, errs)
}
}
}
}
}
func TestKeys(t *testing.T) {
type Test struct {
Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey,endkeys,eq=testval" json:"test1"`
Test2 map[int]int `validate:"gt=0,dive,keys,eq=3,endkeys,eq=4" json:"test2"`
Test3 map[int]int `validate:"gt=0,dive,keys,eq=3,endkeys" json:"test3"`
}
var tst Test
validate := New()
err := validate.Struct(tst)
NotEqual(t, err, nil)
Equal(t, len(err.(ValidationErrors)), 3)
AssertError(t, err.(ValidationErrors), "Test.Test1", "Test.Test1", "Test1", "Test1", "gt")
AssertError(t, err.(ValidationErrors), "Test.Test2", "Test.Test2", "Test2", "Test2", "gt")
AssertError(t, err.(ValidationErrors), "Test.Test3", "Test.Test3", "Test3", "Test3", "gt")
tst.Test1 = map[string]string{
"testkey": "testval",
}
tst.Test2 = map[int]int{
3: 4,
}
tst.Test3 = map[int]int{
3: 4,
}
err = validate.Struct(tst)
Equal(t, err, nil)
tst.Test1["badtestkey"] = "badtestvalue"
tst.Test2[10] = 11
err = validate.Struct(tst)
NotEqual(t, err, nil)
errs := err.(ValidationErrors)
Equal(t, len(errs), 4)
AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq")
AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq")
AssertDeepError(t, errs, "Test.Test2[10]", "Test.Test2[10]", "Test2[10]", "Test2[10]", "eq", "eq")
AssertDeepError(t, errs, "Test.Test2[10]", "Test.Test2[10]", "Test2[10]", "Test2[10]", "eq", "eq")
type Test2 struct {
NestedKeys map[[1]string]string `validate:"gt=0,dive,keys,dive,eq=innertestkey,endkeys,eq=outertestval"`
}
var tst2 Test2
err = validate.Struct(tst2)
NotEqual(t, err, nil)
Equal(t, len(err.(ValidationErrors)), 1)
AssertError(t, err.(ValidationErrors), "Test2.NestedKeys", "Test2.NestedKeys", "NestedKeys", "NestedKeys", "gt")
tst2.NestedKeys = map[[1]string]string{
[1]string{"innertestkey"}: "outertestval",
}
err = validate.Struct(tst2)
Equal(t, err, nil)
tst2.NestedKeys[[1]string{"badtestkey"}] = "badtestvalue"
err = validate.Struct(tst2)
NotEqual(t, err, nil)
errs = err.(ValidationErrors)
Equal(t, len(errs), 2)
AssertDeepError(t, errs, "Test2.NestedKeys[[badtestkey]][0]", "Test2.NestedKeys[[badtestkey]][0]", "NestedKeys[[badtestkey]][0]", "NestedKeys[[badtestkey]][0]", "eq", "eq")
AssertDeepError(t, errs, "Test2.NestedKeys[[badtestkey]]", "Test2.NestedKeys[[badtestkey]]", "NestedKeys[[badtestkey]]", "NestedKeys[[badtestkey]]", "eq", "eq")
// test bad tag definitions
5 years ago
PanicMatches(t, func() { _ = validate.Var(map[string]string{"key": "val"}, "endkeys,dive,eq=val") }, "'endkeys' tag encountered without a corresponding 'keys' tag")
PanicMatches(t, func() { _ = validate.Var(1, "keys,eq=1,endkeys") }, "'keys' tag must be immediately preceded by the 'dive' tag")
// test custom tag name
validate = New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
err = validate.Struct(tst)
NotEqual(t, err, nil)
errs = err.(ValidationErrors)
Equal(t, len(errs), 4)
AssertDeepError(t, errs, "Test.test1[badtestkey]", "Test.Test1[badtestkey]", "test1[badtestkey]", "Test1[badtestkey]", "eq", "eq")
AssertDeepError(t, errs, "Test.test1[badtestkey]", "Test.Test1[badtestkey]", "test1[badtestkey]", "Test1[badtestkey]", "eq", "eq")
AssertDeepError(t, errs, "Test.test2[10]", "Test.Test2[10]", "test2[10]", "Test2[10]", "eq", "eq")
AssertDeepError(t, errs, "Test.test2[10]", "Test.Test2[10]", "test2[10]", "Test2[10]", "eq", "eq")
}
// Thanks @adrian-sgn specific test for your specific scenario
func TestKeysCustomValidation(t *testing.T) {
type LangCode string
type Label map[LangCode]string
type TestMapStructPtr struct {
Label Label `validate:"dive,keys,lang_code,endkeys,required"`
}
validate := New()
5 years ago
err := validate.RegisterValidation("lang_code", func(fl FieldLevel) bool {
validLangCodes := map[LangCode]struct{}{
"en": {},
"es": {},
"pt": {},
}
_, ok := validLangCodes[fl.Field().Interface().(LangCode)]
return ok
})
5 years ago
Equal(t, err, nil)
label := Label{
"en": "Good morning!",
"pt": "",
"es": "¡Buenos días!",
"xx": "Bad key",
"xxx": "",
}
5 years ago
err = validate.Struct(TestMapStructPtr{label})
NotEqual(t, err, nil)
errs := err.(ValidationErrors)
Equal(t, len(errs), 4)
AssertDeepError(t, errs, "TestMapStructPtr.Label[xx]", "TestMapStructPtr.Label[xx]", "Label[xx]", "Label[xx]", "lang_code", "lang_code")
AssertDeepError(t, errs, "TestMapStructPtr.Label[pt]", "TestMapStructPtr.Label[pt]", "Label[pt]", "Label[pt]", "required", "required")
AssertDeepError(t, errs, "TestMapStructPtr.Label[xxx]", "TestMapStructPtr.Label[xxx]", "Label[xxx]", "Label[xxx]", "lang_code", "lang_code")
AssertDeepError(t, errs, "TestMapStructPtr.Label[xxx]", "TestMapStructPtr.Label[xxx]", "Label[xxx]", "Label[xxx]", "required", "required")
// find specific error
var e FieldError
for _, e = range errs {
if e.Namespace() == "TestMapStructPtr.Label[xxx]" {
break
}
}
Equal(t, e.Param(), "")
Equal(t, e.Value().(LangCode), LangCode("xxx"))
for _, e = range errs {
if e.Namespace() == "TestMapStructPtr.Label[xxx]" && e.Tag() == "required" {
break
}
}
Equal(t, e.Param(), "")
Equal(t, e.Value().(string), "")
}
func TestKeyOrs(t *testing.T) {
type Test struct {
Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey|eq=testkeyok,endkeys,eq=testval" json:"test1"`
}
var tst Test
validate := New()
err := validate.Struct(tst)
NotEqual(t, err, nil)
Equal(t, len(err.(ValidationErrors)), 1)
AssertError(t, err.(ValidationErrors), "Test.Test1", "Test.Test1", "Test1", "Test1", "gt")
tst.Test1 = map[string]string{
"testkey": "testval",
}
err = validate.Struct(tst)
Equal(t, err, nil)
tst.Test1["badtestkey"] = "badtestval"
err = validate.Struct(tst)
NotEqual(t, err, nil)
errs := err.(ValidationErrors)
Equal(t, len(errs), 2)
AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq=testkey|eq=testkeyok", "eq=testkey|eq=testkeyok")
AssertDeepError(t, errs, "Test.Test1[badtestkey]", "Test.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq")
validate.RegisterAlias("okkey", "eq=testkey|eq=testkeyok")
type Test2 struct {
Test1 map[string]string `validate:"gt=0,dive,keys,okkey,endkeys,eq=testval" json:"test1"`
}
var tst2 Test2
err = validate.Struct(tst2)
NotEqual(t, err, nil)
Equal(t, len(err.(ValidationErrors)), 1)
AssertError(t, err.(ValidationErrors), "Test2.Test1", "Test2.Test1", "Test1", "Test1", "gt")
tst2.Test1 = map[string]string{
"testkey": "testval",
}
err = validate.Struct(tst2)
Equal(t, err, nil)
tst2.Test1["badtestkey"] = "badtestval"
err = validate.Struct(tst2)
NotEqual(t, err, nil)
errs = err.(ValidationErrors)
Equal(t, len(errs), 2)
AssertDeepError(t, errs, "Test2.Test1[badtestkey]", "Test2.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "okkey", "eq=testkey|eq=testkeyok")
AssertDeepError(t, errs, "Test2.Test1[badtestkey]", "Test2.Test1[badtestkey]", "Test1[badtestkey]", "Test1[badtestkey]", "eq", "eq")
}
func TestStructLevelValidationsPointerPassing(t *testing.T) {
v1 := New()
v1.RegisterStructValidation(StructValidationTestStruct, &TestStruct{})
tst := &TestStruct{
String: "good value",
}
errs := v1.Struct(tst)
NotEqual(t, errs, nil)
AssertError(t, errs, "TestStruct.StringVal", "TestStruct.String", "StringVal", "String", "badvalueteststruct")
}
func TestDirValidation(t *testing.T) {
validate := New()
tests := []struct {
title string
param string
expected bool
}{
{"existing dir", "testdata", true},
{"existing self dir", ".", true},
{"existing parent dir", "..", true},
{"empty dir", "", false},
{"missing dir", "non_existing_testdata", false},
{"a file not a directory", filepath.Join("testdata", "a.go"), false},
}
for _, test := range tests {
errs := validate.Var(test.param, "dir")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Test: '%s' failed Error: %s", test.title, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Test: '%s' failed Error: %s", test.title, errs)
}
}
}
PanicMatches(t, func() {
5 years ago
_ = validate.Var(2, "dir")
}, "Bad field type int")
}
func TestStartsWithValidation(t *testing.T) {
tests := []struct {
Value string `validate:"startswith=(/^ヮ^)/*:・゚✧"`
Tag string
ExpectedNil bool
}{
{Value: "(/^ヮ^)/*:・゚✧ glitter", Tag: "startswith=(/^ヮ^)/*:・゚✧", ExpectedNil: true},
{Value: "abcd", Tag: "startswith=(/^ヮ^)/*:・゚✧", ExpectedNil: false},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
errs = validate.Struct(s)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
}
}
func TestEndsWithValidation(t *testing.T) {
tests := []struct {
Value string `validate:"endswith=(/^ヮ^)/*:・゚✧"`
Tag string
ExpectedNil bool
}{
{Value: "glitter (/^ヮ^)/*:・゚✧", Tag: "endswith=(/^ヮ^)/*:・゚✧", ExpectedNil: true},
{Value: "(/^ヮ^)/*:・゚✧ glitter", Tag: "endswith=(/^ヮ^)/*:・゚✧", ExpectedNil: false},
}
validate := New()
for i, s := range tests {
errs := validate.Var(s.Value, s.Tag)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
errs = validate.Struct(s)
if (s.ExpectedNil && errs != nil) || (!s.ExpectedNil && errs == nil) {
t.Fatalf("Index: %d failed Error: %s", i, errs)
}
}
}
func TestRequiredWith(t *testing.T) {
type Inner struct {
Field *string
}
fieldVal := "test"
test := struct {
Inner *Inner
FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with=Field3" json:"field_4"`
Field5 string `validate:"required_with=Inner.Field" json:"field_5"`
}{
Inner: &Inner{Field: &fieldVal},
Field2: &fieldVal,
Field3: map[string]string{"key": "val"},
Field4: "test",
Field5: "test",
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test2 := struct {
Inner *Inner
Inner2 *Inner
FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with=Field2" json:"field_4"`
Field5 string `validate:"required_with=Field3" json:"field_5"`
Field6 string `validate:"required_with=Inner.Field" json:"field_6"`
Field7 string `validate:"required_with=Inner2.Field" json:"field_7"`
}{
Inner: &Inner{Field: &fieldVal},
Field2: &fieldVal,
}
errs = validate.Struct(test2)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 3)
AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with")
AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_with")
AssertError(t, errs, "Field6", "Field6", "Field6", "Field6", "required_with")
}
func TestRequiredWithAll(t *testing.T) {
type Inner struct {
Field *string
}
fieldVal := "test"
test := struct {
Inner *Inner
FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with_all=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with_all=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with_all=Field3" json:"field_4"`
Field5 string `validate:"required_with_all=Inner.Field" json:"field_5"`
}{
Inner: &Inner{Field: &fieldVal},
Field1: "test_field1",
Field2: &fieldVal,
Field3: map[string]string{"key": "val"},
Field4: "test",
Field5: "test",
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test2 := struct {
Inner *Inner
Inner2 *Inner
FieldE string `validate:"omitempty" json:"field_e"`
FieldER string `validate:"required_with_all=FieldE" json:"field_er"`
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_with_all=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_with_all=Field2" json:"field_3"`
Field4 interface{} `validate:"required_with_all=Field1 FieldE" json:"field_4"`
Field5 string `validate:"required_with_all=Inner.Field Field2" json:"field_5"`
Field6 string `validate:"required_with_all=Inner2.Field Field2" json:"field_6"`
}{
Inner: &Inner{Field: &fieldVal},
Field2: &fieldVal,
}
errs = validate.Struct(test2)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 2)
AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_with_all")
AssertError(t, errs, "Field5", "Field5", "Field5", "Field5", "required_with_all")
}
func TestRequiredWithout(t *testing.T) {
type Inner struct {
Field *string
}
fieldVal := "test"
test := struct {
Inner *Inner
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_without=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_without=Field2" json:"field_3"`
Field4 interface{} `validate:"required_without=Field3" json:"field_4"`
Field5 string `validate:"required_without=Field3" json:"field_5"`
}{
Inner: &Inner{Field: &fieldVal},
Field2: &fieldVal,
Field3: map[string]string{"key": "val"},
Field4: "test",
Field5: "test",
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test2 := struct {
Inner *Inner
Inner2 *Inner
Field1 string `json:"field_1"`
Field2 *string `validate:"required_without=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_without=Field2" json:"field_3"`
Field4 interface{} `validate:"required_without=Field3" json:"field_4"`
Field5 string `validate:"required_without=Field3" json:"field_5"`
Field6 string `validate:"required_without=Field1" json:"field_6"`
Field7 string `validate:"required_without=Inner.Field" json:"field_7"`
Field8 string `validate:"required_without=Inner.Field" json:"field_8"`
}{
Inner: &Inner{},
Field3: map[string]string{"key": "val"},
Field4: "test",
Field5: "test",
}
errs = validate.Struct(&test2)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 4)
AssertError(t, errs, "Field2", "Field2", "Field2", "Field2", "required_without")
AssertError(t, errs, "Field6", "Field6", "Field6", "Field6", "required_without")
AssertError(t, errs, "Field7", "Field7", "Field7", "Field7", "required_without")
AssertError(t, errs, "Field8", "Field8", "Field8", "Field8", "required_without")
}
func TestRequiredWithoutAll(t *testing.T) {
fieldVal := "test"
test := struct {
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_without_all=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_without_all=Field2" json:"field_3"`
Field4 interface{} `validate:"required_without_all=Field3" json:"field_4"`
Field5 string `validate:"required_without_all=Field3" json:"field_5"`
}{
Field1: "",
Field2: &fieldVal,
Field3: map[string]string{"key": "val"},
Field4: "test",
Field5: "test",
}
validate := New()
errs := validate.Struct(test)
Equal(t, errs, nil)
test2 := struct {
Field1 string `validate:"omitempty" json:"field_1"`
Field2 *string `validate:"required_without_all=Field1" json:"field_2"`
Field3 map[string]string `validate:"required_without_all=Field2" json:"field_3"`
Field4 interface{} `validate:"required_without_all=Field3" json:"field_4"`
Field5 string `validate:"required_without_all=Field3" json:"field_5"`
Field6 string `validate:"required_without_all=Field1 Field3" json:"field_6"`
}{
Field3: map[string]string{"key": "val"},
Field4: "test",
Field5: "test",
}
errs = validate.Struct(test2)
NotEqual(t, errs, nil)
ve := errs.(ValidationErrors)
Equal(t, len(ve), 1)
AssertError(t, errs, "Field2", "Field2", "Field2", "Field2", "required_without_all")
}
func TestLookup(t *testing.T) {
type Lookup struct {
FieldA *string `json:"fieldA,omitempty" validate:"required_without=FieldB"`
FieldB *string `json:"fieldB,omitempty" validate:"required_without=FieldA"`
}
fieldAValue := "1232"
lookup := Lookup{
FieldA: &fieldAValue,
FieldB: nil,
}
Equal(t, New().Struct(lookup), nil)
}
func TestAbilityToValidateNils(t *testing.T) {
type TestStruct struct {
Test *string `validate:"nil"`
}
ts := TestStruct{}
val := New()
fn := func(fl FieldLevel) bool {
return fl.Field().Kind() == reflect.Ptr && fl.Field().IsNil()
}
err := val.RegisterValidation("nil", fn, true)
Equal(t, err, nil)
errs := val.Struct(ts)
Equal(t, errs, nil)
str := "string"
ts.Test = &str
errs = val.Struct(ts)
NotEqual(t, errs, nil)
}
5 years ago
func TestRequiredWithoutPointers(t *testing.T) {
type Lookup struct {
FieldA *bool `json:"fieldA,omitempty" validate:"required_without=FieldB"`
FieldB *bool `json:"fieldB,omitempty" validate:"required_without=FieldA"`
}
b := true
lookup := Lookup{
FieldA: &b,
FieldB: nil,
}
val := New()
errs := val.Struct(lookup)
Equal(t, errs, nil)
b = false
lookup = Lookup{
FieldA: &b,
FieldB: nil,
}
errs = val.Struct(lookup)
Equal(t, errs, nil)
}
func TestRequiredWithoutAllPointers(t *testing.T) {
type Lookup struct {
FieldA *bool `json:"fieldA,omitempty" validate:"required_without_all=FieldB"`
FieldB *bool `json:"fieldB,omitempty" validate:"required_without_all=FieldA"`
}
b := true
lookup := Lookup{
FieldA: &b,
FieldB: nil,
}
val := New()
errs := val.Struct(lookup)
Equal(t, errs, nil)
b = false
lookup = Lookup{
FieldA: &b,
FieldB: nil,
}
errs = val.Struct(lookup)
Equal(t, errs, nil)
}
func TestGetTag(t *testing.T) {
var tag string
type Test struct {
String string `validate:"mytag"`
}
val := New()
val.RegisterValidation("mytag", func(fl FieldLevel) bool {
tag = fl.GetTag()
return true
})
var test Test
errs := val.Struct(test)
Equal(t, errs, nil)
Equal(t, tag, "mytag")
}
func TestJSONValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{`foo`, false},
{`}{`, false},
{`{]`, false},
{`{}`, true},
{`{"foo":"bar"}`, true},
{`{"foo":"bar","bar":{"baz":["qux"]}}`, true},
{`{"foo": 3 "bar": 4}`, false},
{`{"foo": 3 ,"bar": 4`, false},
{`{foo": 3, "bar": 4}`, false},
{`foo`, false},
{`1`, true},
{`true`, true},
{`null`, true},
{`"null"`, true},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "json")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d json failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d json failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "json" {
t.Fatalf("Index: %d json failed Error: %s", i, errs)
}
}
}
}
PanicMatches(t, func() {
_ = validate.Var(2, "json")
}, "Bad field type int")
}
func Test_hostnameport_validator(t *testing.T) {
type Host struct {
Addr string `validate:"hostname_port"`
}
type testInput struct {
data string
expected bool
}
testData := []testInput{
{"bad..domain.name:234", false},
{"extra.dot.com.", false},
{"localhost:1234", true},
{"192.168.1.1:1234", true},
{":1234", true},
{"domain.com:1334", true},
{"this.domain.com:234", true},
{"domain:75000", false},
{"missing.port", false},
}
for _, td := range testData {
h := Host{Addr: td.data}
v := New()
err := v.Struct(h)
if td.expected != (err == nil) {
t.Fatalf("Test failed for data: %v Error: %v", td.data, err)
}
}
}
func TestLowercaseValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{`abcdefg`, true},
{`Abcdefg`, false},
{"", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "lowercase")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d lowercase failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d lowercase failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "lowercase" {
t.Fatalf("Index: %d lowercase failed Error: %s", i, errs)
}
}
}
}
PanicMatches(t, func() {
_ = validate.Var(2, "lowercase")
}, "Bad field type int")
}
func TestUppercaseValidation(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{`ABCDEFG`, true},
{`aBCDEFG`, false},
{"", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "uppercase")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d uppercase failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d uppercase failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "uppercase" {
t.Fatalf("Index: %d uppercase failed Error: %s", i, errs)
}
}
}
}
PanicMatches(t, func() {
_ = validate.Var(2, "uppercase")
}, "Bad field type int")
}
func TestDatetimeValidation(t *testing.T) {
tests := []struct {
value string `validate:"datetime=2006-01-02"`
tag string
expected bool
}{
{"2008-02-01", `datetime=2006-01-02`, true},
{"2008-Feb-01", `datetime=2006-01-02`, false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.value, test.tag)
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d datetime failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d datetime failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "datetime" {
t.Fatalf("Index: %d datetime failed Error: %s", i, errs)
}
}
}
}
PanicMatches(t, func() {
_ = validate.Var(2, "datetime")
}, "Bad field type int")
}