diff --git a/README.md b/README.md index f184196..9001de0 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Each validation rule in GoValidator has it's own default message, e.g: `required | RequiredSlice | `RequiredSlice` checks if a slice has any value or not. | | BetweenInt | `BetweenInt` checks whether value falls within the specified range or not. | | BetweenFloat | `BetweenFloat` checks whether value falls within the specified range or not. | +| BetweenString | `BetweenString` checks whether string length falls within the specified range or not. | | Date | `Date` checks value to be a valid, non-relative date. | | Email | `Email` checks value to match `EmailRegex` regular expression. | | Exists | `Exists` checks given value exists in given table or not. | diff --git a/between.go b/between.go index fd2011c..c9addd8 100644 --- a/between.go +++ b/between.go @@ -1,5 +1,11 @@ package govalidator +import ( + "fmt" + "strings" + "unicode/utf8" +) + const ( // Between represents rule name which will be used to find the default error message. Between = "between" @@ -36,3 +42,19 @@ func (v Validator) BetweenFloat(f, min, max float64, field, msg string) Validato return v } + +// BetweenString checks if the length of given string to have an integer value between the given min and max. +// +// Example: +// +// v := validator.New() +// v.BetweenString("Obi-one", 3, 10, "name", "name must be between 3 and 10 characters.") +// if v.IsFailed() { +// fmt.Printf("validation errors: %#v\n", v.Errors()) +// } +func (v Validator) BetweenString(s string, minLen, maxLen int, field, msg string) Validator { + v.check(utf8.RuneCountInString(strings.TrimSpace(s)) >= minLen && utf8.RuneCountInString(strings.TrimSpace(s)) <= maxLen, field, + v.msg(Between, msg, fmt.Sprintf("%s length", field), minLen, maxLen)) + + return v +} diff --git a/between_test.go b/between_test.go index 4f79823..bae21c3 100644 --- a/between_test.go +++ b/between_test.go @@ -151,3 +151,96 @@ func Test_BetweenFloat(t *testing.T) { } } } + +func Test_BetweenString(t *testing.T) { + tests := []struct { + name string + field string + value string + min int + max int + isPassed bool + msg string + expectedMsg string + }{ + { + name: "test string length of `Hi there!` is within [3, 35] range", + field: "greeting", + value: "Hi there!", + min: 3, + max: 35, + isPassed: true, + msg: "", + expectedMsg: "", + }, + { + name: "test string length of `hey` is within [3, 35] range", + field: "greeting", + value: "hey", + min: 3, + max: 35, + isPassed: true, + msg: "", + expectedMsg: "", + }, + { + name: "test string length of `hi` is not within [3, 35] range", + field: "greeting", + value: "hi", + min: 3, + max: 35, + isPassed: false, + msg: "", + expectedMsg: "greeting length should be greater than or equal 3 and less than or equal 35", + }, + { + name: "test string length of `hi` is not within [3, 35] range with custom msg", + field: "greeting", + value: "hi", + min: 3, + max: 35, + isPassed: false, + msg: "The length of greeting should be greater than or equal 3 and less than or equal 35", + expectedMsg: "The length of greeting should be greater than or equal 3 and less than or equal 35", + }, + { + name: "test string length of `Hi there lovely, how are you today sweetheart?` is not within [3, 35] range", + field: "greeting", + value: "Hi there lovely, how are you today sweetheart?", + min: 3, + max: 35, + isPassed: false, + msg: "", + expectedMsg: "greeting length should be greater than or equal 3 and less than or equal 35", + }, + { + name: "test string length of `Hi there lovely, how are you today sweetheart?` is not within [3, 35] range with custom msg", + field: "greeting", + value: "Hi there lovely, how are you today sweetheart?", + min: 3, + max: 35, + isPassed: false, + msg: "The length of greeting should be greater than or equal 3 and less than or equal 35", + expectedMsg: "The length of greeting should be greater than or equal 3 and less than or equal 35", + }, + } + + for _, test := range tests { + v := New() + + v.BetweenString(test.value, test.min, test.max, test.field, test.msg) + + assert.Equal(t, test.isPassed, v.IsPassed()) + + if !test.isPassed { + assert.Equalf( + t, + test.expectedMsg, + v.Errors()[test.field], + "test case %q failed, expected: %s, got: %s", + test.expectedMsg, + v.Errors()[test.field], + ) + } + } +} diff --git a/required_test.go b/required_test.go index 1f40b01..c210f57 100644 --- a/required_test.go +++ b/required_test.go @@ -16,7 +16,7 @@ func Test_RequiredInt(t *testing.T) { expectedMsg string }{ { - name: "test integer value of `21` will pass the required int valiation", + name: "test integer value of `21` will pass the required int validation", field: "age", value: 21, isPassed: true, @@ -24,7 +24,7 @@ func Test_RequiredInt(t *testing.T) { expectedMsg: "", }, { - name: "test integer value of `0` won't pass the required int valiation", + name: "test integer value of `0` won't pass the required int validation", field: "age", value: 0, isPassed: false, @@ -32,7 +32,7 @@ func Test_RequiredInt(t *testing.T) { expectedMsg: "age is required", }, { - name: "test integer value of `0` won't pass the required int valiation", + name: "test integer value of `0` won't pass the required int validation", field: "age", value: 0, isPassed: false, @@ -71,7 +71,7 @@ func Test_RequiredString(t *testing.T) { expectedMsg string }{ { - name: "test string value of `lion` will pass the required string valiation", + name: "test string value of `lion` will pass the required string validation", field: "animal", value: "lion", isPassed: true, @@ -79,7 +79,7 @@ func Test_RequiredString(t *testing.T) { expectedMsg: "", }, { - name: "test string value of `1160277052` will pass the required string valiation", + name: "test string value of `1160277052` will pass the required string validation", field: "id", value: "1160277052", isPassed: true, @@ -87,7 +87,7 @@ func Test_RequiredString(t *testing.T) { expectedMsg: "", }, { - name: "test emtpy string value won't pass the required string valiation", + name: "test emtpy string value won't pass the required string validation", field: "name", value: "", isPassed: false, @@ -95,7 +95,7 @@ func Test_RequiredString(t *testing.T) { expectedMsg: "name is required", }, { - name: "test emtpy space string value won't pass the required string valiation", + name: "test emtpy space string value won't pass the required string validation", field: "last_name", value: " ", isPassed: false, @@ -134,7 +134,7 @@ func Test_RequiredFloat(t *testing.T) { expectedMsg string }{ { - name: "test float value of `12.23` will pass the required float valiation", + name: "test float value of `12.23` will pass the required float validation", field: "average", value: 12.23, isPassed: true, @@ -142,7 +142,7 @@ func Test_RequiredFloat(t *testing.T) { expectedMsg: "", }, { - name: "test float value of `0` won't pass the required float valiation", + name: "test float value of `0` won't pass the required float validation", field: "score", value: 0, isPassed: false, @@ -150,7 +150,7 @@ func Test_RequiredFloat(t *testing.T) { expectedMsg: "score is required", }, { - name: "test float value of `0` won't pass the required float valiation", + name: "test float value of `0` won't pass the required float validation", field: "number", value: 0, isPassed: false, @@ -189,7 +189,7 @@ func Test_RequiredSlice(t *testing.T) { expectedMsg string }{ { - name: "test slice of `[]{1, 2, 3}` will pass the required slice valiation", + name: "test slice of `[]{1, 2, 3}` will pass the required slice validation", field: "scores", value: []any{1, 2, 3}, isPassed: true, @@ -197,7 +197,7 @@ func Test_RequiredSlice(t *testing.T) { expectedMsg: "", }, { - name: "test slice of `{2.2, 12.6, 13.6}` will pass the required slice valiation", + name: "test slice of `{2.2, 12.6, 13.6}` will pass the required slice validation", field: "averages", value: []any{2.2, 12.6, 13.6}, isPassed: true, @@ -205,7 +205,7 @@ func Test_RequiredSlice(t *testing.T) { expectedMsg: "", }, { - name: "test emtpy slice won't pass the required slice valiation", + name: "test emtpy slice won't pass the required slice validation", field: "scores", value: []any{}, isPassed: false, @@ -213,7 +213,7 @@ func Test_RequiredSlice(t *testing.T) { expectedMsg: "scores is required", }, { - name: "test slice of names won't pass the required slice valiation", + name: "test slice of names won't pass the required slice validation", field: "names", value: []any{}, isPassed: false,