Skip to content

Commit

Permalink
#200 Moved valpar pkg into main repo
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed Aug 18, 2018
2 parents 6fba774 + 6c42d78 commit 7771a6d
Show file tree
Hide file tree
Showing 4 changed files with 883 additions and 0 deletions.
132 changes: 132 additions & 0 deletions valpar/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) Jeevanandam M (https://github.com/jeevatkm)
// aahframework.org/valpar source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package valpar

import (
"errors"
"fmt"
"strings"

"gopkg.in/go-playground/validator.v9"
)

// Integrating a library `https://github.com/go-playground/validator` (Version 9)
// as a validtor.
//
// Currently points at `gopkg.in/go-playground/validator.v9`
var aahValidator *validator.Validate

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Package methods
//______________________________________________________________________________

// Validator method return the default validator of aah framework.
//
// Refer to https://godoc.org/gopkg.in/go-playground/validator.v9 for detailed
// documentation.
func Validator() *validator.Validate {
if aahValidator == nil {
aahValidator = validator.New()

// Do customizations here
}
return aahValidator
}

// Validate method is to validate struct via underneath validator.
//
// Returns:
//
// - For validation errors: returns `validator.ValidationErrors` and nil
//
// - For invalid input: returns nil, error (invalid input such as nil, non-struct, etc.)
//
// - For no validation errors: nil, nil
func Validate(s interface{}) (validator.ValidationErrors, error) {
return checkAndReturn(Validator().Struct(s))
}

// ValidateValue method is to validate individual value. Returns true if
// validation is passed otherwise false.
//
// For example:
//
// i := 15
// result := valpar.ValidateValue(i, "gt=1,lt=10")
//
// emailAddress := "sample@sample"
// result := valpar.ValidateValue(emailAddress, "email")
//
// numbers := []int{23, 67, 87, 23, 90}
// result := valpar.ValidateValue(numbers, "unique")
func ValidateValue(v interface{}, constraint string) bool {
return Validator().Var(v, constraint) == nil
}

// ValidateValues method validates the values with respective constraints.
// Returns nil if no errors otherwise slice of error.
func ValidateValues(values map[string]string, constraints map[string]string) Errors {
var errs Errors
for k, v := range values {
if !ValidateValue(v, constraints[k]) {
errs = append(errs, &Error{
Field: k,
Value: v,
Constraint: constraints[k],
})
}
}
return errs
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Error type and its methods
//______________________________________________________________________________

// Errors type represents list errors.
type Errors []*Error

// String is Stringer interface.
func (e Errors) String() string {
if len(e) == 0 {
return ""
}

var errs []string
for _, er := range e {
errs = append(errs, er.String())
}
return strings.Join(errs, ",")
}

// Error represents single validation error details.
type Error struct {
Field string
Value string
Key string // i18n key
Msg string // i18n message
Constraint string
}

// String is Stringer interface.
func (e Error) String() string {
return fmt.Sprintf("error(field:%s value:%v key:%s msg:%v constraint:%s)",
e.Field, e.Value, e.Key, e.Msg, e.Constraint)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Unexported methods
//______________________________________________________________________________

func checkAndReturn(err error) (validator.ValidationErrors, error) {
if err != nil {
if ive, ok := err.(*validator.InvalidValidationError); ok {
return nil, errors.New(ive.Error())
}

return err.(validator.ValidationErrors), nil
}
return nil, nil
}
139 changes: 139 additions & 0 deletions valpar/validator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright (c) Jeevanandam M (https://github.com/jeevatkm)
// aahframework.org/valpar source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package valpar

import (
"reflect"
"testing"

"aahframework.org/test.v0/assert"
)

func TestValidatorValidate(t *testing.T) {
type testAddress struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}

type testValidateStruct1 struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
Addresses []*testAddress `validate:"required,dive,required"` // a person can have a home and cottage...
}

address := &testAddress{
Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
}

testUser := &testValidateStruct1{
FirstName: "Badger",
LastName: "Smith",
Age: 135,
Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000-",
Addresses: []*testAddress{address},
}

result, err := Validate(testUser)
assert.NotNil(t, result)
assert.Nil(t, err)

type testDummy1 struct {
Street string
City string
Planet string
Phone string
}

result, err = Validate(testDummy1{})
assert.Nil(t, result)
assert.Nil(t, err)

result, err = Validate(nil)
assert.Nil(t, result)
assert.NotNil(t, err)
assert.Equal(t, "validator: (nil)", err.Error())

type testStruct struct {
FirstName string `bind:"first_name" validate:"required"`
LastName string `bind:"last_name" validate:"required"`
Age uint8 `bind:"age" validate:"gte=0,lte=130"`
Email string `bind:"email" validate:"required,email"`
FavouriteColor string `bind:"favourite_color" validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
}

testUser1 := &testStruct{
FirstName: "Badger",
LastName: "Smith",
Age: 135,
Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000-",
}

rv := reflect.ValueOf(testUser1)
result, err = Validate(rv.Interface())
assert.NotNil(t, result)
assert.Nil(t, err)
}

func TestValidatorValidateValue(t *testing.T) {
// Validation failed
i := 15
result := ValidateValue(i, "gt=1,lt=10")
assert.False(t, result)

emailAddress := "sample@sample"
result = ValidateValue(emailAddress, "required,email")
assert.False(t, result)

numbers := []int{23, 67, 87, 23, 90}
result = ValidateValue(numbers, "unique")
assert.False(t, result)

// validation pass
i = 9
result = ValidateValue(i, "gt=1,lt=10")
assert.True(t, result)

emailAddress = "sample@sample.com"
result = ValidateValue(emailAddress, "required,email")
assert.True(t, result)

numbers = []int{23, 67, 87, 56, 90}
result = ValidateValue(numbers, "unique")
assert.True(t, result)
}

func TestValidatorValidateValues(t *testing.T) {
values := map[string]string{
"id": "5de80bf1-b2c7-4c6e-e47758b7d817",
"state": "green",
}

constraints := map[string]string{
"id": "uuid",
"state": "oneof=3 7 8",
}

verrs := map[string]*Error{
"id": {Field: "id", Value: "5de80bf1-b2c7-4c6e-e47758b7d817", Constraint: "uuid"},
"state": {Field: "state", Value: "green", Constraint: "oneof=3 7 8"},
}

errs := ValidateValues(values, constraints)
t.Log(errs.String())
for _, e := range errs {
if ev, found := verrs[e.Field]; found {
assert.Equal(t, ev, e)
}
}
}
Loading

0 comments on commit 7771a6d

Please sign in to comment.