adapter: validation module

This commit is contained in:
Ming Deng 2020-09-02 23:23:48 +08:00
parent bdd8df6751
commit cbd51616f1
4 changed files with 1457 additions and 0 deletions

View File

@ -0,0 +1,62 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validation
import (
"reflect"
"github.com/astaxie/beego/pkg/infrastructure/validation"
)
const (
// ValidTag struct tag
ValidTag = validation.ValidTag
LabelTag = validation.LabelTag
)
var (
ErrInt64On32 = validation.ErrInt64On32
)
// CustomFunc is for custom validate function
type CustomFunc func(v *Validation, obj interface{}, key string)
// AddCustomFunc Add a custom function to validation
// The name can not be:
// Clear
// HasErrors
// ErrorMap
// Error
// Check
// Valid
// NoMatch
// If the name is same with exists function, it will replace the origin valid function
func AddCustomFunc(name string, f CustomFunc) error {
return validation.AddCustomFunc(name, func(v *validation.Validation, obj interface{}, key string) {
f((*Validation)(v), obj, key)
})
}
// ValidFunc Valid function type
type ValidFunc validation.ValidFunc
// Funcs Validate function map
type Funcs validation.Funcs
// Call validate values with named type string
func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) {
return (validation.Funcs(f)).Call(name, params...)
}

View File

