From 44f3347f13195a5cb9624b35d4574ebeac7eb5af Mon Sep 17 00:00:00 2001 From: math-nao Date: Sat, 25 Jul 2020 19:39:27 +0200 Subject: [PATCH 01/23] Add support for time zone validation --- baked_in.go | 27 +++++++++++++++++++++++++++ doc.go | 8 ++++++++ validator_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/baked_in.go b/baked_in.go index 36e8057..4d7d917 100644 --- a/baked_in.go +++ b/baked_in.go @@ -174,6 +174,7 @@ var ( "lowercase": isLowercase, "uppercase": isUppercase, "datetime": isDatetime, + "timeZone": isTimeZone, } ) @@ -2096,3 +2097,29 @@ func isDatetime(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } + +// isTimeZone is the validation function for validating if the current field's value is a valid time zone string. +func isTimeZone(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + // empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name + if field.String() == "" { + return false + } + + // Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name + if strings.ToLower(field.String()) == "local" { + return false + } + + _, err := time.LoadLocation(field.String()) + if err != nil { + return false + } + + return true + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} diff --git a/doc.go b/doc.go index 4aba75f..814a6cf 100644 --- a/doc.go +++ b/doc.go @@ -1088,6 +1088,14 @@ Supplied format must match the official Go time format layout as documented in h Usage: datetime=2006-01-02 +TimeZone + +This validates that a string value is a valid time zone based on the time zone database present on the system. +Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. +More information on https://golang.org/pkg/time/#LoadLocation + + Usage: timeZone + Alias Validators and Tags NOTE: When returning an error, the tag returned in "FieldError" will be diff --git a/validator_test.go b/validator_test.go index e76a3cd..519a2b2 100644 --- a/validator_test.go +++ b/validator_test.go @@ -9201,3 +9201,44 @@ func TestDatetimeValidation(t *testing.T) { _ = validate.Var(2, "datetime") }, "Bad field type int") } + +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") +} From 1c4e56307bd3181110f6f7cbc351fc2e5706bc27 Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sat, 25 Jul 2020 22:59:44 -0300 Subject: [PATCH 02/23] Add bin to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 792ca00..6e43fac 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # Folders _obj _test +bin # Architecture specific extensions/prefixes *.[568vq] @@ -26,4 +27,4 @@ _testmain.go *.out *.txt cover.html -README.html \ No newline at end of file +README.html From 94470e68f3abff382927bcba5ce5e1cd743ddd8d Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sat, 25 Jul 2020 23:00:27 -0300 Subject: [PATCH 03/23] Add function asIntFromTimeDuration() --- util.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/util.go b/util.go index 0d3a181..cb7f0ee 100644 --- a/util.go +++ b/util.go @@ -4,6 +4,7 @@ import ( "reflect" "strconv" "strings" + "time" ) // extractTypeInternal gets the actual underlying type of field value. @@ -229,6 +230,15 @@ func asInt(param string) int64 { return i } +// asIntFromTimeDuration parses param as time.Duration and returns it as int64 +// or panics on error. +func asIntFromTimeDuration(param string) int64 { + d, err := time.ParseDuration(param) + panicIf(err) + + return int64(d) +} + // asUint returns the parameter as a uint64 // or panics if it can't convert func asUint(param string) uint64 { From 0c71d5cc08a4f89b9f634e806b2721d57163e122 Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sat, 25 Jul 2020 23:01:01 -0300 Subject: [PATCH 04/23] Add var timeDurationType --- validator_instance.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validator_instance.go b/validator_instance.go index 4a89d40..905ce58 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -41,8 +41,9 @@ const ( ) var ( - timeType = reflect.TypeOf(time.Time{}) - defaultCField = &cField{namesEqual: true} + timeType = reflect.TypeOf(time.Time{}) + timeDurationType = reflect.TypeOf(time.Duration(0)) + defaultCField = &cField{namesEqual: true} ) // FilterFunc is the type used to filter fields using From 48684f91aa7fde72a7b1704caf53c8585569c8ec Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sat, 25 Jul 2020 23:02:42 -0300 Subject: [PATCH 05/23] Add baked-in support for time.Duration --- baked_in.go | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/baked_in.go b/baked_in.go index 36e8057..caae8a7 100644 --- a/baked_in.go +++ b/baked_in.go @@ -1129,7 +1129,13 @@ func isEq(fl FieldLevel) bool { return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asInt(param) + var p int64 + + if field.Type() == timeDurationType { + p = asIntFromTimeDuration(param) + } else { + p = asInt(param) + } return field.Int() == p @@ -1541,7 +1547,13 @@ func isGte(fl FieldLevel) bool { return int64(field.Len()) >= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asInt(param) + var p int64 + + if field.Type() == timeDurationType { + p = asIntFromTimeDuration(param) + } else { + p = asInt(param) + } return field.Int() >= p @@ -1588,7 +1600,13 @@ func isGt(fl FieldLevel) bool { return int64(field.Len()) > p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asInt(param) + var p int64 + + if field.Type() == timeDurationType { + p = asIntFromTimeDuration(param) + } else { + p = asInt(param) + } return field.Int() > p @@ -1631,7 +1649,13 @@ func hasLengthOf(fl FieldLevel) bool { return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asInt(param) + var p int64 + + if field.Type() == timeDurationType { + p = asIntFromTimeDuration(param) + } else { + p = asInt(param) + } return field.Int() == p @@ -1767,7 +1791,13 @@ func isLte(fl FieldLevel) bool { return int64(field.Len()) <= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asInt(param) + var p int64 + + if field.Type() == timeDurationType { + p = asIntFromTimeDuration(param) + } else { + p = asInt(param) + } return field.Int() <= p @@ -1814,7 +1844,13 @@ func isLt(fl FieldLevel) bool { return int64(field.Len()) < p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asInt(param) + var p int64 + + if field.Type() == timeDurationType { + p = asIntFromTimeDuration(param) + } else { + p = asInt(param) + } return field.Int() < p From f525f0b64fdf0f7001702812e0b4617acec9ac0b Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sat, 25 Jul 2020 23:05:24 -0300 Subject: [PATCH 06/23] Add tests for baked-in time.Duration supported tags --- validator_test.go | 1175 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1159 insertions(+), 16 deletions(-) diff --git a/validator_test.go b/validator_test.go index e76a3cd..fe21574 100644 --- a/validator_test.go +++ b/validator_test.go @@ -1046,6 +1046,61 @@ func TestCrossStructLteFieldValidation(t *testing.T) { errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltecsfield") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.VarWithValue(duration, duration+time.Minute, "ltecsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "ltecsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration-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 a inner struct with time.Duration type fields. + + type TimeDurationInner struct { + Duration time.Duration + } + + type TimeDurationTest struct { + Inner *TimeDurationInner + Duration time.Duration `validate:"ltecsfield=Inner.Duration"` + } + + timeDurationInner := &TimeDurationInner{duration + time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration - time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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"` + } + timeDurationInner = &TimeDurationInner{-time.Minute} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + errs = validate.Struct(timeDurationOmitemptyTest) + Equal(t, errs, nil) } func TestCrossStructLtFieldValidation(t *testing.T) { @@ -1142,6 +1197,64 @@ func TestCrossStructLtFieldValidation(t *testing.T) { errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "ltcsfield") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.VarWithValue(duration, duration+time.Minute, "ltcsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "ltcsfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "ltcsfield") + + errs = validate.VarWithValue(duration, duration-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 a inner struct with time.Duration type fields. + + type TimeDurationInner struct { + Duration time.Duration + } + + type TimeDurationTest struct { + Inner *TimeDurationInner + Duration time.Duration `validate:"ltcsfield=Inner.Duration"` + } + + timeDurationInner := &TimeDurationInner{duration + time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "ltcsfield") + + timeDurationInner = &TimeDurationInner{duration - time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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"` + } + + timeDurationInner = &TimeDurationInner{-time.Minute} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + errs = validate.Struct(timeDurationOmitemptyTest) + Equal(t, errs, nil) } func TestCrossStructGteFieldValidation(t *testing.T) { @@ -1250,6 +1363,62 @@ func TestCrossStructGteFieldValidation(t *testing.T) { errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtecsfield") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.VarWithValue(duration, duration-time.Minute, "gtecsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "gtecsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration+time.Minute, "gtecsfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "gtecsfield") + + errs = validate.VarWithValue(time.Duration(0), duration, "omitempty,gtecsfield") + Equal(t, errs, nil) + + // -- Validations for a struct and a inner struct with time.Duration type fields. + + type TimeDurationInner struct { + Duration time.Duration + } + + type TimeDurationTest struct { + Inner *TimeDurationInner + Duration time.Duration `validate:"gtecsfield=Inner.Duration"` + } + + timeDurationInner := &TimeDurationInner{duration - time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration + time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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"` + } + + timeDurationInner = &TimeDurationInner{duration} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + errs = validate.Struct(timeDurationOmitemptyTest) + Equal(t, errs, nil) } func TestCrossStructGtFieldValidation(t *testing.T) { @@ -1346,6 +1515,64 @@ func TestCrossStructGtFieldValidation(t *testing.T) { errs = validate.Struct(tst) NotEqual(t, errs, nil) AssertError(t, errs, "Test2.Time", "Test2.Time", "Time", "Time", "gtcsfield") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.VarWithValue(duration, duration-time.Minute, "gtcsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "gtcsfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "gtcsfield") + + errs = validate.VarWithValue(duration, duration+time.Minute, "gtcsfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "gtcsfield") + + errs = validate.VarWithValue(time.Duration(0), duration, "omitempty,gtcsfield") + Equal(t, errs, nil) + + // -- Validations for a struct and a inner struct with time.Duration type fields. + + type TimeDurationInner struct { + Duration time.Duration + } + + type TimeDurationTest struct { + Inner *TimeDurationInner + Duration time.Duration `validate:"gtcsfield=Inner.Duration"` + } + + timeDurationInner := &TimeDurationInner{duration - time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gtcsfield") + + timeDurationInner = &TimeDurationInner{duration + time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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"` + } + + timeDurationInner = &TimeDurationInner{duration} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + errs = validate.Struct(timeDurationOmitemptyTest) + Equal(t, errs, nil) } func TestCrossStructNeFieldValidation(t *testing.T) { @@ -1454,6 +1681,62 @@ func TestCrossStructNeFieldValidation(t *testing.T) { errs = validate.VarWithValue(nil, 1, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.VarWithValue(duration, duration-time.Minute, "necsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration+time.Minute, "necsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "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 a inner struct with time.Duration type fields. + + type TimeDurationInner struct { + Duration time.Duration + } + + type TimeDurationTest struct { + Inner *TimeDurationInner + Duration time.Duration `validate:"necsfield=Inner.Duration"` + } + + timeDurationInner := &TimeDurationInner{duration - time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration + time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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"` + } + + timeDurationInner = &TimeDurationInner{time.Duration(0)} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + errs = validate.Struct(timeDurationOmitemptyTest) + Equal(t, errs, nil) } func TestCrossStructEqFieldValidation(t *testing.T) { @@ -1559,6 +1842,64 @@ func TestCrossStructEqFieldValidation(t *testing.T) { errs = validate.VarWithValue(nil, 1, "eqcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqcsfield") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.VarWithValue(duration, duration, "eqcsfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration-time.Minute, "eqcsfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "eqcsfield") + + errs = validate.VarWithValue(duration, duration+time.Minute, "eqcsfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "eqcsfield") + + errs = validate.VarWithValue(time.Duration(0), duration, "omitempty,eqcsfield") + Equal(t, errs, nil) + + // -- Validations for a struct and a inner struct with time.Duration type fields. + + type TimeDurationInner struct { + Duration time.Duration + } + + type TimeDurationTest struct { + Inner *TimeDurationInner + Duration time.Duration `validate:"eqcsfield=Inner.Duration"` + } + + timeDurationInner := &TimeDurationInner{duration} + timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationInner = &TimeDurationInner{duration - time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "eqcsfield") + + timeDurationInner = &TimeDurationInner{duration + time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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"` + } + + timeDurationInner = &TimeDurationInner{duration} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + errs = validate.Struct(timeDurationOmitemptyTest) + Equal(t, errs, nil) } func TestCrossNamespaceFieldValidation(t *testing.T) { @@ -4287,6 +4628,54 @@ func TestIsNeFieldValidation(t *testing.T) { errs = validate.Struct(tst) Equal(t, errs, nil) + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for variables of time.Duration type. + + errs = validate.VarWithValue(duration, duration-time.Minute, "nefield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration+time.Minute, "nefield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "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 + } + + timeDurationTest := &TimeDurationTest{duration, duration - time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration + time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration} + 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) { @@ -4322,6 +4711,52 @@ func TestIsNeValidation(t *testing.T) { AssertError(t, errs, "", "", "", "", "ne") PanicMatches(t, func() { _ = validate.Var(now, "ne=now") }, "Bad field type time.Time") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.Var(duration-time.Minute, "ne=1h") + Equal(t, errs, nil) + + errs = validate.Var(duration+time.Minute, "ne=1h") + Equal(t, errs, nil) + + errs = validate.Var(duration, "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"` + } + + timeDurationTest := &TimeDurationTest{duration - time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration + time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration} + 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) { @@ -4441,6 +4876,56 @@ func TestIsEqFieldValidation(t *testing.T) { errs = validate.Struct(test) NotEqual(t, errs, nil) AssertError(t, errs, "TStruct.CreatedAt", "TStruct.CreatedAt", "CreatedAt", "CreatedAt", "eqfield") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for variables of time.Duration type. + + errs = validate.VarWithValue(duration, duration, "eqfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration-time.Minute, "eqfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "eqfield") + + errs = validate.VarWithValue(duration, duration+time.Minute, "eqfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "eqfield") + + errs = validate.VarWithValue(time.Duration(0), duration, "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 + } + + timeDurationTest := &TimeDurationTest{duration, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration - time.Minute} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "eqfield") + + timeDurationTest = &TimeDurationTest{duration, duration + 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), duration} + errs = validate.Struct(timeDurationOmitemptyTest) + Equal(t, errs, nil) } func TestIsEqValidation(t *testing.T) { @@ -4476,24 +4961,72 @@ func TestIsEqValidation(t *testing.T) { AssertError(t, errs, "", "", "", "", "eq") PanicMatches(t, func() { _ = validate.Var(now, "eq=now") }, "Bad field type time.Time") -} -func TestOneOfValidation(t *testing.T) { - validate := New() + // Tests for time.Duration type. - 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"}, + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.Var(duration, "eq=1h") + Equal(t, errs, nil) + + errs = validate.Var(duration-time.Minute, "eq=1h") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "eq") + + errs = validate.Var(duration+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"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - time.Minute} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "eq") + + timeDurationTest = &TimeDurationTest{duration + 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"}, @@ -4997,6 +5530,58 @@ func TestGtField(t *testing.T) { errs = validate.VarWithValue("test bigger", "test", "gtfield") Equal(t, errs, nil) + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for variables of time.Duration type. + + errs = validate.VarWithValue(duration, duration-time.Minute, "gtfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "gtfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "gtfield") + + errs = validate.VarWithValue(duration, duration+time.Minute, "gtfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "gtfield") + + errs = validate.VarWithValue(time.Duration(0), duration, "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 + } + + timeDurationTest := &TimeDurationTest{duration, duration - time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "gtfield") + + timeDurationTest = &TimeDurationTest{duration, duration + 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), duration} + 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"` @@ -5173,6 +5758,58 @@ func TestLtField(t *testing.T) { errs = validate.VarWithValue("tes", "test", "ltfield") Equal(t, errs, nil) + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for variables of time.Duration type. + + errs = validate.VarWithValue(duration, duration+time.Minute, "ltfield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "ltfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "ltfield") + + errs = validate.VarWithValue(duration, duration-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 + } + + timeDurationTest := &TimeDurationTest{duration, duration + time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "ltfield") + + timeDurationTest = &TimeDurationTest{duration, duration - 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"` @@ -5457,6 +6094,56 @@ func TestLteField(t *testing.T) { errs = validate.VarWithValue("test", "test", "ltefield") Equal(t, errs, nil) + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for variables of time.Duration type. + + errs = validate.VarWithValue(duration, duration+time.Minute, "ltefield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "ltefield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration-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 + } + + timeDurationTest := &TimeDurationTest{duration, duration + time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration - 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"` @@ -5618,6 +6305,56 @@ func TestGteField(t *testing.T) { errs = validate.VarWithValue("test bigger", "test", "gtefield") Equal(t, errs, nil) + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for variables of time.Duration type. + + errs = validate.VarWithValue(duration, duration-time.Minute, "gtefield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration, "gtefield") + Equal(t, errs, nil) + + errs = validate.VarWithValue(duration, duration+time.Minute, "gtefield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "gtefield") + + errs = validate.VarWithValue(time.Duration(0), duration, "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 + } + + timeDurationTest := &TimeDurationTest{duration, duration - time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration, duration + 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), duration} + 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"` @@ -5900,6 +6637,54 @@ func TestIsGt(t *testing.T) { errs = validate.Struct(s) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "gt") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.Var(duration, "gt=59m") + Equal(t, errs, nil) + + errs = validate.Var(duration-time.Minute, "gt=59m") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "gt") + + errs = validate.Var(duration-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 time.Duration type fields. + + type TimeDurationTest struct { + Duration time.Duration `validate:"gt=59m"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - time.Minute} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "gt") + + timeDurationTest = &TimeDurationTest{duration - 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) { @@ -5936,6 +6721,270 @@ func TestIsGte(t *testing.T) { errs = validate.Struct(s) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "gte") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.Var(duration, "gte=59m") + Equal(t, errs, nil) + + errs = validate.Var(duration-time.Minute, "gte=59m") + Equal(t, errs, nil) + + errs = validate.Var(duration-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 time.Duration type fields. + + type TimeDurationTest struct { + Duration time.Duration `validate:"gte=59m"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - 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) { + validate := New() + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs := validate.Var(duration, "min=59m") + Equal(t, errs, nil) + + errs = validate.Var(duration-time.Minute, "min=59m") + Equal(t, errs, nil) + + errs = validate.Var(duration-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 time.Duration type field. + + type TimeDurationTest struct { + Duration time.Duration `validate:"min=59m"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - 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) { + validate := New() + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs := validate.Var(duration, "max=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration+time.Minute, "max=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration+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 time.Duration type field. + + type TimeDurationTest struct { + Duration time.Duration `validate:"max=1h1m"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration + time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration + 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) { + validate := New() + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs := validate.Var(duration, "min=59m,max=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration-time.Minute, "min=59m,max=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration+time.Minute, "min=59m,max=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration-2*time.Minute, "min=59m,max=1h1m") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "min") + + errs = validate.Var(duration+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 time.Duration type field. + + type TimeDurationTest struct { + Duration time.Duration `validate:"min=59m,max=1h1m"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration + time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - 2*time.Minute} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "min") + + timeDurationTest = &TimeDurationTest{duration + 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) { + validate := New() + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs := validate.Var(duration, "len=1h") + Equal(t, errs, nil) + + errs = validate.Var(duration-time.Minute, "len=1h") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "len") + + errs = validate.Var(duration+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 time.Duration type field. + + type TimeDurationTest struct { + Duration time.Duration `validate:"len=1h"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration - time.Minute} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "len") + + timeDurationTest = &TimeDurationTest{duration + 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) { @@ -5988,6 +7037,54 @@ func TestIsLt(t *testing.T) { errs = validate.Struct(s) NotEqual(t, errs, nil) AssertError(t, errs, "Test.Now", "Test.Now", "Now", "Now", "lt") + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.Var(duration, "lt=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration+time.Minute, "lt=1h1m") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "lt") + + errs = validate.Var(duration+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 time.Duration type fields. + + type TimeDurationTest struct { + Duration time.Duration `validate:"lt=1h1m"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration + time.Minute} + errs = validate.Struct(timeDurationTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "lt") + + timeDurationTest = &TimeDurationTest{duration + 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) { @@ -6026,6 +7123,52 @@ func TestIsLte(t *testing.T) { errs = validate.Struct(s) NotEqual(t, errs, nil) + + // Tests for time.Duration type. + + duration := time.Duration(1 * time.Hour) + + // -- Validations for a variable of time.Duration type. + + errs = validate.Var(duration, "lte=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration+time.Minute, "lte=1h1m") + Equal(t, errs, nil) + + errs = validate.Var(duration+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 time.Duration type fields. + + type TimeDurationTest struct { + Duration time.Duration `validate:"lte=1h1m"` + } + + timeDurationTest := &TimeDurationTest{duration} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration + time.Minute} + errs = validate.Struct(timeDurationTest) + Equal(t, errs, nil) + + timeDurationTest = &TimeDurationTest{duration + 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) { From fc1b28803a85827c8613496bb9c4b380315167f6 Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sat, 25 Jul 2020 23:05:52 -0300 Subject: [PATCH 07/23] Update docs for baked-in time.Duration supported tags --- doc.go | 100 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 14 deletions(-) diff --git a/doc.go b/doc.go index 4aba75f..ec21046 100644 --- a/doc.go +++ b/doc.go @@ -321,8 +321,17 @@ equal to the parameter given. For strings, it checks that the string length is exactly that number of characters. For slices, arrays, and maps, validates the number of items. +Example #1 + Usage: len=10 +Example #2 (time.Duration) + +For time.Duration, len will ensure that the value is equal to the duration given +in the parameter. + + Usage: len=1h30m + Maximum For numbers, max will ensure that the value is @@ -330,8 +339,17 @@ less than or equal to the parameter given. For strings, it checks that the string length is at most that number of characters. For slices, arrays, and maps, validates the number of items. +Example #1 + Usage: max=10 +Example #2 (time.Duration) + +For time.Duration, max will ensure that the value is less than or equal to the +duration given in the parameter. + + Usage: max=1h30m + Minimum For numbers, min will ensure that the value is @@ -339,24 +357,51 @@ greater or equal to the parameter given. For strings, it checks that the string length is at least that number of characters. For slices, arrays, and maps, validates the number of items. +Example #1 + Usage: min=10 +Example #2 (time.Duration) + +For time.Duration, min will ensure that the value is greater than or equal to +the duration given in the parameter. + + Usage: min=1h30m + Equals For strings & numbers, eq will ensure that the value is equal to the parameter given. For slices, arrays, and maps, validates the number of items. +Example #1 + Usage: eq=10 +Example #2 (time.Duration) + +For time.Duration, eq will ensure that the value is equal to the duration given +in the parameter. + + Usage: eq=1h30m + Not Equal For strings & numbers, ne will ensure that the value is not equal to the parameter given. For slices, arrays, and maps, validates the number of items. +Example #1 + Usage: ne=10 +Example #2 (time.Duration) + +For time.Duration, ne will ensure that the value is not equal to the duration +given in the parameter. + + Usage: ne=1h30m + One Of For strings, ints, and uints, oneof will ensure that the value @@ -386,11 +431,17 @@ For time.Time ensures the time value is greater than time.Now.UTC(). Usage: gt +Example #3 (time.Duration) + +For time.Duration, gt will ensure that the value is greater than the duration +given in the parameter. + + Usage: gt=1h30m + Greater Than or Equal Same as 'min' above. Kept both to make terminology with 'len' easier. - Example #1 Usage: gte=10 @@ -401,6 +452,13 @@ For time.Time ensures the time value is greater than or equal to time.Now.UTC(). Usage: gte +Example #3 (time.Duration) + +For time.Duration, gte will ensure that the value is greater than or equal to +the duration given in the parameter. + + Usage: gte=1h30m + Less Than For numbers, this will ensure that the value is less than the parameter given. @@ -412,10 +470,18 @@ Example #1 Usage: lt=10 Example #2 (time.Time) + For time.Time ensures the time value is less than time.Now.UTC(). Usage: lt +Example #3 (time.Duration) + +For time.Duration, lt will ensure that the value is less than the duration given +in the parameter. + + Usage: lt=1h30m + Less Than or Equal Same as 'max' above. Kept both to make terminology with 'len' easier. @@ -430,6 +496,13 @@ For time.Time ensures the time value is less than or equal to time.Now.UTC(). Usage: lte +Example #3 (time.Duration) + +For time.Duration, lte will ensure that the value is less than or equal to the +duration given in the parameter. + + Usage: lte=1h30m + Field Equals Another Field This will validate the field value against another fields value either within @@ -476,9 +549,9 @@ relative to the top level struct. Field Greater Than Another Field -Only valid for Numbers and time.Time types, this will validate the field value -against another fields value either within a struct or passed in field. -usage examples are for validation of a Start and End date: +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: Example #1: @@ -490,7 +563,6 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "gtfield") - Field Greater Than Another Relative Field This does the same as gtfield except that it validates the field provided @@ -500,9 +572,9 @@ relative to the top level struct. Field Greater Than or Equal To Another Field -Only valid for Numbers and time.Time types, this will validate the field value -against another fields value either within a struct or passed in field. -usage examples are for validation of a Start and End date: +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: Example #1: @@ -523,9 +595,9 @@ to the top level struct. Less Than Another Field -Only valid for Numbers and time.Time types, this will validate the field value -against another fields value either within a struct or passed in field. -usage examples are for validation of a Start and End date: +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: Example #1: @@ -546,9 +618,9 @@ to the top level struct. Less Than or Equal To Another Field -Only valid for Numbers and time.Time types, this will validate the field value -against another fields value either within a struct or passed in field. -usage examples are for validation of a Start and End date: +Only valid for Numbers, time.Duration and time.Time types, this will validate +the field value against another fields value either within a struct or passed in +field. usage examples are for validation of a Start and End date: Example #1: From 04749bc4d487eeba404de40d250dd48f251350e8 Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sat, 25 Jul 2020 23:06:22 -0300 Subject: [PATCH 08/23] Fix golangci-lint issues --- baked_in.go | 5 +---- validator_test.go | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/baked_in.go b/baked_in.go index caae8a7..0c05daa 100644 --- a/baked_in.go +++ b/baked_in.go @@ -2123,11 +2123,8 @@ func isDatetime(fl FieldLevel) bool { if field.Kind() == reflect.String { _, err := time.Parse(param, field.String()) - if err != nil { - return false - } - return true + return err == nil } panic(fmt.Sprintf("Bad field type %T", field.Interface())) diff --git a/validator_test.go b/validator_test.go index fe21574..d434e99 100644 --- a/validator_test.go +++ b/validator_test.go @@ -9375,7 +9375,7 @@ func TestUniqueValidationStructSlice(t *testing.T) { } } } - PanicMatches(t, func() { validate.Var(testStructs, "unique=C") }, "Bad field name C") + PanicMatches(t, func() { _ = validate.Var(testStructs, "unique=C") }, "Bad field name C") } func TestHTMLValidation(t *testing.T) { @@ -10143,7 +10143,7 @@ func TestGetTag(t *testing.T) { } val := New() - val.RegisterValidation("mytag", func(fl FieldLevel) bool { + _ = val.RegisterValidation("mytag", func(fl FieldLevel) bool { tag = fl.GetTag() return true }) From 55e0f418d69c1d3036edae0d8a6a22f7c230cce5 Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sun, 26 Jul 2020 11:36:45 -0300 Subject: [PATCH 09/23] Minor edits --- validator_instance.go | 5 +- validator_test.go | 416 +++++++++++++++++++----------------------- 2 files changed, 189 insertions(+), 232 deletions(-) diff --git a/validator_instance.go b/validator_instance.go index 905ce58..234a43f 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -41,9 +41,10 @@ const ( ) var ( - timeType = reflect.TypeOf(time.Time{}) timeDurationType = reflect.TypeOf(time.Duration(0)) - defaultCField = &cField{namesEqual: true} + timeType = reflect.TypeOf(time.Time{}) + + defaultCField = &cField{namesEqual: true} ) // FilterFunc is the type used to filter fields using diff --git a/validator_test.go b/validator_test.go index d434e99..464f1a6 100644 --- a/validator_test.go +++ b/validator_test.go @@ -1049,24 +1049,22 @@ func TestCrossStructLteFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - - // -- Validations for a variable of time.Duration type. + // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration+time.Minute, "ltecsfield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltecsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "ltecsfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "ltecsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration-time.Minute, "ltecsfield") + 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 a inner struct with time.Duration type fields. + // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration @@ -1077,18 +1075,18 @@ func TestCrossStructLteFieldValidation(t *testing.T) { Duration time.Duration `validate:"ltecsfield=Inner.Duration"` } - timeDurationInner := &TimeDurationInner{duration + time.Minute} - timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + timeDurationInner := &TimeDurationInner{time.Hour + time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + timeDurationInner = &TimeDurationInner{time.Hour} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration - time.Minute} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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") @@ -1200,25 +1198,23 @@ func TestCrossStructLtFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - - // -- Validations for a variable of time.Duration type. + // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration+time.Minute, "ltcsfield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltcsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "ltcsfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "ltcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltcsfield") - errs = validate.VarWithValue(duration, duration-time.Minute, "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 a inner struct with time.Duration type fields. + // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration @@ -1229,19 +1225,19 @@ func TestCrossStructLtFieldValidation(t *testing.T) { Duration time.Duration `validate:"ltcsfield=Inner.Duration"` } - timeDurationInner := &TimeDurationInner{duration + time.Minute} - timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + timeDurationInner := &TimeDurationInner{time.Hour + time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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{duration - time.Minute} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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") @@ -1366,24 +1362,22 @@ func TestCrossStructGteFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - - // -- Validations for a variable of time.Duration type. + // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration-time.Minute, "gtecsfield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtecsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "gtecsfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "gtecsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration+time.Minute, "gtecsfield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "gtecsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtecsfield") - errs = validate.VarWithValue(time.Duration(0), duration, "omitempty,gtecsfield") + errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtecsfield") Equal(t, errs, nil) - // -- Validations for a struct and a inner struct with time.Duration type fields. + // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration @@ -1394,18 +1388,18 @@ func TestCrossStructGteFieldValidation(t *testing.T) { Duration time.Duration `validate:"gtecsfield=Inner.Duration"` } - timeDurationInner := &TimeDurationInner{duration - time.Minute} - timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + timeDurationInner := &TimeDurationInner{time.Hour - time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + timeDurationInner = &TimeDurationInner{time.Hour} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration + time.Minute} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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") @@ -1415,7 +1409,7 @@ func TestCrossStructGteFieldValidation(t *testing.T) { Duration time.Duration `validate:"omitempty,gtecsfield=Inner.Duration"` } - timeDurationInner = &TimeDurationInner{duration} + timeDurationInner = &TimeDurationInner{time.Hour} timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) @@ -1518,25 +1512,23 @@ func TestCrossStructGtFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - - // -- Validations for a variable of time.Duration type. + // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration-time.Minute, "gtcsfield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtcsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "gtcsfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "gtcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtcsfield") - errs = validate.VarWithValue(duration, duration+time.Minute, "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), duration, "omitempty,gtcsfield") + errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtcsfield") Equal(t, errs, nil) - // -- Validations for a struct and a inner struct with time.Duration type fields. + // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration @@ -1547,19 +1539,19 @@ func TestCrossStructGtFieldValidation(t *testing.T) { Duration time.Duration `validate:"gtcsfield=Inner.Duration"` } - timeDurationInner := &TimeDurationInner{duration - time.Minute} - timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + timeDurationInner := &TimeDurationInner{time.Hour - time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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{duration + time.Minute} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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") @@ -1569,7 +1561,7 @@ func TestCrossStructGtFieldValidation(t *testing.T) { Duration time.Duration `validate:"omitempty,gtcsfield=Inner.Duration"` } - timeDurationInner = &TimeDurationInner{duration} + timeDurationInner = &TimeDurationInner{time.Hour} timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) @@ -1684,24 +1676,22 @@ func TestCrossStructNeFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - - // -- Validations for a variable of time.Duration type. + // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration-time.Minute, "necsfield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "necsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration+time.Minute, "necsfield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "necsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "necsfield") + 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 a inner struct with time.Duration type fields. + // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration @@ -1712,18 +1702,18 @@ func TestCrossStructNeFieldValidation(t *testing.T) { Duration time.Duration `validate:"necsfield=Inner.Duration"` } - timeDurationInner := &TimeDurationInner{duration - time.Minute} - timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + timeDurationInner := &TimeDurationInner{time.Hour - time.Minute} + timeDurationTest := &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration + time.Minute} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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") @@ -1845,25 +1835,23 @@ func TestCrossStructEqFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - - // -- Validations for a variable of time.Duration type. + // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration, "eqcsfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "eqcsfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration-time.Minute, "eqcsfield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "eqcsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqcsfield") - errs = validate.VarWithValue(duration, duration+time.Minute, "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), duration, "omitempty,eqcsfield") + errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,eqcsfield") Equal(t, errs, nil) - // -- Validations for a struct and a inner struct with time.Duration type fields. + // -- Validations for a struct and an inner struct with time.Duration type fields. type TimeDurationInner struct { Duration time.Duration @@ -1874,19 +1862,19 @@ func TestCrossStructEqFieldValidation(t *testing.T) { Duration time.Duration `validate:"eqcsfield=Inner.Duration"` } - timeDurationInner := &TimeDurationInner{duration} - timeDurationTest := &TimeDurationTest{timeDurationInner, duration} + timeDurationInner := &TimeDurationInner{time.Hour} + timeDurationTest := &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationInner = &TimeDurationInner{duration - time.Minute} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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{duration + time.Minute} - timeDurationTest = &TimeDurationTest{timeDurationInner, duration} + 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") @@ -1896,7 +1884,7 @@ func TestCrossStructEqFieldValidation(t *testing.T) { Duration time.Duration `validate:"omitempty,eqcsfield=Inner.Duration"` } - timeDurationInner = &TimeDurationInner{duration} + timeDurationInner = &TimeDurationInner{time.Hour} timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) @@ -4631,17 +4619,15 @@ func TestIsNeFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration-time.Minute, "nefield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "nefield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration+time.Minute, "nefield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "nefield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "nefield") + errs = validate.VarWithValue(time.Hour, time.Hour, "nefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "nefield") @@ -4655,15 +4641,15 @@ func TestIsNeFieldValidation(t *testing.T) { Second time.Duration } - timeDurationTest := &TimeDurationTest{duration, duration - time.Minute} + timeDurationTest := &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.First", "TimeDurationTest.First", "First", "First", "nefield") @@ -4714,17 +4700,15 @@ func TestIsNeValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs = validate.Var(duration-time.Minute, "ne=1h") + errs = validate.Var(time.Hour-time.Minute, "ne=1h") Equal(t, errs, nil) - errs = validate.Var(duration+time.Minute, "ne=1h") + errs = validate.Var(time.Hour+time.Minute, "ne=1h") Equal(t, errs, nil) - errs = validate.Var(duration, "ne=1h") + errs = validate.Var(time.Hour, "ne=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ne") @@ -4737,15 +4721,15 @@ func TestIsNeValidation(t *testing.T) { Duration time.Duration `validate:"ne=1h"` } - timeDurationTest := &TimeDurationTest{duration - time.Minute} + timeDurationTest := &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "ne") @@ -4879,22 +4863,20 @@ func TestIsEqFieldValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration, "eqfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "eqfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration-time.Minute, "eqfield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "eqfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eqfield") - errs = validate.VarWithValue(duration, duration+time.Minute, "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), duration, "omitempty,eqfield") + errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,eqfield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. @@ -4904,16 +4886,16 @@ func TestIsEqFieldValidation(t *testing.T) { Second time.Duration } - timeDurationTest := &TimeDurationTest{duration, duration} + timeDurationTest := &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration - time.Minute} + 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{duration, duration + time.Minute} + 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") @@ -4923,7 +4905,7 @@ func TestIsEqFieldValidation(t *testing.T) { Second time.Duration } - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), duration} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Hour} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } @@ -4964,18 +4946,16 @@ func TestIsEqValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs = validate.Var(duration, "eq=1h") + errs = validate.Var(time.Hour, "eq=1h") Equal(t, errs, nil) - errs = validate.Var(duration-time.Minute, "eq=1h") + errs = validate.Var(time.Hour-time.Minute, "eq=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eq") - errs = validate.Var(duration+time.Minute, "eq=1h") + errs = validate.Var(time.Hour+time.Minute, "eq=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "eq") @@ -4988,16 +4968,16 @@ func TestIsEqValidation(t *testing.T) { Duration time.Duration `validate:"eq=1h"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - time.Minute} + 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{duration + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "eq") @@ -5532,22 +5512,20 @@ func TestGtField(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration-time.Minute, "gtfield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "gtfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "gtfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtfield") - errs = validate.VarWithValue(duration, duration+time.Minute, "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), duration, "omitempty,gtfield") + errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtfield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. @@ -5557,16 +5535,16 @@ func TestGtField(t *testing.T) { Second time.Duration } - timeDurationTest := &TimeDurationTest{duration, duration - time.Minute} + timeDurationTest := &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration} + 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{duration, duration + time.Minute} + 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") @@ -5576,7 +5554,7 @@ func TestGtField(t *testing.T) { Second time.Duration } - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), duration} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Hour} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) @@ -5760,18 +5738,16 @@ func TestLtField(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration+time.Minute, "ltfield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltfield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "ltfield") + errs = validate.VarWithValue(time.Hour, time.Hour, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") - errs = validate.VarWithValue(duration, duration-time.Minute, "ltfield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "ltfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltfield") @@ -5785,16 +5761,16 @@ func TestLtField(t *testing.T) { Second time.Duration } - timeDurationTest := &TimeDurationTest{duration, duration + time.Minute} + timeDurationTest := &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration} + 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{duration, duration - time.Minute} + 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") @@ -6096,17 +6072,15 @@ func TestLteField(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration+time.Minute, "ltefield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "ltefield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "ltefield") + errs = validate.VarWithValue(time.Hour, time.Hour, "ltefield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration-time.Minute, "ltefield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "ltefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "ltefield") @@ -6120,15 +6094,15 @@ func TestLteField(t *testing.T) { Second time.Duration } - timeDurationTest := &TimeDurationTest{duration, duration + time.Minute} + timeDurationTest := &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration - time.Minute} + 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") @@ -6307,21 +6281,19 @@ func TestGteField(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for variables of time.Duration type. - errs = validate.VarWithValue(duration, duration-time.Minute, "gtefield") + errs = validate.VarWithValue(time.Hour, time.Hour-time.Minute, "gtefield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration, "gtefield") + errs = validate.VarWithValue(time.Hour, time.Hour, "gtefield") Equal(t, errs, nil) - errs = validate.VarWithValue(duration, duration+time.Minute, "gtefield") + errs = validate.VarWithValue(time.Hour, time.Hour+time.Minute, "gtefield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gtefield") - errs = validate.VarWithValue(time.Duration(0), duration, "omitempty,gtefield") + errs = validate.VarWithValue(time.Duration(0), time.Hour, "omitempty,gtefield") Equal(t, errs, nil) // -- Validations for a struct with time.Duration type fields. @@ -6331,15 +6303,15 @@ func TestGteField(t *testing.T) { Second time.Duration } - timeDurationTest := &TimeDurationTest{duration, duration - time.Minute} + timeDurationTest := &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration, duration + time.Minute} + 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") @@ -6349,7 +6321,7 @@ func TestGteField(t *testing.T) { Second time.Duration } - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), duration} + timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{time.Duration(0), time.Hour} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) @@ -6640,40 +6612,38 @@ func TestIsGt(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs = validate.Var(duration, "gt=59m") + errs = validate.Var(time.Hour, "gt=59m") Equal(t, errs, nil) - errs = validate.Var(duration-time.Minute, "gt=59m") + errs = validate.Var(time.Hour-time.Minute, "gt=59m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "gt") - errs = validate.Var(duration-2*time.Minute, "gt=59m") + 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 time.Duration type fields. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"gt=59m"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - time.Minute} + 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{duration - 2*time.Minute} + 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") @@ -6724,38 +6694,36 @@ func TestIsGte(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs = validate.Var(duration, "gte=59m") + errs = validate.Var(time.Hour, "gte=59m") Equal(t, errs, nil) - errs = validate.Var(duration-time.Minute, "gte=59m") + errs = validate.Var(time.Hour-time.Minute, "gte=59m") Equal(t, errs, nil) - errs = validate.Var(duration-2*time.Minute, "gte=59m") + 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 time.Duration type fields. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"gte=59m"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - 2*time.Minute} + 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") @@ -6774,38 +6742,36 @@ func TestMinValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs := validate.Var(duration, "min=59m") + errs := validate.Var(time.Hour, "min=59m") Equal(t, errs, nil) - errs = validate.Var(duration-time.Minute, "min=59m") + errs = validate.Var(time.Hour-time.Minute, "min=59m") Equal(t, errs, nil) - errs = validate.Var(duration-2*time.Minute, "min=59m") + 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 time.Duration type field. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"min=59m"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - 2*time.Minute} + 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") @@ -6824,38 +6790,36 @@ func TestMaxValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs := validate.Var(duration, "max=1h1m") + errs := validate.Var(time.Hour, "max=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration+time.Minute, "max=1h1m") + errs = validate.Var(time.Hour+time.Minute, "max=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration+2*time.Minute, "max=1h1m") + 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 time.Duration type field. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"max=1h1m"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration + 2*time.Minute} + 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") @@ -6874,54 +6838,52 @@ func TestMinMaxValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs := validate.Var(duration, "min=59m,max=1h1m") + errs := validate.Var(time.Hour, "min=59m,max=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration-time.Minute, "min=59m,max=1h1m") + errs = validate.Var(time.Hour-time.Minute, "min=59m,max=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration+time.Minute, "min=59m,max=1h1m") + errs = validate.Var(time.Hour+time.Minute, "min=59m,max=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration-2*time.Minute, "min=59m,max=1h1m") + errs = validate.Var(time.Hour-2*time.Minute, "min=59m,max=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "min") - errs = validate.Var(duration+2*time.Minute, "min=59m,max=1h1m") + 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 time.Duration type field. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"min=59m,max=1h1m"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - 2*time.Minute} + 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{duration + 2*time.Minute} + 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") @@ -6940,40 +6902,38 @@ func TestLenValidation(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs := validate.Var(duration, "len=1h") + errs := validate.Var(time.Hour, "len=1h") Equal(t, errs, nil) - errs = validate.Var(duration-time.Minute, "len=1h") + errs = validate.Var(time.Hour-time.Minute, "len=1h") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "len") - errs = validate.Var(duration+time.Minute, "len=1h") + 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 time.Duration type field. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"len=1h"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration - time.Minute} + 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{duration + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) NotEqual(t, errs, nil) AssertError(t, errs, "TimeDurationTest.Duration", "TimeDurationTest.Duration", "Duration", "Duration", "len") @@ -7040,40 +7000,38 @@ func TestIsLt(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs = validate.Var(duration, "lt=1h1m") + errs = validate.Var(time.Hour, "lt=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration+time.Minute, "lt=1h1m") + errs = validate.Var(time.Hour+time.Minute, "lt=1h1m") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") - errs = validate.Var(duration+2*time.Minute, "lt=1h1m") + 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 time.Duration type fields. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"lt=1h1m"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration + time.Minute} + 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{duration + 2*time.Minute} + 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") @@ -7126,38 +7084,36 @@ func TestIsLte(t *testing.T) { // Tests for time.Duration type. - duration := time.Duration(1 * time.Hour) - // -- Validations for a variable of time.Duration type. - errs = validate.Var(duration, "lte=1h1m") + errs = validate.Var(time.Hour, "lte=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration+time.Minute, "lte=1h1m") + errs = validate.Var(time.Hour+time.Minute, "lte=1h1m") Equal(t, errs, nil) - errs = validate.Var(duration+2*time.Minute, "lte=1h1m") + 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 time.Duration type fields. + // -- Validations for a struct with a time.Duration type field. type TimeDurationTest struct { Duration time.Duration `validate:"lte=1h1m"` } - timeDurationTest := &TimeDurationTest{duration} + timeDurationTest := &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) - timeDurationTest = &TimeDurationTest{duration + 2*time.Minute} + 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") From 33ffa4a31f4653b94dcb2b0c076be275611295fc Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Sun, 26 Jul 2020 12:15:22 -0300 Subject: [PATCH 10/23] Move var declarations to the top in test functions --- validator_test.go | 193 +++++++++++++++++++++++++++++----------------- 1 file changed, 122 insertions(+), 71 deletions(-) diff --git a/validator_test.go b/validator_test.go index 464f1a6..74b679e 100644 --- a/validator_test.go +++ b/validator_test.go @@ -940,6 +940,8 @@ func TestStructPartial(t *testing.T) { } func TestCrossStructLteFieldValidation(t *testing.T) { + var errs error + validate := New() type Inner struct { CreatedAt *time.Time @@ -982,8 +984,7 @@ func TestCrossStructLteFieldValidation(t *testing.T) { Array: []string{"val1"}, } - validate := New() - errs := validate.Struct(test) + errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then @@ -1069,14 +1070,16 @@ func TestCrossStructLteFieldValidation(t *testing.T) { 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} + timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -1095,13 +1098,17 @@ func TestCrossStructLteFieldValidation(t *testing.T) { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,ltecsfield=Inner.Duration"` } + var timeDurationOmitemptyTest *TimeDurationOmitemptyTest + timeDurationInner = &TimeDurationInner{-time.Minute} - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + 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 @@ -1144,8 +1151,7 @@ func TestCrossStructLtFieldValidation(t *testing.T) { Array: []string{"val1"}, } - validate := New() - errs := validate.Struct(test) + errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then @@ -1219,14 +1225,16 @@ func TestCrossStructLtFieldValidation(t *testing.T) { 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} + timeDurationInner = &TimeDurationInner{time.Hour + time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -1246,14 +1254,17 @@ func TestCrossStructLtFieldValidation(t *testing.T) { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,ltcsfield=Inner.Duration"` } + var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{-time.Minute} - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + 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 @@ -1296,8 +1307,7 @@ func TestCrossStructGteFieldValidation(t *testing.T) { Array: []string{"val1", "val2", "val3"}, } - validate := New() - errs := validate.Struct(test) + errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then @@ -1382,14 +1392,16 @@ func TestCrossStructGteFieldValidation(t *testing.T) { 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} + timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -1408,14 +1420,17 @@ func TestCrossStructGteFieldValidation(t *testing.T) { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,gtecsfield=Inner.Duration"` } + var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Hour} - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + 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 @@ -1458,8 +1473,7 @@ func TestCrossStructGtFieldValidation(t *testing.T) { Array: []string{"val1", "val2", "val3"}, } - validate := New() - errs := validate.Struct(test) + errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then @@ -1533,14 +1547,16 @@ func TestCrossStructGtFieldValidation(t *testing.T) { 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} + timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -1560,14 +1576,17 @@ func TestCrossStructGtFieldValidation(t *testing.T) { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,gtcsfield=Inner.Duration"` } + var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Hour} - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + 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 @@ -1590,8 +1609,7 @@ func TestCrossStructNeFieldValidation(t *testing.T) { CreatedAt: &now, } - validate := New() - errs := validate.Struct(test) + errs = validate.Struct(test) Equal(t, errs, nil) test.CreatedAt = &then @@ -1696,14 +1714,16 @@ func TestCrossStructNeFieldValidation(t *testing.T) { 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} + timeDurationInner = &TimeDurationInner{time.Hour - time.Minute} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -1722,14 +1742,17 @@ func TestCrossStructNeFieldValidation(t *testing.T) { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,necsfield=Inner.Duration"` } + var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Duration(0)} - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{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 @@ -1751,8 +1774,7 @@ func TestCrossStructEqFieldValidation(t *testing.T) { CreatedAt: &now, } - validate := New() - errs := validate.Struct(test) + errs = validate.Struct(test) Equal(t, errs, nil) newTime := time.Now().UTC() @@ -1856,14 +1878,16 @@ func TestCrossStructEqFieldValidation(t *testing.T) { 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} + timeDurationInner = &TimeDurationInner{time.Hour} + timeDurationTest = &TimeDurationTest{timeDurationInner, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -1883,9 +1907,10 @@ func TestCrossStructEqFieldValidation(t *testing.T) { Inner *TimeDurationInner Duration time.Duration `validate:"omitempty,eqcsfield=Inner.Duration"` } + var timeDurationOmitemptyTest *TimeDurationOmitemptyTest timeDurationInner = &TimeDurationInner{time.Hour} - timeDurationOmitemptyTest := &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} + timeDurationOmitemptyTest = &TimeDurationOmitemptyTest{timeDurationInner, time.Duration(0)} errs = validate.Struct(timeDurationOmitemptyTest) Equal(t, errs, nil) } @@ -4511,7 +4536,7 @@ func TestContainsValidation(t *testing.T) { } func TestIsNeFieldValidation(t *testing.T) { - + var errs error validate := New() var j uint64 @@ -4533,7 +4558,7 @@ func TestIsNeFieldValidation(t *testing.T) { arr3 := []string{"test"} now2 := now - errs := validate.VarWithValue(s, s2, "nefield") + errs = validate.VarWithValue(s, s2, "nefield") Equal(t, errs, nil) errs = validate.VarWithValue(i2, i, "nefield") @@ -4640,8 +4665,9 @@ func TestIsNeFieldValidation(t *testing.T) { First time.Duration `validate:"nefield=Second"` Second time.Duration } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour, time.Hour - time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -4665,7 +4691,7 @@ func TestIsNeFieldValidation(t *testing.T) { } func TestIsNeValidation(t *testing.T) { - + var errs error validate := New() var j uint64 @@ -4677,7 +4703,7 @@ func TestIsNeValidation(t *testing.T) { arr := []string{"test"} now := time.Now().UTC() - errs := validate.Var(s, "ne=abcd") + errs = validate.Var(s, "ne=abcd") Equal(t, errs, nil) errs = validate.Var(i, "ne=1") @@ -4720,8 +4746,9 @@ func TestIsNeValidation(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"ne=1h"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour - time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -4744,7 +4771,7 @@ func TestIsNeValidation(t *testing.T) { } func TestIsEqFieldValidation(t *testing.T) { - + var errs error validate := New() var j uint64 @@ -4766,7 +4793,7 @@ func TestIsEqFieldValidation(t *testing.T) { arr3 := []string{"test", "test2"} now2 := now - errs := validate.VarWithValue(s, s2, "eqfield") + errs = validate.VarWithValue(s, s2, "eqfield") Equal(t, errs, nil) errs = validate.VarWithValue(i2, i, "eqfield") @@ -4885,8 +4912,9 @@ func TestIsEqFieldValidation(t *testing.T) { First time.Duration `validate:"eqfield=Second"` Second time.Duration } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour, time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -4911,7 +4939,7 @@ func TestIsEqFieldValidation(t *testing.T) { } func TestIsEqValidation(t *testing.T) { - + var errs error validate := New() var j uint64 @@ -4923,7 +4951,7 @@ func TestIsEqValidation(t *testing.T) { arr := []string{"test"} now := time.Now().UTC() - errs := validate.Var(s, "eq=abcd") + errs = validate.Var(s, "eq=abcd") Equal(t, errs, nil) errs = validate.Var(i, "eq=1") @@ -4967,8 +4995,9 @@ func TestIsEqValidation(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"eq=1h"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -5465,7 +5494,7 @@ func TestStructOnlyValidation(t *testing.T) { } func TestGtField(t *testing.T) { - + var errs error validate := New() type TimeTest struct { @@ -5482,7 +5511,7 @@ func TestGtField(t *testing.T) { End: &end, } - errs := validate.Struct(timeTest) + errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ @@ -5534,8 +5563,9 @@ func TestGtField(t *testing.T) { First time.Duration `validate:"gtfield=Second"` Second time.Duration } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour, time.Hour - time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -5693,7 +5723,7 @@ func TestGtField(t *testing.T) { } func TestLtField(t *testing.T) { - + var errs error validate := New() type TimeTest struct { @@ -5710,7 +5740,7 @@ func TestLtField(t *testing.T) { End: &end, } - errs := validate.Struct(timeTest) + errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ @@ -5760,8 +5790,9 @@ func TestLtField(t *testing.T) { First time.Duration `validate:"ltfield=Second"` Second time.Duration } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour, time.Hour + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6024,7 +6055,7 @@ func TestContainsAndExcludes(t *testing.T) { } func TestLteField(t *testing.T) { - + var errs error validate := New() type TimeTest struct { @@ -6041,7 +6072,7 @@ func TestLteField(t *testing.T) { End: &end, } - errs := validate.Struct(timeTest) + errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ @@ -6093,8 +6124,9 @@ func TestLteField(t *testing.T) { First time.Duration `validate:"ltefield=Second"` Second time.Duration } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour, time.Hour + time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour + time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6233,7 +6265,7 @@ func TestLteField(t *testing.T) { } func TestGteField(t *testing.T) { - + var errs error validate := New() type TimeTest struct { @@ -6250,7 +6282,7 @@ func TestGteField(t *testing.T) { End: &end, } - errs := validate.Struct(timeTest) + errs = validate.Struct(timeTest) Equal(t, errs, nil) timeTest = &TimeTest{ @@ -6302,8 +6334,9 @@ func TestGteField(t *testing.T) { First time.Duration `validate:"gtefield=Second"` Second time.Duration } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour, time.Hour - time.Minute} + timeDurationTest = &TimeDurationTest{time.Hour, time.Hour - time.Minute} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6562,9 +6595,11 @@ func TestLength(t *testing.T) { } func TestIsGt(t *testing.T) { + var errs error validate := New() + myMap := map[string]string{} - errs := validate.Var(myMap, "gt=0") + errs = validate.Var(myMap, "gt=0") NotEqual(t, errs, nil) f := 1.23 @@ -6633,8 +6668,9 @@ func TestIsGt(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"gt=59m"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6658,14 +6694,16 @@ func TestIsGt(t *testing.T) { } 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") + errs = validate.Var(t1, "gte") Equal(t, errs, nil) t2 := time.Now().UTC().Add(-time.Hour) @@ -6714,8 +6752,9 @@ func TestIsGte(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"gte=59m"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6738,13 +6777,14 @@ func TestIsGte(t *testing.T) { } 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") + errs = validate.Var(time.Hour, "min=59m") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "min=59m") @@ -6762,8 +6802,9 @@ func TestMinValidation(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"min=59m"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6786,13 +6827,14 @@ func TestMinValidation(t *testing.T) { } 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") + errs = validate.Var(time.Hour, "max=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour+time.Minute, "max=1h1m") @@ -6810,8 +6852,9 @@ func TestMaxValidation(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"max=1h1m"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6834,13 +6877,14 @@ func TestMaxValidation(t *testing.T) { } 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") + errs = validate.Var(time.Hour, "min=59m,max=1h1m") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "min=59m,max=1h1m") @@ -6865,8 +6909,9 @@ func TestMinMaxValidation(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"min=59m,max=1h1m"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6898,13 +6943,14 @@ func TestMinMaxValidation(t *testing.T) { } 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") + errs = validate.Var(time.Hour, "len=1h") Equal(t, errs, nil) errs = validate.Var(time.Hour-time.Minute, "len=1h") @@ -6923,8 +6969,9 @@ func TestLenValidation(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"len=1h"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -6948,9 +6995,11 @@ func TestLenValidation(t *testing.T) { } func TestIsLt(t *testing.T) { + var errs error validate := New() + myMap := map[string]string{} - errs := validate.Var(myMap, "lt=0") + errs = validate.Var(myMap, "lt=0") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "lt") @@ -7021,8 +7070,9 @@ func TestIsLt(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"lt=1h1m"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) @@ -7046,7 +7096,7 @@ func TestIsLt(t *testing.T) { } func TestIsLte(t *testing.T) { - + var errs error validate := New() i := true @@ -7054,7 +7104,7 @@ func TestIsLte(t *testing.T) { t1 := time.Now().UTC().Add(-time.Hour) - errs := validate.Var(t1, "lte") + errs = validate.Var(t1, "lte") Equal(t, errs, nil) t2 := time.Now().UTC() @@ -7104,8 +7154,9 @@ func TestIsLte(t *testing.T) { type TimeDurationTest struct { Duration time.Duration `validate:"lte=1h1m"` } + var timeDurationTest *TimeDurationTest - timeDurationTest := &TimeDurationTest{time.Hour} + timeDurationTest = &TimeDurationTest{time.Hour} errs = validate.Struct(timeDurationTest) Equal(t, errs, nil) From 1cbd3081e4efd12130be2f0dfb87a89746789bba Mon Sep 17 00:00:00 2001 From: Elias Rodrigues Date: Tue, 28 Jul 2020 11:47:26 -0300 Subject: [PATCH 11/23] Add function asIntFromType --- baked_in.go | 48 ++++++------------------------------------------ util.go | 11 +++++++++++ 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/baked_in.go b/baked_in.go index 0c05daa..8ad1e64 100644 --- a/baked_in.go +++ b/baked_in.go @@ -1129,13 +1129,7 @@ func isEq(fl FieldLevel) bool { return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - var p int64 - - if field.Type() == timeDurationType { - p = asIntFromTimeDuration(param) - } else { - p = asInt(param) - } + p := asIntFromType(field.Type(), param) return field.Int() == p @@ -1547,13 +1541,7 @@ func isGte(fl FieldLevel) bool { return int64(field.Len()) >= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - var p int64 - - if field.Type() == timeDurationType { - p = asIntFromTimeDuration(param) - } else { - p = asInt(param) - } + p := asIntFromType(field.Type(), param) return field.Int() >= p @@ -1600,13 +1588,7 @@ func isGt(fl FieldLevel) bool { return int64(field.Len()) > p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - var p int64 - - if field.Type() == timeDurationType { - p = asIntFromTimeDuration(param) - } else { - p = asInt(param) - } + p := asIntFromType(field.Type(), param) return field.Int() > p @@ -1649,13 +1631,7 @@ func hasLengthOf(fl FieldLevel) bool { return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - var p int64 - - if field.Type() == timeDurationType { - p = asIntFromTimeDuration(param) - } else { - p = asInt(param) - } + p := asIntFromType(field.Type(), param) return field.Int() == p @@ -1791,13 +1767,7 @@ func isLte(fl FieldLevel) bool { return int64(field.Len()) <= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - var p int64 - - if field.Type() == timeDurationType { - p = asIntFromTimeDuration(param) - } else { - p = asInt(param) - } + p := asIntFromType(field.Type(), param) return field.Int() <= p @@ -1844,13 +1814,7 @@ func isLt(fl FieldLevel) bool { return int64(field.Len()) < p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - var p int64 - - if field.Type() == timeDurationType { - p = asIntFromTimeDuration(param) - } else { - p = asInt(param) - } + p := asIntFromType(field.Type(), param) return field.Int() < p diff --git a/util.go b/util.go index cb7f0ee..6e568f8 100644 --- a/util.go +++ b/util.go @@ -239,6 +239,17 @@ func asIntFromTimeDuration(param string) int64 { return int64(d) } +// asIntFromType calls the proper function to parse param as int64, +// given a field's Type t. +func asIntFromType(t reflect.Type, param string) int64 { + switch t { + case timeDurationType: + return asIntFromTimeDuration(param) + default: + return asInt(param) + } +} + // asUint returns the parameter as a uint64 // or panics if it can't convert func asUint(param string) uint64 { From 67c4fdf0dec848d8c8201971c03b624791a07c5e Mon Sep 17 00:00:00 2001 From: Long Bui Date: Wed, 29 Jul 2020 23:07:14 +0700 Subject: [PATCH 12/23] Make unique tag work with pointer fields. --- baked_in.go | 20 ++++++++++---- validator_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/baked_in.go b/baked_in.go index 36e8057..902eb4e 100644 --- a/baked_in.go +++ b/baked_in.go @@ -241,23 +241,33 @@ func isUnique(fl FieldLevel) bool { switch field.Kind() { case reflect.Slice, reflect.Array: + elem := field.Type().Elem() + if elem.Kind() == reflect.Ptr { + elem = elem.Elem() + } + if param == "" { - m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type())) + m := reflect.MakeMap(reflect.MapOf(elem, v.Type())) for i := 0; i < field.Len(); i++ { - m.SetMapIndex(field.Index(i), v) + m.SetMapIndex(reflect.Indirect(field.Index(i)), v) } return field.Len() == m.Len() } - sf, ok := field.Type().Elem().FieldByName(param) + sf, ok := elem.FieldByName(param) if !ok { panic(fmt.Sprintf("Bad field name %s", param)) } - m := reflect.MakeMap(reflect.MapOf(sf.Type, v.Type())) + sfTyp := sf.Type + if sfTyp.Kind() == reflect.Ptr { + sfTyp = sfTyp.Elem() + } + + m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type())) for i := 0; i < field.Len(); i++ { - m.SetMapIndex(field.Index(i).FieldByName(param), v) + m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v) } return field.Len() == m.Len() case reflect.Map: diff --git a/validator_test.go b/validator_test.go index e76a3cd..00bd11a 100644 --- a/validator_test.go +++ b/validator_test.go @@ -346,6 +346,18 @@ func StructLevelInvalidError(sl StructLevel) { } } +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() @@ -8144,6 +8156,12 @@ func TestUniqueValidation(t *testing.T) { {[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}, @@ -8155,6 +8173,12 @@ func TestUniqueValidation(t *testing.T) { {[]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}, @@ -8235,6 +8259,49 @@ func TestUniqueValidationStructSlice(t *testing.T) { 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 From 7dbe685a0221ea3b620dd70a3f250a4826880134 Mon Sep 17 00:00:00 2001 From: math-nao Date: Sun, 2 Aug 2020 13:59:46 +0200 Subject: [PATCH 13/23] Update timeZone tag name to timezone --- baked_in.go | 2 +- doc.go | 2 +- validator_test.go | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/baked_in.go b/baked_in.go index 4d7d917..9708165 100644 --- a/baked_in.go +++ b/baked_in.go @@ -174,7 +174,7 @@ var ( "lowercase": isLowercase, "uppercase": isUppercase, "datetime": isDatetime, - "timeZone": isTimeZone, + "timezone": isTimeZone, } ) diff --git a/doc.go b/doc.go index 814a6cf..afdb2ab 100644 --- a/doc.go +++ b/doc.go @@ -1094,7 +1094,7 @@ This validates that a string value is a valid time zone based on the time zone d Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. More information on https://golang.org/pkg/time/#LoadLocation - Usage: timeZone + Usage: timezone Alias Validators and Tags diff --git a/validator_test.go b/validator_test.go index 519a2b2..8e39e0c 100644 --- a/validator_test.go +++ b/validator_test.go @@ -9204,16 +9204,16 @@ func TestDatetimeValidation(t *testing.T) { func TestTimeZoneValidation(t *testing.T) { tests := []struct { - value string `validate:"timeZone"` + 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}, + {"America/New_York", `timezone`, true}, + {"UTC", `timezone`, true}, + {"", `timezone`, false}, + {"Local", `timezone`, false}, + {"Unknown", `timezone`, false}, } validate := New() @@ -9231,7 +9231,7 @@ func TestTimeZoneValidation(t *testing.T) { t.Fatalf("Index: %d time zone failed Error: %s", i, errs) } else { val := getError(errs, "", "") - if val.Tag() != "timeZone" { + if val.Tag() != "timezone" { t.Fatalf("Index: %d time zone failed Error: %s", i, errs) } } @@ -9239,6 +9239,6 @@ func TestTimeZoneValidation(t *testing.T) { } PanicMatches(t, func() { - _ = validate.Var(2, "timeZone") + _ = validate.Var(2, "timezone") }, "Bad field type int") } From 6f81b7d8d0b81a4c5c233d7d83221dac425da9fe Mon Sep 17 00:00:00 2001 From: nigelis Date: Tue, 1 Sep 2020 21:11:11 +0800 Subject: [PATCH 14/23] Validate tag omitempty, only base on field value --- validator.go | 2 +- validator_test.go | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/validator.go b/validator.go index 342e72e..f097f39 100644 --- a/validator.go +++ b/validator.go @@ -249,7 +249,7 @@ OUTER: v.cf = cf v.ct = ct - if !v.fldIsPointer && !hasValue(v) { + if !hasValue(v) { return } diff --git a/validator_test.go b/validator_test.go index e76a3cd..a26dc75 100644 --- a/validator_test.go +++ b/validator_test.go @@ -8858,6 +8858,16 @@ func TestRequiredWithout(t *testing.T) { 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) { From 44a150f3593441156b2d568bcad45f66e8f7339c Mon Sep 17 00:00:00 2001 From: hzw Date: Thu, 3 Sep 2020 20:27:05 +0800 Subject: [PATCH 15/23] add required_if and required_unless --- README.md | 2 + baked_in.go | 59 +++++++++++++++++ doc.go | 34 ++++++++++ validator_instance.go | 4 +- validator_test.go | 145 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 243 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f552826..f71bbaf 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,8 @@ Baked-in Validations | min | Minimum | | oneof | One Of | | required | Required | +| required_if | Required If | +| required_unless | Required Unless | | required_with | Required With | | required_with_all | Required With All | | required_without | Required Without | diff --git a/baked_in.go b/baked_in.go index 36e8057..8d80b7a 100644 --- a/baked_in.go +++ b/baked_in.go @@ -64,6 +64,8 @@ var ( // or even disregard and use your own map if so desired. bakedInValidators = map[string]Func{ "required": hasValue, + "required_if": requiredIf, + "required_unless": requiredUnless, "required_with": requiredWith, "required_with_all": requiredWithAll, "required_without": requiredWithout, @@ -1383,6 +1385,63 @@ func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue boo } } +// requireCheckFieldValue is a func for check field value +func requireCheckFieldValue(fl FieldLevel, param string, value string, defaultNotFoundValue bool) bool { + field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param) + if !found { + return defaultNotFoundValue + } + + switch kind { + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return field.Int() == asInt(value) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return field.Uint() == asUint(value) + + case reflect.Float32, reflect.Float64: + return field.Float() == asFloat(value) + + case reflect.Slice, reflect.Map, reflect.Array: + return int64(field.Len()) == asInt(value) + } + + // default reflect.String: + return field.String() == value +} + +// requiredIf is the validation function +// The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field. +func requiredIf(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + if len(params)%2 != 0 { + panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName())) + } + for i := 0; i < len(params); i += 2 { + if !requireCheckFieldValue(fl, params[i], params[i+1], false) { + return true + } + } + return hasValue(fl) +} + +// requiredUnless is the validation function +// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field. +func requiredUnless(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + if len(params)%2 != 0 { + panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName())) + } + + for i := 0; i < len(params); i += 2 { + if requireCheckFieldValue(fl, params[i], params[i+1], false) { + return true + } + } + return hasValue(fl) +} + // RequiredWith is the validation function // The field under validation must be present and not empty only if any of the other specified fields are present. func requiredWith(fl FieldLevel) bool { diff --git a/doc.go b/doc.go index 4aba75f..85527e9 100644 --- a/doc.go +++ b/doc.go @@ -245,6 +245,40 @@ ensures the value is not nil. Usage: required +Required If + +The field under validation must be present and not empty only if all +the other specified fields are equal to the value following the specified +field. For strings ensures value is not "". For slices, maps, pointers, +interfaces, channels and functions ensures the value is not nil. + + Usage: required_if + +Examples: + + // require the field if the Field1 is equal to the parameter given: + Usage: required_if=Field1 foobar + + // require the field if the Field1 and Field2 is equal to the value respectively: + Usage: required_if=Field1 foo Field2 bar + +Required Unless + +The field under validation must be present and not empty unless all +the other specified fields are equal to the value following the specified +field. For strings ensures value is not "". For slices, maps, pointers, +interfaces, channels and functions ensures the value is not nil. + + Usage: required_unless + +Examples: + + // require the field unless the Field1 is equal to the parameter given: + Usage: required_unless=Field1 foobar + + // require the field unless the Field1 and Field2 is equal to the value respectively: + Usage: required_unless=Field1 foo Field2 bar + Required With The field under validation must be present and not empty only if any diff --git a/validator_instance.go b/validator_instance.go index 4a89d40..74acec0 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -27,6 +27,8 @@ const ( requiredWithoutTag = "required_without" requiredWithTag = "required_with" requiredWithAllTag = "required_with_all" + requiredIfTag = "required_if" + requiredUnlessTag = "required_unless" skipValidationTag = "-" diveTag = "dive" keysTag = "keys" @@ -107,7 +109,7 @@ func New() *Validate { switch k { // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour - case requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag: + case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag: _ = v.registerValidation(k, wrapFunc(val), true, true) default: // no need to error check here, baked in will always be valid diff --git a/validator_test.go b/validator_test.go index e76a3cd..e5e6edc 100644 --- a/validator_test.go +++ b/validator_test.go @@ -8695,6 +8695,151 @@ func TestEndsWithValidation(t *testing.T) { } } +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 From 742006d126b63deb951c05d1f25b4e61fc910a78 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 15 Sep 2020 18:13:38 +0200 Subject: [PATCH 16/23] Closes #660 added excluded with and without --- baked_in.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/baked_in.go b/baked_in.go index 36e8057..da0363f 100644 --- a/baked_in.go +++ b/baked_in.go @@ -68,6 +68,10 @@ var ( "required_with_all": requiredWithAll, "required_without": requiredWithout, "required_without_all": requiredWithoutAll, + "excluded_with": excludedWith, + "excluded_with_all": excludedWithAll, + "excluded_without": excludedWithout, + "excluded_without_all": excludedWithoutAll, "isdefault": isDefault, "len": hasLengthOf, "min": hasMinOf, @@ -1383,6 +1387,18 @@ func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue boo } } +// ExcludedWith is the validation function +// The field under validation must not be present or is empty if any of the other specified fields are present. +func excludedWith(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if !requireCheckFieldKind(fl, param, true) { + return !hasValue(fl) + } + } + return true +} + // RequiredWith is the validation function // The field under validation must be present and not empty only if any of the other specified fields are present. func requiredWith(fl FieldLevel) bool { @@ -1395,6 +1411,18 @@ func requiredWith(fl FieldLevel) bool { return true } +// ExcludedWithAll is the validation function +// The field under validation must not be present or is empty if all of the other specified fields are present. +func excludedWithAll(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if requireCheckFieldKind(fl, param, true) { + return true + } + } + return !hasValue(fl) +} + // RequiredWithAll is the validation function // The field under validation must be present and not empty only if all of the other specified fields are present. func requiredWithAll(fl FieldLevel) bool { @@ -1407,6 +1435,15 @@ func requiredWithAll(fl FieldLevel) bool { return hasValue(fl) } +// ExcludedWithout is the validation function +// The field under validation must not be present or is empty when any of the other specified fields are not present. +func excludedWithout(fl FieldLevel) bool { + if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { + return !hasValue(fl) + } + return true +} + // RequiredWithout is the validation function // The field under validation must be present and not empty only when any of the other specified fields are not present. func requiredWithout(fl FieldLevel) bool { @@ -1416,6 +1453,18 @@ func requiredWithout(fl FieldLevel) bool { return true } +// RequiredWithoutAll is the validation function +// The field under validation must not be present or is empty when all of the other specified fields are not present. +func excludedWithoutAll(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if !requireCheckFieldKind(fl, param, true) { + return true + } + } + return !hasValue(fl) +} + // RequiredWithoutAll is the validation function // The field under validation must be present and not empty only when all of the other specified fields are not present. func requiredWithoutAll(fl FieldLevel) bool { From 490e2537923b67d8a5b6d96111aff7768a06a34b Mon Sep 17 00:00:00 2001 From: root Date: Tue, 15 Sep 2020 19:40:20 +0200 Subject: [PATCH 17/23] Closes #660 added excluded with and without tests --- validator_test.go | 262 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) diff --git a/validator_test.go b/validator_test.go index e76a3cd..714b71b 100644 --- a/validator_test.go +++ b/validator_test.go @@ -8750,6 +8750,268 @@ func TestRequiredWith(t *testing.T) { 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") + } +} + +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") + } +} + +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") + } +} + +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 Inner.Field2" 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_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") + } +} + func TestRequiredWithAll(t *testing.T) { type Inner struct { Field *string From ca0533bb970bed5f048a23479ea9881fb70ca285 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 15 Sep 2020 19:45:48 +0200 Subject: [PATCH 18/23] Closes #660 readme updates --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f552826..eec60ea 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,10 @@ Baked-in Validations | required_with_all | Required With All | | required_without | Required Without | | required_without_all | Required Without All | +| excluded_with | Excluded With | +| excluded_with_all | Excluded With All | +| excluded_without | Excluded Without | +| excluded_without_all | Excluded Without All | | unique | Unique | Benchmarks From 1bf11c92993341053af72a7a99d6d9a76425dc1e Mon Sep 17 00:00:00 2001 From: David Ketch Date: Wed, 16 Sep 2020 15:14:29 -0500 Subject: [PATCH 19/23] Includes Error in FieldError's interface --- errors.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/errors.go b/errors.go index 86420b9..9682052 100644 --- a/errors.go +++ b/errors.go @@ -155,6 +155,9 @@ type FieldError interface { // NOTE: if no registered translator can be found it returns the same as // calling fe.Error() Translate(ut ut.Translator) string + + // Error returns the FieldError's message + Error() string } // compile time interface checks From f2ce6a4f9288fb6dd8cc205b6e5c7694b13623f6 Mon Sep 17 00:00:00 2001 From: Takeshi Kaneko Date: Thu, 17 Sep 2020 21:04:54 +0900 Subject: [PATCH 20/23] Fix a category of endswith in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f552826..1f795dd 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ Baked-in Validations | contains | Contains | | containsany | Contains Any | | containsrune | Contains Rune | +| endswith | Ends With | | lowercase | Lowercase | | multibyte | Multi-Byte Characters | | number | NOT DOCUMENTED IN doc.go | @@ -186,7 +187,6 @@ Baked-in Validations | - | - | | dir | Directory | | e164 | NOT DOCUMENTED IN doc.go | -| endswith | Ends With | | excludes | Excludes | | excludesall | Excludes All | | excludesrune | Excludes Rune | From 0d657b4731be9539ccb8e6fc1cce2452d34231e1 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 27 Sep 2020 11:04:00 -0700 Subject: [PATCH 21/23] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6484f3..641b331 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - 1.13.7 + - 1.15.2 - tip matrix: allow_failures: @@ -26,4 +26,4 @@ script: after_success: | [ $TRAVIS_GO_VERSION = 1.13.7 ] && - goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN \ No newline at end of file + goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN From ace513eddd249390d67a8c04e219aaa0b4e82fc1 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 27 Sep 2020 11:04:12 -0700 Subject: [PATCH 22/23] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 641b331..85a7be3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,5 +25,5 @@ script: - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... after_success: | - [ $TRAVIS_GO_VERSION = 1.13.7 ] && + [ $TRAVIS_GO_VERSION = 1.15.2 ] && goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN From d9e95d55e9ee3f1db93a7ab765aac0b14346c191 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 27 Sep 2020 11:35:18 -0700 Subject: [PATCH 23/23] Update errors.go --- errors.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/errors.go b/errors.go index 9682052..63293cf 100644 --- a/errors.go +++ b/errors.go @@ -257,8 +257,8 @@ func (fe *fieldError) Error() string { // Translate returns the FieldError's translated error // from the provided 'ut.Translator' and registered 'TranslationFunc' // -// NOTE: is not registered translation can be found it returns the same -// as calling fe.Error() +// NOTE: if no registered translation can be found, it returns the original +// untranslated error message. func (fe *fieldError) Translate(ut ut.Translator) string { m, ok := fe.v.transTagFunc[ut]