Skip to content
This repository was archived by the owner on Sep 17, 2022. It is now read-only.

Commit bd533a6

Browse files
committed
Added type and range matchers
1 parent 613f56f commit bd533a6

File tree

10 files changed

+257
-29
lines changed

10 files changed

+257
-29
lines changed

spec/matcher/and_matcher.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ func (m andMatcher) Match(data interface{}, location string) (ok bool, pass []st
3535
}
3636

3737
func (m andMatcher) String() string {
38-
return fmt.Sprintf("%d", m.matchers)
38+
return fmt.Sprintf("%v", m.matchers)
3939
}

spec/matcher/matcher.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ func tryGetMatcherFromMap(m map[string]interface{}) Matcher {
5656
return AndMatcherWithOptions(params)
5757
case "or":
5858
return OrMatcherWithOptions(params)
59+
case "range":
60+
return RangeMatcherWithOptions(params)
61+
case "type::int":
62+
return TypeIntMatcherWithOptions(params)
63+
case "type::float":
64+
return TypeFloatMatcherWithOptions(params)
65+
case "type::string":
66+
return TypeStringMatcherWithOptions(params)
67+
case "type::object":
68+
return TypeObjectMatcherWithOptions(params)
69+
case "type::array":
70+
return TypeArrayMatcherWithOptions(params)
5971
default:
6072
log.L.Fatalf("unknown matcher type %s", t)
6173
return nil

spec/matcher/range_matcher.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package matcher
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/getapid/apid/log"
7+
)
8+
9+
type rangeMatcher struct {
10+
from, to float64
11+
}
12+
13+
func RangeMatcherWithOptions(value interface{}) Matcher {
14+
params, err := extractMap(value)
15+
if err != nil {
16+
log.L.Fatalf("invalid range matcher, got %v", value)
17+
}
18+
19+
from, err := extractFloat(params["from"])
20+
if err != nil {
21+
log.L.Fatalf("invalid range matcher, got %v", value)
22+
}
23+
24+
to, err := extractFloat(params["to"])
25+
if err != nil {
26+
log.L.Fatalf("invalid range matcher, got %v", value)
27+
}
28+
29+
return &rangeMatcher{from: from, to: to}
30+
}
31+
32+
func (m rangeMatcher) Match(data interface{}, location string) (bool, []string, []string) {
33+
switch val := data.(type) {
34+
case float64:
35+
return m.check(val, location)
36+
case int64:
37+
return m.check(float64(val), location)
38+
}
39+
40+
return false, nil, []string{fmt.Sprintf("%s wanted in range [%f, %f], got %v", location, m.from, m.to, data)}
41+
}
42+
43+
func (m rangeMatcher) check(val float64, location string) (bool, []string, []string) {
44+
if val >= m.from && val <= m.to {
45+
return true, []string{fmt.Sprintf("%s is between %f and %f", location, m.from, m.to)}, nil
46+
}
47+
return false, nil, []string{fmt.Sprintf("%s is not between %f and %f", location, m.from, m.to)}
48+
}
49+
50+
func (m rangeMatcher) String() string {
51+
return fmt.Sprintf("[%f, %f]", m.from, m.to)
52+
}

spec/matcher/type_array.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package matcher
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type typeArrayMatcher struct{}
8+
9+
func TypeArrayMatcherWithOptions(value interface{}) Matcher {
10+
return &typeArrayMatcher{}
11+
}
12+
13+
func (m typeArrayMatcher) Match(data interface{}, location string) (bool, []string, []string) {
14+
switch data.(type) {
15+
case []interface{}:
16+
return true, []string{fmt.Sprintf("%s is an array", location)}, nil
17+
}
18+
19+
return false, nil, []string{fmt.Sprintf("%s wanted array, got %v", location, data)}
20+
}
21+
22+
func (m typeArrayMatcher) String() string {
23+
return "type::array"
24+
}

spec/matcher/type_float.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package matcher
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type typeFloatMatcher struct{}
8+
9+
func TypeFloatMatcherWithOptions(value interface{}) Matcher {
10+
return &typeFloatMatcher{}
11+
}
12+
13+
func (m typeFloatMatcher) Match(data interface{}, location string) (bool, []string, []string) {
14+
switch data.(type) {
15+
case int64:
16+
return true, []string{fmt.Sprintf("%s is float", location)}, nil
17+
case float64:
18+
return true, []string{fmt.Sprintf("%s is float", location)}, nil
19+
}
20+
21+
return false, nil, []string{fmt.Sprintf("%s wanted float, got %v", location, data)}
22+
}
23+
24+
func (m typeFloatMatcher) String() string {
25+
return "type::float"
26+
}

spec/matcher/type_int.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package matcher
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type typeIntMatcher struct{}
8+
9+
func TypeIntMatcherWithOptions(value interface{}) Matcher {
10+
return &typeIntMatcher{}
11+
}
12+
13+
func (m typeIntMatcher) Match(data interface{}, location string) (bool, []string, []string) {
14+
switch val := data.(type) {
15+
case int64:
16+
return m.check(float64(val), location)
17+
case float64:
18+
return m.check(val, location)
19+
}
20+
21+
return false, nil, []string{fmt.Sprintf("%s wanted int, got %v", location, data)}
22+
}
23+
24+
func (m typeIntMatcher) check(val float64, location string) (bool, []string, []string) {
25+
if val == float64(int(val)) {
26+
return true, []string{fmt.Sprintf("%s is int", location)}, nil
27+
}
28+
return false, nil, []string{fmt.Sprintf("%s wanted int, got %v", location, val)}
29+
}
30+
31+
func (m typeIntMatcher) String() string {
32+
return "type::integer"
33+
}