@ -0,0 +1,274 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package validation for validations
//
// import (
// "github.com/astaxie/beego/validation"
// "log"
// )
//
// type User struct {
// Name string
// Age int
// }
//
// func main() {
// u := User{"man", 40}
// valid := validation.Validation{}
// valid.Required(u.Name, "name")
// valid.MaxSize(u.Name, 15, "nameMax")
// valid.Range(u.Age, 0, 140, "age")
// if valid.HasErrors() {
// // validation does not pass
// // print invalid message
// for _, err := range valid.Errors {
// log.Println(err.Key, err.Message)
// }
// }
// // or use like this
// if v := valid.Max(u.Age, 140, "ageMax"); !v.Ok {
// log.Println(v.Error.Key, v.Error.Message)
// }
// }
//
// more info: http://beego.me/docs/mvc/controller/validation.md
package validation
import (
"fmt"
"regexp"
"github.com/astaxie/beego/pkg/infrastructure/validation"
)
// ValidFormer valid interface
type ValidFormer interface {
Valid(*Validation)
}
// Error show the error
type Error validation.Error
// String Returns the Message.
func (e *Error) String() string {
if e == nil {
return ""
}
return e.Message
}
// Implement Error interface.
// Return e.String()
func (e *Error) Error() string { return e.String() }
// Result is returned from every validation method.
// It provides an indication of success, and a pointer to the Error (if any).
type Result validation.Result
// Key Get Result by given key string.
func (r *Result) Key(key string) *Result {
if r.Error != nil {
r.Error.Key = key
}
return r
}
// Message Set Result message by string or format string with args
func (r *Result) Message(message string, args ...interface{}) *Result {
if r.Error != nil {
if len(args) == 0 {
r.Error.Message = message
} else {
r.Error.Message = fmt.Sprintf(message, args...)
}
}
return r
}
// A Validation context manages data validation and error messages.
type Validation validation.Validation
// Clear Clean all ValidationError.
func (v *Validation) Clear() {
(*validation.Validation)(v).Clear()
}
// HasErrors Has ValidationError nor not.
func (v *Validation) HasErrors() bool {
return (*validation.Validation)(v).HasErrors()
}
// ErrorMap Return the errors mapped by key.
// If there are multiple validation errors associated with a single key, the
// first one "wins". (Typically the first validation will be the more basic).
func (v *Validation) ErrorMap() map[string][]*Error {
newErrors := (*validation.Validation)(v).ErrorMap()
res := make(map[string][]*Error, len(newErrors))
for n, es := range newErrors {
errs := make([]*Error, 0, len(es))
for _, e := range es {
errs = append(errs, (*Error)(e))
}
res[n] = errs
}
return res
}
// Error Add an error to the validation context.
func (v *Validation) Error(message string, args ...interface{}) *Result {
return (*Result)((*validation.Validation)(v).Error(message, args...))
}
// Required Test that the argument is non-nil and non-empty (if string or list)
func (v *Validation) Required(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Required(obj, key))
}
// Min Test that the obj is greater than min if obj's type is int
func (v *Validation) Min(obj interface{}, min int, key string) *Result {
return (*Result)((*validation.Validation)(v).Min(obj, min, key))
}
// Max Test that the obj is less than max if obj's type is int
func (v *Validation) Max(obj interface{}, max int, key string) *Result {
return (*Result)((*validation.Validation)(v).Max(obj, max, key))
}
// Range Test that the obj is between mni and max if obj's type is int
func (v *Validation) Range(obj interface{}, min, max int, key string) *Result {
return (*Result)((*validation.Validation)(v).Range(obj, min, max, key))
}
// MinSize Test that the obj is longer than min size if type is string or slice
func (v *Validation) MinSize(obj interface{}, min int, key string) *Result {
return (*Result)((*validation.Validation)(v).MinSize(obj, min, key))
}
// MaxSize Test that the obj is shorter than max size if type is string or slice
func (v *Validation) MaxSize(obj interface{}, max int, key string) *Result {
return (*Result)((*validation.Validation)(v).MaxSize(obj, max, key))
}
// Length Test that the obj is same length to n if type is string or slice
func (v *Validation) Length(obj interface{}, n int, key string) *Result {
return (*Result)((*validation.Validation)(v).Length(obj, n, key))
}
// Alpha Test that the obj is [a-zA-Z] if type is string
func (v *Validation) Alpha(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Alpha(obj, key))
}
// Numeric Test that the obj is [0-9] if type is string
func (v *Validation) Numeric(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Numeric(obj, key))
}
// AlphaNumeric Test that the obj is [0-9a-zA-Z] if type is string
func (v *Validation) AlphaNumeric(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).AlphaNumeric(obj, key))
}
// Match Test that the obj matches regexp if type is string
func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *Result {
return (*Result)((*validation.Validation)(v).Match(obj, regex, key))
}
// NoMatch Test that the obj doesn't match regexp if type is string
func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *Result {
return (*Result)((*validation.Validation)(v).NoMatch(obj, regex, key))
}
// AlphaDash Test that the obj is [0-9a-zA-Z_-] if type is string
func (v *Validation) AlphaDash(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).AlphaDash(obj, key))
}
// Email Test that the obj is email address if type is string
func (v *Validation) Email(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Email(obj, key))
}
// IP Test that the obj is IP address if type is string
func (v *Validation) IP(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).IP(obj, key))
}
// Base64 Test that the obj is base64 encoded if type is string
func (v *Validation) Base64(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Base64(obj, key))
}
// Mobile Test that the obj is chinese mobile number if type is string
func (v *Validation) Mobile(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Mobile(obj, key))
}
// Tel Test that the obj is chinese telephone number if type is string
func (v *Validation) Tel(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Tel(obj, key))
}
// Phone Test that the obj is chinese mobile or telephone number if type is string
func (v *Validation) Phone(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).Phone(obj, key))
}
// ZipCode Test that the obj is chinese zip code if type is string
func (v *Validation) ZipCode(obj interface{}, key string) *Result {
return (*Result)((*validation.Validation)(v).ZipCode(obj, key))
}
// key must like aa.bb.cc or aa.bb.
// AddError adds independent error message for the provided key
func (v *Validation) AddError(key, message string) {
(*validation.Validation)(v).AddError(key, message)
}
// SetError Set error message for one field in ValidationError
func (v *Validation) SetError(fieldName string, errMsg string) *Error {
return (*Error)((*validation.Validation)(v).SetError(fieldName, errMsg))
}
// Check Apply a group of validators to a field, in order, and return the
// ValidationResult from the first one that fails, or the last one that
// succeeds.
func (v *Validation) Check(obj interface{}, checks ...Validator) *Result {
vldts := make([]validation.Validator, 0, len(checks))
for _, v := range checks {
vldts = append(vldts, validation.Validator(v))
}
return (*Result)((*validation.Validation)(v).Check(obj, vldts...))
}
// Valid Validate a struct.
// the obj parameter must be a struct or a struct pointer
func (v *Validation) Valid(obj interface{}) (b bool, err error) {
return (*validation.Validation)(v).Valid(obj)
}
// RecursiveValid Recursively validate a struct.
// Step1: Validate by v.Valid
// Step2: If pass on step1, then reflect obj's fields
// Step3: Do the Recursively validation to all struct or struct pointer fields
func (v *Validation) RecursiveValid(objc interface{}) (bool, error) {
return (*validation.Validation)(v).RecursiveValid(objc)
}
func (v *Validation) CanSkipAlso(skipFunc string) {
(*validation.Validation)(v).CanSkipAlso(skipFunc)
}

View File

