Skip to content

Commit d7abf32

Browse files
Add oneofci validator (oneof case insensitive) (#1321)
## Fixes Or Enhances - Adds oneofci, a case insensitive version of oneof - resolves #840 **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. @go-playground/validator-maintainers
1 parent 078d0c0 commit d7abf32

File tree

3 files changed

+101
-0
lines changed

3 files changed

+101
-0
lines changed

baked_in.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ var (
205205
"fqdn": isFQDN,
206206
"unique": isUnique,
207207
"oneof": isOneOf,
208+
"oneofci": isOneOfCI,
208209
"html": isHTML,
209210
"html_encoded": isHTMLEncoded,
210211
"url_encoded": isURLEncoded,
@@ -299,6 +300,23 @@ func isOneOf(fl FieldLevel) bool {
299300
return false
300301
}
301302

303+
// isOneOfCI is the validation function for validating if the current field's value is one of the provided string values (case insensitive).
304+
func isOneOfCI(fl FieldLevel) bool {
305+
vals := parseOneOfParam2(fl.Param())
306+
field := fl.Field()
307+
308+
if field.Kind() != reflect.String {
309+
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
310+
}
311+
v := field.String()
312+
for _, val := range vals {
313+
if strings.EqualFold(val, v) {
314+
return true
315+
}
316+
}
317+
return false
318+
}
319+
302320
// isUnique is the validation function for validating if each array|slice|map value is unique
303321
func isUnique(fl FieldLevel) bool {
304322
field := fl.Field()

doc.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,13 @@ the target string between single quotes. Kind of like an 'enum'.
495495
oneof='red green' 'blue yellow'
496496
oneof=5 7 9
497497
498+
# One Of Case Insensitive
499+
500+
Works the same as oneof but is case insensitive and therefore only accepts strings.
501+
502+
Usage: oneofci=red green
503+
oneofci='red green' 'blue yellow'
504+
498505
# Greater Than
499506
500507
For numbers, this will ensure that the value is greater than the

validator_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5680,6 +5680,82 @@ func TestOneOfValidation(t *testing.T) {
56805680
}, "Bad field type float64")
56815681
}
56825682

5683+
func TestOneOfCIValidation(t *testing.T) {
5684+
validate := New()
5685+
5686+
passSpecs := []struct {
5687+
f interface{}
5688+
t string
5689+
}{
5690+
{f: "red", t: "oneofci=RED GREEN"},
5691+
{f: "RED", t: "oneofci=red green"},
5692+
{f: "red", t: "oneofci=red green"},
5693+
{f: "RED", t: "oneofci=RED GREEN"},
5694+
{f: "green", t: "oneofci=red green"},
5695+
{f: "red green", t: "oneofci='red green' blue"},
5696+
{f: "blue", t: "oneofci='red green' blue"},
5697+
{f: "GREEN", t: "oneofci=Red Green"},
5698+
{f: "ReD", t: "oneofci=RED GREEN"},
5699+
{f: "gReEn", t: "oneofci=rEd GrEeN"},
5700+
{f: "RED GREEN", t: "oneofci='red green' blue"},
5701+
{f: "red Green", t: "oneofci='RED GREEN' Blue"},
5702+
{f: "Red green", t: "oneofci='Red Green' BLUE"},
5703+
{f: "rEd GrEeN", t: "oneofci='ReD gReEn' BlUe"},
5704+
{f: "BLUE", t: "oneofci='Red Green' BLUE"},
5705+
{f: "BlUe", t: "oneofci='RED GREEN' Blue"},
5706+
{f: "bLuE", t: "oneofci='red green' BLUE"},
5707+
}
5708+
5709+
for _, spec := range passSpecs {
5710+
t.Logf("%#v", spec)
5711+
errs := validate.Var(spec.f, spec.t)
5712+
Equal(t, errs, nil)
5713+
}
5714+
5715+
failSpecs := []struct {
5716+
f interface{}
5717+
t string
5718+
}{
5719+
{f: "", t: "oneofci=red green"},
5720+
{f: "yellow", t: "oneofci=red green"},
5721+
{f: "green", t: "oneofci='red green' blue"},
5722+
}
5723+
5724+
for _, spec := range failSpecs {
5725+
t.Logf("%#v", spec)
5726+
errs := validate.Var(spec.f, spec.t)
5727+
AssertError(t, errs, "", "", "", "", "oneofci")
5728+
}
5729+
5730+
panicSpecs := []struct {
5731+
f interface{}
5732+
t string
5733+
}{
5734+
{f: 3.14, t: "oneofci=red green"},
5735+
{f: 5, t: "oneofci=red green"},
5736+
{f: uint(6), t: "oneofci=7"},
5737+
{f: int8(5), t: "oneofci=red green"},
5738+
{f: int16(5), t: "oneofci=red green"},
5739+
{f: int32(5), t: "oneofci=red green"},
5740+
{f: int64(5), t: "oneofci=red green"},
5741+
{f: uint(5), t: "oneofci=red green"},
5742+
{f: uint8(5), t: "oneofci=red green"},
5743+
{f: uint16(5), t: "oneofci=red green"},
5744+
{f: uint32(5), t: "oneofci=red green"},
5745+
{f: uint64(5), t: "oneofci=red green"},
5746+
}
5747+
5748+
panicCount := 0
5749+
for _, spec := range panicSpecs {
5750+
t.Logf("%#v", spec)
5751+
PanicMatches(t, func() {
5752+
_ = validate.Var(spec.f, spec.t)
5753+
}, fmt.Sprintf("Bad field type %T", spec.f))
5754+
panicCount++
5755+
}
5756+
Equal(t, panicCount, len(panicSpecs))
5757+
}
5758+
56835759
func TestBase32Validation(t *testing.T) {
56845760
validate := New()
56855761

0 commit comments

Comments
 (0)