Skip to content

Commit d8fcebf

Browse files
authored
Merge pull request #66 from wklken/ft_contains_support_array
2 parents 9306d95 + f6aa0af commit d8fcebf

File tree

6 files changed

+104
-17
lines changed

6 files changed

+104
-17
lines changed

docs/Usage/assert.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ nav_order: 4
77
---
88

99
# Assert
10+
1011
{: .no_toc }
1112

1213
Some examples show how to assert the response.
1314
{: .fs-6 .fw-300 }
1415

1516

1617
## Table of contents
18+
1719
{: .no_toc .text-delta }
1820

1921
1. TOC
@@ -75,6 +77,23 @@ assert:
7577
protoMinor: 0
7678
```
7779
80+
note: the `*contains` support a single string or a list of strings, if the value is a list, it's `AND` relationship.
81+
82+
```yaml
83+
assert:
84+
# body should both contains Hello and world
85+
body_contains:
86+
- Hello
87+
- world
88+
# body should not contains Hello and world
89+
body_not_contains:
90+
- Hello
91+
- world
92+
body_icontains:
93+
- hello
94+
- world
95+
```
96+
7897
## assert header
7998

8099
```yaml
@@ -140,6 +159,16 @@ assert:
140159
error_contains: context deadline exceeded
141160
```
142161

162+
note: the `error_contains` support a single string or a list of strings, if the value is a list, it's `AND` relationship.
163+
164+
```yaml
165+
assert:
166+
# error should both contains Hello and world
167+
error_contains:
168+
- Hello
169+
- world
170+
```
171+
143172
## assert json
144173

145174
```yaml

pkg/assert/string.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,39 @@ func NotEndsWith(s, suffix interface{}) (bool, string) {
5656

5757
return true, "OK"
5858
}
59+
60+
// StringContainsAll string a should contains all elements
61+
func StringContainsAll(s, elements interface{}) (bool, string) {
62+
listValue := reflect.ValueOf(elements)
63+
if reflect.TypeOf(elements).Kind() != reflect.Slice {
64+
return false, fmt.Sprintf("contains_all | `%v` should be slice", prettyLine(elements))
65+
}
66+
67+
for i := 0; i < listValue.Len(); i++ {
68+
element := listValue.Index(i).Interface()
69+
if !test(s, element, strings.Contains) {
70+
// FIXME: add index in error info
71+
return false, fmt.Sprintf("contains | `%v` should contains `%v`", prettyLine(s), element)
72+
}
73+
}
74+
75+
return true, "OK"
76+
}
77+
78+
// StringContainsAll string a should not contains all elements
79+
func StringNotContainsAll(s, elements interface{}) (bool, string) {
80+
listValue := reflect.ValueOf(elements)
81+
if reflect.TypeOf(elements).Kind() != reflect.Slice {
82+
return false, fmt.Sprintf("contains_all | `%v` should be slice", prettyLine(elements))
83+
}
84+
85+
for i := 0; i < listValue.Len(); i++ {
86+
element := listValue.Index(i).Interface()
87+
if test(s, element, strings.Contains) {
88+
// FIXME: add index in error info
89+
return false, fmt.Sprintf("contains | `%v` should not contains `%v`", prettyLine(s), element)
90+
}
91+
}
92+
93+
return true, "OK"
94+
}