@ -0,0 +1,609 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validation
import (
"regexp"
"testing"
"time"
)
func TestRequired(t *testing.T) {
valid := Validation{}
if valid.Required(nil, "nil").Ok {
t.Error("nil object should be false")
}
if !valid.Required(true, "bool").Ok {
t.Error("Bool value should always return true")
}
if !valid.Required(false, "bool").Ok {
t.Error("Bool value should always return true")
}
if valid.Required("", "string").Ok {
t.Error("\"'\" string should be false")
}
if valid.Required(" ", "string").Ok {
t.Error("\" \" string should be false") // For #2361
}
if valid.Required("\n", "string").Ok {
t.Error("new line string should be false") // For #2361
}
if !valid.Required("astaxie", "string").Ok {
t.Error("string should be true")
}
if valid.Required(0, "zero").Ok {
t.Error("Integer should not be equal 0")
}
if !valid.Required(1, "int").Ok {
t.Error("Integer except 0 should be true")
}
if !valid.Required(time.Now(), "time").Ok {
t.Error("time should be true")
}
if valid.Required([]string{}, "emptySlice").Ok {
t.Error("empty slice should be false")
}
if !valid.Required([]interface{}{"ok"}, "slice").Ok {
t.Error("slice should be true")
}
}
func TestMin(t *testing.T) {
valid := Validation{}
if valid.Min(-1, 0, "min0").Ok {
t.Error("-1 is less than the minimum value of 0 should be false")
}
if !valid.Min(1, 0, "min0").Ok {
t.Error("1 is greater or equal than the minimum value of 0 should be true")
}
}
func TestMax(t *testing.T) {
valid := Validation{}
if valid.Max(1, 0, "max0").Ok {
t.Error("1 is greater than the minimum value of 0 should be false")
}
if !valid.Max(-1, 0, "max0").Ok {
t.Error("-1 is less or equal than the maximum value of 0 should be true")
}
}
func TestRange(t *testing.T) {
valid := Validation{}
if valid.Range(-1, 0, 1, "range0_1").Ok {
t.Error("-1 is between 0 and 1 should be false")
}
if !valid.Range(1, 0, 1, "range0_1").Ok {
t.Error("1 is between 0 and 1 should be true")
}
}
func TestMinSize(t *testing.T) {
valid := Validation{}
if valid.MinSize("", 1, "minSize1").Ok {
t.Error("the length of \"\" is less than the minimum value of 1 should be false")
}
if !valid.MinSize("ok", 1, "minSize1").Ok {
t.Error("the length of \"ok\" is greater or equal than the minimum value of 1 should be true")
}
if valid.MinSize([]string{}, 1, "minSize1").Ok {
t.Error("the length of empty slice is less than the minimum value of 1 should be false")
}
if !valid.MinSize([]interface{}{"ok"}, 1, "minSize1").Ok {
t.Error("the length of [\"ok\"] is greater or equal than the minimum value of 1 should be true")
}
}
func TestMaxSize(t *testing.T) {
valid := Validation{}
if valid.MaxSize("ok", 1, "maxSize1").Ok {
t.Error("the length of \"ok\" is greater than the maximum value of 1 should be false")
}
if !valid.MaxSize("", 1, "maxSize1").Ok {
t.Error("the length of \"\" is less or equal than the maximum value of 1 should be true")
}
if valid.MaxSize([]interface{}{"ok", false}, 1, "maxSize1").Ok {
t.Error("the length of [\"ok\", false] is greater than the maximum value of 1 should be false")
}
if !valid.MaxSize([]string{}, 1, "maxSize1").Ok {
t.Error("the length of empty slice is less or equal than the maximum value of 1 should be true")
}
}
func TestLength(t *testing.T) {
valid := Validation{}
if valid.Length("", 1, "length1").Ok {
t.Error("the length of \"\" must equal 1 should be false")
}
if !valid.Length("1", 1, "length1").Ok {
t.Error("the length of \"1\" must equal 1 should be true")
}
if valid.Length([]string{}, 1, "length1").Ok {
t.Error("the length of empty slice must equal 1 should be false")
}
if !valid.Length([]interface{}{"ok"}, 1, "length1").Ok {
t.Error("the length of [\"ok\"] must equal 1 should be true")
}
}
func TestAlpha(t *testing.T) {
valid := Validation{}
if valid.Alpha("a,1-@ $", "alpha").Ok {
t.Error("\"a,1-@ $\" are valid alpha characters should be false")
}
if !valid.Alpha("abCD", "alpha").Ok {
t.Error("\"abCD\" are valid alpha characters should be true")
}
}
func TestNumeric(t *testing.T) {
valid := Validation{}
if valid.Numeric("a,1-@ $", "numeric").Ok {
t.Error("\"a,1-@ $\" are valid numeric characters should be false")
}
if !valid.Numeric("1234", "numeric").Ok {
t.Error("\"1234\" are valid numeric characters should be true")
}
}
func TestAlphaNumeric(t *testing.T) {
valid := Validation{}
if valid.AlphaNumeric("a,1-@ $", "alphaNumeric").Ok {
t.Error("\"a,1-@ $\" are valid alpha or numeric characters should be false")
}
if !valid.AlphaNumeric("1234aB", "alphaNumeric").Ok {
t.Error("\"1234aB\" are valid alpha or numeric characters should be true")
}
}
func TestMatch(t *testing.T) {
valid := Validation{}
if valid.Match("suchuangji@gmail", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok {
t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be false")
}
if !valid.Match("suchuangji@gmail.com", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok {
t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be true")
}
}
func TestNoMatch(t *testing.T) {
valid := Validation{}
if valid.NoMatch("123@gmail", regexp.MustCompile(`[^\w\d]`), "nomatch").Ok {
t.Error("\"123@gmail\" not match \"[^\\w\\d]\" should be false")
}
if !valid.NoMatch("123gmail", regexp.MustCompile(`[^\w\d]`), "match").Ok {
t.Error("\"123@gmail\" not match \"[^\\w\\d@]\" should be true")
}
}
func TestAlphaDash(t *testing.T) {
valid := Validation{}
if valid.AlphaDash("a,1-@ $", "alphaDash").Ok {
t.Error("\"a,1-@ $\" are valid alpha or numeric or dash(-_) characters should be false")
}
if !valid.AlphaDash("1234aB-_", "alphaDash").Ok {
t.Error("\"1234aB\" are valid alpha or numeric or dash(-_) characters should be true")
}
}
func TestEmail(t *testing.T) {
valid := Validation{}
if valid.Email("not@a email", "email").Ok {
t.Error("\"not@a email\" is a valid email address should be false")
}
if !valid.Email("suchuangji@gmail.com", "email").Ok {
t.Error("\"suchuangji@gmail.com\" is a valid email address should be true")
}
if valid.Email("@suchuangji@gmail.com", "email").Ok {
t.Error("\"@suchuangji@gmail.com\" is a valid email address should be false")
}
if valid.Email("suchuangji@gmail.com ok", "email").Ok {
t.Error("\"suchuangji@gmail.com ok\" is a valid email address should be false")
}
}
func TestIP(t *testing.T) {
valid := Validation{}
if valid.IP("11.255.255.256", "IP").Ok {
t.Error("\"11.255.255.256\" is a valid ip address should be false")
}
if !valid.IP("01.11.11.11", "IP").Ok {
t.Error("\"suchuangji@gmail.com\" is a valid ip address should be true")
}
}
func TestBase64(t *testing.T) {
valid := Validation{}
if valid.Base64("suchuangji@gmail.com", "base64").Ok {
t.Error("\"suchuangji@gmail.com\" are a valid base64 characters should be false")
}
if !valid.Base64("c3VjaHVhbmdqaUBnbWFpbC5jb20=", "base64").Ok {
t.Error("\"c3VjaHVhbmdqaUBnbWFpbC5jb20=\" are a valid base64 characters should be true")
}
}
func TestMobile(t *testing.T) {
valid := Validation{}
validMobiles := []string{
"19800008888",
"18800008888",
"18000008888",
"8618300008888",
"+8614700008888",
"17300008888",
"+8617100008888",
"8617500008888",
"8617400008888",
"16200008888",
"16500008888",
"16600008888",
"16700008888",
"13300008888",
"14900008888",
"15300008888",
"17300008888",
"17700008888",
"18000008888",
"18900008888",
"19100008888",
"19900008888",
"19300008888",
"13000008888",
"13100008888",
"13200008888",
"14500008888",
"15500008888",
"15600008888",
"16600008888",
"17100008888",
"17500008888",
"17600008888",
"18500008888",
"18600008888",
"13400008888",
"13500008888",
"13600008888",
"13700008888",
"13800008888",
"13900008888",
"14700008888",
"15000008888",
"15100008888",
"15200008888",
"15800008888",
"15900008888",
"17200008888",
"17800008888",
"18200008888",
"18300008888",
"18400008888",
"18700008888",
"18800008888",
"19800008888",
}
for _, m := range validMobiles {
if !valid.Mobile(m, "mobile").Ok {
t.Error(m + " is a valid mobile phone number should be true")
}
}
}
func TestTel(t *testing.T) {
valid := Validation{}
if valid.Tel("222-00008888", "telephone").Ok {
t.Error("\"222-00008888\" is a valid telephone number should be false")
}
if !valid.Tel("022-70008888", "telephone").Ok {
t.Error("\"022-70008888\" is a valid telephone number should be true")
}
if !valid.Tel("02270008888", "telephone").Ok {
t.Error("\"02270008888\" is a valid telephone number should be true")
}
if !valid.Tel("70008888", "telephone").Ok {
t.Error("\"70008888\" is a valid telephone number should be true")
}
}
func TestPhone(t *testing.T) {
valid := Validation{}
if valid.Phone("222-00008888", "phone").Ok {
t.Error("\"222-00008888\" is a valid phone number should be false")
}
if !valid.Mobile("+8614700008888", "phone").Ok {
t.Error("\"+8614700008888\" is a valid phone number should be true")
}
if !valid.Tel("02270008888", "phone").Ok {
t.Error("\"02270008888\" is a valid phone number should be true")
}
}
func TestZipCode(t *testing.T) {
valid := Validation{}
if valid.ZipCode("", "zipcode").Ok {
t.Error("\"00008888\" is a valid zipcode should be false")
}
if !valid.ZipCode("536000", "zipcode").Ok {
t.Error("\"536000\" is a valid zipcode should be true")
}
}
func TestValid(t *testing.T) {
type user struct {
ID int
Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"`
Age int `valid:"Required;Range(1, 140)"`
}
valid := Validation{}
u := user{Name: "test@/test/;com", Age: 40}
b, err := valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if !b {
t.Error("validation should be passed")
}
uptr := &user{Name: "test", Age: 40}
valid.Clear()
b, err = valid.Valid(uptr)
if err != nil {
t.Fatal(err)
}
if b {
t.Error("validation should not be passed")
}
if len(valid.Errors) != 1 {
t.Fatalf("valid errors len should be 1 but got %d", len(valid.Errors))
}
if valid.Errors[0].Key != "Name.Match" {
t.Errorf("Message key should be `Name.Match` but got %s", valid.Errors[0].Key)
}
u = user{Name: "test@/test/;com", Age: 180}
valid.Clear()
b, err = valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Error("validation should not be passed")
}
if len(valid.Errors) != 1 {
t.Fatalf("valid errors len should be 1 but got %d", len(valid.Errors))
}
if valid.Errors[0].Key != "Age.Range." {
t.Errorf("Message key should be `Age.Range` but got %s", valid.Errors[0].Key)
}
}
func TestRecursiveValid(t *testing.T) {
type User struct {
ID int
Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"`
Age int `valid:"Required;Range(1, 140)"`
}
type AnonymouseUser struct {
ID2 int
Name2 string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"`
Age2 int `valid:"Required;Range(1, 140)"`
}
type Account struct {
Password string `valid:"Required"`
U User
AnonymouseUser
}
valid := Validation{}
u := Account{Password: "abc123_", U: User{}}
b, err := valid.RecursiveValid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Error("validation should not be passed")
}
}
func TestSkipValid(t *testing.T) {
type User struct {
ID int
Email string `valid:"Email"`
ReqEmail string `valid:"Required;Email"`
IP string `valid:"IP"`
ReqIP string `valid:"Required;IP"`
Mobile string `valid:"Mobile"`
ReqMobile string `valid:"Required;Mobile"`
Tel string `valid:"Tel"`
ReqTel string `valid:"Required;Tel"`
Phone string `valid:"Phone"`
ReqPhone string `valid:"Required;Phone"`
ZipCode string `valid:"ZipCode"`
ReqZipCode string `valid:"Required;ZipCode"`
}
u := User{
ReqEmail: "a@a.com",
ReqIP: "127.0.0.1",
ReqMobile: "18888888888",
ReqTel: "02088888888",
ReqPhone: "02088888888",
ReqZipCode: "510000",
}
valid := Validation{}
b, err := valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Fatal("validation should not be passed")
}
valid = Validation{RequiredFirst: true}
b, err = valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if !b {
t.Fatal("validation should be passed")
}
}
func TestPointer(t *testing.T) {
type User struct {
ID int
Email *string `valid:"Email"`
ReqEmail *string `valid:"Required;Email"`
}
u := User{
ReqEmail: nil,
Email: nil,
}
valid := Validation{}
b, err := valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Fatal("validation should not be passed")
}
validEmail := "a@a.com"
u = User{
ReqEmail: &validEmail,
Email: nil,
}
valid = Validation{RequiredFirst: true}
b, err = valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if !b {
t.Fatal("validation should be passed")
}
u = User{
ReqEmail: &validEmail,
Email: nil,
}
valid = Validation{}
b, err = valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Fatal("validation should not be passed")
}
invalidEmail := "a@a"
u = User{
ReqEmail: &validEmail,
Email: &invalidEmail,
}
valid = Validation{RequiredFirst: true}
b, err = valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Fatal("validation should not be passed")
}
u = User{
ReqEmail: &validEmail,
Email: &invalidEmail,
}
valid = Validation{}
b, err = valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Fatal("validation should not be passed")
}
}
func TestCanSkipAlso(t *testing.T) {
type User struct {
ID int
Email string `valid:"Email"`
ReqEmail string `valid:"Required;Email"`
MatchRange int `valid:"Range(10, 20)"`
}
u := User{
ReqEmail: "a@a.com",
Email: "",
MatchRange: 0,
}
valid := Validation{RequiredFirst: true}
b, err := valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if b {
t.Fatal("validation should not be passed")
}
valid = Validation{RequiredFirst: true}
valid.CanSkipAlso("Range")
b, err = valid.Valid(u)
if err != nil {
t.Fatal(err)
}
if !b {
t.Fatal("validation should be passed")
}
}

