Repository navigation
Expand file tree
/
Copy pathbuiltins_integration_test.go
More file actions
92 lines (86 loc) · 2.52 KB
/
Copy pathbuiltins_integration_test.go
File metadata and controls
92 lines (86 loc) · 2.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package validator
import (
"reflect"
"testing"
)
// TestBuiltinCatalogNoDuplicateSignatures guards that no two builtins share a signature (silent registry overwrite).
func TestBuiltinCatalogNoDuplicateSignatures(t *testing.T) {
seen := map[string]bool{}
for _, r := range Rules() {
if seen[r.Signature()] {
t.Errorf("duplicate built-in rule signature: %q", r.Signature())
}
seen[r.Signature()] = true
}
fseen := map[string]bool{}
for _, f := range Filters() {
if fseen[f.Signature()] {
t.Errorf("duplicate built-in filter signature: %q", f.Signature())
}
fseen[f.Signature()] = true
}
// sanity: catalog should be substantial
if n := len(Rules()); n < 40 {
t.Errorf("expected >=40 built-in rules, got %d", n)
}
if n := len(Filters()); n < 8 {
t.Errorf("expected >=8 built-in filters, got %d", n)
}
}
// TestBuiltinRulesThroughDSL guards that registered builtins compile via the DSL and evaluate over a field.
func TestBuiltinRulesThroughDSL(t *testing.T) {
v := MustNew()
cases := []struct {
expr string
val any
want bool
}{
{"required && email", "a@b.com", true},
{"required && email", "not-an-email", false},
{"required && email", "", true}, // default required: "" present; email skips empty
{"required && (in:a,b || alpha)", "a", true},
{"required && (in:a,b || alpha)", "xyz", true},
{"required && (in:a,b || alpha)", "12", false},
{`regex:"^x.+"`, "xylophone", true}, // raw-arg quoted regex
{`regex:"^x.+"`, "nope", false},
{"min:3", "abcd", true},
{"min:3", "ab", false},
{"min:3", 5, true}, // numeric value, not length
{"max:10 && numeric", "7", true},
}
for _, c := range cases {
compiled, err := v.compile(c.expr)
if err != nil {
t.Errorf("compile(%q): %v", c.expr, err)
continue
}
f := &Field{name: "field", rv: reflect.ValueOf(c.val)}
got, err := compiled.Fast(f)
if err != nil {
t.Errorf("%q over %v: %v", c.expr, c.val, err)
continue
}
if got != c.want {
t.Errorf("%q over %v = %v, want %v", c.expr, c.val, got, c.want)
}
}
}
// TestBuiltinFilters spot-checks a couple of built-in filters end to end.
func TestBuiltinFilters(t *testing.T) {
v := MustNew()
trim, ok := v.registry.filter("trim")
if !ok {
t.Fatal("trim filter not registered")
}
out, err := trim.Handle(" hi ")
if err != nil || out != "hi" {
t.Errorf("trim(\" hi \") = %v, %v", out, err)
}
lower, ok := v.registry.filter("lower")
if !ok {
t.Fatal("lower filter not registered")
}
if out, _ := lower.Handle("ABC"); out != "abc" {
t.Errorf("lower(ABC) = %v", out)
}
}