pkg/assertion/error.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import (
1010

1111
func DoErrorAssertions(c *config.Case, err error) (stats util.Stats) {
1212
stats.AddInfofMessage("assert.error_contains: ")
13-
ok, message := assert.Contains(err.Error(), c.Assert.ErrorContains)
13+
// ok, message := assert.Contains(err.Error(), c.Assert.ErrorContains)
14+
ok, message := assert.StringContainsAll(err.Error(), c.Assert.ErrorContains)
1415
if ok {
1516
stats.AddPassMessage()
1617
stats.IncrOkAssertCount()

pkg/assertion/key.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,25 +226,28 @@ func DoKeysAssertion(
226226
{
227227
key: "assert.body_contains",
228228
ctx: Ctx{
229-
f: assert.Contains,
229+
// f: assert.Contains,
230+
f: assert.StringContainsAll,
230231
element1: bodyStr,
231232
element2: c.Assert.BodyContains,
232233
},
233234
},
234235
{
235236
key: "assert.body_not_contains",
236237
ctx: Ctx{
237-
f: assert.NotContains,
238+
// f: assert.NotContains,
239+
f: assert.StringNotContainsAll,
238240
element1: bodyStr,
239241
element2: c.Assert.BodyNotContains,
240242
},
241243
},
242244
{
243245
key: "assert.body_icontains",
244246
ctx: Ctx{
245-
f: assert.Contains,
247+
// f: assert.Contains,
248+
f: assert.StringContainsAll,
246249
element1: strings.ToLower(bodyStr),
247-
element2: strings.ToLower(c.Assert.BodyIContains),
250+
element2: util.StringArrayMapFunc(c.Assert.BodyIContains, strings.ToLower),
248251
},
249252
},
250253
{

pkg/config/assert.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ type Assert struct {
3737

3838
Body string `yaml:"body"`
3939

40-
BodyContains string `yaml:"body_contains" mapstructure:"body_contains"`
41-
BodyNotContains string `yaml:"body_not_contains" mapstructure:"body_not_contains"`
42-
BodyIContains string `yaml:"body_icontains" mapstructure:"body_icontains"`
43-
BodyStartsWith string `yaml:"body_startswith" mapstructure:"body_startswith"`
44-
BodyEndsWith string `yaml:"body_endswith" mapstructure:"body_endswith"`
45-
BodyNotStartsWith string `yaml:"body_not_startswith" mapstructure:"body_not_startswith"`
46-
BodyNotEndsWith string `yaml:"body_not_endswith" mapstructure:"body_not_endswith"`
47-
BodyMatches string `yaml:"body_matches" mapstructure:"body_matches"`
48-
BodyNotMatches string `yaml:"body_not_matches" mapstructure:"body_not_matches"`
40+
BodyContains []string `yaml:"body_contains" mapstructure:"body_contains"`
41+
BodyNotContains []string `yaml:"body_not_contains" mapstructure:"body_not_contains"`
42+
BodyIContains []string `yaml:"body_icontains" mapstructure:"body_icontains"`
43+
BodyStartsWith string `yaml:"body_startswith" mapstructure:"body_startswith"`
44+
BodyEndsWith string `yaml:"body_endswith" mapstructure:"body_endswith"`
45+
BodyNotStartsWith string `yaml:"body_not_startswith" mapstructure:"body_not_startswith"`
46+
BodyNotEndsWith string `yaml:"body_not_endswith" mapstructure:"body_not_endswith"`
47+
BodyMatches string `yaml:"body_matches" mapstructure:"body_matches"`
48+
BodyNotMatches string `yaml:"body_not_matches" mapstructure:"body_not_matches"`
4949

5050
Header map[string]interface{} `yaml:"header"`
5151
HeaderExists []string `yaml:"header_exists" mapstructure:"header_exists"`
@@ -65,7 +65,7 @@ type Assert struct {
6565

6666
// if request fail like dial fail/context deadline exceeded, will do assert error_contains only,
6767
// will pass if the error message contains the string
68-
ErrorContains string `yaml:"error_contains" mapstructure:"error_contains"`
68+
ErrorContains []string `yaml:"error_contains" mapstructure:"error_contains"`
6969

7070
HasRedirect bool `yaml:"has_redirect" mapstructure:"has_redirect"`
7171
RedirectCountLt int64 `yaml:"redirectCount_lt" mapstructure:"redirectCount_lt"`
@@ -115,8 +115,8 @@ func (a *Assert) Render(ctx map[string]interface{}) {
115115

116116
a.Body = tpl.Render(a.Body, ctx)
117117

118-
a.BodyContains = tpl.Render(a.BodyContains, ctx)
119-
a.BodyNotContains = tpl.Render(a.BodyNotContains, ctx)
118+
a.BodyContains = renderStringArray(a.BodyContains, ctx)
119+
a.BodyNotContains = renderStringArray(a.BodyNotContains, ctx)
120120
a.BodyStartsWith = tpl.Render(a.BodyStartsWith, ctx)
121121
a.BodyEndsWith = tpl.Render(a.BodyEndsWith, ctx)
122122
a.BodyNotStartsWith = tpl.Render(a.BodyNotStartsWith, ctx)
@@ -127,6 +127,17 @@ func (a *Assert) Render(ctx map[string]interface{}) {
127127
}
128128
}
129129

130+
func renderStringArray(elements []string, ctx map[string]interface{}) []string {
131+
if len(elements) == 0 {
132+
return elements
133+
}
134+
n := make([]string, 0, len(elements))
135+
for _, s := range elements {
136+
n = append(n, tpl.Render(s, ctx))
137+
}
138+
return n
139+
}
140+
130141
type AssertJSON struct {
131142
Path string
132143
Value interface{}

pkg/util/string.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,10 @@ func OmitMiddle(s string, head int, tail int) string {
3535
func PrettyStringSlice(s []string) string {
3636
return "[" + strings.Join(s, ", ") + "]"
3737
}
38+
39+
func StringArrayMapFunc(elements []string, f func(string) string) (result []string) {
40+
for _, element := range elements {
41+
result = append(result, f(element))
42+
}
43+
return
44+
}

0 commit comments

Comments
 (0)