Skip to content
This repository was archived by the owner on Dec 23, 2025. It is now read-only.

Commit e47d0b9

Browse files
committed
fix: fixed 'rang($, in(#v, ...))'
Change-Id: I309dd275c2cff690356e0de1440c7c11d781bbd1
1 parent a44f579 commit e47d0b9

File tree

6 files changed

+88
-49
lines changed

6 files changed

+88
-49
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ NOTE: **The `exprName` under the same struct field cannot be the same!**
140140
|`regexp('^\\w*$')`|Regular match the current struct field, return boolean|
141141
|`sprintf('X value: %v', (X)$)`|`fmt.Sprintf`, format the value of struct field X|
142142
|`range(KvExpr, forEachExpr)`|Iterate over an array, slice, or dictionary <br> - `#k` is the element key var <br> - `#v` is the element value var <br> - `##` is the number of elements <br> - e.g. [example](spec_range_test.go)|
143+
|`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters|
143144

144145
<!-- |`(X)$k`|Traverse each element key of the struct field X(type: map, slice, array)|
145146
|`(X)$v`|Traverse each element value of the struct field X(type: map, slice, array)| -->

spec_func.go

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,28 @@ import (
2828

2929
var funcList = map[string]func(p *Expr, expr *string) ExprNode{}
3030

31+
// MustRegFunc registers function expression.
32+
// NOTE:
33+
//
34+
// example: len($), regexp("\\d") or regexp("\\d",$);
35+
// If @force=true, allow to cover the existed same @funcName;
36+
// The go number types always are float64;
37+
// The go string types always are string;
38+
// Panic if there is an error.
39+
func MustRegFunc(funcName string, fn func(...interface{}) interface{}, force ...bool) {
40+
err := RegFunc(funcName, fn, force...)
41+
if err != nil {
42+
panic(err)
43+
}
44+
}
45+
3146
// RegFunc registers function expression.
3247
// NOTE:
33-
// example: len($), regexp("\\d") or regexp("\\d",$);
34-
// If @force=true, allow to cover the existed same @funcName;
35-
// The go number types always are float64;
36-
// The go string types always are string.
48+
//
49+
// example: len($), regexp("\\d") or regexp("\\d",$);
50+
// If @force=true, allow to cover the existed same @funcName;
51+
// The go number types always are float64;
52+
// The go string types always are string.
3753
func RegFunc(funcName string, fn func(...interface{}) interface{}, force ...bool) error {
3854
if len(force) == 0 || !force[0] {
3955
_, ok := funcList[funcName]
@@ -125,7 +141,8 @@ func init() {
125141
funcList["regexp"] = readRegexpFuncExprNode
126142
funcList["sprintf"] = readSprintfFuncExprNode
127143
funcList["range"] = readRangeFuncExprNode
128-
err := RegFunc("len", func(args ...interface{}) (n interface{}) {
144+
// len: Built-in function len, the length of struct field X
145+
MustRegFunc("len", func(args ...interface{}) (n interface{}) {
129146
if len(args) != 1 {
130147
return 0
131148
}
@@ -143,10 +160,8 @@ func init() {
143160
}()
144161
return float64(reflect.ValueOf(v).Len())
145162
}, true)
146-
if err != nil {
147-
panic(err)
148-
}
149-
err = RegFunc("mblen", func(args ...interface{}) (n interface{}) {
163+
// mblen: get the length of string field X (character number)
164+
MustRegFunc("mblen", func(args ...interface{}) (n interface{}) {
150165
if len(args) != 1 {
151166
return 0
152167
}
@@ -164,9 +179,25 @@ func init() {
164179
}()
165180
return float64(reflect.ValueOf(v).Len())
166181
}, true)
167-
if err != nil {
168-
panic(err)
169-
}
182+
183+
// in: Check if the first parameter is one of the enumerated parameters
184+
MustRegFunc("in", func(args ...interface{}) interface{} {
185+
switch len(args) {
186+
case 0:
187+
return true
188+
case 1:
189+
return false
190+
default:
191+
elem := args[0]
192+
set := args[1:]
193+
for _, e := range set {
194+
if elem == e {
195+
return true
196+
}
197+
}
198+
return false
199+
}
200+
}, true)
170201
}
171202

172203
type regexpFuncExprNode struct {

spec_func_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"testing"
2020

2121
"github.com/bytedance/go-tagexpr/v2"
22+
"github.com/stretchr/testify/assert"
2223
)
2324

2425
func TestFunc(t *testing.T) {
@@ -83,5 +84,17 @@ func TestFunc(t *testing.T) {
8384
t.Fatalf("string: %v, expect: %v, but got: %v", lenCase.str, lenCase.expect, got)
8485
}
8586
}
87+
}
8688

89+
func TestRangeIn(t *testing.T) {
90+
var vm = tagexpr.New("te")
91+
type S struct {
92+
F []string `te:"range($, in(#v, '', 'ttp', 'euttp'))"`
93+
}
94+
a := []string{"ttp", "", "euttp"}
95+
r := vm.MustRun(S{
96+
F: a,
97+
// F: b,
98+
})
99+
assert.Equal(t, []interface{}{true, true, true}, r.Eval("F"))
87100
}

validator/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ type T struct {
179179
|`regexp('^\\w*$')`|Regular match the current struct field, return boolean|
180180
|`sprintf('X value: %v', (X)$)`|`fmt.Sprintf`, format the value of struct field X|
181181
|`range(KvExpr, forEachExpr)`|Iterate over an array, slice, or dictionary <br> - `#k` is the element key var <br> - `#v` is the element value var <br> - `##` is the number of elements <br> - e.g. [example](../spec_range_test.go)|
182+
|`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters|
182183
|`email((X)$)`|Regular match the struct field X, return true if it is email|
183184
|`phone((X)$,<'defaultRegion'>)`|Regular match the struct field X, return true if it is phone|
184-
|`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters|
185185

