From 2073d33609bc6741d94bd278b98e7837e829581f Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 15 Feb 2015 23:20:33 -0500 Subject: [PATCH] issue-#1 add lt validation function + test code add lte validation function + test code add gt validation function + test code add get validation function + test code --- baked_in.go | 116 ++++++++++++++++++++++++++++++++++++++++------ doc.go | 21 +++++++++ validator_test.go | 40 +++++++++++++++- 3 files changed, 160 insertions(+), 17 deletions(-) diff --git a/baked_in.go b/baked_in.go index 76bc0c6..a0285b3 100644 --- a/baked_in.go +++ b/baked_in.go @@ -13,6 +13,10 @@ var BakedInValidators = map[string]ValidationFunc{ "len": length, "min": min, "max": max, + "lt": lt, + "lte": lte, + "gt": gt, + "gte": gte, "alpha": alpha, "alphanum": alphanum, "numeric": numeric, @@ -183,6 +187,78 @@ func required(field interface{}, param string) bool { } } +func gte(field interface{}, param string) bool { + + st := reflect.ValueOf(field) + + switch st.Kind() { + + case reflect.String: + p := asInt(param) + + return int64(len(st.String())) >= p + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(st.Len()) >= p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asInt(param) + + return st.Int() >= p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return st.Uint() >= p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return st.Float() >= p + + default: + panic(fmt.Sprintf("Bad field type for Input Param %s for %s\n", param, field)) + } +} + +func gt(field interface{}, param string) bool { + + st := reflect.ValueOf(field) + + switch st.Kind() { + + case reflect.String: + p := asInt(param) + + return int64(len(st.String())) > p + + case reflect.Slice, reflect.Map, reflect.Array: + p := asInt(param) + + return int64(st.Len()) > p + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p := asInt(param) + + return st.Int() > p + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p := asUint(param) + + return st.Uint() > p + + case reflect.Float32, reflect.Float64: + p := asFloat(param) + + return st.Float() > p + + default: + panic(fmt.Sprintf("Bad field type for Input Param %s for %s\n", param, field)) + } +} + // length tests whether a variable's length is equal to a given // value. For strings it tests the number of characters whereas // for maps and slices it tests the number of items. @@ -228,6 +304,11 @@ func length(field interface{}, param string) bool { // and slices it tests the number of items. func min(field interface{}, param string) bool { + return gte(field, param) +} + +func lte(field interface{}, param string) bool { + st := reflect.ValueOf(field) switch st.Kind() { @@ -235,38 +316,34 @@ func min(field interface{}, param string) bool { case reflect.String: p := asInt(param) - return int64(len(st.String())) >= p + return int64(len(st.String())) <= p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) - return int64(st.Len()) >= p + return int64(st.Len()) <= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) - return st.Int() >= p + return st.Int() <= p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) - return st.Uint() >= p + return st.Uint() <= p case reflect.Float32, reflect.Float64: p := asFloat(param) - return st.Float() >= p + return st.Float() <= p default: panic(fmt.Sprintf("Bad field type for Input Param %s for %s\n", param, field)) } } -// max tests whether a variable value is lesser than a given -// value. For numbers, it's a simple lesser-than test; for -// strings it tests the number of characters whereas for maps -// and slices it tests the number of items. -func max(field interface{}, param string) bool { +func lt(field interface{}, param string) bool { st := reflect.ValueOf(field) @@ -275,33 +352,42 @@ func max(field interface{}, param string) bool { case reflect.String: p := asInt(param) - return int64(len(st.String())) <= p + return int64(len(st.String())) < p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) - return int64(st.Len()) <= p + return int64(st.Len()) < p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) - return st.Int() <= p + return st.Int() < p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) - return st.Uint() <= p + return st.Uint() < p case reflect.Float32, reflect.Float64: p := asFloat(param) - return st.Float() <= p + return st.Float() < p default: panic(fmt.Sprintf("Bad field type for Input Param %s for %s\n", param, field)) } } +// max tests whether a variable value is lesser than a given +// value. For numbers, it's a simple lesser-than test; for +// strings it tests the number of characters whereas for maps +// and slices it tests the number of items. +func max(field interface{}, param string) bool { + + return lte(field, param) +} + // asInt retuns the parameter as a int64 // or panics if it can't convert func asInt(param string) int64 { diff --git a/doc.go b/doc.go index 5485a8e..8a4e074 100644 --- a/doc.go +++ b/doc.go @@ -163,6 +163,27 @@ Here is a list of the current built in validators: the string length is at least that number of characters. For slices, arrays, and maps, validates the number of items. (Usage: min=10) + gt + For numbers, this will ensure that the value is greater than the + parameter given. For strings, it checks that the string length + is greater than that number of characters. For slices, arrays + and maps it validates the number of items. (Usage: gt=10) + + gte + Same as 'min' above. Kept both to make terminology with 'len' easier + (Usage: gte=10) + + lt + For numbers, this will ensure that the value is + less than the parameter given. For strings, it checks + that the string length is less than that number of characters. + For slices, arrays, and maps it validates the number of items. + (Usage: lt=10) + + lte + Same as 'max' above. Kept both to make terminology with 'len' easier + (Usage: lte=10) + alpha This validates that a strings value contains alpha characters only (Usage: alpha) diff --git a/validator_test.go b/validator_test.go index e677dc0..6940dfb 100644 --- a/validator_test.go +++ b/validator_test.go @@ -34,6 +34,10 @@ type TestString struct { Min string `validate:"min=1"` Max string `validate:"max=10"` MinMax string `validate:"min=1,max=10"` + Lt string `validate:"lt=10"` + Lte string `validate:"lte=10"` + Gt string `validate:"gt=10"` + Gte string `validate:"gte=10"` OmitEmpty string `validate:"omitempty,min=1,max=10"` Sub *SubTest SubIgnore *SubTest `validate:"-"` @@ -49,6 +53,10 @@ type TestInt32 struct { Min int `validate:"min=1"` Max int `validate:"max=10"` MinMax int `validate:"min=1,max=10"` + Lt int `validate:"lt=10"` + Lte int `validate:"lte=10"` + Gt int `validate:"gt=10"` + Gte int `validate:"gte=10"` OmitEmpty int `validate:"omitempty,min=1,max=10"` } @@ -425,6 +433,10 @@ func (ms *MySuite) TestFlattening(c *C) { Min: "min=1", Max: "1234567890", MinMax: "12345", + Lt: "012345678", + Lte: "0123456789", + Gt: "01234567890", + Gte: "0123456789", OmitEmpty: "", Sub: &SubTest{ Test: "1", @@ -472,6 +484,8 @@ func (ms *MySuite) TestFlattening(c *C) { // Assert Fields AssertMapFieldError(err2, "Len", "len", c) + AssertMapFieldError(err2, "Gt", "gt", c) + AssertMapFieldError(err2, "Gte", "gte", c) // Assert Struct Field AssertMapFieldError(err2, "Sub.Test", "required", c) @@ -491,6 +505,10 @@ func (ms *MySuite) TestStructStringValidation(c *C) { Min: "min=1", Max: "1234567890", MinMax: "12345", + Lt: "012345678", + Lte: "0123456789", + Gt: "01234567890", + Gte: "0123456789", OmitEmpty: "", Sub: &SubTest{ Test: "1", @@ -517,6 +535,10 @@ func (ms *MySuite) TestStructStringValidation(c *C) { Min: "", Max: "12345678901", MinMax: "", + Lt: "0123456789", + Lte: "01234567890", + Gt: "1", + Gte: "1", OmitEmpty: "12345678901", Sub: &SubTest{ Test: "", @@ -536,7 +558,7 @@ func (ms *MySuite) TestStructStringValidation(c *C) { // Assert Top Level c.Assert(err, NotNil) c.Assert(err.Struct, Equals, "TestString") - c.Assert(len(err.Errors), Equals, 6) + c.Assert(len(err.Errors), Equals, 10) c.Assert(len(err.StructErrors), Equals, 3) // Assert Fields @@ -545,6 +567,8 @@ func (ms *MySuite) TestStructStringValidation(c *C) { AssertFieldError(err, "Min", "min", c) AssertFieldError(err, "Max", "max", c) AssertFieldError(err, "MinMax", "min", c) + AssertFieldError(err, "Gt", "gt", c) + AssertFieldError(err, "Gte", "gte", c) AssertFieldError(err, "OmitEmpty", "max", c) // Assert Anonymous embedded struct @@ -566,6 +590,10 @@ func (ms *MySuite) TestStructInt32Validation(c *C) { Min: 1, Max: 10, MinMax: 5, + Lt: 9, + Lte: 10, + Gt: 11, + Gte: 10, OmitEmpty: 0, } @@ -578,6 +606,10 @@ func (ms *MySuite) TestStructInt32Validation(c *C) { Min: -1, Max: 11, MinMax: -1, + Lt: 10, + Lte: 11, + Gt: 10, + Gte: 9, OmitEmpty: 11, } @@ -586,7 +618,7 @@ func (ms *MySuite) TestStructInt32Validation(c *C) { // Assert Top Level c.Assert(err, NotNil) c.Assert(err.Struct, Equals, "TestInt32") - c.Assert(len(err.Errors), Equals, 6) + c.Assert(len(err.Errors), Equals, 10) c.Assert(len(err.StructErrors), Equals, 0) // Assert Fields @@ -595,6 +627,10 @@ func (ms *MySuite) TestStructInt32Validation(c *C) { AssertFieldError(err, "Min", "min", c) AssertFieldError(err, "Max", "max", c) AssertFieldError(err, "MinMax", "min", c) + AssertFieldError(err, "Lt", "lt", c) + AssertFieldError(err, "Lte", "lte", c) + AssertFieldError(err, "Gt", "gt", c) + AssertFieldError(err, "Gte", "gte", c) AssertFieldError(err, "OmitEmpty", "max", c) }