Compare commits

...

17 Commits
master ... v5

Author SHA1 Message Date
Dean Karn d5acf1dac4 Merge pull request #179 from go-playground/v5-development 9 years ago
Dean Karn a77585b68f Merge pull request #178 from joeybloggs/v5-development 9 years ago
joeybloggs 2055811d7f update org from bluesuncorp to go-playground 9 years ago
Dean Karn 98121ac23f Merge pull request #145 from bluesuncorp/v5-development 9 years ago
Dean Karn 627fcfaedd Merge pull request #143 from joeybloggs/v5-development 9 years ago
joeybloggs 8eb07da269 Add exists tag 9 years ago
Dean Karn 4b62444380 Merge pull request #132 from bluesuncorp/v5-development 9 years ago
Dean Karn c6b12744c3 Merge pull request #131 from joeybloggs/v5-development 9 years ago
joeybloggs 0a785236d1 Merge remote-tracking branch 'upstream/v5' into v5-development 9 years ago
Dean Karn ec0b27fac6 Merge pull request #130 from joeybloggs/v5-development 9 years ago
joeybloggs b870cbab2f Porting Back fixes from v6 9 years ago
joeybloggs b37bef4e66 Merge remote-tracking branch 'upstream/v5-development' into v5-development 9 years ago
Dean Karn aa3fec1835 Delete .travis.yml 9 years ago
Dean Karn 757d391c29 Update README.md 9 years ago
Dean Karn 9a8368398d Update README.md 9 years ago
Dean Karn 77108103e5 Delete .travis.yml 9 years ago
Dean Karn 5a21300017 Update README.md 9 years ago
  1. 20
      .travis.yml
  2. 18
      README.md
  3. 10
      baked_in.go
  4. 13
      doc.go
  5. 2
      examples/simple.go
  6. 2
      examples_test.go
  7. 46
      validator.go
  8. 157
      validator_test.go

@ -1,20 +0,0 @@
language: go
notificaitons:
email:
recipients: bluesuncorp01@gmail.com
on_success: change
on_failure: always
go:
- 1.3
- 1.4
- tip
script:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
- go test -v -covermode=count -coverprofile=cover.out
after_success:
- goveralls -coverprofile=cover.out -service=travis-ci -repotoken I6M8FiXZzErImgwMotJ7fwFlHOX8Hqdq1