186186
<!-- |`(X)$k`|Traverse each element key of the struct field X(type: map, slice, array)|
187187
|`(X)$v`|Traverse each element value of the struct field X(type: map, slice, array)| -->

validator/func.go

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@ package validator
22

33
import (
44
"errors"
5-
"fmt"
65
"regexp"
76

87
"github.com/nyaruka/phonenumbers"
98

10-
tagexpr "github.com/bytedance/go-tagexpr/v2"
9+
"github.com/bytedance/go-tagexpr/v2"
1110
)
1211

1312
// ErrInvalidWithoutMsg verification error without error message.
1413
var ErrInvalidWithoutMsg = errors.New("")
1514

1615
// MustRegFunc registers validator function expression.
1716
// NOTE:
18-
// panic if exist error;
19-
// example: phone($) or phone($,'CN');
20-
// If @force=true, allow to cover the existed same @funcName;
21-
// The go number types always are float64;
22-
// The go string types always are string.
17+
//
18+
// panic if exist error;
19+
// example: phone($) or phone($,'CN');
20+
// If @force=true, allow to cover the existed same @funcName;
21+
// The go number types always are float64;
22+
// The go string types always are string.
2323
func MustRegFunc(funcName string, fn func(args ...interface{}) error, force ...bool) {
2424
err := RegFunc(funcName, fn, force...)
2525
if err != nil {
@@ -29,10 +29,11 @@ func MustRegFunc(funcName string, fn func(args ...interface{}) error, force ...b
2929

3030
// RegFunc registers validator function expression.
3131
// NOTE:
32-
// example: phone($) or phone($,'CN');
33-
// If @force=true, allow to cover the existed same @funcName;
34-
// The go number types always are float64;
35-
// The go string types always are string.
32+
//
33+
// example: phone($) or phone($,'CN');
34+
// If @force=true, allow to cover the existed same @funcName;
35+
// The go number types always are float64;
36+
// The go string types always are string.
3637
func RegFunc(funcName string, fn func(args ...interface{}) error, force ...bool) error {
3738
return tagexpr.RegFunc(funcName, func(args ...interface{}) interface{} {
3839
err := fn(args...)
@@ -99,24 +100,3 @@ func init() {
99100
return nil
100101
}, true)
101102
}
102-
103-
func init() {
104-
// in: Check if the first parameter is one of the enumerated parameters
105-
MustRegFunc("in", func(args ...interface{}) error {
106-
switch len(args) {
107-
case 0:
108-
return nil
109-
case 1:
110-
return errors.New("input parameters of the in function are at least two")
111-
default:
112-
elem := args[0]
113-
set := args[1:]
114-
for _, e := range set {
115-
if elem == e {
116-
return nil
117-
}
118-
}
119-
return fmt.Errorf("%#v is not in the list %+v", elem, set)
120-
}
121-
}, true)
122-
}

validator/validator_test.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,10 @@ func TestIn(t *testing.T) {
183183
v := vd.New("vd")
184184
data := &T{}
185185
err := v.Validate(data)
186-
assert.EqualError(t, err, "\"\" is not in the list [a b c]")
186+
assert.EqualError(t, err, "invalid parameter: A")
187187
data.A = "b"
188188
err = v.Validate(data)
189-
assert.EqualError(t, err, "0 is not in the list [1 2 3]")
189+
assert.EqualError(t, err, "invalid parameter: B")
190190
data.B = 2
191191
err = v.Validate(data)
192192
assert.NoError(t, err)
@@ -196,14 +196,14 @@ func TestIn(t *testing.T) {
196196
}
197197
data2 := &T2{}
198198
err = v.Validate(data2)
199-
assert.EqualError(t, err, "input parameters of the in function are at least two")
199+
assert.EqualError(t, err, "invalid parameter: C")
200200

201201
type T3 struct {
202202
C string `vd:"in($,1)"`
203203
}
204204
data3 := &T3{}
205205
err = v.Validate(data3)
206-
assert.EqualError(t, err, "\"\" is not in the list [1]")
206+
assert.EqualError(t, err, "invalid parameter: C")
207207
}
208208

209209
type (
@@ -309,3 +309,17 @@ func TestRegexp(t *testing.T) {
309309
assert.EqualError(t, vd.Validate(&TStruct{A: "abc1"}), "invalid parameter: A")
310310
assert.EqualError(t, vd.Validate(&TStruct{A: "0?0?0?0"}), "invalid parameter: A")
311311
}
312+
313+
func TestRangeIn(t *testing.T) {
314+
type S struct {
315+
F []string `vd:"range($, in(#v, '', 'ttp', 'euttp'))"`
316+
}
317+
err := vd.Validate(S{
318+
F: []string{"ttp", "", "euttp"},
319+
})
320+
assert.NoError(t, err)
321+
err = vd.Validate(S{
322+
F: []string{"ttp", "?", "euttp"},
323+
})
324+
assert.EqualError(t, err, "invalid parameter: F")
325+
}

0 commit comments

Comments
 (0)