package validator
import (
"bytes"
"context"
"database/sql"
"database/sql/driver"
"encoding/base64"
"encoding/json"
"fmt"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
. "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" `
}
func AssertError ( t * testing . T , err error , nsKey , structNsKey , field , structField , expectedTag 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 {
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 )
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 )
}
func getError ( err error , nsKey , structNsKey string ) FieldError {
errs := err . ( ValidationErrors )
var fe FieldError
for i := 0 ; i < len ( errs ) ; i ++ {
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" `
}
func StructValidationTestStructSuccess ( sl StructLevel ) {
st := sl . Current ( ) . Interface ( ) . ( TestStruct )
if st . String != "good value" {
sl . ReportError ( st . String , "StringVal" , "String" , "badvalueteststruct" , "good value" )
}
}
func StructValidationTestStruct ( sl StructLevel ) {
st := sl . Current ( ) . Interface ( ) . ( TestStruct )
if st . String != "bad value" {
sl . ReportError ( st . String , "StringVal" , "String" , "badvalueteststruct" , "bad value" )
}
}
func StructValidationNoTestStructCustomName ( sl StructLevel ) {
st := sl . Current ( ) . Interface ( ) . ( TestStruct )
if st . String != "bad value" {
sl . ReportError ( st . String , "String" , "" , "badvalueteststruct" , "bad value" )
}
}
func StructValidationTestStructInvalid ( sl StructLevel ) {
st := sl . Current ( ) . Interface ( ) . ( TestStruct )
if st . String != "bad value" {
sl . ReportError ( nil , "StringVal" , "String" , "badvalueteststruct" , "bad value" )
}
}
func StructValidationTestStructReturnValidationErrors ( sl StructLevel ) {
s := sl . Current ( ) . Interface ( ) . ( TestStructReturnValidationErrors )
errs := sl . Validator ( ) . Struct ( s . Inner1 . Inner2 )
if errs == nil {
return
}
sl . ReportValidationErrors ( "Inner1." , "Inner1." , errs . ( ValidationErrors ) )
}
func StructValidationTestStructReturnValidationErrors2 ( sl StructLevel ) {
s := sl . Current ( ) . Interface ( ) . ( TestStructReturnValidationErrors )
errs := sl . Validator ( ) . Struct ( s . Inner1 . Inner2 )
if errs == nil {
return
}
sl . ReportValidationErrors ( "Inner1JSON." , "Inner1." , errs . ( ValidationErrors ) )
}
type TestStructReturnValidationErrorsInner2 struct {
String string ` validate:"required" json:"JSONString" `
}
type TestStructReturnValidationErrorsInner1 struct {
Inner2 * TestStructReturnValidationErrorsInner2
}
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 stringPtr ( v string ) * string {
return & v
}
func intPtr ( v int ) * int {
return & v
}
func float64Ptr ( v float64 ) * float64 {
return & v
}
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 )
AssertError ( t , errs , "Namespace.Inner1JSON.Inner2JSON.JSONString[1]" , "Namespace.Inner1.Inner2.String[1]" , "JSONString[1]" , "String[1]" , "required" )
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]" )
}
func TestAnonymous ( 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 {
Anonymous struct {
A string ` validate:"required" json:"EH" `
}
AnonymousB struct {
B string ` validate:"required" json:"BEE" `
}
anonymousC struct {
c string ` validate:"required" `
}
}
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 : "" ,
} ,
}
Equal ( t , tst . anonymousC . c , "" )
err := validate . Struct ( tst )
NotEqual ( t , err , nil )
errs := err . ( ValidationErrors )
Equal ( t , len ( errs ) , 1 )
AssertError ( t , errs , "Test.AnonymousB.BEE" , "Test.AnonymousB.B" , "BEE" , "B" , "required" )
fe := getError ( errs , "Test.AnonymousB.BEE" , "Test.AnonymousB.B" )
NotEqual ( t , fe , nil )
Equal ( t , fe . Field ( ) , "BEE" )
Equal ( t , fe . StructField ( ) , "B" )
s := struct {
c string ` validate:"required" `
} {
c : "" ,
}
err = validate . Struct ( s )
Equal ( t , err , nil )
}
func TestAnonymousSameStructDifferentTags ( 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 {
A interface { }
}
tst := & Test {
A : struct {
A string ` validate:"required" `
} {
A : "" ,
} ,
}
err := validate . Struct ( tst )
NotEqual ( t , err , nil )
errs := err . ( ValidationErrors )
Equal ( t , len ( errs ) , 1 )
AssertError ( t , errs , "Test.A.A" , "Test.A.A" , "A" , "A" , "required" )
tst = & Test {
A : struct {
A string ` validate:"omitempty,required" `
} {
A : "" ,
} ,
}
err = validate . Struct ( tst )
Equal ( t , err , nil )
}
func TestStructLevelReturnValidationErrors ( t * testing . T ) {
validate := New ( )
validate . RegisterStructValidation ( StructValidationTestStructReturnValidationErrors , TestStructReturnValidationErrors { } )
inner2 := & TestStructReturnValidationErrorsInner2 {
String : "I'm HERE" ,
}
inner1 := & TestStructReturnValidationErrorsInner1 {
Inner2 : inner2 ,
}
val := & TestStructReturnValidationErrors {
Inner1 : inner1 ,
}
errs := validate . Struct ( val )
Equal ( t , errs , nil )
inner2 . String = ""
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" )
}
func TestStructLevelReturnValidationErrorsWithJSON ( 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
} )
validate . RegisterStructValidation ( StructValidationTestStructReturnValidationErrors2 , TestStructReturnValidationErrors { } )
inner2 := & TestStructReturnValidationErrorsInner2 {
String : "I'm HERE" ,
}
inner1 := & TestStructReturnValidationErrorsInner1 {
Inner2 : inner2 ,
}
val := & TestStructReturnValidationErrors {
Inner1 : inner1 ,
}
errs := validate . Struct ( val )
Equal ( t , errs , nil )
inner2 . String = ""
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" )
fe := getError ( errs , "TestStructReturnValidationErrors.Inner1JSON.Inner2.JSONString" , "TestStructReturnValidationErrors.Inner1.Inner2.String" )
NotEqual ( t , fe , nil )
// 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" )
fe = getError ( errs , "TestStructReturnValidationErrors.Inner1JSON.TestStructReturnValidationErrorsInner2.JSONString" , "TestStructReturnValidationErrors.Inner1.TestStructReturnValidationErrorsInner2.String" )
NotEqual ( t , fe , nil )
// 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" )
}
func TestStructLevelValidations ( 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" )
v2 := New ( )
v2 . RegisterStructValidation ( StructValidationNoTestStructCustomName , TestStruct { } )
errs = v2 . Struct ( tst )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TestStruct.String" , "TestStruct.String" , "String" , "String" , "badvalueteststruct" )
v3 := New ( )
v3 . RegisterStructValidation ( StructValidationTestStructInvalid , TestStruct { } )
errs = v3 . Struct ( tst )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TestStruct.StringVal" , "TestStruct.String" , "StringVal" , "String" , "badvalueteststruct" )
v4 := New ( )
v4 . RegisterStructValidation ( StructValidationTestStructSuccess , TestStruct { } )
errs = v4 . Struct ( tst )
Equal ( t , errs , nil )
}
func TestAliasTags ( t * testing . T ) {
validate := New ( )
validate . RegisterAlias ( "iscoloralias" , "hexcolor|rgb|rgba|hsl|hsla" )
s := "rgb(255,255,255)"
errs := validate . Var ( s , "iscoloralias" )
Equal ( t , errs , nil )
s = ""
errs = validate . Var ( s , "omitempty,iscoloralias" )
Equal ( t , errs , nil )
s = "rgb(255,255,0)"
errs = validate . Var ( s , "iscoloralias,len=5" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "len" )
type Test struct {
Color string ` validate:"iscoloralias" `
}
tst := & Test {
Color : "#000" ,
}
errs = validate . Struct ( tst )
Equal ( t , errs , nil )
tst . Color = "cfvre"
errs = validate . Struct ( tst )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "Test.Color" , "Test.Color" , "Color" , "Color" , "iscoloralias" )
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" )
}
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" )
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" )
// Test for unnamed struct
testStruct := & TestStruct {
String : "test" ,
}
unnamedStruct := struct {
String string ` validate:"required" json:"StringVal" `
} { String : "test" }
composedUnnamedStruct := struct { * TestStruct } { & TestStruct { String : "test" } }
errs = validate . StructPartial ( testStruct , "String" )
Equal ( t , errs , nil )
errs = validate . StructPartial ( unnamedStruct , "String" )
Equal ( t , errs , nil )
errs = validate . StructPartial ( composedUnnamedStruct , "TestStruct.String" )
Equal ( t , errs , nil )
testStruct . String = ""
errs = validate . StructPartial ( testStruct , "String" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TestStruct.String" , "TestStruct.String" , "String" , "String" , "required" )
unnamedStruct . String = ""
errs = validate . StructPartial ( unnamedStruct , "String" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "String" , "String" , "String" , "String" , "required" )
composedUnnamedStruct . String = ""
errs = validate . StructPartial ( composedUnnamedStruct , "TestStruct.String" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TestStruct.String" , "TestStruct.String" , "String" , "String" , "required" )
}
func TestCrossStructLteFieldValidation ( t * testing . T ) {
var errs error
validate := New ( )
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" } ,
}
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" )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "ltecsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "ltecsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "ltecsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "ltecsfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , - time . Minute , "omitempty,ltecsfield" )
Equal ( t , errs , nil )
// -- Validations for a struct and an inner struct with time.Duration type fields.
type TimeDurationInner struct {
Duration time . Duration
}
var timeDurationInner * TimeDurationInner
type TimeDurationTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"ltecsfield=Inner.Duration" `
}
var timeDurationTest * TimeDurationTest
timeDurationInner = & TimeDurationInner { time . Hour + time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour - time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "ltecsfield" )
type TimeDurationOmitemptyTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"omitempty,ltecsfield=Inner.Duration" `
}
var timeDurationOmitemptyTest * TimeDurationOmitemptyTest
timeDurationInner = & TimeDurationInner { - time . Minute }
timeDurationOmitemptyTest = & TimeDurationOmitemptyTest { timeDurationInner , time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestCrossStructLtFieldValidation ( t * testing . T ) {
var errs error
validate := New ( )
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" } ,
}
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" )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "ltcsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "ltcsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "ltcsfield" )
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "ltcsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "ltcsfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , - time . Minute , "omitempty,ltcsfield" )
Equal ( t , errs , nil )
// -- Validations for a struct and an inner struct with time.Duration type fields.
type TimeDurationInner struct {
Duration time . Duration
}
var timeDurationInner * TimeDurationInner
type TimeDurationTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"ltcsfield=Inner.Duration" `
}
var timeDurationTest * TimeDurationTest
timeDurationInner = & TimeDurationInner { time . Hour + time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "ltcsfield" )
timeDurationInner = & TimeDurationInner { time . Hour - time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "ltcsfield" )
type TimeDurationOmitemptyTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"omitempty,ltcsfield=Inner.Duration" `
}
var timeDurationOmitemptyTest * TimeDurationOmitemptyTest
timeDurationInner = & TimeDurationInner { - time . Minute }
timeDurationOmitemptyTest = & TimeDurationOmitemptyTest { timeDurationInner , time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestCrossStructGteFieldValidation ( t * testing . T ) {
var errs error
validate := New ( )
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" } ,
}
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" )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "gtecsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "gtecsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "gtecsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gtecsfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Hour , "omitempty,gtecsfield" )
Equal ( t , errs , nil )
// -- Validations for a struct and an inner struct with time.Duration type fields.
type TimeDurationInner struct {
Duration time . Duration
}
var timeDurationInner * TimeDurationInner
type TimeDurationTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"gtecsfield=Inner.Duration" `
}
var timeDurationTest * TimeDurationTest
timeDurationInner = & TimeDurationInner { time . Hour - time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour + time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "gtecsfield" )
type TimeDurationOmitemptyTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"omitempty,gtecsfield=Inner.Duration" `
}
var timeDurationOmitemptyTest * TimeDurationOmitemptyTest
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationOmitemptyTest = & TimeDurationOmitemptyTest { timeDurationInner , time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestCrossStructGtFieldValidation ( t * testing . T ) {
var errs error
validate := New ( )
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" } ,
}
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" )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "gtcsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "gtcsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gtcsfield" )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "gtcsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gtcsfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Hour , "omitempty,gtcsfield" )
Equal ( t , errs , nil )
// -- Validations for a struct and an inner struct with time.Duration type fields.
type TimeDurationInner struct {
Duration time . Duration
}
var timeDurationInner * TimeDurationInner
type TimeDurationTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"gtcsfield=Inner.Duration" `
}
var timeDurationTest * TimeDurationTest
timeDurationInner = & TimeDurationInner { time . Hour - time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "gtcsfield" )
timeDurationInner = & TimeDurationInner { time . Hour + time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "gtcsfield" )
type TimeDurationOmitemptyTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"omitempty,gtcsfield=Inner.Duration" `
}
var timeDurationOmitemptyTest * TimeDurationOmitemptyTest
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationOmitemptyTest = & TimeDurationOmitemptyTest { timeDurationInner , time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestCrossStructNeFieldValidation ( t * testing . T ) {
var errs error
validate := New ( )
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 ,
}
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" )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "necsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "necsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "necsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "necsfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Duration ( 0 ) , "omitempty,necsfield" )
Equal ( t , errs , nil )
// -- Validations for a struct and an inner struct with time.Duration type fields.
type TimeDurationInner struct {
Duration time . Duration
}
var timeDurationInner * TimeDurationInner
type TimeDurationTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"necsfield=Inner.Duration" `
}
var timeDurationTest * TimeDurationTest
timeDurationInner = & TimeDurationInner { time . Hour - time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour + time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "necsfield" )
type TimeDurationOmitemptyTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"omitempty,necsfield=Inner.Duration" `
}
var timeDurationOmitemptyTest * TimeDurationOmitemptyTest
timeDurationInner = & TimeDurationInner { time . Duration ( 0 ) }
timeDurationOmitemptyTest = & TimeDurationOmitemptyTest { timeDurationInner , time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestCrossStructEqFieldValidation ( t * testing . T ) {
var errs error
validate := New ( )
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 ,
}
errs = validate . Struct ( test )
Equal ( t , errs , nil )
newTime := time . Now ( ) . Add ( time . Hour ) . 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" )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour , "eqcsfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "eqcsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "eqcsfield" )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "eqcsfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "eqcsfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Hour , "omitempty,eqcsfield" )
Equal ( t , errs , nil )
// -- Validations for a struct and an inner struct with time.Duration type fields.
type TimeDurationInner struct {
Duration time . Duration
}
var timeDurationInner * TimeDurationInner
type TimeDurationTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"eqcsfield=Inner.Duration" `
}
var timeDurationTest * TimeDurationTest
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationInner = & TimeDurationInner { time . Hour - time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "eqcsfield" )
timeDurationInner = & TimeDurationInner { time . Hour + time . Minute }
timeDurationTest = & TimeDurationTest { timeDurationInner , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "eqcsfield" )
type TimeDurationOmitemptyTest struct {
Inner * TimeDurationInner
Duration time . Duration ` validate:"omitempty,eqcsfield=Inner.Duration" `
}
var timeDurationOmitemptyTest * TimeDurationOmitemptyTest
timeDurationInner = & TimeDurationInner { time . Hour }
timeDurationOmitemptyTest = & TimeDurationOmitemptyTest { timeDurationInner , time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
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 ,
}
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 )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.Slice[1]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , _ , _ , ok = v . getStructFieldOKInternal ( val , "Inner.CrazyNonExistantField" )
Equal ( t , ok , false )
current , _ , _ , ok = v . getStructFieldOKInternal ( val , "Inner.Slice[101]" )
Equal ( t , ok , false )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.Map[key3]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val3" )
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" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapStructs[key2].Name" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "name2" )
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" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.SliceSlice[2][0]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "7" )
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" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.SliceMap[1][key5]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val5" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapSlice[key3][2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "9" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapInt[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapInt8[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapInt16[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapInt32[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapInt64[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapUint[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapUint8[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapUint16[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapUint32[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapUint64[2]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapFloat32[3.03]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val3" )
current , kind , _ , ok = v . getStructFieldOKInternal ( val , "Inner.MapFloat64[2.02]" )
Equal ( t , ok , true )
Equal ( t , kind , reflect . String )
Equal ( t , current . String ( ) , "val2" )
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 )
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 )
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"
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 ( )
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" ,
}
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" ,
}
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 )
}
}
}
}
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 )
}
}
}
}
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 )
}
}
}
}
}
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 ) {
var errs error
validate := New ( )
var j uint64
var k float64
s := "abcd"
i := 1
j = 1
k = 1.543
b := true
arr := [ ] string { "test" }
now := time . Now ( ) . UTC ( )
var j2 uint64
var k2 float64
s2 := "abcdef"
i2 := 3
j2 = 2
k2 = 1.5434456
b2 := false
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 ( b2 , b , "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 ( ) . Add ( time . Hour ) . 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 )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "nefield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "nefield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "nefield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "nefield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Duration ( 0 ) , "omitempty,nefield" )
Equal ( t , errs , nil )
// -- Validations for a struct with time.Duration type fields.
type TimeDurationTest struct {
First time . Duration ` validate:"nefield=Second" `
Second time . Duration
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "nefield" )
type TimeDurationOmitemptyTest struct {
First time . Duration ` validate:"omitempty,nefield=Second" `
Second time . Duration
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) , time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestIsNeValidation ( t * testing . T ) {
var errs error
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" )
PanicMatches ( t , func ( ) { _ = validate . Var ( now , "ne=now" ) } , "Bad field type time.Time" )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour - time . Minute , "ne=1h" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour + time . Minute , "ne=1h" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour , "ne=1h" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "ne" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,ne=0" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"ne=1h" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "ne" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,ne=0" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestIsEqFieldValidation ( t * testing . T ) {
var errs error
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 ( ) . Add ( time . Hour ) . 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" )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour , "eqfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "eqfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "eqfield" )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "eqfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "eqfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Hour , "omitempty,eqfield" )
Equal ( t , errs , nil )
// -- Validations for a struct with time.Duration type fields.
type TimeDurationTest struct {
First time . Duration ` validate:"eqfield=Second" `
Second time . Duration
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "eqfield" )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "eqfield" )
type TimeDurationOmitemptyTest struct {
First time . Duration ` validate:"omitempty,eqfield=Second" `
Second time . Duration
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) , time . Hour }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestIsEqValidation ( t * testing . T ) {
var errs error
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" )
PanicMatches ( t , func ( ) { _ = validate . Var ( now , "eq=now" ) } , "Bad field type time.Time" )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "eq=1h" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - time . Minute , "eq=1h" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "eq" )
errs = validate . Var ( time . Hour + time . Minute , "eq=1h" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "eq" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,eq=1h" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"eq=1h" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "eq" )
timeDurationTest = & TimeDurationTest { time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "eq" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,eq=1h" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
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 ( ) {
_ = 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 ( ) {
_ = validate . Var ( 6 , "file" )
} , "Bad field type int" )
}
func TestEthereumAddressValidation ( t * testing . T ) {
validate := New ( )
tests := [ ] struct {
param string
expected bool
} {
// All caps.
{ "0x52908400098527886E0F7030069857D2E4169EE7" , true } ,
{ "0x8617E340B3D01FA5F11F306F4090FD50E238070D" , true } ,
// All lower.
{ "0xde709f2102306220921060314715629080e2fb77" , true } ,
{ "0x27b1fdb04752bbc536007a920d24acb045561c26" , true } ,
{ "0x123f681646d4a755815f9cb19e1acc8565a0c2ac" , true } ,
// Mixed case: runs checksum validation.
{ "0x02F9AE5f22EA3fA88F05780B30385bECFacbf130" , true } ,
{ "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed" , true } ,
{ "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359" , true } ,
{ "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB" , true } ,
{ "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb" , true } ,
{ "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDB" , false } , // Invalid checksum.
// Other.
{ "" , false } ,
{ "D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb" , false } , // Missing "0x" prefix.
{ "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDbc" , false } , // More than 40 hex digits.
{ "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aD" , false } , // Less than 40 hex digits.
{ "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDw" , false } , // Invalid hex digit "w".
}
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 ) {
var errs error
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 )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "gtfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "gtfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gtfield" )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "gtfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gtfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Hour , "omitempty,gtfield" )
Equal ( t , errs , nil )
// -- Validations for a struct with time.Duration type fields.
type TimeDurationTest struct {
First time . Duration ` validate:"gtfield=Second" `
Second time . Duration
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "gtfield" )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "gtfield" )
type TimeDurationOmitemptyTest struct {
First time . Duration ` validate:"omitempty,gtfield=Second" `
Second time . Duration
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) , time . Hour }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
// Tests for Ints types.
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 ) {
var errs error
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 )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "ltfield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "ltfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "ltfield" )
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "ltfield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "ltfield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , - time . Minute , "omitempty,ltfield" )
Equal ( t , errs , nil )
// -- Validations for a struct with time.Duration type fields.
type TimeDurationTest struct {
First time . Duration ` validate:"ltfield=Second" `
Second time . Duration
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "ltfield" )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "ltfield" )
type TimeDurationOmitemptyTest struct {
First time . Duration ` validate:"omitempty,ltfield=Second" `
Second time . Duration
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) , - time . Minute }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
// Tests for Ints types.
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 ) {
var errs error
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 )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "ltefield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "ltefield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "ltefield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "ltefield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , - time . Minute , "omitempty,ltefield" )
Equal ( t , errs , nil )
// -- Validations for a struct with time.Duration type fields.
type TimeDurationTest struct {
First time . Duration ` validate:"ltefield=Second" `
Second time . Duration
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "ltefield" )
type TimeDurationOmitemptyTest struct {
First time . Duration ` validate:"omitempty,ltefield=Second" `
Second time . Duration
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) , - time . Minute }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
// Tests for Ints types.
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 ) {
var errs error
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 )
// Tests for time.Duration type.
// -- Validations for variables of time.Duration type.
errs = validate . VarWithValue ( time . Hour , time . Hour - time . Minute , "gtefield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour , "gtefield" )
Equal ( t , errs , nil )
errs = validate . VarWithValue ( time . Hour , time . Hour + time . Minute , "gtefield" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gtefield" )
errs = validate . VarWithValue ( time . Duration ( 0 ) , time . Hour , "omitempty,gtefield" )
Equal ( t , errs , nil )
// -- Validations for a struct with time.Duration type fields.
type TimeDurationTest struct {
First time . Duration ` validate:"gtefield=Second" `
Second time . Duration
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour , time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.First" , "TimeDurationTest.First" , "First" , "First" , "gtefield" )
type TimeDurationOmitemptyTest struct {
First time . Duration ` validate:"omitempty,gtefield=Second" `
Second time . Duration
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) , time . Hour }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
// Tests for Ints types.
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 ( )
}
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 )
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 )
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" ,
}
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 )
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
PanicMatches ( t , func ( ) { _ = validate . Var ( ui , "len=a" ) } , "strconv.ParseUint: parsing \"a\": invalid syntax" )
f := 1.23
PanicMatches ( t , func ( ) { _ = validate . Var ( f , "len=a" ) } , "strconv.ParseFloat: parsing \"a\": invalid syntax" )
}
func TestLength ( t * testing . T ) {
validate := New ( )
i := true
PanicMatches ( t , func ( ) { _ = validate . Var ( i , "len" ) } , "Bad field type bool" )
}
func TestIsGt ( t * testing . T ) {
var errs error
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
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" )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "gt=59m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - time . Minute , "gt=59m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gt" )
errs = validate . Var ( time . Hour - 2 * time . Minute , "gt=59m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gt" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,gt=59m" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"gt=59m" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "gt" )
timeDurationTest = & TimeDurationTest { time . Hour - 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "gt" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,gt=59m" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestIsGte ( t * testing . T ) {
var errs error
validate := New ( )
i := true
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" )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "gte=59m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - time . Minute , "gte=59m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - 2 * time . Minute , "gte=59m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "gte" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,gte=59m" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"gte=59m" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "gte" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,gte=59m" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestMinValidation ( t * testing . T ) {
var errs error
validate := New ( )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "min=59m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - time . Minute , "min=59m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - 2 * time . Minute , "min=59m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "min" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,min=59m" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"min=59m" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "min" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,min=59m" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestMaxValidation ( t * testing . T ) {
var errs error
validate := New ( )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "max=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour + time . Minute , "max=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour + 2 * time . Minute , "max=1h1m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "max" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,max=-1s" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"max=1h1m" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour + 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "max" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,max=-1s" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestMinMaxValidation ( t * testing . T ) {
var errs error
validate := New ( )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "min=59m,max=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - time . Minute , "min=59m,max=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour + time . Minute , "min=59m,max=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - 2 * time . Minute , "min=59m,max=1h1m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "min" )
errs = validate . Var ( time . Hour + 2 * time . Minute , "min=59m,max=1h1m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "max" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,min=59m,max=1h1m" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"min=59m,max=1h1m" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "min" )
timeDurationTest = & TimeDurationTest { time . Hour + 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "max" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,min=59m,max=1h1m" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestLenValidation ( t * testing . T ) {
var errs error
validate := New ( )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "len=1h" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour - time . Minute , "len=1h" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "len" )
errs = validate . Var ( time . Hour + time . Minute , "len=1h" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "len" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,len=1h" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"len=1h" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour - time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "len" )
timeDurationTest = & TimeDurationTest { time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "len" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,len=1h" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestIsLt ( t * testing . T ) {
var errs error
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
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" )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "lt=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour + time . Minute , "lt=1h1m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "lt" )
errs = validate . Var ( time . Hour + 2 * time . Minute , "lt=1h1m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "lt" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,lt=0" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"lt=1h1m" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "lt" )
timeDurationTest = & TimeDurationTest { time . Hour + 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "lt" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,lt=0" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( t , errs , nil )
}
func TestIsLte ( t * testing . T ) {
var errs error
validate := New ( )
i := true
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 )
// Tests for time.Duration type.
// -- Validations for a variable of time.Duration type.
errs = validate . Var ( time . Hour , "lte=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour + time . Minute , "lte=1h1m" )
Equal ( t , errs , nil )
errs = validate . Var ( time . Hour + 2 * time . Minute , "lte=1h1m" )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "" , "" , "" , "" , "lte" )
errs = validate . Var ( time . Duration ( 0 ) , "omitempty,lte=-1s" )
Equal ( t , errs , nil )
// -- Validations for a struct with a time.Duration type field.
type TimeDurationTest struct {
Duration time . Duration ` validate:"lte=1h1m" `
}
var timeDurationTest * TimeDurationTest
timeDurationTest = & TimeDurationTest { time . Hour }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour + time . Minute }
errs = validate . Struct ( timeDurationTest )
Equal ( t , errs , nil )
timeDurationTest = & TimeDurationTest { time . Hour + 2 * time . Minute }
errs = validate . Struct ( timeDurationTest )
NotEqual ( t , errs , nil )
AssertError ( t , errs , "TimeDurationTest.Duration" , "TimeDurationTest.Duration" , "Duration" , "Duration" , "lte" )
type TimeDurationOmitemptyTest struct {
Duration time . Duration ` validate:"omitempty,lte=-1s" `
}
timeDurationOmitemptyTest := & TimeDurationOmitemptyTest { time . Duration ( 0 ) }
errs = validate . Struct ( timeDurationOmitemptyTest )
Equal ( 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
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
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
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"
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
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" )
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 = "0xff0044"
errs = validate . Var ( s , "hexadecimal" )
Equal ( t , errs , nil )
s = "0Xff0044"
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" )
}
func TestStructInt32Validation ( t * testing . T ) {
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 ,
}
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
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" ,
}
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" )
err := trans . Add ( "required" , "{0} is a required field" , false ) // using translator outside of validator also
Equal ( t , err , nil )
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
} )
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" )
}
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" ) )
}
// 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 )
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
} )
err := validate . RegisterValidation ( "custom1" , func ( fl FieldLevel ) bool {
res1 = fl . FieldName ( )
alt1 = fl . StructFieldName ( )
return true
} )
Equal ( t , err , nil )
err = validate . RegisterValidation ( "custom2" , func ( fl FieldLevel ) bool {
res2 = fl . FieldName ( )
alt2 = fl . StructFieldName ( )
return true
} )
Equal ( t , err , nil )
err = validate . RegisterValidation ( "custom3" , func ( fl FieldLevel ) bool {
res3 = fl . FieldName ( )
alt3 = fl . StructFieldName ( )
return true
} )
Equal ( t , err , nil )
err = validate . RegisterValidation ( "custom4" , func ( fl FieldLevel ) bool {
res4 = fl . FieldName ( )
alt4 = fl . StructFieldName ( )
return true
} )
Equal ( t , err , nil )
err = validate . RegisterValidation ( "custom5" , func ( fl FieldLevel ) bool {
res5 = fl . FieldName ( )
alt5 = fl . StructFieldName ( )
return true
} )
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 ( )
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 } ,
{ "example..........com" , false } ,
{ "1234" , false } ,
{ "abc1234" , true } ,
{ "example. com" , false } ,
{ "ex ample.com" , 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 } ,
{ [ 2 ] * string { stringPtr ( "a" ) , stringPtr ( "b" ) } , true } ,
{ [ 2 ] * int { intPtr ( 1 ) , intPtr ( 2 ) } , true } ,
{ [ 2 ] * float64 { float64Ptr ( 1 ) , float64Ptr ( 2 ) } , true } ,
{ [ 2 ] * string { stringPtr ( "a" ) , stringPtr ( "a" ) } , false } ,
{ [ 2 ] * float64 { float64Ptr ( 1 ) , float64Ptr ( 1 ) } , false } ,
{ [ 2 ] * int { intPtr ( 1 ) , intPtr ( 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 } ,
{ [ ] * string { stringPtr ( "a" ) , stringPtr ( "b" ) } , true } ,
{ [ ] * int { intPtr ( 1 ) , intPtr ( 2 ) } , true } ,
{ [ ] * float64 { float64Ptr ( 1 ) , float64Ptr ( 2 ) } , true } ,
{ [ ] * string { stringPtr ( "a" ) , stringPtr ( "a" ) } , false } ,
{ [ ] * float64 { float64Ptr ( 1 ) , float64Ptr ( 1 ) } , false } ,
{ [ ] * int { intPtr ( 1 ) , intPtr ( 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 )
}
}
}
}
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 TestUniqueValidationStructPtrSlice ( t * testing . T ) {
testStructs := [ ] * struct {
A * string
B * string
} {
{ A : stringPtr ( "one" ) , B : stringPtr ( "two" ) } ,
{ A : stringPtr ( "one" ) , B : stringPtr ( "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
} {
{ "<" , true } ,
{ "¯" , true } ,
{ "�" , true } ,
{ "ð" , true } ,
{ "<" , true } ,
{ "¯" , true } ,
{ "�" , true } ,
{ "ð" , true } ,
{ "&#ab" , true } ,
{ "<" , true } ,
{ ">" , true } ,
{ """ , true } ,
{ "&" , true } ,
{ "#x0a" , false } ,
{ "&x00" , false } ,
{ "z" , 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
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 ( )
err := validate . RegisterValidation ( "lang_code" , func ( fl FieldLevel ) bool {
validLangCodes := map [ LangCode ] struct { } {
"en" : { } ,
"es" : { } ,
"pt" : { } ,
}
_ , ok := validLangCodes [ fl . Field ( ) . Interface ( ) . ( LangCode ) ]
return ok
} )
Equal ( t , err , nil )
label := Label {
"en" : "Good morning!" ,
"pt" : "" ,
"es" : "¡Buenos días!" ,
"xx" : "Bad key" ,
"xxx" : "" ,
}
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 ( ) {
_ = 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 TestRequiredIf ( 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_if=FieldE test" json:"field_er" `
Field1 string ` validate:"omitempty" json:"field_1" `
Field2 * string ` validate:"required_if=Field1 test" json:"field_2" `
Field3 map [ string ] string ` validate:"required_if=Field2 test" json:"field_3" `
Field4 interface { } ` validate:"required_if=Field3 1" json:"field_4" `
Field5 int ` validate:"required_if=Inner.Field test" json:"field_5" `
Field6 uint ` validate:"required_if=Field5 1" json:"field_6" `
Field7 float32 ` validate:"required_if=Field6 1" json:"field_7" `
Field8 float64 ` validate:"required_if=Field7 1.0" json:"field_8" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : 2 ,
}
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_if=FieldE test" json:"field_er" `
Field1 string ` validate:"omitempty" json:"field_1" `
Field2 * string ` validate:"required_if=Field1 test" json:"field_2" `
Field3 map [ string ] string ` validate:"required_if=Field2 test" json:"field_3" `
Field4 interface { } ` validate:"required_if=Field2 test" json:"field_4" `
Field5 string ` validate:"required_if=Field3 1" json:"field_5" `
Field6 string ` validate:"required_if=Inner.Field test" json:"field_6" `
Field7 string ` validate:"required_if=Inner2.Field test" 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_if" )
AssertError ( t , errs , "Field4" , "Field4" , "Field4" , "Field4" , "required_if" )
AssertError ( t , errs , "Field6" , "Field6" , "Field6" , "Field6" , "required_if" )
defer func ( ) {
if r := recover ( ) ; r == nil {
t . Errorf ( "test3 should have panicked!" )
}
} ( )
test3 := struct {
Inner * Inner
Field1 string ` validate:"required_if=Inner.Field" json:"field_1" `
} {
Inner : & Inner { Field : & fieldVal } ,
}
_ = validate . Struct ( test3 )
}
func TestRequiredUnless ( 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_unless=FieldE test" json:"field_er" `
Field1 string ` validate:"omitempty" json:"field_1" `
Field2 * string ` validate:"required_unless=Field1 test" json:"field_2" `
Field3 map [ string ] string ` validate:"required_unless=Field2 test" json:"field_3" `
Field4 interface { } ` validate:"required_unless=Field3 1" json:"field_4" `
Field5 int ` validate:"required_unless=Inner.Field test" json:"field_5" `
Field6 uint ` validate:"required_unless=Field5 2" json:"field_6" `
Field7 float32 ` validate:"required_unless=Field6 0" json:"field_7" `
Field8 float64 ` validate:"required_unless=Field7 0.0" json:"field_8" `
} {
FieldE : "test" ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : 2 ,
}
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_unless=FieldE test" json:"field_er" `
Field1 string ` validate:"omitempty" json:"field_1" `
Field2 * string ` validate:"required_unless=Field1 test" json:"field_2" `
Field3 map [ string ] string ` validate:"required_unless=Field2 test" json:"field_3" `
Field4 interface { } ` validate:"required_unless=Field2 test" json:"field_4" `
Field5 string ` validate:"required_unless=Field3 0" json:"field_5" `
Field6 string ` validate:"required_unless=Inner.Field test" json:"field_6" `
Field7 string ` validate:"required_unless=Inner2.Field test" json:"field_7" `
} {
Inner : & Inner { Field : & fieldVal } ,
FieldE : "test" ,
Field1 : "test" ,
}
errs = validate . Struct ( test2 )
NotEqual ( t , errs , nil )
ve := errs . ( ValidationErrors )
Equal ( t , len ( ve ) , 3 )
AssertError ( t , errs , "Field3" , "Field3" , "Field3" , "Field3" , "required_unless" )
AssertError ( t , errs , "Field4" , "Field4" , "Field4" , "Field4" , "required_unless" )
AssertError ( t , errs , "Field7" , "Field7" , "Field7" , "Field7" , "required_unless" )
defer func ( ) {
if r := recover ( ) ; r == nil {
t . Errorf ( "test3 should have panicked!" )
}
} ( )
test3 := struct {
Inner * Inner
Field1 string ` validate:"required_unless=Inner.Field" json:"field_1" `
} {
Inner : & Inner { Field : & fieldVal } ,
}
_ = validate . Struct ( test3 )
}
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 TestExcludedWith ( t * testing . T ) {
type Inner struct {
FieldE string
Field * string
}
fieldVal := "test"
test := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_with=FieldE" json:"field_1" `
Field2 * string ` validate:"excluded_with=FieldE" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_with=FieldE" json:"field_3" `
Field4 interface { } ` validate:"excluded_with=FieldE" json:"field_4" `
Field5 string ` validate:"excluded_with=Inner.FieldE" json:"field_5" `
Field6 string ` validate:"excluded_with=Inner2.FieldE" json:"field_6" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field1 : fieldVal ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : "test" ,
Field6 : "test" ,
}
validate := New ( )
errs := validate . Struct ( test )
Equal ( t , errs , nil )
test2 := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_with=Field" json:"field_1" `
Field2 * string ` validate:"excluded_with=Field" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_with=Field" json:"field_3" `
Field4 interface { } ` validate:"excluded_with=Field" json:"field_4" `
Field5 string ` validate:"excluded_with=Inner.Field" json:"field_5" `
Field6 string ` validate:"excluded_with=Inner2.Field" json:"field_6" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field : "populated" ,
Field1 : fieldVal ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : "test" ,
Field6 : "test" ,
}
errs = validate . Struct ( test2 )
NotEqual ( t , errs , nil )
ve := errs . ( ValidationErrors )
Equal ( t , len ( ve ) , 5 )
for i := 1 ; i <= 5 ; i ++ {
name := fmt . Sprintf ( "Field%d" , i )
AssertError ( t , errs , name , name , name , name , "excluded_with" )
}
test3 := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_with=FieldE" json:"field_1" `
Field2 * string ` validate:"excluded_with=FieldE" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_with=FieldE" json:"field_3" `
Field4 interface { } ` validate:"excluded_with=FieldE" json:"field_4" `
Field5 string ` validate:"excluded_with=Inner.FieldE" json:"field_5" `
Field6 string ` validate:"excluded_with=Inner2.FieldE" json:"field_6" `
} {
Inner : & Inner { FieldE : "populated" } ,
Inner2 : & Inner { FieldE : "populated" } ,
FieldE : "populated" ,
}
validate = New ( )
errs = validate . Struct ( test3 )
Equal ( t , errs , nil )
}
func TestExcludedWithout ( t * testing . T ) {
type Inner struct {
FieldE string
Field * string
}
fieldVal := "test"
test := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_without=Field" json:"field_1" `
Field2 * string ` validate:"excluded_without=Field" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_without=Field" json:"field_3" `
Field4 interface { } ` validate:"excluded_without=Field" json:"field_4" `
Field5 string ` validate:"excluded_without=Inner.Field" json:"field_5" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field : "populated" ,
Field1 : 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
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_without=FieldE" json:"field_1" `
Field2 * string ` validate:"excluded_without=FieldE" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_without=FieldE" json:"field_3" `
Field4 interface { } ` validate:"excluded_without=FieldE" json:"field_4" `
Field5 string ` validate:"excluded_without=Inner.FieldE" json:"field_5" `
Field6 string ` validate:"excluded_without=Inner2.FieldE" json:"field_6" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field1 : fieldVal ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : "test" ,
Field6 : "test" ,
}
errs = validate . Struct ( test2 )
NotEqual ( t , errs , nil )
ve := errs . ( ValidationErrors )
Equal ( t , len ( ve ) , 6 )
for i := 1 ; i <= 6 ; i ++ {
name := fmt . Sprintf ( "Field%d" , i )
AssertError ( t , errs , name , name , name , name , "excluded_without" )
}
test3 := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_without=Field" json:"field_1" `
Field2 * string ` validate:"excluded_without=Field" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_without=Field" json:"field_3" `
Field4 interface { } ` validate:"excluded_without=Field" json:"field_4" `
Field5 string ` validate:"excluded_without=Inner.Field" json:"field_5" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field : "populated" ,
}
validate = New ( )
errs = validate . Struct ( test3 )
Equal ( t , errs , nil )
}
func TestExcludedWithAll ( t * testing . T ) {
type Inner struct {
FieldE string
Field * string
}
fieldVal := "test"
test := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_with_all=FieldE Field" json:"field_1" `
Field2 * string ` validate:"excluded_with_all=FieldE Field" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_with_all=FieldE Field" json:"field_3" `
Field4 interface { } ` validate:"excluded_with_all=FieldE Field" json:"field_4" `
Field5 string ` validate:"excluded_with_all=Inner.FieldE" json:"field_5" `
Field6 string ` validate:"excluded_with_all=Inner2.FieldE" json:"field_6" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field : fieldVal ,
Field1 : fieldVal ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : "test" ,
Field6 : "test" ,
}
validate := New ( )
errs := validate . Struct ( test )
Equal ( t , errs , nil )
test2 := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_with_all=Field FieldE" json:"field_1" `
Field2 * string ` validate:"excluded_with_all=Field FieldE" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_with_all=Field FieldE" json:"field_3" `
Field4 interface { } ` validate:"excluded_with_all=Field FieldE" json:"field_4" `
Field5 string ` validate:"excluded_with_all=Inner.Field" json:"field_5" `
Field6 string ` validate:"excluded_with_all=Inner2.Field" json:"field_6" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field : "populated" ,
FieldE : "populated" ,
Field1 : fieldVal ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : "test" ,
Field6 : "test" ,
}
errs = validate . Struct ( test2 )
NotEqual ( t , errs , nil )
ve := errs . ( ValidationErrors )
Equal ( t , len ( ve ) , 5 )
for i := 1 ; i <= 5 ; i ++ {
name := fmt . Sprintf ( "Field%d" , i )
AssertError ( t , errs , name , name , name , name , "excluded_with_all" )
}
test3 := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_with_all=FieldE Field" json:"field_1" `
Field2 * string ` validate:"excluded_with_all=FieldE Field" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_with_all=FieldE Field" json:"field_3" `
Field4 interface { } ` validate:"excluded_with_all=FieldE Field" json:"field_4" `
Field5 string ` validate:"excluded_with_all=Inner.FieldE" json:"field_5" `
Field6 string ` validate:"excluded_with_all=Inner2.FieldE" json:"field_6" `
} {
Inner : & Inner { FieldE : "populated" } ,
Inner2 : & Inner { FieldE : "populated" } ,
Field : "populated" ,
FieldE : "populated" ,
}
validate = New ( )
errs = validate . Struct ( test3 )
Equal ( t , errs , nil )
}
func TestExcludedWithoutAll ( t * testing . T ) {
type Inner struct {
FieldE string
Field * string
}
fieldVal := "test"
test := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_without_all=Field FieldE" json:"field_1" `
Field2 * string ` validate:"excluded_without_all=Field FieldE" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_without_all=Field FieldE" json:"field_3" `
Field4 interface { } ` validate:"excluded_without_all=Field FieldE" json:"field_4" `
Field5 string ` validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5" `
} {
Inner : & Inner { Field : & fieldVal } ,
Inner2 : & Inner { Field : & fieldVal } ,
Field : "populated" ,
Field1 : 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
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_without_all=FieldE Field" json:"field_1" `
Field2 * string ` validate:"excluded_without_all=FieldE Field" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_without_all=FieldE Field" json:"field_3" `
Field4 interface { } ` validate:"excluded_without_all=FieldE Field" json:"field_4" `
Field5 string ` validate:"excluded_without_all=Inner.FieldE" json:"field_5" `
Field6 string ` validate:"excluded_without_all=Inner2.FieldE" json:"field_6" `
} {
Inner : & Inner { Field : & fieldVal } ,
Field1 : fieldVal ,
Field2 : & fieldVal ,
Field3 : map [ string ] string { "key" : "val" } ,
Field4 : "test" ,
Field5 : "test" ,
Field6 : "test" ,
}
errs = validate . Struct ( test2 )
NotEqual ( t , errs , nil )
ve := errs . ( ValidationErrors )
Equal ( t , len ( ve ) , 6 )
for i := 1 ; i <= 6 ; i ++ {
name := fmt . Sprintf ( "Field%d" , i )
AssertError ( t , errs , name , name , name , name , "excluded_without_all" )
}
test3 := struct {
Inner * Inner
Inner2 * Inner
Field string ` validate:"omitempty" json:"field" `
FieldE string ` validate:"omitempty" json:"field_e" `
Field1 string ` validate:"excluded_without_all=Field FieldE" json:"field_1" `
Field2 * string ` validate:"excluded_without_all=Field FieldE" json:"field_2" `
Field3 map [ string ] string ` validate:"excluded_without_all=Field FieldE" json:"field_3" `
Field4 interface { } ` validate:"excluded_without_all=Field FieldE" json:"field_4" `
Field5 string ` validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5" `
} {
Inner : & Inner { Field : & fieldVal } ,
Inner2 : & Inner { Field : & fieldVal } ,
Field : "populated" ,
FieldE : "populated" ,
}
validate = New ( )
errs = validate . Struct ( test3 )
Equal ( t , errs , nil )
}
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" )
test3 := struct {
Field1 * string ` validate:"required_without=Field2,omitempty,min=1" json:"field_1" `
Field2 * string ` validate:"required_without=Field1,omitempty,min=1" json:"field_2" `
} {
Field1 : & fieldVal ,
}
errs = validate . Struct ( & test3 )
Equal ( t , errs , nil )
}
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 )
}
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" )
}
func TestIsIso3166Alpha2Validation ( t * testing . T ) {
tests := [ ] struct {
value string ` validate:"iso3166_1_alpha2" `
expected bool
} {
{ "PL" , true } ,
{ "POL" , false } ,
{ "AA" , false } ,
}
validate := New ( )
for i , test := range tests {
errs := validate . Var ( test . value , "iso3166_1_alpha2" )
if test . expected {
if ! IsEqual ( errs , nil ) {
t . Fatalf ( "Index: %d iso3166_1_alpha2 failed Error: %s" , i , errs )
}
} else {
if IsEqual ( errs , nil ) {
t . Fatalf ( "Index: %d iso3166_1_alpha2 failed Error: %s" , i , errs )
}
}
}
}
func TestIsIso3166Alpha3Validation ( t * testing . T ) {
tests := [ ] struct {
value string ` validate:"iso3166_1_alpha3" `
expected bool
} {
{ "POL" , true } ,
{ "PL" , false } ,
{ "AAA" , false } ,
}
validate := New ( )
for i , test := range tests {
errs := validate . Var ( test . value , "iso3166_1_alpha3" )
if test . expected {
if ! IsEqual ( errs , nil ) {
t . Fatalf ( "Index: %d iso3166_1_alpha3 failed Error: %s" , i , errs )
}
} else {
if IsEqual ( errs , nil ) {
t . Fatalf ( "Index: %d iso3166_1_alpha3 failed Error: %s" , i , errs )
}
}
}
}
func TestIsIso3166AlphaNumericValidation ( t * testing . T ) {
tests := [ ] struct {
value int
expected bool
} {
{ 248 , true } ,
{ 0 , false } ,
{ 1 , false } ,
}
validate := New ( )
for i , test := range tests {
errs := validate . Var ( test . value , "iso3166_1_alpha_numeric" )
if test . expected {
if ! IsEqual ( errs , nil ) {
t . Fatalf ( "Index: %d iso3166_1_alpha_numeric failed Error: %s" , i , errs )
}
} else {
if IsEqual ( errs , nil ) {
t . Fatalf ( "Index: %d iso3166_1_alpha_numeric failed Error: %s" , i , errs )
}
}
}
PanicMatches ( t , func ( ) {
_ = validate . Var ( "1" , "iso3166_1_alpha_numeric" )
} , "Bad field type string" )
}
func TestTimeZoneValidation ( t * testing . T ) {
tests := [ ] struct {
value string ` validate:"timezone" `
tag string
expected bool
} {
// systems may have different time zone database, some systems time zone are case insensitive
{ "America/New_York" , ` timezone ` , true } ,
{ "UTC" , ` timezone ` , true } ,
{ "" , ` timezone ` , false } ,
{ "Local" , ` timezone ` , false } ,
{ "Unknown" , ` timezone ` , 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 time zone failed Error: %s" , i , errs )
}
} else {
if IsEqual ( errs , nil ) {
t . Fatalf ( "Index: %d time zone failed Error: %s" , i , errs )
} else {
val := getError ( errs , "" , "" )
if val . Tag ( ) != "timezone" {
t . Fatalf ( "Index: %d time zone failed Error: %s" , i , errs )
}
}
}
}
PanicMatches ( t , func ( ) {
_ = validate . Var ( 2 , "timezone" )
} , "Bad field type int" )
}
func TestDurationType ( t * testing . T ) {
tests := [ ] struct {
name string
s interface { } // struct
success bool
} {
{
name : "valid duration string pass" ,
s : struct {
Value time . Duration ` validate:"gte=500ns" `
} {
Value : time . Second ,
} ,
success : true ,
} ,
{
name : "valid duration int pass" ,
s : struct {
Value time . Duration ` validate:"gte=500" `
} {
Value : time . Second ,
} ,
success : true ,
} ,
}
validate := New ( )
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
errs := validate . Struct ( tc . s )
if tc . success {
Equal ( t , errs , nil )
return
}
NotEqual ( t , errs , nil )
} )
}
}