github.com/sandwich-go/boost@v1.3.29/validator/validator_test.go (about)

     1  package validator
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"database/sql"
     7  	"database/sql/driver"
     8  	"fmt"
     9  	"github.com/go-playground/locales/en"
    10  	"github.com/go-playground/locales/fr"
    11  	"github.com/go-playground/locales/nl"
    12  	ut "github.com/go-playground/universal-translator"
    13  	. "github.com/smartystreets/goconvey/convey"
    14  	"reflect"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  type StructLevelInvalidErr struct {
    21  	Value string
    22  }
    23  
    24  type SubTest struct {
    25  	Test string `validate:"required"`
    26  }
    27  
    28  type TestStruct struct {
    29  	String string `validate:"required" json:"StringVal"`
    30  }
    31  
    32  type TestPartial struct {
    33  	NoTag     string
    34  	BlankTag  string     `validate:""`
    35  	Required  string     `validate:"required"`
    36  	SubSlice  []*SubTest `validate:"required,dive"`
    37  	Sub       *SubTest
    38  	SubIgnore *SubTest `validate:"-"`
    39  	Anonymous struct {
    40  		A         string     `validate:"required"`
    41  		ASubSlice []*SubTest `validate:"required,dive"`
    42  
    43  		SubAnonStruct []struct {
    44  			Test      string `validate:"required"`
    45  			OtherTest string `validate:"required"`
    46  		} `validate:"required,dive"`
    47  	}
    48  }
    49  
    50  func StructLevelInvalidError(_ context.Context, sl StructLevel) {
    51  	top := sl.Top().Interface().(StructLevelInvalidErr)
    52  	s := sl.Current().Interface().(StructLevelInvalidErr)
    53  
    54  	if top.Value == s.Value {
    55  		sl.ReportError(nil, "Value", "Value", "required", "")
    56  	}
    57  }
    58  
    59  type valuer struct {
    60  	Name string
    61  }
    62  
    63  func (v valuer) Value() (driver.Value, error) {
    64  	if v.Name == "errorme" {
    65  		panic("SQL Driver Valuer error: some kind of error")
    66  		// return nil, errors.New("some kind of error")
    67  	}
    68  
    69  	if len(v.Name) == 0 {
    70  		return nil, nil
    71  	}
    72  
    73  	return v.Name, nil
    74  }
    75  
    76  func ValidateValuerType(field reflect.Value) interface{} {
    77  	if valuer, ok := field.Interface().(driver.Valuer); ok {
    78  
    79  		val, err := valuer.Value()
    80  		if err != nil {
    81  			// handle the error how you want
    82  			return nil
    83  		}
    84  
    85  		return val
    86  	}
    87  
    88  	return nil
    89  }
    90  
    91  type MadeUpCustomType struct {
    92  	FirstName string
    93  	LastName  string
    94  }
    95  
    96  func ValidateCustomType(field reflect.Value) interface{} {
    97  	if cust, ok := field.Interface().(MadeUpCustomType); ok {
    98  
    99  		if len(cust.FirstName) == 0 || len(cust.LastName) == 0 {
   100  			return ""
   101  		}
   102  
   103  		return cust.FirstName + " " + cust.LastName
   104  	}
   105  
   106  	return ""
   107  }
   108  
   109  type CustomMadeUpStruct struct {
   110  	MadeUp        MadeUpCustomType `validate:"required"`
   111  	OverriddenInt int              `validate:"gt=1"`
   112  }
   113  
   114  func OverrideIntTypeForSomeReason(field reflect.Value) interface{} {
   115  	if i, ok := field.Interface().(int); ok {
   116  		if i == 1 {
   117  			return "1"
   118  		}
   119  
   120  		if i == 2 {
   121  			return "12"
   122  		}
   123  	}
   124  
   125  	return ""
   126  }
   127  
   128  func TestValidator(t *testing.T) {
   129  	Convey(`test validator.SetTagName`, t, func() {
   130  		Default.SetTagName("val")
   131  		type Test struct {
   132  			Name string `val:"len=4"`
   133  		}
   134  		s := &Test{
   135  			Name: "TEST",
   136  		}
   137  		So(Default.Struct(context.Background(), s), ShouldBeNil)
   138  		s.Name = ""
   139  		err := Default.Struct(context.Background(), s)
   140  		So(err, ShouldNotBeNil)
   141  		So(err.Error(), ShouldEqual, "Key: 'Test.Name' Error:Field validation for 'Name' failed on the 'len' tag")
   142  	})
   143  
   144  	Convey(`test validator.ValidateMap`, t, func() {
   145  		type args struct {
   146  			data  map[string]interface{}
   147  			rules map[string]interface{}
   148  		}
   149  		tests := []struct {
   150  			name string
   151  			args args
   152  			want int
   153  		}{
   154  			{
   155  				name: "test nested map in slice",
   156  				args: args{
   157  					data: map[string]interface{}{
   158  						"Test_A": map[string]interface{}{
   159  							"Test_B": "Test_B",
   160  							"Test_C": []map[string]interface{}{
   161  								{
   162  									"Test_D": "Test_D",
   163  								},
   164  							},
   165  							"Test_E": map[string]interface{}{
   166  								"Test_F": "Test_F",
   167  							},
   168  						},
   169  					},
   170  					rules: map[string]interface{}{
   171  						"Test_A": map[string]interface{}{
   172  							"Test_B": "min=2",
   173  							"Test_C": map[string]interface{}{
   174  								"Test_D": "min=2",
   175  							},
   176  							"Test_E": map[string]interface{}{
   177  								"Test_F": "min=2",
   178  							},
   179  						},
   180  					},
   181  				},
   182  				want: 0,
   183  			},
   184  
   185  			{
   186  				name: "test nested map error",
   187  				args: args{
   188  					data: map[string]interface{}{
   189  						"Test_A": map[string]interface{}{
   190  							"Test_B": "Test_B",
   191  							"Test_C": []interface{}{"Test_D"},
   192  							"Test_E": map[string]interface{}{
   193  								"Test_F": "Test_F",
   194  							},
   195  							"Test_G": "Test_G",
   196  							"Test_I": []map[string]interface{}{
   197  								{
   198  									"Test_J": "Test_J",
   199  								},
   200  							},
   201  						},
   202  					},
   203  					rules: map[string]interface{}{
   204  						"Test_A": map[string]interface{}{
   205  							"Test_B": "min=2",
   206  							"Test_C": map[string]interface{}{
   207  								"Test_D": "min=2",
   208  							},
   209  							"Test_E": map[string]interface{}{
   210  								"Test_F": "min=100",
   211  							},
   212  							"Test_G": map[string]interface{}{
   213  								"Test_H": "min=2",
   214  							},
   215  							"Test_I": map[string]interface{}{
   216  								"Test_J": "min=100",
   217  							},
   218  						},
   219  					},
   220  				},
   221  				want: 1,
   222  			},
   223  		}
   224  		for _, tt := range tests {
   225  			got := Validate.ValidateMap(context.Background(), tt.args.data, tt.args.rules)
   226  			So(len(got), ShouldEqual, tt.want)
   227  		}
   228  	})
   229  
   230  	Convey(`test validator.RegisterTagNameFunc`, t, func() {
   231  		v := New()
   232  		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
   233  			name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
   234  
   235  			if name == "-" {
   236  				return ""
   237  			}
   238  
   239  			return name
   240  		})
   241  
   242  		type Test struct {
   243  			A interface{}
   244  		}
   245  
   246  		tst := &Test{
   247  			A: struct {
   248  				A string `validate:"required"`
   249  			}{
   250  				A: "",
   251  			},
   252  		}
   253  
   254  		err := v.Struct(context.Background(), tst)
   255  		So(err, ShouldNotBeNil)
   256  
   257  		errs := err.(ValidationErrors)
   258  
   259  		So(len(errs), ShouldEqual, 1)
   260  		So(errs.Error(), ShouldEqual, "Key: 'Test.A.A' Error:Field validation for 'A' failed on the 'required' tag")
   261  
   262  		tst = &Test{
   263  			A: struct {
   264  				A string `validate:"omitempty,required"`
   265  			}{
   266  				A: "",
   267  			},
   268  		}
   269  
   270  		err = v.Struct(context.Background(), tst)
   271  		So(err, ShouldBeNil)
   272  	})
   273  
   274  	Convey(`test validator.RegisterAlias`, t, func() {
   275  		v := New()
   276  		v.RegisterAlias("iscoloralias", "hexcolor|rgb|rgba|hsl|hsla")
   277  
   278  		s := "rgb(255,255,255)"
   279  		errs := v.Var(context.Background(), s, "iscoloralias")
   280  		So(errs, ShouldBeNil)
   281  
   282  		s = ""
   283  		errs = v.Var(context.Background(), s, "omitempty,iscoloralias")
   284  		So(errs, ShouldBeNil)
   285  
   286  		s = "rgb(255,255,0)"
   287  		errs = v.Var(context.Background(), s, "iscoloralias,len=5")
   288  		So(errs, ShouldNotBeNil)
   289  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'len' tag")
   290  
   291  		type Test struct {
   292  			Color string `validate:"iscoloralias"`
   293  		}
   294  
   295  		tst := &Test{
   296  			Color: "#000",
   297  		}
   298  
   299  		errs = v.Struct(context.Background(), tst)
   300  		So(errs, ShouldBeNil)
   301  
   302  		tst.Color = "cfvre"
   303  		errs = v.Struct(context.Background(), tst)
   304  		So(errs, ShouldNotBeNil)
   305  		So(errs.Error(), ShouldEqual, "Key: 'Test.Color' Error:Field validation for 'Color' failed on the 'iscoloralias' tag")
   306  
   307  		v.RegisterAlias("req", "required,dive,iscoloralias")
   308  		arr := []string{"val1", "#fff", "#000"}
   309  
   310  		errs = v.Var(context.Background(), arr, "req")
   311  		So(errs, ShouldNotBeNil)
   312  		So(errs.Error(), ShouldEqual, "Key: '[0]' Error:Field validation for '[0]' failed on the 'iscoloralias' tag")
   313  
   314  		So(func() { v.RegisterAlias("exists!", "gt=5,lt=10") }, ShouldPanic)
   315  	})
   316  
   317  	Convey(`test validator.RegisterValidation`, t, func() {
   318  		var tag string
   319  
   320  		type Test struct {
   321  			String string `validate:"mytag"`
   322  		}
   323  
   324  		val := New()
   325  		_ = val.RegisterValidation("mytag", func(ctx context.Context, fl FieldLevel) bool {
   326  			tag = fl.GetTag()
   327  			return true
   328  		})
   329  
   330  		var test Test
   331  		errs := val.Struct(context.Background(), test)
   332  		So(errs, ShouldBeNil)
   333  		So(tag, ShouldEqual, "mytag")
   334  	})
   335  
   336  	Convey(`test validator.RegisterStructValidation`, t, func() {
   337  		v := New()
   338  		v.RegisterStructValidation(StructLevelInvalidError, StructLevelInvalidErr{})
   339  
   340  		var test StructLevelInvalidErr
   341  
   342  		err := v.Struct(context.Background(), test)
   343  		So(err, ShouldNotBeNil)
   344  
   345  		errs, ok := err.(ValidationErrors)
   346  		So(ok, ShouldBeTrue)
   347  
   348  		fe := errs[0]
   349  		So(fe.Field(), ShouldEqual, "Value")
   350  		So(fe.StructField(), ShouldEqual, "Value")
   351  		So(fe.Namespace(), ShouldEqual, "StructLevelInvalidErr.Value")
   352  		So(fe.StructNamespace(), ShouldEqual, "StructLevelInvalidErr.Value")
   353  		So(fe.Tag(), ShouldEqual, "required")
   354  		So(fe.ActualTag(), ShouldEqual, "required")
   355  		So(fe.Kind(), ShouldEqual, reflect.Invalid)
   356  		So(fe.Type(), ShouldEqual, reflect.TypeOf(nil))
   357  	})
   358  
   359  	Convey(`test validator.RegisterStructValidationMapRules`, t, func() {
   360  		type Data struct {
   361  			Name string
   362  			Age  uint32
   363  		}
   364  
   365  		data := Data{
   366  			Name: "leo",
   367  			Age:  1000,
   368  		}
   369  
   370  		rules := map[string]string{
   371  			"Name": "min=4,max=6",
   372  			"Age":  "min=4,max=6",
   373  		}
   374  
   375  		v := New()
   376  		v.RegisterStructValidationMapRules(rules, Data{})
   377  
   378  		err := v.Struct(context.Background(), data)
   379  		errs, ok := err.(ValidationErrors)
   380  		So(ok, ShouldBeTrue)
   381  		So(len(errs), ShouldEqual, 2)
   382  		So(errs[0].Error(), ShouldEqual, "Key: 'Data.Name' Error:Field validation for 'Name' failed on the 'min' tag")
   383  		So(errs[1].Error(), ShouldEqual, "Key: 'Data.Age' Error:Field validation for 'Age' failed on the 'max' tag")
   384  	})
   385  
   386  	Convey(`test validator.RegisterCustomTypeFunc`, t, func() {
   387  		v := New()
   388  		v.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
   389  		v.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{})
   390  		v.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1)
   391  
   392  		val := valuer{
   393  			Name: "",
   394  		}
   395  
   396  		errs := v.Var(context.Background(), val, "required")
   397  		So(errs, ShouldNotBeNil)
   398  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'required' tag")
   399  
   400  		val.Name = "Valid Name"
   401  		errs = v.Var(context.Background(), val, "required")
   402  		So(errs, ShouldBeNil)
   403  
   404  		val.Name = "errorme"
   405  		errs = v.Var(context.Background(), val, "required")
   406  		So(errs, ShouldNotBeNil)
   407  		So(errs.Error(), ShouldEqual, "validate panic with val: {errorme}, tag: required, reason: SQL Driver Valuer error: some kind of error")
   408  
   409  		myVal := valuer{
   410  			Name: "",
   411  		}
   412  
   413  		errs = v.Var(context.Background(), myVal, "required")
   414  		So(errs, ShouldNotBeNil)
   415  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'required' tag")
   416  
   417  		cust := MadeUpCustomType{
   418  			FirstName: "Joey",
   419  			LastName:  "Bloggs",
   420  		}
   421  
   422  		c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2}
   423  
   424  		errs = v.Struct(context.Background(), c)
   425  		So(errs, ShouldBeNil)
   426  
   427  		c.MadeUp.FirstName = ""
   428  		c.OverriddenInt = 1
   429  
   430  		err := v.Struct(context.Background(), c)
   431  		So(err, ShouldNotBeNil)
   432  		errs0, ok := err.(ValidationErrors)
   433  		So(ok, ShouldBeTrue)
   434  		So(len(errs0), ShouldEqual, 2)
   435  		So(errs0[0].Error(), ShouldEqual, "Key: 'CustomMadeUpStruct.MadeUp' Error:Field validation for 'MadeUp' failed on the 'required' tag")
   436  		So(errs0[1].Error(), ShouldEqual, "Key: 'CustomMadeUpStruct.OverriddenInt' Error:Field validation for 'OverriddenInt' failed on the 'gt' tag")
   437  	})
   438  
   439  	Convey(`test validator.RegisterTranslation`, t, func() {
   440  		en0 := en.New()
   441  		uni := ut.New(en0, en0, fr.New())
   442  
   443  		trans, _ := uni.GetTranslator("en")
   444  		fr0, _ := uni.GetTranslator("fr")
   445  
   446  		v := New()
   447  		err := v.RegisterTranslation("required", trans,
   448  			func(ut ut.Translator) (err error) {
   449  				// using this stype because multiple translation may have to be added for the full translation
   450  				if err = ut.Add("required", "{0} is a required field", false); err != nil {
   451  					return
   452  				}
   453  
   454  				return
   455  			}, func(ut ut.Translator, fe FieldError) string {
   456  				t0, err := ut.T(fe.Tag(), fe.Field())
   457  				if err != nil {
   458  					fmt.Printf("warning: error translating FieldError: %#v", fe)
   459  					return fe.Error()
   460  				}
   461  
   462  				return t0
   463  			})
   464  		So(err, ShouldBeNil)
   465  
   466  		err = v.RegisterTranslation("required", fr0,
   467  			func(ut ut.Translator) (err error) {
   468  				// using this stype because multiple translation may have to be added for the full translation
   469  				if err = ut.Add("required", "{0} est un champ obligatoire", false); err != nil {
   470  					return
   471  				}
   472  
   473  				return
   474  			}, func(ut ut.Translator, fe FieldError) string {
   475  				t0, transErr := ut.T(fe.Tag(), fe.Field())
   476  				if transErr != nil {
   477  					fmt.Printf("warning: error translating FieldError: %#v", fe)
   478  					return fe.Error()
   479  				}
   480  
   481  				return t0
   482  			})
   483  
   484  		So(err, ShouldBeNil)
   485  
   486  		type Test struct {
   487  			Value interface{} `validate:"required"`
   488  		}
   489  
   490  		var test Test
   491  
   492  		err = v.Struct(context.Background(), test)
   493  		So(err, ShouldNotBeNil)
   494  
   495  		errs := err.(ValidationErrors)
   496  		So(len(errs), ShouldEqual, 1)
   497  
   498  		fe := errs[0]
   499  		So(fe.Tag(), ShouldEqual, "required")
   500  		So(fe.Namespace(), ShouldEqual, "Test.Value")
   501  		So(fe.Translate(trans), ShouldEqual, fmt.Sprintf("%s is a required field", fe.Field()))
   502  		So(fe.Translate(fr0), ShouldEqual, fmt.Sprintf("%s est un champ obligatoire", fe.Field()))
   503  
   504  		nl0 := nl.New()
   505  		uni2 := ut.New(nl0, nl0)
   506  		trans2, _ := uni2.GetTranslator("nl")
   507  		So(fe.Translate(trans2), ShouldEqual, "Key: 'Test.Value' Error:Field validation for 'Value' failed on the 'required' tag")
   508  
   509  		terrs := errs.Translate(trans)
   510  		So(len(terrs), ShouldEqual, 1)
   511  
   512  		v0, ok := terrs["Test.Value"]
   513  		So(ok, ShouldBeTrue)
   514  		So(v0, ShouldEqual, fmt.Sprintf("%s is a required field", fe.Field()))
   515  
   516  		terrs = errs.Translate(fr0)
   517  		So(len(terrs), ShouldEqual, 1)
   518  
   519  		v0, ok = terrs["Test.Value"]
   520  		So(ok, ShouldBeTrue)
   521  		So(v0, ShouldEqual, fmt.Sprintf("%s est un champ obligatoire", fe.Field()))
   522  
   523  		type Test2 struct {
   524  			Value string `validate:"gt=1"`
   525  		}
   526  
   527  		var t2 Test2
   528  
   529  		err = v.Struct(context.Background(), t2)
   530  		So(err, ShouldNotBeNil)
   531  
   532  		errs = err.(ValidationErrors)
   533  		So(len(errs), ShouldEqual, 1)
   534  
   535  		fe = errs[0]
   536  		So(fe.Tag(), ShouldEqual, "gt")
   537  		So(fe.Namespace(), ShouldEqual, "Test2.Value")
   538  		So(fe.Translate(trans), ShouldEqual, "Key: 'Test2.Value' Error:Field validation for 'Value' failed on the 'gt' tag")
   539  	})
   540  
   541  	Convey(`test validator.Struct`, t, func() {
   542  		var ctxVal string
   543  
   544  		fnCtx := func(ctx context.Context, fl FieldLevel) bool {
   545  			ctxVal = ctx.Value(&ctxVal).(string)
   546  			return true
   547  		}
   548  
   549  		var ctxSlVal string
   550  		slFn := func(ctx context.Context, sl StructLevel) {
   551  			ctxSlVal = ctx.Value(&ctxSlVal).(string)
   552  		}
   553  
   554  		type Test struct {
   555  			Field string `validate:"val"`
   556  		}
   557  
   558  		var tst Test
   559  
   560  		v := New()
   561  		err := v.RegisterValidation("val", fnCtx)
   562  		So(err, ShouldBeNil)
   563  
   564  		v.RegisterStructValidation(slFn, Test{})
   565  
   566  		ctx := context.WithValue(context.Background(), &ctxVal, "testval")
   567  		ctx = context.WithValue(ctx, &ctxSlVal, "slVal")
   568  		errs := v.Struct(ctx, tst)
   569  		So(errs, ShouldBeNil)
   570  		So(ctxVal, ShouldEqual, "testval")
   571  		So(ctxSlVal, ShouldEqual, "slVal")
   572  	})
   573  
   574  	Convey(`test validator.StructFiltered`, t, func() {
   575  		p1 := func(ns []byte) bool {
   576  			if bytes.HasSuffix(ns, []byte("NoTag")) || bytes.HasSuffix(ns, []byte("Required")) {
   577  				return false
   578  			}
   579  
   580  			return true
   581  		}
   582  
   583  		p2 := func(ns []byte) bool {
   584  			if bytes.HasSuffix(ns, []byte("SubSlice[0].Test")) ||
   585  				bytes.HasSuffix(ns, []byte("SubSlice[0]")) ||
   586  				bytes.HasSuffix(ns, []byte("SubSlice")) ||
   587  				bytes.HasSuffix(ns, []byte("Sub")) ||
   588  				bytes.HasSuffix(ns, []byte("SubIgnore")) ||
   589  				bytes.HasSuffix(ns, []byte("Anonymous")) ||
   590  				bytes.HasSuffix(ns, []byte("Anonymous.A")) {
   591  				return false
   592  			}
   593  
   594  			return true
   595  		}
   596  
   597  		p3 := func(ns []byte) bool {
   598  			return !bytes.HasSuffix(ns, []byte("SubTest.Test"))
   599  		}
   600  
   601  		// p4 := []string{
   602  		// 	"A",
   603  		// }
   604  
   605  		tPartial := &TestPartial{
   606  			NoTag:    "NoTag",
   607  			Required: "Required",
   608  
   609  			SubSlice: []*SubTest{
   610  				{
   611  
   612  					Test: "Required",
   613  				},
   614  				{
   615  
   616  					Test: "Required",
   617  				},
   618  			},
   619  
   620  			Sub: &SubTest{
   621  				Test: "1",
   622  			},
   623  			SubIgnore: &SubTest{
   624  				Test: "",
   625  			},
   626  			Anonymous: struct {
   627  				A             string     `validate:"required"`
   628  				ASubSlice     []*SubTest `validate:"required,dive"`
   629  				SubAnonStruct []struct {
   630  					Test      string `validate:"required"`
   631  					OtherTest string `validate:"required"`
   632  				} `validate:"required,dive"`
   633  			}{
   634  				A: "1",
   635  				ASubSlice: []*SubTest{
   636  					{
   637  						Test: "Required",
   638  					},
   639  					{
   640  						Test: "Required",
   641  					},
   642  				},
   643  
   644  				SubAnonStruct: []struct {
   645  					Test      string `validate:"required"`
   646  					OtherTest string `validate:"required"`
   647  				}{
   648  					{"Required", "RequiredOther"},
   649  					{"Required", "RequiredOther"},
   650  				},
   651  			},
   652  		}
   653  
   654  		v := New()
   655  
   656  		// the following should all return no errors as everything is valid in
   657  		// the default state
   658  		errs := v.StructFiltered(context.Background(), tPartial, p1)
   659  		So(errs, ShouldBeNil)
   660  
   661  		errs = v.StructFiltered(context.Background(), tPartial, p2)
   662  		So(errs, ShouldBeNil)
   663  
   664  		// this isn't really a robust test, but is ment to illustrate the ANON CASE below
   665  		errs = v.StructFiltered(context.Background(), tPartial.SubSlice[0], p3)
   666  		So(errs, ShouldBeNil)
   667  
   668  		// mod tParial for required feild and re-test making sure invalid fields are NOT required:
   669  		tPartial.Required = ""
   670  
   671  		// inversion and retesting Partial to generate failures:
   672  		errs = v.StructFiltered(context.Background(), tPartial, p1)
   673  		So(errs, ShouldNotBeNil)
   674  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Required' Error:Field validation for 'Required' failed on the 'required' tag")
   675  
   676  		// reset Required field, and set nested struct
   677  		tPartial.Required = "Required"
   678  		tPartial.Anonymous.A = ""
   679  
   680  		// will pass as unset feilds is not going to be tested
   681  		errs = v.StructFiltered(context.Background(), tPartial, p1)
   682  		So(errs, ShouldBeNil)
   683  
   684  		// will fail as unset feild is tested
   685  		errs = v.StructFiltered(context.Background(), tPartial, p2)
   686  		So(errs, ShouldNotBeNil)
   687  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Anonymous.A' Error:Field validation for 'A' failed on the 'required' tag")
   688  
   689  		// reset nested struct and unset struct in slice
   690  		tPartial.Anonymous.A = "Required"
   691  		tPartial.SubSlice[0].Test = ""
   692  
   693  		// these will pass as unset item is NOT tested
   694  		errs = v.StructFiltered(context.Background(), tPartial, p1)
   695  		So(errs, ShouldBeNil)
   696  
   697  		errs = v.StructFiltered(context.Background(), tPartial, p2)
   698  		So(errs, ShouldNotBeNil)
   699  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   700  		So(len(errs.(ValidationErrors)), ShouldEqual, 1)
   701  
   702  		// Unset second slice member concurrently to test dive behavior:
   703  		tPartial.SubSlice[1].Test = ""
   704  
   705  		errs = v.StructFiltered(context.Background(), tPartial, p1)
   706  		So(errs, ShouldBeNil)
   707  
   708  		errs = v.StructFiltered(context.Background(), tPartial, p2)
   709  		So(errs, ShouldNotBeNil)
   710  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   711  		So(len(errs.(ValidationErrors)), ShouldEqual, 1)
   712  
   713  		// reset struct in slice, and unset struct in slice in unset posistion
   714  		tPartial.SubSlice[0].Test = "Required"
   715  
   716  		// these will pass as the unset item is NOT tested
   717  		errs = v.StructFiltered(context.Background(), tPartial, p1)
   718  		So(errs, ShouldBeNil)
   719  
   720  		errs = v.StructFiltered(context.Background(), tPartial, p2)
   721  		So(errs, ShouldBeNil)
   722  
   723  		tPartial.SubSlice[1].Test = "Required"
   724  		tPartial.Anonymous.SubAnonStruct[0].Test = ""
   725  
   726  		// these will pass as the unset item is NOT tested
   727  		errs = v.StructFiltered(context.Background(), tPartial, p1)
   728  		So(errs, ShouldBeNil)
   729  
   730  		errs = v.StructFiltered(context.Background(), tPartial, p2)
   731  		So(errs, ShouldBeNil)
   732  
   733  		dt := time.Now()
   734  		err := v.StructFiltered(context.Background(), &dt, func(ns []byte) bool { return true })
   735  		So(err, ShouldNotBeNil)
   736  		So(err.Error(), ShouldEqual, "validator: (nil *time.Time)")
   737  	})
   738  
   739  	Convey(`test validator.StructPartial/validator.StructExcept`, t, func() {
   740  		p1 := []string{
   741  			"NoTag",
   742  			"Required",
   743  		}
   744  
   745  		p2 := []string{
   746  			"SubSlice[0].Test",
   747  			"Sub",
   748  			"SubIgnore",
   749  			"Anonymous.A",
   750  		}
   751  
   752  		p3 := []string{
   753  			"SubTest.Test",
   754  		}
   755  
   756  		p4 := []string{
   757  			"A",
   758  		}
   759  
   760  		tPartial := &TestPartial{
   761  			NoTag:    "NoTag",
   762  			Required: "Required",
   763  
   764  			SubSlice: []*SubTest{
   765  				{
   766  
   767  					Test: "Required",
   768  				},
   769  				{
   770  
   771  					Test: "Required",
   772  				},
   773  			},
   774  
   775  			Sub: &SubTest{
   776  				Test: "1",
   777  			},
   778  			SubIgnore: &SubTest{
   779  				Test: "",
   780  			},
   781  			Anonymous: struct {
   782  				A             string     `validate:"required"`
   783  				ASubSlice     []*SubTest `validate:"required,dive"`
   784  				SubAnonStruct []struct {
   785  					Test      string `validate:"required"`
   786  					OtherTest string `validate:"required"`
   787  				} `validate:"required,dive"`
   788  			}{
   789  				A: "1",
   790  				ASubSlice: []*SubTest{
   791  					{
   792  						Test: "Required",
   793  					},
   794  					{
   795  						Test: "Required",
   796  					},
   797  				},
   798  
   799  				SubAnonStruct: []struct {
   800  					Test      string `validate:"required"`
   801  					OtherTest string `validate:"required"`
   802  				}{
   803  					{"Required", "RequiredOther"},
   804  					{"Required", "RequiredOther"},
   805  				},
   806  			},
   807  		}
   808  
   809  		v := New()
   810  
   811  		// the following should all return no errors as everything is valid in
   812  		// the default state
   813  		errs := v.StructPartial(context.Background(), tPartial, p1...)
   814  		So(errs, ShouldBeNil)
   815  
   816  		errs = v.StructPartial(context.Background(), tPartial, p2...)
   817  		So(errs, ShouldBeNil)
   818  
   819  		// this isn't really a robust test, but is ment to illustrate the ANON CASE below
   820  		errs = v.StructPartial(context.Background(), tPartial.SubSlice[0], p3...)
   821  		So(errs, ShouldBeNil)
   822  
   823  		errs = v.StructExcept(context.Background(), tPartial, p1...)
   824  		So(errs, ShouldBeNil)
   825  
   826  		errs = v.StructExcept(context.Background(), tPartial, p2...)
   827  		So(errs, ShouldBeNil)
   828  
   829  		// mod tParial for required feild and re-test making sure invalid fields are NOT required:
   830  		tPartial.Required = ""
   831  
   832  		errs = v.StructExcept(context.Background(), tPartial, p1...)
   833  		So(errs, ShouldBeNil)
   834  
   835  		errs = v.StructPartial(context.Background(), tPartial, p2...)
   836  		So(errs, ShouldBeNil)
   837  
   838  		// inversion and retesting Partial to generate failures:
   839  		errs = v.StructPartial(context.Background(), tPartial, p1...)
   840  		So(errs, ShouldNotBeNil)
   841  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Required' Error:Field validation for 'Required' failed on the 'required' tag")
   842  
   843  		errs = v.StructExcept(context.Background(), tPartial, p2...)
   844  		So(errs, ShouldNotBeNil)
   845  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Required' Error:Field validation for 'Required' failed on the 'required' tag")
   846  
   847  		// reset Required field, and set nested struct
   848  		tPartial.Required = "Required"
   849  		tPartial.Anonymous.A = ""
   850  
   851  		// will pass as unset feilds is not going to be tested
   852  		errs = v.StructPartial(context.Background(), tPartial, p1...)
   853  		So(errs, ShouldBeNil)
   854  
   855  		errs = v.StructExcept(context.Background(), tPartial, p2...)
   856  		So(errs, ShouldBeNil)
   857  
   858  		// ANON CASE the response here is strange, it clearly does what it is being told to
   859  		errs = v.StructExcept(context.Background(), tPartial.Anonymous, p4...)
   860  		So(errs, ShouldBeNil)
   861  
   862  		// will fail as unset feild is tested
   863  		errs = v.StructPartial(context.Background(), tPartial, p2...)
   864  		So(errs, ShouldNotBeNil)
   865  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Anonymous.A' Error:Field validation for 'A' failed on the 'required' tag")
   866  
   867  		errs = v.StructExcept(context.Background(), tPartial, p1...)
   868  		So(errs, ShouldNotBeNil)
   869  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Anonymous.A' Error:Field validation for 'A' failed on the 'required' tag")
   870  
   871  		// reset nested struct and unset struct in slice
   872  		tPartial.Anonymous.A = "Required"
   873  		tPartial.SubSlice[0].Test = ""
   874  
   875  		// these will pass as unset item is NOT tested
   876  		errs = v.StructPartial(context.Background(), tPartial, p1...)
   877  		So(errs, ShouldBeNil)
   878  
   879  		errs = v.StructExcept(context.Background(), tPartial, p2...)
   880  		So(errs, ShouldBeNil)
   881  
   882  		// these will fail as unset item IS tested
   883  		errs = v.StructExcept(context.Background(), tPartial, p1...)
   884  		So(errs, ShouldNotBeNil)
   885  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   886  		So(len(errs.(ValidationErrors)), ShouldEqual, 1)
   887  
   888  		errs = v.StructPartial(context.Background(), tPartial, p2...)
   889  		So(errs, ShouldNotBeNil)
   890  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   891  		So(len(errs.(ValidationErrors)), ShouldEqual, 1)
   892  
   893  		// Unset second slice member concurrently to test dive behavior:
   894  		tPartial.SubSlice[1].Test = ""
   895  
   896  		errs = v.StructPartial(context.Background(), tPartial, p1...)
   897  		So(errs, ShouldBeNil)
   898  
   899  		// NOTE: When specifying nested items, it is still the users responsibility
   900  		// to specify the dive tag, the library does not override this.
   901  		errs = v.StructExcept(context.Background(), tPartial, p2...)
   902  		So(errs, ShouldNotBeNil)
   903  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[1].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   904  
   905  		errs = v.StructExcept(context.Background(), tPartial, p1...)
   906  		So(errs, ShouldNotBeNil)
   907  		So(len(errs.(ValidationErrors)), ShouldEqual, 2)
   908  		So(errs.(ValidationErrors)[0].Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   909  		So(errs.(ValidationErrors)[1].Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[1].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   910  
   911  		errs = v.StructPartial(context.Background(), tPartial, p2...)
   912  		So(errs, ShouldNotBeNil)
   913  		So(len(errs.(ValidationErrors)), ShouldEqual, 1)
   914  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   915  
   916  		// reset struct in slice, and unset struct in slice in unset posistion
   917  		tPartial.SubSlice[0].Test = "Required"
   918  
   919  		// these will pass as the unset item is NOT tested
   920  		errs = v.StructPartial(context.Background(), tPartial, p1...)
   921  		So(errs, ShouldBeNil)
   922  
   923  		errs = v.StructPartial(context.Background(), tPartial, p2...)
   924  		So(errs, ShouldBeNil)
   925  
   926  		// testing for missing item by exception, yes it dives and fails
   927  		errs = v.StructExcept(context.Background(), tPartial, p1...)
   928  		So(errs, ShouldNotBeNil)
   929  		So(len(errs.(ValidationErrors)), ShouldEqual, 1)
   930  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[1].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   931  
   932  		errs = v.StructExcept(context.Background(), tPartial, p2...)
   933  		So(errs, ShouldNotBeNil)
   934  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.SubSlice[1].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   935  
   936  		tPartial.SubSlice[1].Test = "Required"
   937  
   938  		tPartial.Anonymous.SubAnonStruct[0].Test = ""
   939  		// these will pass as the unset item is NOT tested
   940  		errs = v.StructPartial(context.Background(), tPartial, p1...)
   941  		So(errs, ShouldBeNil)
   942  
   943  		errs = v.StructPartial(context.Background(), tPartial, p2...)
   944  		So(errs, ShouldBeNil)
   945  
   946  		errs = v.StructExcept(context.Background(), tPartial, p1...)
   947  		So(errs, ShouldNotBeNil)
   948  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Anonymous.SubAnonStruct[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   949  
   950  		errs = v.StructExcept(context.Background(), tPartial, p2...)
   951  		So(errs, ShouldNotBeNil)
   952  		So(errs.Error(), ShouldEqual, "Key: 'TestPartial.Anonymous.SubAnonStruct[0].Test' Error:Field validation for 'Test' failed on the 'required' tag")
   953  
   954  		// Test for unnamed struct
   955  		testStruct := &TestStruct{
   956  			String: "test",
   957  		}
   958  		unnamedStruct := struct {
   959  			String string `validate:"required" json:"StringVal"`
   960  		}{String: "test"}
   961  		composedUnnamedStruct := struct{ *TestStruct }{&TestStruct{String: "test"}}
   962  
   963  		errs = v.StructPartial(context.Background(), testStruct, "String")
   964  		So(errs, ShouldBeNil)
   965  
   966  		errs = v.StructPartial(context.Background(), unnamedStruct, "String")
   967  		So(errs, ShouldBeNil)
   968  
   969  		errs = v.StructPartial(context.Background(), composedUnnamedStruct, "TestStruct.String")
   970  		So(errs, ShouldBeNil)
   971  
   972  		testStruct.String = ""
   973  		errs = v.StructPartial(context.Background(), testStruct, "String")
   974  		So(errs, ShouldNotBeNil)
   975  		So(errs.Error(), ShouldEqual, "Key: 'TestStruct.String' Error:Field validation for 'String' failed on the 'required' tag")
   976  
   977  		unnamedStruct.String = ""
   978  		errs = v.StructPartial(context.Background(), unnamedStruct, "String")
   979  		So(errs, ShouldNotBeNil)
   980  		So(errs.Error(), ShouldEqual, "Key: 'String' Error:Field validation for 'String' failed on the 'required' tag")
   981  
   982  		composedUnnamedStruct.String = ""
   983  		errs = v.StructPartial(context.Background(), composedUnnamedStruct, "TestStruct.String")
   984  		So(errs, ShouldNotBeNil)
   985  		So(errs.Error(), ShouldEqual, "Key: 'TestStruct.String' Error:Field validation for 'String' failed on the 'required' tag")
   986  	})
   987  
   988  	Convey(`test validator.VarWithValue`, t, func() {
   989  		var errs error
   990  		v := New()
   991  
   992  		type TimeTest struct {
   993  			Start *time.Time `validate:"required,gt"`
   994  			End   *time.Time `validate:"required,gt,gtfield=Start"`
   995  		}
   996  
   997  		now := time.Now()
   998  		start := now.Add(time.Hour * 24)
   999  		end := start.Add(time.Hour * 24)
  1000  
  1001  		timeTest := &TimeTest{
  1002  			Start: &start,
  1003  			End:   &end,
  1004  		}
  1005  
  1006  		errs = v.Struct(context.Background(), timeTest)
  1007  		So(errs, ShouldBeNil)
  1008  
  1009  		timeTest = &TimeTest{
  1010  			Start: &end,
  1011  			End:   &start,
  1012  		}
  1013  
  1014  		errs = v.Struct(context.Background(), timeTest)
  1015  		So(errs, ShouldNotBeNil)
  1016  		So(errs.Error(), ShouldEqual, "Key: 'TimeTest.End' Error:Field validation for 'End' failed on the 'gtfield' tag")
  1017  
  1018  		errs = v.VarWithValue(context.Background(), &end, &start, "gtfield")
  1019  		So(errs, ShouldBeNil)
  1020  
  1021  		errs = v.VarWithValue(context.Background(), &start, &end, "gtfield")
  1022  		So(errs, ShouldNotBeNil)
  1023  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1024  
  1025  		errs = v.VarWithValue(context.Background(), &end, &start, "gtfield")
  1026  		So(errs, ShouldBeNil)
  1027  
  1028  		errs = v.VarWithValue(context.Background(), &timeTest, &end, "gtfield")
  1029  		So(errs, ShouldNotBeNil)
  1030  		So(errs.Error(), ShouldEqual, "Key: 'TimeTest.End' Error:Field validation for 'End' failed on the 'gtfield' tag")
  1031  
  1032  		errs = v.VarWithValue(context.Background(), "test bigger", "test", "gtfield")
  1033  		So(errs, ShouldBeNil)
  1034  
  1035  		// Tests for time.Duration type.
  1036  
  1037  		// -- Validations for variables of time.Duration type.
  1038  
  1039  		errs = v.VarWithValue(context.Background(), time.Hour, time.Hour-time.Minute, "gtfield")
  1040  		So(errs, ShouldBeNil)
  1041  
  1042  		errs = v.VarWithValue(context.Background(), time.Hour, time.Hour, "gtfield")
  1043  		So(errs, ShouldNotBeNil)
  1044  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1045  
  1046  		errs = v.VarWithValue(context.Background(), time.Hour, time.Hour+time.Minute, "gtfield")
  1047  		So(errs, ShouldNotBeNil)
  1048  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1049  
  1050  		errs = v.VarWithValue(context.Background(), time.Duration(0), time.Hour, "omitempty,gtfield")
  1051  		So(errs, ShouldBeNil)
  1052  
  1053  		// -- Validations for a struct with time.Duration type fields.
  1054  
  1055  		type TimeDurationTest struct {
  1056  			First  time.Duration `validate:"gtfield=Second"`
  1057  			Second time.Duration
  1058  		}
  1059  		var timeDurationTest *TimeDurationTest
  1060  
  1061  		timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute}
  1062  		errs = v.Struct(context.Background(), timeDurationTest)
  1063  		So(errs, ShouldBeNil)
  1064  
  1065  		timeDurationTest = &TimeDurationTest{time.Hour, time.Hour}
  1066  		errs = v.Struct(context.Background(), timeDurationTest)
  1067  		So(errs, ShouldNotBeNil)
  1068  		So(errs.Error(), ShouldEqual, "Key: 'TimeDurationTest.First' Error:Field validation for 'First' failed on the 'gtfield' tag")
  1069  
  1070  		timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute}
  1071  		errs = v.Struct(context.Background(), timeDurationTest)
  1072  		So(errs, ShouldNotBeNil)
  1073  		So(errs.Error(), ShouldEqual, "Key: 'TimeDurationTest.First' Error:Field validation for 'First' failed on the 'gtfield' tag")
  1074  
  1075  		type TimeDurationOmitemptyTest struct {
  1076  			First  time.Duration `validate:"omitempty,gtfield=Second"`
  1077  			Second time.Duration
  1078  		}
  1079  
  1080  		timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Hour}
  1081  		errs = v.Struct(context.Background(), timeDurationOmitemptyTest)
  1082  		So(errs, ShouldBeNil)
  1083  
  1084  		// Tests for Ints types.
  1085  
  1086  		type IntTest struct {
  1087  			Val1 int `validate:"required"`
  1088  			Val2 int `validate:"required,gtfield=Val1"`
  1089  		}
  1090  
  1091  		intTest := &IntTest{
  1092  			Val1: 1,
  1093  			Val2: 5,
  1094  		}
  1095  
  1096  		errs = v.Struct(context.Background(), intTest)
  1097  		So(errs, ShouldBeNil)
  1098  
  1099  		intTest = &IntTest{
  1100  			Val1: 5,
  1101  			Val2: 1,
  1102  		}
  1103  
  1104  		errs = v.Struct(context.Background(), intTest)
  1105  		So(errs, ShouldNotBeNil)
  1106  		So(errs.Error(), ShouldEqual, "Key: 'IntTest.Val2' Error:Field validation for 'Val2' failed on the 'gtfield' tag")
  1107  
  1108  		errs = v.VarWithValue(context.Background(), int(5), int(1), "gtfield")
  1109  		So(errs, ShouldBeNil)
  1110  
  1111  		errs = v.VarWithValue(context.Background(), int(1), int(5), "gtfield")
  1112  		So(errs, ShouldNotBeNil)
  1113  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1114  
  1115  		type UIntTest struct {
  1116  			Val1 uint `validate:"required"`
  1117  			Val2 uint `validate:"required,gtfield=Val1"`
  1118  		}
  1119  
  1120  		uIntTest := &UIntTest{
  1121  			Val1: 1,
  1122  			Val2: 5,
  1123  		}
  1124  
  1125  		errs = v.Struct(context.Background(), uIntTest)
  1126  		So(errs, ShouldBeNil)
  1127  
  1128  		uIntTest = &UIntTest{
  1129  			Val1: 5,
  1130  			Val2: 1,
  1131  		}
  1132  
  1133  		errs = v.Struct(context.Background(), uIntTest)
  1134  		So(errs, ShouldNotBeNil)
  1135  		So(errs.Error(), ShouldEqual, "Key: 'UIntTest.Val2' Error:Field validation for 'Val2' failed on the 'gtfield' tag")
  1136  
  1137  		errs = v.VarWithValue(context.Background(), uint(5), uint(1), "gtfield")
  1138  		So(errs, ShouldBeNil)
  1139  
  1140  		errs = v.VarWithValue(context.Background(), uint(1), uint(5), "gtfield")
  1141  		So(errs, ShouldNotBeNil)
  1142  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1143  
  1144  		type FloatTest struct {
  1145  			Val1 float64 `validate:"required"`
  1146  			Val2 float64 `validate:"required,gtfield=Val1"`
  1147  		}
  1148  
  1149  		floatTest := &FloatTest{
  1150  			Val1: 1,
  1151  			Val2: 5,
  1152  		}
  1153  
  1154  		errs = v.Struct(context.Background(), floatTest)
  1155  		So(errs, ShouldBeNil)
  1156  
  1157  		floatTest = &FloatTest{
  1158  			Val1: 5,
  1159  			Val2: 1,
  1160  		}
  1161  
  1162  		errs = v.Struct(context.Background(), floatTest)
  1163  		So(errs, ShouldNotBeNil)
  1164  		So(errs.Error(), ShouldEqual, "Key: 'FloatTest.Val2' Error:Field validation for 'Val2' failed on the 'gtfield' tag")
  1165  
  1166  		errs = v.VarWithValue(context.Background(), float32(5), float32(1), "gtfield")
  1167  		So(errs, ShouldBeNil)
  1168  
  1169  		errs = v.VarWithValue(context.Background(), float32(1), float32(5), "gtfield")
  1170  		So(errs, ShouldNotBeNil)
  1171  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1172  
  1173  		errs = v.VarWithValue(context.Background(), nil, 1, "gtfield")
  1174  		So(errs, ShouldNotBeNil)
  1175  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1176  
  1177  		errs = v.VarWithValue(context.Background(), 5, "T", "gtfield")
  1178  		So(errs, ShouldNotBeNil)
  1179  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1180  
  1181  		errs = v.VarWithValue(context.Background(), 5, start, "gtfield")
  1182  		So(errs, ShouldNotBeNil)
  1183  		So(errs.Error(), ShouldEqual, "Key: '' Error:Field validation for '' failed on the 'gtfield' tag")
  1184  
  1185  		type TimeTest2 struct {
  1186  			Start *time.Time `validate:"required"`
  1187  			End   *time.Time `validate:"required,gtfield=NonExistantField"`
  1188  		}
  1189  
  1190  		timeTest2 := &TimeTest2{
  1191  			Start: &start,
  1192  			End:   &end,
  1193  		}
  1194  
  1195  		errs = v.Struct(context.Background(), timeTest2)
  1196  		So(errs, ShouldNotBeNil)
  1197  		So(errs.Error(), ShouldEqual, "Key: 'TimeTest2.End' Error:Field validation for 'End' failed on the 'gtfield' tag")
  1198  
  1199  		type Other struct {
  1200  			Value string
  1201  		}
  1202  
  1203  		type Test struct {
  1204  			Value Other
  1205  			Time  time.Time `validate:"gtfield=Value"`
  1206  		}
  1207  
  1208  		tst := Test{
  1209  			Value: Other{Value: "StringVal"},
  1210  			Time:  end,
  1211  		}
  1212  
  1213  		errs = v.Struct(context.Background(), tst)
  1214  		So(errs, ShouldNotBeNil)
  1215  		So(errs.Error(), ShouldEqual, "Key: 'Test.Time' Error:Field validation for 'Time' failed on the 'gtfield' tag")
  1216  	})
  1217  }