@ -1,10 +1,10 @@
Package validator
================
[![Join the chat at https://gitter.im/bluesuncorp/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bluesuncorp/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/bluesuncorp/validator.svg?branch=v5.1)](https://travis-ci.org/bluesuncorp/validator)
[![Coverage Status](https://coveralls.io/repos/bluesuncorp/validator/badge.svg?branch=v5)](https://coveralls.io/r/bluesuncorp/validator?branch=v5)
[![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v5?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v5)
[![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)
[![Build Status](https://semaphoreci.com/api/v1/projects/ec20115f-ef1b-4c7d-9393-cc76aba74eb4/487382/badge.svg)](https://semaphoreci.com/joeybloggs/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v5)](https://coveralls.io/r/go-playground/validator?branch=v5)
[![GoDoc](https://godoc.org/gopkg.in/go-playground/validator.v5?status.svg)](https://godoc.org/gopkg.in/go-playground/validator.v5)
Package validator implements value validations for structs and individual fields based on tags.
@ -19,20 +19,20 @@ Installation
Use go get.
go get gopkg.in/bluesuncorp/validator.v5
go get gopkg.in/go-playground/validator.v5
or to update
go get -u gopkg.in/bluesuncorp/validator.v5
go get -u gopkg.in/go-playground/validator.v5
Then import the validator package into your own code.
import "gopkg.in/bluesuncorp/validator.v5"
import "gopkg.in/go-playground/validator.v5"
Usage and documentation
------
Please see http://godoc.org/gopkg.in/bluesuncorp/validator.v5 for detailed usage docs.
Please see http://godoc.org/gopkg.in/go-playground/validator.v5 for detailed usage docs.
##### Example:
```go
@ -41,7 +41,7 @@ package main
import (
"fmt"
"gopkg.in/bluesuncorp/validator.v5"
"gopkg.in/go-playground/validator.v5"
)
// User contains user information

@ -424,10 +424,12 @@ func hasValue(top interface{}, current interface{}, field interface{}, param str
st := reflect.ValueOf(field)
switch st.Kind() {
case reflect.Slice, reflect.Map, reflect.Array:
return field != nil && int64(st.Len()) > 0
case reflect.Invalid:
return false
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !st.IsNil()
case reflect.Array:
return field != reflect.Zero(reflect.TypeOf(field)).Interface()
default:
return field != nil && field != reflect.Zero(reflect.TypeOf(field)).Interface()
}

@ -167,6 +167,14 @@ Here is a list of the current built in validators:
inside of you program you know the struct will be valid, but need to
verify it has been assigned.
exists
Is a special tag without a validation function attached. It is used when a field
is a Pointer, Interface or Invalid and you wish to validate that it exists.
Example: want to ensure a bool exists if you define the bool as a pointer and
use exists it will ensure there is a value; couldn't use required as it would
fail when the bool was false. exists will fail is the value is a Pointer, Interface
or Invalid and is nil. (Usage: exists)
omitempty
Allows conditional validation, for example if a field is not set with
a value (Determined by the required validator) then other validation
@ -193,9 +201,10 @@ Here is a list of the current built in validators:
within its SliceOrArrayErrs or MapErrs fields.
required
This validates that the value is not the data types default value.
This validates that the value is not the data types default zero value.
For numbers ensures value is not zero. For strings ensures value is
not "". For slices, arrays, and maps, ensures the length is not zero.
not "". For slices, maps, pointers, interfaces, channels and functions
ensures the value is not nil.
(Usage: required)
len

@ -3,7 +3,7 @@ package main
import (
"fmt"
"gopkg.in/bluesuncorp/validator.v5"
"gopkg.in/go-playground/validator.v5"
)
// User contains user information

@ -3,7 +3,7 @@ package validator_test
import (
"fmt"
"../validator"
"gopkg.in/go-playground/validator.v5"
)
func ExampleValidate_new() {

@ -33,6 +33,7 @@ const (
mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s"
structErrMsg = "Struct:%s\n"
diveTag = "dive"
existsTag = "exists"
arrayIndexFieldName = "%s[%d]"
mapIndexFieldName = "%s[%v]"
)
@ -627,7 +628,11 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
f = valueField.Interface()
}
cField = &cachedField{name: name, kind: valueField.Kind(), tag: tag, typ: valueField.Type()}
cField = &cachedField{name: name, kind: valueField.Kind(), tag: tag}
if cField.kind != reflect.Invalid {
cField.typ = valueField.Type()
}
switch cField.kind {
case reflect.Slice, reflect.Array:
@ -648,8 +653,14 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
}
switch cField.kind {
case reflect.Invalid:
return &FieldError{
Field: cField.name,
Tag: cField.tag,
Kind: cField.kind,
}
case reflect.Struct, reflect.Interface, reflect.Invalid:
case reflect.Struct, reflect.Interface:
if cField.typ != reflect.TypeOf(time.Time{}) {
panic("Invalid field passed to fieldWithNameAndValue")
@ -712,7 +723,22 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
for _, val := range cTag.keyVals {
// if (idxField.Kind() == reflect.Ptr || idxField.Kind() == reflect.Interface) && idxField.IsNil() {
// if val[0] == existsTag {
// if (cField.kind == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {
// fieldErr = &FieldError{
// Field: name,
// Tag: val[0],
// Value: f,
// Param: val[1],
// }
// err = errors.New(fieldErr.Tag)
// }
// } else {
fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, val[0], val[1], name)
// }
if err == nil {
return nil
@ -730,6 +756,18 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
return fieldErr
}
if cTag.keyVals[0][0] == existsTag {
if (cField.kind == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {
return &FieldError{
Field: name,
Tag: cTag.keyVals[0][0],
Value: f,
Param: cTag.keyVals[0][1],
}
}
continue
}
if fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, cTag.keyVals[0][0], cTag.keyVals[0][1], name); err != nil {
fieldErr.Kind = cField.kind
@ -971,6 +1009,10 @@ func (v *Validate) fieldWithNameAndSingleTag(val interface{}, current interface{
return nil, nil
}
// if key == existsTag {
// continue
// }
valFunc, ok := v.validationFuncs[key]
if !ok {
panic(fmt.Sprintf("Undefined validation function on field %s", name))

@ -1,6 +1,7 @@
package validator
import (
"encoding/json"
"fmt"
"path"
"reflect"
@ -231,6 +232,112 @@ func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, e
EqualSkip(t, 2, val.Tag, expectedTag)
}
func TestExistsValidation(t *testing.T) {
jsonText := "{ \"truthiness2\": true }"
type Thing struct {
Truthiness *bool `json:"truthiness" validate:"exists,required"`
}
var ting Thing
err := json.Unmarshal([]byte(jsonText), &ting)
Equal(t, err, nil)
NotEqual(t, ting, nil)
Equal(t, ting.Truthiness, nil)
errs := validate.Struct(ting)
NotEqual(t, errs, nil)
AssertFieldError(t, errs, "Truthiness", "exists")
jsonText = "{ \"truthiness\": true }"
err = json.Unmarshal([]byte(jsonText), &ting)
Equal(t, err, nil)
NotEqual(t, ting, nil)
Equal(t, ting.Truthiness, true)
errs = validate.Struct(ting)
Equal(t, errs, nil)
}
func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) {
var m map[string]string
errs := validate.Field(m, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")
m = map[string]string{}
errs = validate.Field(m, "required")
Equal(t, errs, nil)
var arr [5]string
errs = validate.Field(arr, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")
arr[0] = "ok"
errs = validate.Field(arr, "required")
Equal(t, errs, nil)
var s []string
errs = validate.Field(s, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")
s = []string{}
errs = validate.Field(s, "required")
Equal(t, errs, nil)
var c chan string
errs = validate.Field(c, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")
c = make(chan string)
errs = validate.Field(c, "required")
Equal(t, errs, nil)
var tst *int
errs = validate.Field(tst, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")
one := 1
tst = &one
errs = validate.Field(tst, "required")
Equal(t, errs, nil)
var iface interface{}
errs = validate.Field(iface, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")
errs = validate.Field(iface, "omitempty,required")
Equal(t, errs, nil)
errs = validate.Field(iface, "")
Equal(t, errs, nil)
errs = validate.Field(iface, "len=1")
NotEqual(t, errs, nil)
var f func(string)
errs = validate.Field(f, "required")
NotEqual(t, errs, nil)
// AssertError(t, errs, "", "", "required")
f = func(name string) {}
errs = validate.Field(f, "required")
Equal(t, errs, nil)
}
func TestBadKeyValidation(t *testing.T) {
type Test struct {
Name string `validate:"required, "`
@ -255,7 +362,7 @@ func TestFlattenValidation(t *testing.T) {
var errStructPtrArray [][]*Inner
errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{"ok"}})
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {"ok"}})
tmsp := &TestMultiDimensionalStructsPtr{
Errs: errStructPtrArray,
@ -289,7 +396,7 @@ func TestFlattenValidation(t *testing.T) {
Equal(t, structErrFlatten.Tag, "required")
errStructPtrArray = [][]*Inner{}
errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, nil, &Inner{"ok"}})
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, nil, {"ok"}})
tmsp = &TestMultiDimensionalStructsPtr{
Errs: errStructPtrArray,
@ -321,7 +428,7 @@ func TestFlattenValidation(t *testing.T) {
Errs map[int]*Inner `validate:"gt=0,dive,required"`
}
mip := map[int]*Inner{0: &Inner{"ok"}, 3: &Inner{""}, 4: &Inner{"ok"}}
mip := map[int]*Inner{0: {"ok"}, 3: {""}, 4: {"ok"}}
msp := &TestMapStructPtr{
Errs: mip,
@ -353,7 +460,7 @@ func TestFlattenValidation(t *testing.T) {
Equal(t, flatErrs.Field, "Name")
Equal(t, flatErrs.Tag, "required")
mip2 := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}}
mip2 := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}}
msp2 := &TestMapStructPtr{
Errs: mip2,
@ -384,7 +491,7 @@ func TestFlattenValidation(t *testing.T) {
Errs map[int][]string `validate:"gt=0,dive,dive,required"`
}
mias := map[int][]string{0: []string{"ok"}, 3: []string{"ok", ""}, 4: []string{"ok"}}
mias := map[int][]string{0: {"ok"}, 3: {"ok", ""}, 4: {"ok"}}
mia := &TestMapInnerArrayStruct{
Errs: mias,
@ -551,9 +658,9 @@ func TestInterfaceErrValidation(t *testing.T) {
var errStructPtr2Array [][]*Inner
errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil})
tmsp2 := &TestMultiDimensionalStructsPtr2{
Errs: errStructPtr2Array,
@ -660,7 +767,7 @@ func TestMapDiveValidation(t *testing.T) {
Errs map[int]Inner `validate:"gt=0,dive"`
}
mi := map[int]Inner{0: Inner{"ok"}, 3: Inner{""}, 4: Inner{"ok"}}
mi := map[int]Inner{0: {"ok"}, 3: {""}, 4: {"ok"}}
ms := &TestMapStruct{
Errs: mi,
@ -721,7 +828,7 @@ func TestMapDiveValidation(t *testing.T) {
Errs map[int]*Inner `validate:"gt=0,dive,required"`
}
mip := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}}
mip := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}}
msp := &TestMapStructPtr{
Errs: mip,
@ -748,7 +855,7 @@ func TestMapDiveValidation(t *testing.T) {
Errs map[int]*Inner `validate:"gt=0,dive,omitempty,required"`
}
mip2 := map[int]*Inner{0: &Inner{"ok"}, 3: nil, 4: &Inner{"ok"}}
mip2 := map[int]*Inner{0: {"ok"}, 3: nil, 4: {"ok"}}
msp2 := &TestMapStructPtr2{
Errs: mip2,
@ -887,8 +994,8 @@ func TestArrayDiveValidation(t *testing.T) {
var errStructArray [][]Inner
errStructArray = append(errStructArray, []Inner{Inner{"ok"}, Inner{""}, Inner{""}})
errStructArray = append(errStructArray, []Inner{Inner{"ok"}, Inner{""}, Inner{""}})
errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}})
errStructArray = append(errStructArray, []Inner{{"ok"}, {""}, {""}})
tms := &TestMultiDimensionalStructs{
Errs: errStructArray,
@ -925,9 +1032,9 @@ func TestArrayDiveValidation(t *testing.T) {
var errStructPtrArray [][]*Inner
errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtrArray = append(errStructPtrArray, []*Inner{&Inner{"ok"}, &Inner{""}, nil})
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}})
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, {""}})
errStructPtrArray = append(errStructPtrArray, []*Inner{{"ok"}, {""}, nil})
tmsp := &TestMultiDimensionalStructsPtr{
Errs: errStructPtrArray,
@ -979,9 +1086,9 @@ func TestArrayDiveValidation(t *testing.T) {
var errStructPtr2Array [][]*Inner
errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr2Array = append(errStructPtr2Array, []*Inner{{"ok"}, {""}, nil})
tmsp2 := &TestMultiDimensionalStructsPtr2{
Errs: errStructPtr2Array,
@ -1025,9 +1132,9 @@ func TestArrayDiveValidation(t *testing.T) {
var errStructPtr3Array [][]*Inner
errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, &Inner{""}})
errStructPtr3Array = append(errStructPtr3Array, []*Inner{&Inner{"ok"}, &Inner{""}, nil})
errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, {""}})
errStructPtr3Array = append(errStructPtr3Array, []*Inner{{"ok"}, {""}, nil})
tmsp3 := &TestMultiDimensionalStructsPtr3{
Errs: errStructPtr3Array,
@ -3735,14 +3842,14 @@ func TestStructSliceValidation(t *testing.T) {
Min: []int{1, 2},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
MinMax: []int{1, 2, 3, 4, 5},
OmitEmpty: []int{},
OmitEmpty: nil,
}
err := validate.Struct(tSuccess)
Equal(t, err, nil)
tFail := &TestSlice{
Required: []int{},
Required: nil,
Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1},
Min: []int{},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1},
@ -3810,7 +3917,7 @@ func TestPoolObjectMaxSizeValidation(t *testing.T) {
Min: []int{1, 2},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
MinMax: []int{1, 2, 3, 4, 5},
OmitEmpty: []int{},
OmitEmpty: nil,
}
for i := 0; i < 2; i++ {

Loading…
Cancel
Save