Merge pull request #307 from go-playground/fix_fqdn

Fix fqdn + add isdefault
pull/317/head v9.7.0
Dean Karn 7 years ago committed by GitHub
commit a021b2ec9a
  1. 2
      README.md
  2. 11
      baked_in.go
  3. 5
      cache.go
  4. 7
      doc.go
  5. 39
      validator.go
  6. 1
      validator_instance.go
  7. 59
      validator_test.go

@ -1,7 +1,7 @@
Package validator Package validator
================ ================
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-9.6.0-green.svg) ![Project status](https://img.shields.io/badge/version-9.7.0-green.svg)
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/validator) [![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)

@ -39,6 +39,7 @@ var (
utf8Pipe: {}, utf8Pipe: {},
noStructLevelTag: {}, noStructLevelTag: {},
requiredTag: {}, requiredTag: {},
isdefault: {},
} }
// BakedInAliasValidators is a default mapping of a single validation tag that // BakedInAliasValidators is a default mapping of a single validation tag that
@ -53,6 +54,7 @@ var (
// or even disregard and use your own map if so desired. // or even disregard and use your own map if so desired.
bakedInValidators = map[string]Func{ bakedInValidators = map[string]Func{
"required": hasValue, "required": hasValue,
"isdefault": isDefault,
"len": hasLengthOf, "len": hasLengthOf,
"min": hasMinOf, "min": hasMinOf,
"max": hasMaxOf, "max": hasMaxOf,
@ -905,6 +907,11 @@ func isAlphaUnicode(fl FieldLevel) bool {
return alphaUnicodeRegex.MatchString(fl.Field().String()) return alphaUnicodeRegex.MatchString(fl.Field().String())
} }
// isDefault is the opposite of required aka hasValue
func isDefault(fl FieldLevel) bool {
return !hasValue(fl)
}
// HasValue is the validation function for validating if the current field's value is not the default static value. // HasValue is the validation function for validating if the current field's value is not the default static value.
func hasValue(fl FieldLevel) bool { func hasValue(fl FieldLevel) bool {
@ -1489,6 +1496,10 @@ func isHostname(fl FieldLevel) bool {
func isFQDN(fl FieldLevel) bool { func isFQDN(fl FieldLevel) bool {
val := fl.Field().String() val := fl.Field().String()
if val == "" {
return false
}
if val[len(val)-1] == '.' { if val[len(val)-1] == '.' {
val = val[0 : len(val)-1] val = val[0 : len(val)-1]
} }

@ -13,6 +13,7 @@ type tagType uint8
const ( const (
typeDefault tagType = iota typeDefault tagType = iota
typeOmitEmpty typeOmitEmpty
typeIsDefault
typeNoStructLevel typeNoStructLevel
typeStructOnly typeStructOnly
typeDive typeDive
@ -224,6 +225,10 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
default: default:
if t == isdefault {
current.typeof = typeIsDefault
}
// if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
orVals := strings.Split(t, orSeparator) orVals := strings.Split(t, orSeparator)

@ -220,6 +220,13 @@ ensures the value is not nil.
Usage: required Usage: required
Is Default
This validates that the value is the default value and is almost the
opposite of required.
Usage: isdefault
Length Length
For numbers, length will ensure that the value is For numbers, length will ensure that the value is

@ -112,7 +112,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
return return
} }
if ct.typeof == typeOmitEmpty { if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault {
return return
} }
@ -174,6 +174,39 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
if ct.typeof == typeStructOnly { if ct.typeof == typeStructOnly {
goto CONTINUE goto CONTINUE
} else if ct.typeof == typeIsDefault {
// set Field Level fields
v.slflParent = parent
v.flField = current
v.cf = cf
v.ct = ct
if !ct.fn(ctx, v) {
v.str1 = string(append(ns, cf.altName...))
if v.v.hasTagNameFunc {
v.str2 = string(append(structNs, cf.name...))
} else {
v.str2 = v.str1
}
v.errs = append(v.errs,
&fieldError{
v: v.v,
tag: ct.aliasTag,
actualTag: ct.tag,
ns: v.str1,
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
value: current.Interface(),
param: ct.param,
kind: kind,
typ: typ,
},
)
return
}
} }
ct = ct.next ct = ct.next
@ -404,10 +437,6 @@ OUTER:
v.cf = cf v.cf = cf
v.ct = ct v.ct = ct
// // report error interface functions need these
// v.ns = ns
// v.actualNs = structNs
if !ct.fn(ctx, v) { if !ct.fn(ctx, v) {
v.str1 = string(append(ns, cf.altName...)) v.str1 = string(append(ns, cf.altName...))

@ -22,6 +22,7 @@ const (
structOnlyTag = "structonly" structOnlyTag = "structonly"
noStructLevelTag = "nostructlevel" noStructLevelTag = "nostructlevel"
omitempty = "omitempty" omitempty = "omitempty"
isdefault = "isdefault"
skipValidationTag = "-" skipValidationTag = "-"
diveTag = "dive" diveTag = "dive"
requiredTag = "required" requiredTag = "required"

@ -7189,6 +7189,7 @@ func TestFQDNValidation(t *testing.T) {
{"2001:cdba:0000:0000:0000:0000:3257:9652", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", false},
{"2001:cdba:0:0:0:0:3257:9652", false}, {"2001:cdba:0:0:0:0:3257:9652", false},
{"2001:cdba::3257:9652", false}, {"2001:cdba::3257:9652", false},
{"", false},
} }
validate := New() validate := New()
@ -7213,3 +7214,61 @@ func TestFQDNValidation(t *testing.T) {
} }
} }
} }
func TestIsDefault(t *testing.T) {
validate := New()
type Inner struct {
String string `validate:"isdefault"`
}
type Test struct {
String string `validate:"isdefault"`
Inner *Inner `validate:"isdefault"`
}
var tt Test
errs := validate.Struct(tt)
Equal(t, errs, nil)
tt.Inner = &Inner{String: ""}
errs = validate.Struct(tt)
NotEqual(t, errs, nil)
fe := errs.(ValidationErrors)[0]
Equal(t, fe.Field(), "Inner")
Equal(t, fe.Namespace(), "Test.Inner")
Equal(t, fe.Tag(), "isdefault")
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
type Inner2 struct {
String string `validate:"isdefault"`
}
type Test2 struct {
Inner Inner2 `validate:"isdefault" json:"inner"`
}
var t2 Test2
errs = validate.Struct(t2)
Equal(t, errs, nil)
t2.Inner.String = "Changed"
errs = validate.Struct(t2)
NotEqual(t, errs, nil)
fe = errs.(ValidationErrors)[0]
Equal(t, fe.Field(), "inner")
Equal(t, fe.Namespace(), "Test2.inner")
Equal(t, fe.Tag(), "isdefault")
}

Loading…
Cancel
Save