From 0a01f0fb5133582d9d0e931e98fe9ea0661c77bb Mon Sep 17 00:00:00 2001 From: Arthur Hamon Date: Wed, 12 Jun 2019 12:20:30 +0200 Subject: [PATCH] change all the matchers with an assert statement and refactor the requests_match function In order to use the new assert mechanism that returns explicit assertion failure message, all the default matchers does not return a boolean, but only do an assert statement with a basic assertion message (value_1 != value_2). The requests_match function has been refactored to use the 'get_matchers_results' function in order to have explicit failures that are logged if any. Many unit tests have been changed as the matchers does not return a boolean value anymore. Note: Only the matchers "body" and "raw_body" does not have an assertion message, the body values might be big and not useful to be display to spot the differences. --- tests/unit/test_matchers.py | 63 +++++++++++++++++++++++++++++-------- vcr/matchers.py | 60 +++++++++++++++++------------------ 2 files changed, 78 insertions(+), 45 deletions(-) diff --git a/tests/unit/test_matchers.py b/tests/unit/test_matchers.py index 5ddb583..604b650 100644 --- a/tests/unit/test_matchers.py +++ b/tests/unit/test_matchers.py @@ -1,4 +1,5 @@ import itertools +from vcr.compat import mock import pytest @@ -21,20 +22,22 @@ REQUESTS = { def assert_matcher(matcher_name): matcher = getattr(matchers, matcher_name) for k1, k2 in itertools.permutations(REQUESTS, 2): - matched = matcher(REQUESTS[k1], REQUESTS[k2]) - if matcher_name in {k1, k2}: - assert not matched + expecting_assertion_error = matcher_name in {k1, k2} + if expecting_assertion_error: + with pytest.raises(AssertionError): + matcher(REQUESTS[k1], REQUESTS[k2]) else: - assert matched + assert matcher(REQUESTS[k1], REQUESTS[k2]) is None def test_uri_matcher(): for k1, k2 in itertools.permutations(REQUESTS, 2): - matched = matchers.uri(REQUESTS[k1], REQUESTS[k2]) - if {k1, k2} != {'base', 'method'}: - assert not matched + expecting_assertion_error = {k1, k2} != {"base", "method"} + if expecting_assertion_error: + with pytest.raises(AssertionError): + matchers.uri(REQUESTS[k1], REQUESTS[k2]) else: - assert matched + assert matchers.uri(REQUESTS[k1], REQUESTS[k2]) is None req1_body = (b"test" @@ -107,7 +110,7 @@ req2_body = (b"test" ) ]) def test_body_matcher_does_match(r1, r2): - assert matchers.body(r1, r2) + assert matchers.body(r1, r2) is None @pytest.mark.parametrize("r1, r2", [ @@ -135,13 +138,30 @@ def test_body_matcher_does_match(r1, r2): ) ]) def test_body_match_does_not_match(r1, r2): - assert not matchers.body(r1, r2) + with pytest.raises(AssertionError): + matchers.body(r1, r2) def test_query_matcher(): - req1 = request.Request('GET', 'http://host.com/?a=b&c=d', '', {}) - req2 = request.Request('GET', 'http://host.com/?c=d&a=b', '', {}) - assert matchers.query(req1, req2) + req1 = request.Request("GET", "http://host.com/?a=b&c=d", "", {}) + req2 = request.Request("GET", "http://host.com/?c=d&a=b", "", {}) + assert matchers.query(req1, req2) is None + + req1 = request.Request("GET", "http://host.com/?a=b&a=b&c=d", "", {}) + req2 = request.Request("GET", "http://host.com/?a=b&c=d&a=b", "", {}) + req3 = request.Request("GET", "http://host.com/?c=d&a=b&a=b", "", {}) + assert matchers.query(req1, req2) is None + assert matchers.query(req1, req3) is None + + +def test_matchers(): + assert_matcher("method") + assert_matcher("scheme") + assert_matcher("host") + assert_matcher("port") + assert_matcher("path") + assert_matcher("query") + def test_evaluate_matcher_does_match(): def bool_matcher(r1, r2): @@ -230,3 +250,20 @@ def test_get_matchers_results(r1, r2, expected_successes, expected_failures): for i, expected_failure in enumerate(expected_failures): assert failures[i][0] == expected_failure assert failures[i][1] is not None + + +@mock.patch("vcr.matchers.get_matchers_results") +@pytest.mark.parametrize( + "successes, failures, expected_match", + [ + (["method", "path"], [], True), + (["method"], ["path"], False), + ([], ["method", "path"], False), + ], +) +def test_requests_match(mock_get_matchers_results, successes, failures, expected_match): + mock_get_matchers_results.return_value = (successes, failures) + r1 = request.Request("GET", "http://host.com/p?a=b", "", {}) + r2 = request.Request("GET", "http://host.com/p?a=b", "", {}) + match = matchers.requests_match(r1, r2, [matchers.method, matchers.path]) + assert match is expected_match diff --git a/vcr/matchers.py b/vcr/matchers.py index ede73fb..1714018 100644 --- a/vcr/matchers.py +++ b/vcr/matchers.py @@ -8,35 +8,47 @@ log = logging.getLogger(__name__) def method(r1, r2): - return r1.method == r2.method + assert r1.method == r2.method, "{} != {}".format(r1.method, r2.method) def uri(r1, r2): - return r1.uri == r2.uri + assert r1.uri == r2.uri, "{} != {}".format(r1.uri, r2.uri) def host(r1, r2): - return r1.host == r2.host + assert r1.host == r2.host, "{} != {}".format(r1.host, r2.host) def scheme(r1, r2): - return r1.scheme == r2.scheme + assert r1.scheme == r2.scheme, "{} != {}".format(r1.scheme, r2.scheme) def port(r1, r2): - return r1.port == r2.port + assert r1.port == r2.port, "{} != {}".format(r1.port, r2.port) def path(r1, r2): - return r1.path == r2.path + assert r1.path == r2.path, "{} != {}".format(r1.path, r2.path) def query(r1, r2): - return r1.query == r2.query + assert r1.query == r2.query, "{} != {}".format(r1.query, r2.query) def raw_body(r1, r2): - return read_body(r1) == read_body(r2) + assert read_body(r1) == read_body(r2) + + +def body(r1, r2): + transformer = _get_transformer(r1) + r2_transformer = _get_transformer(r2) + if transformer != r2_transformer: + transformer = _identity + assert transformer(read_body(r1)) == transformer(read_body(r2)) + + +def headers(r1, r2): + assert r1.headers == r2.headers, "{} != {}".format(r1.headers, r2.headers) def _header_checker(value, header='Content-Type'): @@ -74,31 +86,15 @@ def _get_transformer(request): return _identity -def body(r1, r2): - transformer = _get_transformer(r1) - r2_transformer = _get_transformer(r2) - if transformer != r2_transformer: - transformer = _identity - return transformer(read_body(r1)) == transformer(read_body(r2)) - - -def headers(r1, r2): - return r1.headers == r2.headers - - -def _log_matches(r1, r2, matches): - differences = [m for m in matches if not m[0]] - if differences: - log.debug( - "Requests {} and {} differ according to " - "the following matchers: {}".format(r1, r2, differences) - ) - - def requests_match(r1, r2, matchers): - matches = [(m(r1, r2), m) for m in matchers] - _log_matches(r1, r2, matches) - return all(m[0] for m in matches) + successes, failures = get_matchers_results(r1, r2, matchers) + if failures: + log.debug( + "Requests {} and {} differ.\n" + "Failure details:\n" + "{}".format(r1, r2, failures) + ) + return len(failures) == 0 def _evaluate_matcher(matcher_function, *args):