spec/matcher/type_object.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package matcher
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type typeObjectMatcher struct{}
8+
9+
func TypeObjectMatcherWithOptions(value interface{}) Matcher {
10+
return &typeObjectMatcher{}
11+
}
12+
13+
func (m typeObjectMatcher) Match(data interface{}, location string) (bool, []string, []string) {
14+
switch data.(type) {
15+
case map[string]interface{}:
16+
return true, []string{fmt.Sprintf("%s is an object", location)}, nil
17+
}
18+
19+
return false, nil, []string{fmt.Sprintf("%s wanted object, got %v", location, data)}
20+
}
21+
22+
func (m typeObjectMatcher) String() string {
23+
return "type::object"
24+
}

spec/matcher/type_string.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package matcher
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type typeStringMatcher struct{}
8+
9+
func TypeStringMatcherWithOptions(value interface{}) Matcher {
10+
return &typeStringMatcher{}
11+
}
12+
13+
func (m typeStringMatcher) Match(data interface{}, location string) (bool, []string, []string) {
14+
switch data.(type) {
15+
case string:
16+
return true, []string{fmt.Sprintf("%s is string", location)}, nil
17+
}
18+
19+
return false, nil, []string{fmt.Sprintf("%s wanted string, got %v", location, data)}
20+
}
21+
22+
func (m typeStringMatcher) String() string {
23+
return "type::string"
24+
}

tests/passing/apid/is.libsonnet

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,31 @@ local or_matcher(matchers) =
6969
'$$matcher_params$$': matchers,
7070
};
7171

72-
local json_to_string(json) = std.manifestJsonEx(json, '');
72+
local range_matcher(from, to) =
73+
{
74+
'$$matcher_type$$': 'range',
75+
'$$matcher_params$$': {
76+
from: from,
77+
to: to,
78+
},
79+
};
80+
81+
local type_matcher(type) =
82+
{
83+
'$$matcher_type$$': 'type::%s' % type,
84+
'$$matcher_params$$': null,
85+
};
7386

7487
{
75-
key: {
76-
regex(regex):: '%s%s' % [SHORTHAND_MATCHER_PREFIX, json_to_string(regex_matcher(regex))],
77-
string(string, case_sensitive=true):: '%s%s' % [SHORTHAND_MATCHER_PREFIX, json_to_string(string_matcher(string, case_sensitive))],
78-
int(int):: '%s%s' % [SHORTHAND_MATCHER_PREFIX, json_to_string(int_matcher(int))],
79-
float(float):: '%s%s' % [SHORTHAND_MATCHER_PREFIX, json_to_string(float_matcher(float))],
80-
len(len):: '%s%s' % [SHORTHAND_MATCHER_PREFIX, json_to_string(len_matcher(len))],
81-
or(matchers):: '%s%s' % [SHORTHAND_MATCHER_PREFIX, json_to_string(or_matcher(matchers))],
88+
type: {
89+
int():: type_matcher('int'),
90+
float():: type_matcher('float'),
91+
string():: type_matcher('string'),
92+
object():: type_matcher('object'),
93+
array():: type_matcher('array'),
8294
},
8395

96+
key(matcher):: '%s%s' % [SHORTHAND_MATCHER_PREFIX, std.manifestJsonEx(matcher, '')],
8497
any():: any_matcher(),
8598
regex(regex):: regex_matcher(regex),
8699
string(string, case_sensitive=true):: string_matcher(string, case_sensitive),
@@ -91,4 +104,5 @@ local json_to_string(json) = std.manifestJsonEx(json, '');
91104
len(len):: len_matcher(len),
92105
and(matchers):: and_matcher(matchers),
93106
or(matchers):: or_matcher(matchers),
107+
range(from, to):: range_matcher(from, to),
94108
}

tests/passing/body_pass.jsonnet

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,49 @@ local steps(method, body, expected) = [
3838
for body in [vars.json]
3939
for expected in [
4040
{
41-
'random float': _.float(66.861),
42-
[_.key.string('random')]: _.int(88),
43-
[_.key.regex('first\\w+')]: 'Lilith',
44-
[_.key.or([
45-
_.string("Stephanie"),
46-
_.len(9)
47-
])]: {
48-
age: 93,
49-
address: _.json({
50-
city: 'Kobe',
51-
country: 'Australia',
52-
countryCode: 'VE',
53-
}),
41+
'random float': _.and([
42+
_.float(66.861),
43+
_.type.float(),
44+
]),
45+
[_.key(_.string('random'))]: _.int(88),
46+
[_.key(_.regex('first\\w+'))]: 'Lilith',
47+
[_.key(
48+
_.or([
49+
_.string('Stephanie'),
50+
_.len(9),
51+
])
52+
)]: {
53+
age: _.and([
54+
_.range(90, 94),
55+
_.type.int()
56+
]),
57+
address: _.and([
58+
_.json({
59+
city: 'Kobe',
60+
country: 'Australia',
61+
countryCode: 'VE',
62+
}),
63+
_.type.object()
64+
]),
5465
},
55-
array: [
56-
'Marline',
57-
'Catharine',
58-
],
66+
array: _.and(
67+
[
68+
_.type.array(),
69+
[
70+
_.and([
71+
'Marline',
72+
_.type.string(),
73+
]),
74+
'Catharine',
75+
],
76+
]
77+
),
5978
countryCode: _.and(
6079
[
6180
_.len(2),
62-
_.string('VE')
81+
_.string('VE'),
6382
]
64-
)
83+
),
6584
},
6685
]
67-
}
86+
}

0 commit comments

Comments
 (0)