Skip to content

Commit

Permalink
Add support for regex in response_strings (#327)
Browse files Browse the repository at this point in the history
* Extract is_regex method for handlers
* Add docs for regex on response strings

Very similar to what is used for headers.

Fixes #326
  • Loading branch information
cdent committed Mar 16, 2024
1 parent 6939357 commit f3b9473
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 10 deletions.
5 changes: 5 additions & 0 deletions docs/source/format.rst
Expand Up @@ -181,6 +181,11 @@ Response Expectations
``response_strings`` A list of string fragments expected
to be present in the response body.

If the value is wrapped in ``/.../``
the response body will be searched
for the value as a regular
expression.

``response_json_paths`` A dictionary of JSONPath rules paired
with expected matches. Using this
rule requires that the content being
Expand Down
9 changes: 9 additions & 0 deletions gabbi/handlers/base.py
Expand Up @@ -66,6 +66,15 @@ def action(self, test, item, value=None):
"""
pass

def is_regex(self, value):
"""Check if the value is formatted to looks like a regular expression.
Meaning it starts and ends with "/".
"""
return (
value.startswith('/') and value.endswith('/') and len(value) > 1
)

def _register(self):
"""Register this handler on the provided test class."""
self.response_handler = None
Expand Down
18 changes: 13 additions & 5 deletions gabbi/handlers/core.py
Expand Up @@ -22,8 +22,18 @@ class StringResponseHandler(base.ResponseHandler):
test_key_value = []

def action(self, test, expected, value=None):
expected = test.replace_template(expected)
test.assert_in_or_print_output(expected, test.output)
is_regex = self.is_regex(expected)
expected = test.replace_template(expected, escape_regex=is_regex)

if is_regex:
# Trim off /
expected = expected[1:-1]
test.assertRegex(
test.output, expected,
'Expect resonse body %s to match /%s/' %
(test.output, expected))
else:
test.assert_in_or_print_output(expected, test.output)


class ForbiddenHeadersResponseHandler(base.ResponseHandler):
Expand Down Expand Up @@ -56,9 +66,7 @@ def action(self, test, header, value=None):
response = test.response

header_value = str(value)
is_regex = (header_value.startswith('/') and
header_value.endswith('/') and
len(header_value) > 1)
is_regex = self.is_regex(header_value)
header_value = test.replace_template(header_value,
escape_regex=is_regex)

Expand Down
5 changes: 1 addition & 4 deletions gabbi/handlers/jsonhandler.py
Expand Up @@ -118,10 +118,7 @@ def action(self, test, path, value=None):
'match %s' % (rhs_path, value))

# If expected is a string, check to see if it is a regex.
is_regex = (isinstance(value, str) and
value.startswith('/') and
value.endswith('/') and
len(value) > 1)
is_regex = isinstance(value, str) and self.is_regex(value)
expected = (rhs_match or
test.replace_template(value, escape_regex=is_regex))
match = lhs_match
Expand Down
29 changes: 28 additions & 1 deletion gabbi/tests/gabbits_intercept/regex.yaml
@@ -1,4 +1,4 @@
# Confirm regex handling in response and json path headers
# Confirm regex handling in response headers, strings and json path handlers
tests:
- name: regex header test
url: /cow?alpha=1
Expand All @@ -19,3 +19,30 @@ tests:
$.alpha: /ow$/
$.beta: /(?!cow).*/
$.gamma: /\d+/

- name: regex string test json
PUT: /cow
request_headers:
content-type: application/json
data:
alpha: cow
beta: pig
gamma: 1
response_strings:
- '/"alpha": "cow",/'

- name: regex string test multiline
GET: /presenter
response_strings:
- '/Hello World/'
- '/dolor sit/'

- name: regex string test splat
GET: /presenter
response_strings:
- '/dolor.*amet/'

- name: regex string test mix
GET: /presenter
response_strings:
- '/[Hh]el{2}o [Ww]orld/'

0 comments on commit f3b9473

Please sign in to comment.