Skip to content

Commit

Permalink
Fixes #33: Added RuneLength validator
Browse files Browse the repository at this point in the history
  • Loading branch information
qiangxue committed Sep 13, 2017
1 parent 2a0d4bd commit 85dcd83
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,9 @@ The following rules are provided in the `validation` package:
* `In(...interface{})`: checks if a value can be found in the given list of values.
* `Length(min, max int)`: checks if the length of a value is within the specified range.
This rule should only be used for validating strings, slices, maps, and arrays.
* `RuneLength(min, max int)`: checks if the length of a string is within the specified range.
This rule is similar as `Length` except that when the value being validated is a string, it checks
its rune length instead of byte length.
* `Min(min interface{})` and `Max(max interface{})`: checks if a value is within the specified range.
These two rules should only be used for validating int, uint, float and time.Time types.
* `Match(*regexp.Regexp)`: checks if a value matches the specified regular expression.
Expand Down
22 changes: 20 additions & 2 deletions length.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package validation
import (
"errors"
"fmt"
"unicode/utf8"
)

// Length returns a validation rule that checks if a value's length is within the specified range.
Expand All @@ -29,9 +30,21 @@ func Length(min, max int) *lengthRule {
}
}

// RuneLength returns a validation rule that checks if a string's rune length is within the specified range.
// If max is 0, it means there is no upper bound for the length.
// This rule should only be used for validating strings, slices, maps, and arrays.
// An empty value is considered valid. Use the Required rule to make sure a value is not empty.
// If the value being validated is not a string, the rule works the same as Length.
func RuneLength(min, max int) *lengthRule {
r := Length(min, max)
r.rune = true
return r
}

type lengthRule struct {
min, max int
message string
rune bool
}

// Validate checks if the given value is valid or not.
Expand All @@ -41,8 +54,13 @@ func (v *lengthRule) Validate(value interface{}) error {
return nil
}

l, err := LengthOfValue(value)
if err != nil {
var (
l int
err error
)
if s, ok := value.(string); ok && v.rune {
l = utf8.RuneCountInString(s)
} else if l, err = LengthOfValue(value); err != nil {
return err
}

Expand Down
35 changes: 35 additions & 0 deletions length_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,41 @@ func TestLength(t *testing.T) {
}
}

func TestRuneLength(t *testing.T) {
var v *string
tests := []struct {
tag string
min, max int
value interface{}
err string
}{
{"t1", 2, 4, "abc", ""},
{"t1.1", 2, 3, "💥💥", ""},
{"t1.2", 2, 3, "💥💥💥", ""},
{"t1.3", 2, 3, "💥", "the length must be between 2 and 3"},
{"t1.4", 2, 3, "💥💥💥💥", "the length must be between 2 and 3"},
{"t2", 2, 4, "", ""},
{"t3", 2, 4, "abcdf", "the length must be between 2 and 4"},
{"t4", 0, 4, "ab", ""},
{"t5", 0, 4, "abcde", "the length must be no more than 4"},
{"t6", 2, 0, "ab", ""},
{"t7", 2, 0, "a", "the length must be no less than 2"},
{"t8", 2, 0, v, ""},
{"t9", 2, 0, 123, "cannot get the length of int"},
{"t10", 2, 4, sql.NullString{String: "abc", Valid: true}, ""},
{"t11", 2, 4, sql.NullString{String: "", Valid: true}, ""},
{"t12", 2, 4, &sql.NullString{String: "abc", Valid: true}, ""},
{"t13", 2, 3, &sql.NullString{String: "💥💥", Valid: true}, ""},
{"t14", 2, 3, &sql.NullString{String: "💥", Valid: true}, "the length must be between 2 and 3"},
}

for _, test := range tests {
r := RuneLength(test.min, test.max)
err := r.Validate(test.value)
assertError(t, test.err, err, test.tag)
}
}

func Test_lengthRule_Error(t *testing.T) {
r := Length(10, 20)
assert.Equal(t, "the length must be between 10 and 20", r.message)
Expand Down

0 comments on commit 85dcd83

Please sign in to comment.