Skip to content

Commit

Permalink
Add support for lists in json_matcher (#569)
Browse files Browse the repository at this point in the history
* cleanup mypy

Co-authored-by: Mark Story <[email protected]>
  • Loading branch information
beliaev-maksim and markstory committed Aug 15, 2022
1 parent d49f829 commit 1db612d
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Add `passthrough` argument to `BaseResponse` object. See #557
* Fix `registries` leak. See #563
* Add support for the `loose` version of `json_params_matcher` via named argument `strict_match`. See #551
* Add lists support as JSON objects in `json_params_matcher`. See #559
* Added project links to pypi listing.

0.21.0
Expand Down
6 changes: 1 addition & 5 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[mypy]
exclude = tests
show_column_numbers=True
show_error_codes = True

Expand Down Expand Up @@ -26,8 +27,3 @@ warn_unreachable=False

strict_equality=True
ignore_missing_imports=True

[mypy-responses.tests.*]
disallow_untyped_defs=False
disallow_untyped_calls=False
disallow_any_decorated=False
29 changes: 19 additions & 10 deletions responses/matchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,17 @@ def match(request: PreparedRequest) -> Tuple[bool, str]:


def json_params_matcher(
params: Optional[Dict[str, Any]], *, strict_match: bool = True
params: Optional[Union[Dict[str, Any], List[Any]]], *, strict_match: bool = True
) -> Callable[..., Any]:
"""Matches JSON encoded data of request body.
Parameters
----------
params : dict
JSON data provided to 'json' arg of request or a part of it if used in
params : dict or list
JSON object provided to 'json' arg of request or a part of it if used in
conjunction with ``strict_match=False``.
strict_match : bool, default=True
Applied only when JSON object is a dictionary.
If set to ``True``, validates that all keys of JSON object match.
If set to ``False``, original request may contain additional keys.
Expand All @@ -121,22 +122,30 @@ def json_params_matcher(
def match(request: PreparedRequest) -> Tuple[bool, str]:
reason = ""
request_body = request.body
params_dict = params or {}
json_params = (params or {}) if not isinstance(params, list) else params
try:
if isinstance(request_body, bytes):
request_body = request_body.decode("utf-8")
json_body = json_module.loads(request_body) if request_body else {}

if not strict_match:
if (
not strict_match
and isinstance(json_body, dict)
and isinstance(json_params, dict)
):
# filter down to just the params specified in the matcher
json_body = _filter_dict_recursively(json_body, params_dict)
json_body = _filter_dict_recursively(json_body, json_params)

valid = params is None if request_body is None else params_dict == json_body
valid = params is None if request_body is None else json_params == json_body

if not valid:
reason = "request.body doesn't match: {} doesn't match {}".format(
_create_key_val_str(json_body), _create_key_val_str(params_dict)
)
if isinstance(json_body, dict) and isinstance(json_params, dict):
reason = "request.body doesn't match: {} doesn't match {}".format(
_create_key_val_str(json_body), _create_key_val_str(json_params)
)
else:
reason = f"request.body doesn't match: {json_body} doesn't match {json_params}"

if not strict_match:
reason += (
"\nNote: You use non-strict parameters check, "
Expand Down
21 changes: 21 additions & 0 deletions responses/tests/test_matchers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from unittest.mock import Mock

import pytest
import requests
from requests.exceptions import ConnectionError
Expand Down Expand Up @@ -136,6 +138,25 @@ def run():
assert_reset()


def test_json_params_matcher_json_list():
json_a = [{"a": "b"}]
json_b = '[{"a": "b", "c": "d"}]'
mock_request = Mock(body=json_b)
result = matchers.json_params_matcher(json_a)(mock_request)
assert result == (
False,
"request.body doesn't match: [{'a': 'b', 'c': 'd'}] doesn't match [{'a': 'b'}]",
)


def test_json_params_matcher_json_list_empty():
json_a = []
json_b = "[]"
mock_request = Mock(body=json_b)
result = matchers.json_params_matcher(json_a)(mock_request)
assert result == (True, "")


def test_urlencoded_params_matcher_blank():
@responses.activate
def run():
Expand Down

0 comments on commit 1db612d

Please sign in to comment.