From 432c17028aaf531a17166dc4c40826e8661b3df9 Mon Sep 17 00:00:00 2001 From: Jonathan Thom Date: Sat, 16 Nov 2019 23:00:37 -0800 Subject: [PATCH 1/2] Adds ability to validate oneof for space separated strings Fixes Or Enhances https://github.com/go-playground/validator/issues/525. **Make sure that you've checked the boxes below before you submit PR:** - [x] Tests exist or have been written that cover this particular change. Change Details: * Adds the ability to match on space separated strings when using the `oneof` validation. Space separted strings must be surrounded by single quotes to be validated as one string. For example: ``` oneof='Awaiting Verification' 'Verified' 'Failed Verification' ``` passes validation for a field that is exactly `Failed Verification` (though just `Failed` would...fail). @go-playground/admins --- baked_in.go | 7 +++++-- doc.go | 6 ++++-- validator_test.go | 5 ++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/baked_in.go b/baked_in.go index 95d613c..8fad9c2 100644 --- a/baked_in.go +++ b/baked_in.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "reflect" + "regexp" "strconv" "strings" "sync" @@ -177,7 +178,8 @@ func parseOneOfParam2(s string) []string { oneofValsCacheRWLock.RUnlock() if !ok { oneofValsCacheRWLock.Lock() - vals = strings.Fields(s) + re := regexp.MustCompile(`'[^']*'|\S+`) + vals = re.FindAllString(s, -1) oneofValsCache[s] = vals oneofValsCacheRWLock.Unlock() } @@ -213,7 +215,8 @@ func isOneOf(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } for i := 0; i < len(vals); i++ { - if vals[i] == v { + val := strings.Replace(vals[i], "'", "", -1) + if val == v { return true } } diff --git a/doc.go b/doc.go index 95029dd..cdfb759 100644 --- a/doc.go +++ b/doc.go @@ -361,10 +361,12 @@ One Of For strings, ints, and uints, oneof will ensure that the value is one of the values in the parameter. The parameter should be -a list of values separated by whitespace. Values may be -strings or numbers. +a list of values separated by whitespace. Values may be +strings or numbers. To match strings with spaces in them, include +the target string between single quotes. Usage: oneof=red green + oneof='red green' 'blue yellow' oneof=5 7 9 Greater Than diff --git a/validator_test.go b/validator_test.go index d74247f..e64a91b 100644 --- a/validator_test.go +++ b/validator_test.go @@ -14,11 +14,11 @@ import ( "testing" "time" + . "github.com/go-playground/assert/v2" "github.com/go-playground/locales/en" "github.com/go-playground/locales/fr" "github.com/go-playground/locales/nl" ut "github.com/go-playground/universal-translator" - . "github.com/go-playground/assert/v2" ) // NOTES: @@ -4484,6 +4484,8 @@ func TestOneOfValidation(t *testing.T) { }{ {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"}, @@ -4509,6 +4511,7 @@ func TestOneOfValidation(t *testing.T) { }{ {f: "", t: "oneof=red green"}, {f: "yellow", t: "oneof=red green"}, + {f: "green", t: "oneof='red green' blue"}, {f: 5, t: "oneof=red green"}, {f: 6, t: "oneof=red green"}, {f: 6, t: "oneof=7"}, From 685d3e21f3435f9f0ac9b7647fc31f32e49e4f63 Mon Sep 17 00:00:00 2001 From: Jonathan Thom Date: Wed, 20 Nov 2019 20:01:45 -0800 Subject: [PATCH 2/2] Makes regex constant & moves single quote replace logic to parseOneOfParam2 --- baked_in.go | 10 +++++----- regexes.go | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/baked_in.go b/baked_in.go index 8fad9c2..ff4da23 100644 --- a/baked_in.go +++ b/baked_in.go @@ -9,7 +9,6 @@ import ( "net/url" "os" "reflect" - "regexp" "strconv" "strings" "sync" @@ -178,8 +177,10 @@ func parseOneOfParam2(s string) []string { oneofValsCacheRWLock.RUnlock() if !ok { oneofValsCacheRWLock.Lock() - re := regexp.MustCompile(`'[^']*'|\S+`) - vals = re.FindAllString(s, -1) + vals = splitParamsRegex.FindAllString(s, -1) + for i := 0; i < len(vals); i++ { + vals[i] = strings.Replace(vals[i], "'", "", -1) + } oneofValsCache[s] = vals oneofValsCacheRWLock.Unlock() } @@ -215,8 +216,7 @@ func isOneOf(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } for i := 0; i < len(vals); i++ { - val := strings.Replace(vals[i], "'", "", -1) - if val == v { + if vals[i] == v { return true } } diff --git a/regexes.go b/regexes.go index 0253d70..fac2545 100644 --- a/regexes.go +++ b/regexes.go @@ -46,6 +46,7 @@ const ( uRLEncodedRegexString = `(%[A-Fa-f0-9]{2})` hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?` hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` + splitParamsRegexString = `'[^']*'|\S+` ) var ( @@ -92,4 +93,5 @@ var ( uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) hTMLRegex = regexp.MustCompile(hTMLRegexString) + splitParamsRegex = regexp.MustCompile(splitParamsRegexString) )