View File

@ -0,0 +1,512 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validation
import (
"sync"
"github.com/astaxie/beego/pkg/infrastructure/validation"
)
// CanSkipFuncs will skip valid if RequiredFirst is true and the struct field's value is empty
var CanSkipFuncs = validation.CanSkipFuncs
// MessageTmpls store commond validate template
var MessageTmpls = map[string]string{
"Required": "Can not be empty",
"Min": "Minimum is %d",
"Max": "Maximum is %d",
"Range": "Range is %d to %d",
"MinSize": "Minimum size is %d",
"MaxSize": "Maximum size is %d",
"Length": "Required length is %d",
"Alpha": "Must be valid alpha characters",
"Numeric": "Must be valid numeric characters",
"AlphaNumeric": "Must be valid alpha or numeric characters",
"Match": "Must match %s",
"NoMatch": "Must not match %s",
"AlphaDash": "Must be valid alpha or numeric or dash(-_) characters",
"Email": "Must be a valid email address",
"IP": "Must be a valid ip address",
"Base64": "Must be valid base64 characters",
"Mobile": "Must be valid mobile number",
"Tel": "Must be valid telephone number",
"Phone": "Must be valid telephone or mobile phone number",
"ZipCode": "Must be valid zipcode",
}
var once sync.Once
// SetDefaultMessage set default messages
// if not set, the default messages are
// "Required": "Can not be empty",
// "Min": "Minimum is %d",
// "Max": "Maximum is %d",
// "Range": "Range is %d to %d",
// "MinSize": "Minimum size is %d",
// "MaxSize": "Maximum size is %d",
// "Length": "Required length is %d",
// "Alpha": "Must be valid alpha characters",
// "Numeric": "Must be valid numeric characters",
// "AlphaNumeric": "Must be valid alpha or numeric characters",
// "Match": "Must match %s",
// "NoMatch": "Must not match %s",
// "AlphaDash": "Must be valid alpha or numeric or dash(-_) characters",
// "Email": "Must be a valid email address",
// "IP": "Must be a valid ip address",
// "Base64": "Must be valid base64 characters",
// "Mobile": "Must be valid mobile number",
// "Tel": "Must be valid telephone number",
// "Phone": "Must be valid telephone or mobile phone number",
// "ZipCode": "Must be valid zipcode",
func SetDefaultMessage(msg map[string]string) {
validation.SetDefaultMessage(msg)
}
// Validator interface
type Validator interface {
IsSatisfied(interface{}) bool
DefaultMessage() string
GetKey() string
GetLimitValue() interface{}
}
// Required struct
type Required validation.Required
// IsSatisfied judge whether obj has value
func (r Required) IsSatisfied(obj interface{}) bool {
return validation.Required(r).IsSatisfied(obj)
}
// DefaultMessage return the default error message
func (r Required) DefaultMessage() string {
return validation.Required(r).DefaultMessage()
}
// GetKey return the r.Key
func (r Required) GetKey() string {
return validation.Required(r).GetKey()
}
// GetLimitValue return nil now
func (r Required) GetLimitValue() interface{} {
return validation.Required(r).GetLimitValue()
}
// Min check struct
type Min validation.Min
// IsSatisfied judge whether obj is valid
// not support int64 on 32-bit platform
func (m Min) IsSatisfied(obj interface{}) bool {
return validation.Min(m).IsSatisfied(obj)
}
// DefaultMessage return the default min error message
func (m Min) DefaultMessage() string {
return validation.Min(m).DefaultMessage()
}
// GetKey return the m.Key
func (m Min) GetKey() string {
return validation.Min(m).GetKey()
}
// GetLimitValue return the limit value, Min
func (m Min) GetLimitValue() interface{} {
return validation.Min(m).GetLimitValue()
}
// Max validate struct
type Max validation.Max
// IsSatisfied judge whether obj is valid
// not support int64 on 32-bit platform
func (m Max) IsSatisfied(obj interface{}) bool {
return validation.Max(m).IsSatisfied(obj)
}
// DefaultMessage return the default max error message
func (m Max) DefaultMessage() string {
return validation.Max(m).DefaultMessage()
}
// GetKey return the m.Key
func (m Max) GetKey() string {
return validation.Max(m).GetKey()
}
// GetLimitValue return the limit value, Max
func (m Max) GetLimitValue() interface{} {
return validation.Max(m).GetLimitValue()
}
// Range Requires an integer to be within Min, Max inclusive.
type Range validation.Range
// IsSatisfied judge whether obj is valid
// not support int64 on 32-bit platform
func (r Range) IsSatisfied(obj interface{}) bool {
return validation.Range(r).IsSatisfied(obj)
}
// DefaultMessage return the default Range error message
func (r Range) DefaultMessage() string {
return validation.Range(r).DefaultMessage()
}
// GetKey return the m.Key
func (r Range) GetKey() string {
return validation.Range(r).GetKey()
}
// GetLimitValue return the limit value, Max
func (r Range) GetLimitValue() interface{} {
return validation.Range(r).GetLimitValue()
}
// MinSize Requires an array or string to be at least a given length.
type MinSize validation.MinSize
// IsSatisfied judge whether obj is valid
func (m MinSize) IsSatisfied(obj interface{}) bool {
return validation.MinSize(m).IsSatisfied(obj)
}
// DefaultMessage return the default MinSize error message
func (m MinSize) DefaultMessage() string {
return validation.MinSize(m).DefaultMessage()
}
// GetKey return the m.Key
func (m MinSize) GetKey() string {
return validation.MinSize(m).GetKey()
}
// GetLimitValue return the limit value
func (m MinSize) GetLimitValue() interface{} {
return validation.MinSize(m).GetLimitValue()
}
// MaxSize Requires an array or string to be at most a given length.
type MaxSize validation.MaxSize
// IsSatisfied judge whether obj is valid
func (m MaxSize) IsSatisfied(obj interface{}) bool {
return validation.MaxSize(m).IsSatisfied(obj)
}
// DefaultMessage return the default MaxSize error message
func (m MaxSize) DefaultMessage() string {
return validation.MaxSize(m).DefaultMessage()
}
// GetKey return the m.Key
func (m MaxSize) GetKey() string {
return validation.MaxSize(m).GetKey()
}
// GetLimitValue return the limit value
func (m MaxSize) GetLimitValue() interface{} {
return validation.MaxSize(m).GetLimitValue()
}
// Length Requires an array or string to be exactly a given length.
type Length validation.Length
// IsSatisfied judge whether obj is valid
func (l Length) IsSatisfied(obj interface{}) bool {
return validation.Length(l).IsSatisfied(obj)
}
// DefaultMessage return the default Length error message
func (l Length) DefaultMessage() string {
return validation.Length(l).DefaultMessage()
}
// GetKey return the m.Key
func (l Length) GetKey() string {
return validation.Length(l).GetKey()
}
// GetLimitValue return the limit value
func (l Length) GetLimitValue() interface{} {
return validation.Length(l).GetLimitValue()
}
// Alpha check the alpha
type Alpha validation.Alpha
// IsSatisfied judge whether obj is valid
func (a Alpha) IsSatisfied(obj interface{}) bool {
return validation.Alpha(a).IsSatisfied(obj)
}
// DefaultMessage return the default Length error message
func (a Alpha) DefaultMessage() string {
return validation.Alpha(a).DefaultMessage()
}
// GetKey return the m.Key
func (a Alpha) GetKey() string {
return validation.Alpha(a).GetKey()
}
// GetLimitValue return the limit value
func (a Alpha) GetLimitValue() interface{} {
return validation.Alpha(a).GetLimitValue()
}
// Numeric check number
type Numeric validation.Numeric
// IsSatisfied judge whether obj is valid
func (n Numeric) IsSatisfied(obj interface{}) bool {
return validation.Numeric(n).IsSatisfied(obj)
}
// DefaultMessage return the default Length error message
func (n Numeric) DefaultMessage() string {
return validation.Numeric(n).DefaultMessage()
}
// GetKey return the n.Key
func (n Numeric) GetKey() string {
return validation.Numeric(n).GetKey()
}
// GetLimitValue return the limit value
func (n Numeric) GetLimitValue() interface{} {
return validation.Numeric(n).GetLimitValue()
}
// AlphaNumeric check alpha and number
type AlphaNumeric validation.AlphaNumeric
// IsSatisfied judge whether obj is valid
func (a AlphaNumeric) IsSatisfied(obj interface{}) bool {
return validation.AlphaNumeric(a).IsSatisfied(obj)
}
// DefaultMessage return the default Length error message
func (a AlphaNumeric) DefaultMessage() string {
return validation.AlphaNumeric(a).DefaultMessage()
}
// GetKey return the a.Key
func (a AlphaNumeric) GetKey() string {
return validation.AlphaNumeric(a).GetKey()
}
// GetLimitValue return the limit value
func (a AlphaNumeric) GetLimitValue() interface{} {
return validation.AlphaNumeric(a).GetLimitValue()
}
// Match Requires a string to match a given regex.
type Match validation.Match
// IsSatisfied judge whether obj is valid
func (m Match) IsSatisfied(obj interface{}) bool {
return validation.Match(m).IsSatisfied(obj)
}
// DefaultMessage return the default Match error message
func (m Match) DefaultMessage() string {
return validation.Match(m).DefaultMessage()
}
// GetKey return the m.Key
func (m Match) GetKey() string {
return validation.Match(m).GetKey()
}
// GetLimitValue return the limit value
func (m Match) GetLimitValue() interface{} {
return validation.Match(m).GetLimitValue()
}
// NoMatch Requires a string to not match a given regex.
type NoMatch validation.NoMatch
// IsSatisfied judge whether obj is valid
func (n NoMatch) IsSatisfied(obj interface{}) bool {
return validation.NoMatch(n).IsSatisfied(obj)
}
// DefaultMessage return the default NoMatch error message
func (n NoMatch) DefaultMessage() string {
return validation.NoMatch(n).DefaultMessage()
}
// GetKey return the n.Key
func (n NoMatch) GetKey() string {
return validation.NoMatch(n).GetKey()
}
// GetLimitValue return the limit value
func (n NoMatch) GetLimitValue() interface{} {
return validation.NoMatch(n).GetLimitValue()
}
// AlphaDash check not Alpha
type AlphaDash validation.AlphaDash
// DefaultMessage return the default AlphaDash error message
func (a AlphaDash) DefaultMessage() string {
return validation.AlphaDash(a).DefaultMessage()
}
// GetKey return the n.Key
func (a AlphaDash) GetKey() string {
return validation.AlphaDash(a).GetKey()
}
// GetLimitValue return the limit value
func (a AlphaDash) GetLimitValue() interface{} {
return validation.AlphaDash(a).GetLimitValue()
}
// Email check struct
type Email validation.Email
// DefaultMessage return the default Email error message
func (e Email) DefaultMessage() string {
return validation.Email(e).DefaultMessage()
}
// GetKey return the n.Key
func (e Email) GetKey() string {
return validation.Email(e).GetKey()
}
// GetLimitValue return the limit value
func (e Email) GetLimitValue() interface{} {
return validation.Email(e).GetLimitValue()
}
// IP check struct
type IP validation.IP
// DefaultMessage return the default IP error message
func (i IP) DefaultMessage() string {
return validation.IP(i).DefaultMessage()
}
// GetKey return the i.Key
func (i IP) GetKey() string {
return validation.IP(i).GetKey()
}
// GetLimitValue return the limit value
func (i IP) GetLimitValue() interface{} {
return validation.IP(i).GetLimitValue()
}
// Base64 check struct
type Base64 validation.Base64
// DefaultMessage return the default Base64 error message
func (b Base64) DefaultMessage() string {
return validation.Base64(b).DefaultMessage()
}
// GetKey return the b.Key
func (b Base64) GetKey() string {
return validation.Base64(b).GetKey()
}
// GetLimitValue return the limit value
func (b Base64) GetLimitValue() interface{} {
return validation.Base64(b).GetLimitValue()
}
// Mobile check struct
type Mobile validation.Mobile
// DefaultMessage return the default Mobile error message
func (m Mobile) DefaultMessage() string {
return validation.Mobile(m).DefaultMessage()
}
// GetKey return the m.Key
func (m Mobile) GetKey() string {
return validation.Mobile(m).GetKey()
}
// GetLimitValue return the limit value
func (m Mobile) GetLimitValue() interface{} {
return validation.Mobile(m).GetLimitValue()
}
// Tel check telephone struct
type Tel validation.Tel
// DefaultMessage return the default Tel error message
func (t Tel) DefaultMessage() string {
return validation.Tel(t).DefaultMessage()
}
// GetKey return the t.Key
func (t Tel) GetKey() string {
return validation.Tel(t).GetKey()
}
// GetLimitValue return the limit value
func (t Tel) GetLimitValue() interface{} {
return validation.Tel(t).GetLimitValue()
}
// Phone just for chinese telephone or mobile phone number
type Phone validation.Phone
// IsSatisfied judge whether obj is valid
func (p Phone) IsSatisfied(obj interface{}) bool {
return validation.Phone(p).IsSatisfied(obj)
}
// DefaultMessage return the default Phone error message
func (p Phone) DefaultMessage() string {
return validation.Phone(p).DefaultMessage()
}
// GetKey return the p.Key
func (p Phone) GetKey() string {
return validation.Phone(p).GetKey()
}
// GetLimitValue return the limit value
func (p Phone) GetLimitValue() interface{} {
return validation.Phone(p).GetLimitValue()
}
// ZipCode check the zip struct
type ZipCode validation.ZipCode
// DefaultMessage return the default Zip error message
func (z ZipCode) DefaultMessage() string {
return validation.ZipCode(z).DefaultMessage()
}
// GetKey return the z.Key
func (z ZipCode) GetKey() string {
return validation.ZipCode(z).GetKey()
}
// GetLimitValue return the limit value
func (z ZipCode) GetLimitValue() interface{} {
return validation.ZipCode(z).GetLimitValue()
}