| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 | 
							- package valid
 
- import (
 
- 	"context"
 
- 	"errors"
 
- 	"strings"
 
- 	"testing"
 
- 	"github.com/stretchr/testify/assert"
 
- )
 
- func TestValidate(t *testing.T) {
 
- 	slice := []String123{String123("abc"), String123("123"), String123("xyz")}
 
- 	ctxSlice := []Model4{{A: "abc"}, {A: "def"}}
 
- 	mp := map[string]String123{"c": String123("abc"), "b": String123("123"), "a": String123("xyz")}
 
- 	mpCtx := map[string]StringValidateContext{"c": StringValidateContext("abc"), "b": StringValidateContext("123"), "a": StringValidateContext("xyz")}
 
- 	var (
 
- 		ptr     *string
 
- 		noCtx   StringValidate        = "abc"
 
- 		withCtx StringValidateContext = "xyz"
 
- 	)
 
- 	tests := []struct {
 
- 		tag            string
 
- 		value          interface{}
 
- 		err            string
 
- 		errWithContext string
 
- 	}{
 
- 		{"t1", 123, "", ""},
 
- 		{"t2", String123("123"), "", ""},
 
- 		{"t3", String123("abc"), "error 123", "error 123"},
 
- 		{"t4", []String123{}, "", ""},
 
- 		{"t4.1", []StringValidateContext{}, "", ""},
 
- 		{"t4.2", map[string]StringValidateContext{}, "", ""},
 
- 		{"t5", slice, "0: error 123; 2: error 123.", "0: error 123; 2: error 123."},
 
- 		{"t6", &slice, "0: error 123; 2: error 123.", "0: error 123; 2: error 123."},
 
- 		{"t7", ctxSlice, "", "1: (A: error abc.)."},
 
- 		{"t8", mp, "a: error 123; c: error 123.", "a: error 123; c: error 123."},
 
- 		{"t8.1", mpCtx, "a: must be abc; b: must be abc.", "a: must be abc with context; b: must be abc with context."},
 
- 		{"t9", &mp, "a: error 123; c: error 123.", "a: error 123; c: error 123."},
 
- 		{"t10", map[string]String123{}, "", ""},
 
- 		{"t11", ptr, "", ""},
 
- 		{"t12", noCtx, "called validate", "called validate"},
 
- 		{"t13", withCtx, "must be abc", "must be abc with context"},
 
- 	}
 
- 	for _, test := range tests {
 
- 		err := Validate(test.value)
 
- 		assertError(t, test.err, err, test.tag)
 
- 		// rules that are not context-aware should still be applied in context-aware validation
 
- 		err = ValidateWithContext(context.Background(), test.value)
 
- 		assertError(t, test.errWithContext, err, test.tag)
 
- 	}
 
- 	// with rules
 
- 	err := Validate("123", &validateAbc{}, &validateXyz{})
 
- 	assert.EqualError(t, err, "error abc")
 
- 	err = Validate("abc", &validateAbc{}, &validateXyz{})
 
- 	assert.EqualError(t, err, "error xyz")
 
- 	err = Validate("abcxyz", &validateAbc{}, &validateXyz{})
 
- 	assert.NoError(t, err)
 
- 	err = Validate("123", &validateAbc{}, Skip, &validateXyz{})
 
- 	assert.EqualError(t, err, "error abc")
 
- 	err = Validate("abc", &validateAbc{}, Skip, &validateXyz{})
 
- 	assert.NoError(t, err)
 
- 	err = Validate("123", &validateAbc{}, Skip.When(true), &validateXyz{})
 
- 	assert.EqualError(t, err, "error abc")
 
- 	err = Validate("abc", &validateAbc{}, Skip.When(true), &validateXyz{})
 
- 	assert.NoError(t, err)
 
- 	err = Validate("123", &validateAbc{}, Skip.When(false), &validateXyz{})
 
- 	assert.EqualError(t, err, "error abc")
 
- 	err = Validate("abc", &validateAbc{}, Skip.When(false), &validateXyz{})
 
- 	assert.EqualError(t, err, "error xyz")
 
- }
 
- func stringEqual(str string) RuleFunc {
 
- 	return func(value interface{}) error {
 
- 		s, _ := value.(string)
 
- 		if s != str {
 
- 			return errors.New("unexpected string")
 
- 		}
 
- 		return nil
 
- 	}
 
- }
 
- func TestBy(t *testing.T) {
 
- 	abcRule := By(func(value interface{}) error {
 
- 		s, _ := value.(string)
 
- 		if s != "abc" {
 
- 			return errors.New("must be abc")
 
- 		}
 
- 		return nil
 
- 	})
 
- 	assert.Nil(t, Validate("abc", abcRule))
 
- 	err := Validate("xyz", abcRule)
 
- 	if assert.NotNil(t, err) {
 
- 		assert.Equal(t, "must be abc", err.Error())
 
- 	}
 
- 	xyzRule := By(stringEqual("xyz"))
 
- 	assert.Nil(t, Validate("xyz", xyzRule))
 
- 	assert.NotNil(t, Validate("abc", xyzRule))
 
- 	assert.Nil(t, ValidateWithContext(context.Background(), "xyz", xyzRule))
 
- 	assert.NotNil(t, ValidateWithContext(context.Background(), "abc", xyzRule))
 
- }
 
