Skip to content

Commit a021b2e

Browse files
author
Dean Karn
authored
Merge pull request #307 from go-playground/fix_fqdn
Fix fqdn + add isdefault
2 parents e303769 + f16354e commit a021b2e

File tree

7 files changed

+118
-6
lines changed

7 files changed

+118
-6
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package validator
22
================
33
<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)
4-
![Project status](https://img.shields.io/badge/version-9.6.0-green.svg)
4+
![Project status](https://img.shields.io/badge/version-9.7.0-green.svg)
55
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/validator)
66
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9)
77
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)

baked_in.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var (
3939
utf8Pipe: {},
4040
noStructLevelTag: {},
4141
requiredTag: {},
42+
isdefault: {},
4243
}
4344

4445
// BakedInAliasValidators is a default mapping of a single validation tag that
@@ -53,6 +54,7 @@ var (
5354
// or even disregard and use your own map if so desired.
5455
bakedInValidators = map[string]Func{
5556
"required": hasValue,
57+
"isdefault": isDefault,
5658
"len": hasLengthOf,
5759
"min": hasMinOf,
5860
"max": hasMaxOf,
@@ -905,6 +907,11 @@ func isAlphaUnicode(fl FieldLevel) bool {
905907
return alphaUnicodeRegex.MatchString(fl.Field().String())
906908
}
907909

910+
// isDefault is the opposite of required aka hasValue
911+
func isDefault(fl FieldLevel) bool {
912+
return !hasValue(fl)
913+
}
914+
908915
// HasValue is the validation function for validating if the current field's value is not the default static value.
909916
func hasValue(fl FieldLevel) bool {
910917

@@ -1489,6 +1496,10 @@ func isHostname(fl FieldLevel) bool {
14891496
func isFQDN(fl FieldLevel) bool {
14901497
val := fl.Field().String()
14911498

1499+
if val == "" {
1500+
return false
1501+
}
1502+
14921503
if val[len(val)-1] == '.' {
14931504
val = val[0 : len(val)-1]
14941505
}

cache.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type tagType uint8
1313
const (
1414
typeDefault tagType = iota
1515
typeOmitEmpty
16+
typeIsDefault
1617
typeNoStructLevel
1718
typeStructOnly
1819
typeDive
@@ -224,6 +225,10 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
224225

225226
default:
226227

228+
if t == isdefault {
229+
current.typeof = typeIsDefault
230+
}
231+
227232
// if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
228233
orVals := strings.Split(t, orSeparator)
229234

doc.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ ensures the value is not nil.
220220
221221
Usage: required
222222
223+
Is Default
224+
225+
This validates that the value is the default value and is almost the
226+
opposite of required.
227+
228+
Usage: isdefault
229+
223230
Length
224231
225232
For numbers, length will ensure that the value is

validator.go

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
112112
return
113113
}
114114

115-
if ct.typeof == typeOmitEmpty {
115+
if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault {
116116
return
117117
}
118118

@@ -174,6 +174,39 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
174174

175175
if ct.typeof == typeStructOnly {
176176
goto CONTINUE
177+
} else if ct.typeof == typeIsDefault {
178+
// set Field Level fields
179+
v.slflParent = parent
180+
v.flField = current
181+
v.cf = cf
182+
v.ct = ct
183+
184+
if !ct.fn(ctx, v) {
185+
v.str1 = string(append(ns, cf.altName...))
186+
187+
if v.v.hasTagNameFunc {
188+
v.str2 = string(append(structNs, cf.name...))
189+
} else {
190+
v.str2 = v.str1
191+
}
192+
193+
v.errs = append(v.errs,
194+
&fieldError{
195+
v: v.v,
196+
tag: ct.aliasTag,
197+
actualTag: ct.tag,
198+
ns: v.str1,
199+
structNs: v.str2,
200+
fieldLen: uint8(len(cf.altName)),
201+
structfieldLen: uint8(len(cf.name)),
202+
value: current.Interface(),
203+
param: ct.param,
204+
kind: kind,
205+
typ: typ,
206+
},
207+
)
208+
return
209+
}
177210
}
178211

179212
ct = ct.next
@@ -404,10 +437,6 @@ OUTER:
404437
v.cf = cf
405438
v.ct = ct
406439

407-
// // report error interface functions need these
408-
// v.ns = ns
409-
// v.actualNs = structNs
410-
411440
if !ct.fn(ctx, v) {
412441

413442
v.str1 = string(append(ns, cf.altName...))

validator_instance.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const (
2222
structOnlyTag = "structonly"
2323
noStructLevelTag = "nostructlevel"
2424
omitempty = "omitempty"
25+
isdefault = "isdefault"
2526
skipValidationTag = "-"
2627
diveTag = "dive"
2728
requiredTag = "required"

validator_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7189,6 +7189,7 @@ func TestFQDNValidation(t *testing.T) {
71897189
{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
71907190
{"2001:cdba:0:0:0:0:3257:9652", false},
71917191
{"2001:cdba::3257:9652", false},
7192+
{"", false},
71927193
}
71937194

71947195
validate := New()
@@ -7213,3 +7214,61 @@ func TestFQDNValidation(t *testing.T) {
72137214
}
72147215
}
72157216
}
7217+
7218+
func TestIsDefault(t *testing.T) {
7219+
7220+
validate := New()
7221+
7222+
type Inner struct {
7223+
String string `validate:"isdefault"`
7224+
}
7225+
type Test struct {
7226+
String string `validate:"isdefault"`
7227+
Inner *Inner `validate:"isdefault"`
7228+
}
7229+
7230+
var tt Test
7231+
7232+
errs := validate.Struct(tt)
7233+
Equal(t, errs, nil)
7234+
7235+
tt.Inner = &Inner{String: ""}
7236+
errs = validate.Struct(tt)
7237+
NotEqual(t, errs, nil)
7238+
7239+
fe := errs.(ValidationErrors)[0]
7240+
Equal(t, fe.Field(), "Inner")
7241+
Equal(t, fe.Namespace(), "Test.Inner")
7242+
Equal(t, fe.Tag(), "isdefault")
7243+
7244+
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
7245+
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
7246+
7247+
if name == "-" {
7248+
return ""
7249+
}
7250+
7251+
return name
7252+
})
7253+
7254+
type Inner2 struct {
7255+
String string `validate:"isdefault"`
7256+
}
7257+
7258+
type Test2 struct {
7259+
Inner Inner2 `validate:"isdefault" json:"inner"`
7260+
}
7261+
7262+
var t2 Test2
7263+
errs = validate.Struct(t2)
7264+
Equal(t, errs, nil)
7265+
7266+
t2.Inner.String = "Changed"
7267+
errs = validate.Struct(t2)
7268+
NotEqual(t, errs, nil)
7269+
7270+
fe = errs.(ValidationErrors)[0]
7271+
Equal(t, fe.Field(), "inner")
7272+
Equal(t, fe.Namespace(), "Test2.inner")
7273+
Equal(t, fe.Tag(), "isdefault")
7274+
}

0 commit comments

Comments
 (0)