Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
qiangxue committed Oct 19, 2020
2 parents 41a7746 + 25eba0b commit fd19c45
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 4 deletions.
22 changes: 20 additions & 2 deletions each.go
Expand Up @@ -5,6 +5,7 @@
package validation

import (
"context"
"errors"
"reflect"
"strconv"
Expand All @@ -26,21 +27,38 @@ type EachRule struct {

// Validate loops through the given iterable and calls the Ozzo Validate() method for each value.
func (r EachRule) Validate(value interface{}) error {
return r.ValidateWithContext(nil, value)
}

// ValidateWithContext loops through the given iterable and calls the Ozzo ValidateWithContext() method for each value.
func (r EachRule) ValidateWithContext(ctx context.Context, value interface{}) error {
errs := Errors{}

v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.Map:
for _, k := range v.MapKeys() {
val := r.getInterface(v.MapIndex(k))
if err := Validate(val, r.rules...); err != nil {
var err error
if ctx == nil {
err = Validate(val, r.rules...)
} else {
err = ValidateWithContext(ctx, val, r.rules...)
}
if err != nil {
errs[r.getString(k)] = err
}
}
case reflect.Slice, reflect.Array:
for i := 0; i < v.Len(); i++ {
val := r.getInterface(v.Index(i))
if err := Validate(val, r.rules...); err != nil {
var err error
if ctx == nil {
err = Validate(val, r.rules...)
} else {
err = ValidateWithContext(ctx, val, r.rules...)
}
if err != nil {
errs[strconv.Itoa(i)] = err
}
}
Expand Down
35 changes: 35 additions & 0 deletions each_test.go
@@ -1,6 +1,9 @@
package validation

import (
"context"
"errors"
"strings"
"testing"
)

Expand Down Expand Up @@ -37,3 +40,35 @@ func TestEach(t *testing.T) {
assertError(t, test.err, err, test.tag)
}
}

func TestEachWithContext(t *testing.T) {
rule := Each(WithContext(func(ctx context.Context, value interface{}) error {
if !strings.Contains(value.(string), ctx.Value("contains").(string)) {
return errors.New("unexpected value")
}
return nil
}))
ctx1 := context.WithValue(context.Background(), "contains", "abc")
ctx2 := context.WithValue(context.Background(), "contains", "xyz")

tests := []struct {
tag string
value interface{}
ctx context.Context
err string
}{
{"t1.1", map[string]string{"key": "abc"}, ctx1, ""},
{"t1.2", map[string]string{"key": "abc"}, ctx2, "key: unexpected value."},
{"t1.3", map[string]string{"key": "xyz"}, ctx1, "key: unexpected value."},
{"t1.4", map[string]string{"key": "xyz"}, ctx2, ""},
{"t1.5", []string{"abc"}, ctx1, ""},
{"t1.6", []string{"abc"}, ctx2, "0: unexpected value."},
{"t1.7", []string{"xyz"}, ctx1, "0: unexpected value."},
{"t1.8", []string{"xyz"}, ctx2, ""},
}

for _, test := range tests {
err := ValidateWithContext(test.ctx, test.value, rule)
assertError(t, test.err, err, test.tag)
}
}
19 changes: 17 additions & 2 deletions when.go
@@ -1,5 +1,7 @@
package validation

import "context"

// When returns a validation rule that executes the given list of rules when the condition is true.
func When(condition bool, rules ...Rule) WhenRule {
return WhenRule{
Expand All @@ -18,11 +20,24 @@ type WhenRule struct {

// Validate checks if the condition is true and if so, it validates the value using the specified rules.
func (r WhenRule) Validate(value interface{}) error {
return r.ValidateWithContext(nil, value)
}

// ValidateWithContext checks if the condition is true and if so, it validates the value using the specified rules.
func (r WhenRule) ValidateWithContext(ctx context.Context, value interface{}) error {
if r.condition {
return Validate(value, r.rules...)
if ctx == nil {
return Validate(value, r.rules...)
} else {
return ValidateWithContext(ctx, value, r.rules...)
}
}

return Validate(value, r.elseRules...)
if ctx == nil {
return Validate(value, r.elseRules...)
} else {
return ValidateWithContext(ctx, value, r.elseRules...)
}
}

// Else returns a validation rule that executes the given list of rules when the condition is false.
Expand Down
39 changes: 39 additions & 0 deletions when_test.go
Expand Up @@ -5,6 +5,9 @@
package validation

import (
"context"
"errors"
"strings"
"testing"
)

Expand Down Expand Up @@ -53,3 +56,39 @@ func TestWhen(t *testing.T) {
assertError(t, test.err, err, test.tag)
}
}

func TestWhenWithContext(t *testing.T) {
rule := WithContext(func(ctx context.Context, value interface{}) error {
if !strings.Contains(value.(string), ctx.Value("contains").(string)) {
return errors.New("unexpected value")
}
return nil
})
ctx1 := context.WithValue(context.Background(), "contains", "abc")
ctx2 := context.WithValue(context.Background(), "contains", "xyz")

tests := []struct {
tag string
condition bool
value interface{}
ctx context.Context
err string
}{
// True condition
{"t1.1", true, "abc", ctx1, ""},
{"t1.2", true, "abc", ctx2, "unexpected value"},
{"t1.3", true, "xyz", ctx1, "unexpected value"},
{"t1.4", true, "xyz", ctx2, ""},

// False condition
{"t2.1", false, "abc", ctx1, ""},
{"t2.2", false, "abc", ctx2, "unexpected value"},
{"t2.3", false, "xyz", ctx1, "unexpected value"},
{"t2.4", false, "xyz", ctx2, ""},
}

for _, test := range tests {
err := ValidateWithContext(test.ctx, test.value, When(test.condition, rule).Else(rule))
assertError(t, test.err, err, test.tag)
}
}

0 comments on commit fd19c45

Please sign in to comment.