diff --git a/docs/source/format.rst b/docs/source/format.rst index 1217255..847c93c 100644 --- a/docs/source/format.rst +++ b/docs/source/format.rst @@ -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 diff --git a/gabbi/handlers/base.py b/gabbi/handlers/base.py index 1bbafe0..980eebb 100644 --- a/gabbi/handlers/base.py +++ b/gabbi/handlers/base.py @@ -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 diff --git a/gabbi/handlers/core.py b/gabbi/handlers/core.py index 97a1d87..cc80b1d 100644 --- a/gabbi/handlers/core.py +++ b/gabbi/handlers/core.py @@ -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): @@ -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) diff --git a/gabbi/handlers/jsonhandler.py b/gabbi/handlers/jsonhandler.py index 34dc7ae..2ee49d5 100644 --- a/gabbi/handlers/jsonhandler.py +++ b/gabbi/handlers/jsonhandler.py @@ -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 diff --git a/gabbi/tests/gabbits_intercept/regex.yaml b/gabbi/tests/gabbits_intercept/regex.yaml index 9a0c055..1c01c63 100644 --- a/gabbi/tests/gabbits_intercept/regex.yaml +++ b/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 @@ -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/'