- type key int
 
- func TestByWithContext(t *testing.T) {
 
- 	k := key(1)
 
- 	abcRule := WithContext(func(ctx context.Context, value interface{}) error {
 
- 		if ctx.Value(k) != value.(string) {
 
- 			return errors.New("must be abc")
 
- 		}
 
- 		return nil
 
- 	})
 
- 	ctx := context.WithValue(context.Background(), k, "abc")
 
- 	assert.Nil(t, ValidateWithContext(ctx, "abc", abcRule))
 
- 	err := ValidateWithContext(ctx, "xyz", abcRule)
 
- 	if assert.NotNil(t, err) {
 
- 		assert.Equal(t, "must be abc", err.Error())
 
- 	}
 
- 	assert.NotNil(t, Validate("abc", abcRule))
 
- }
 
- func Test_skipRule_Validate(t *testing.T) {
 
- 	assert.Nil(t, Skip.Validate(100))
 
- }
 
- func assertError(t *testing.T, expected string, err error, tag string) {
 
- 	if expected == "" {
 
- 		assert.NoError(t, err, tag)
 
- 	} else {
 
- 		assert.EqualError(t, err, expected, tag)
 
- 	}
 
- }
 
- type validateAbc struct{}
 
- func (v *validateAbc) Validate(obj interface{}) error {
 
- 	if !strings.Contains(obj.(string), "abc") {
 
- 		return errors.New("error abc")
 
- 	}
 
- 	return nil
 
- }
 
- type validateContextAbc struct{}
 
- func (v *validateContextAbc) Validate(obj interface{}) error {
 
- 	return v.ValidateWithContext(context.Background(), obj)
 
- }
 
- func (v *validateContextAbc) ValidateWithContext(_ context.Context, obj interface{}) error {
 
- 	if !strings.Contains(obj.(string), "abc") {
 
- 		return errors.New("error abc")
 
- 	}
 
- 	return nil
 
- }
 
- type validateXyz struct{}
 
- func (v *validateXyz) Validate(obj interface{}) error {
 
- 	if !strings.Contains(obj.(string), "xyz") {
 
- 		return errors.New("error xyz")
 
- 	}
 
- 	return nil
 
- }
 
- type validateContextXyz struct{}
 
- func (v *validateContextXyz) Validate(obj interface{}) error {
 
- 	return v.ValidateWithContext(context.Background(), obj)
 
- }
 
- func (v *validateContextXyz) ValidateWithContext(_ context.Context, obj interface{}) error {
 
- 	if !strings.Contains(obj.(string), "xyz") {
 
- 		return errors.New("error xyz")
 
- 	}
 
- 	return nil
 
- }
 
- type validateInternalError struct{}
 
- func (v *validateInternalError) Validate(obj interface{}) error {
 
- 	if strings.Contains(obj.(string), "internal") {
 
- 		return NewInternalError(errors.New("error internal"))
 
- 	}
 
- 	return nil
 
- }
 
- type Model1 struct {
 
- 	A string
 
- 	B string
 
- 	c string
 
- 	D *string
 
- 	E String123
 
- 	F *String123
 
- 	G string `json:"g"`
 
- 	H []string
 
- 	I map[string]string
 
- }
 
- type String123 string
 
- func (s String123) Validate() error {
 
- 	if !strings.Contains(string(s), "123") {
 
- 		return errors.New("error 123")
 
- 	}
 
- 	return nil
 
- }
 
- type Model2 struct {
 
- 	Model3
 
- 	M3 Model3
 
- 	B  string
 
- }
 
- type Model3 struct {
 
- 	A string
 
- }
 
- func (m Model3) Validate() error {
 
- 	return ValidateStruct(&m,
 
- 		Field(&m.A, &validateAbc{}),
 
- 	)
 
- }
 
- type Model4 struct {
 
- 	A string
 
- }
 
- func (m Model4) ValidateWithContext(ctx context.Context) error {
 
- 	return ValidateStructWithContext(ctx, &m,
 
- 		Field(&m.A, &validateContextAbc{}),
 
- 	)
 
- }
 
- type Model5 struct {
 
- 	Model4
 
- 	M4 Model4
 
- 	B  string
 
- }
 
- type StringValidate string
 
- func (s StringValidate) Validate() error {
 
- 	return errors.New("called validate")
 
- }
 
- type StringValidateContext string
 
- func (s StringValidateContext) Validate() error {
 
- 	if string(s) != "abc" {
 
- 		return errors.New("must be abc")
 
- 	}
 
- 	return nil
 
- }
 
- func (s StringValidateContext) ValidateWithContext(context.Context) error {
 
- 	if string(s) != "abc" {
 
- 		return errors.New("must be abc with context")
 
- 	}
 
- 	return nil
 
- }
 
 
  |