[Python-modules-commits] [betamax] 02/08: Import betamax_0.8.0.orig.tar.gz

Daniele Tricoli eriol-guest at moszumanska.debian.org
Sun Sep 18 16:07:02 UTC 2016


This is an automated email from the git hooks/post-receive script.

eriol-guest pushed a commit to branch master
in repository betamax.

commit 9414c3ae38c7c86e7342496e0a8bf5f1aae37a01
Author: Daniele Tricoli <eriol at mornie.org>
Date:   Sun Sep 11 15:58:30 2016 +0200

    Import betamax_0.8.0.orig.tar.gz
---
 HISTORY.rst                                        |  22 +++++
 PKG-INFO                                           |  24 ++++-
 betamax.egg-info/PKG-INFO                          |  24 ++++-
 betamax.egg-info/SOURCES.txt                       |   4 +
 betamax/__init__.py                                |   2 +-
 betamax/exceptions.py                              |  48 ++++++++++
 betamax/fixtures/pytest.py                         | 105 ++++++++++++++++++---
 betamax/matchers/body.py                           |  19 ++--
 betamax/matchers/query.py                          |   5 +-
 betamax/options.py                                 |  13 ++-
 docs/api.rst                                       |   5 +-
 setup.cfg                                          |   4 +-
 tests/cassettes/FakeBetamaxTestCase.test_fake.json |   1 +
 ...est_pytest_fixture[https:-httpbin.org-get].json |   1 +
 tests/integration/test_fixtures.py                 |  25 +++++
 .../regression/test_requests_2_11_body_matcher.py  |  27 ++++++
 tests/unit/test_cassette.py                        |   8 ++
 tests/unit/test_exceptions.py                      |  35 +++++++
 tests/unit/test_matchers.py                        |   3 +
 tests/unit/test_options.py                         |  55 ++++++++---
 20 files changed, 386 insertions(+), 44 deletions(-)

diff --git a/HISTORY.rst b/HISTORY.rst
index af5e772..64bfcd8 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,6 +1,28 @@
 History
 =======
 
+0.8.0 - 2016-08-16
+------------------
+
+- Add ``betamax_parametrized_recorder`` and ``betamax_parametrized_session``
+  to our list of pytest fixtures so that users will have parametrized cassette
+  names when writing parametrized tests with our fixtures. (I wonder if I can
+  mention parametrization a bunch more times so I can say parametrize a lot in
+  this bullet note.)
+- Add ``ValidationError`` and a set of subclasses for each possible validation
+  error.
+- Raise ``InvalidOption`` on unknown cassette options rather than silently
+  ignoring extra options.
+- Raise a subclass of ``ValidationError`` when a particular cassette option is
+  invalid, rather than silently ignoring the validation failure.
+
+0.7.2 - 2016-08-04
+------------------
+
+- Fix bug with query string matcher where query-strings without values (e.g.,
+  ``?foo&bar`` as opposed to ``?foo=1&bar=2``) were treated as if there were
+  no query string.
+
 0.7.1 - 2016-06-14
 ------------------
 
diff --git a/PKG-INFO b/PKG-INFO
index 4964dad..6e2aac6 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: betamax
-Version: 0.7.1
+Version: 0.8.0
 Summary: A VCR imitation for python-requests
 Home-page: https://github.com/sigmavirus24/betamax
 Author: Ian Cordasco
@@ -98,6 +98,28 @@ Description: betamax
         History
         =======
         
+        0.8.0 - 2016-08-16
+        ------------------
+        
+        - Add ``betamax_parametrized_recorder`` and ``betamax_parametrized_session``
+          to our list of pytest fixtures so that users will have parametrized cassette
+          names when writing parametrized tests with our fixtures. (I wonder if I can
+          mention parametrization a bunch more times so I can say parametrize a lot in
+          this bullet note.)
+        - Add ``ValidationError`` and a set of subclasses for each possible validation
+          error.
+        - Raise ``InvalidOption`` on unknown cassette options rather than silently
+          ignoring extra options.
+        - Raise a subclass of ``ValidationError`` when a particular cassette option is
+          invalid, rather than silently ignoring the validation failure.
+        
+        0.7.2 - 2016-08-04
+        ------------------
+        
+        - Fix bug with query string matcher where query-strings without values (e.g.,
+          ``?foo&bar`` as opposed to ``?foo=1&bar=2``) were treated as if there were
+          no query string.
+        
         0.7.1 - 2016-06-14
         ------------------
         
diff --git a/betamax.egg-info/PKG-INFO b/betamax.egg-info/PKG-INFO
index 4964dad..6e2aac6 100644
--- a/betamax.egg-info/PKG-INFO
+++ b/betamax.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: betamax
-Version: 0.7.1
+Version: 0.8.0
 Summary: A VCR imitation for python-requests
 Home-page: https://github.com/sigmavirus24/betamax
 Author: Ian Cordasco
@@ -98,6 +98,28 @@ Description: betamax
         History
         =======
         
+        0.8.0 - 2016-08-16
+        ------------------
+        
+        - Add ``betamax_parametrized_recorder`` and ``betamax_parametrized_session``
+          to our list of pytest fixtures so that users will have parametrized cassette
+          names when writing parametrized tests with our fixtures. (I wonder if I can
+          mention parametrization a bunch more times so I can say parametrize a lot in
+          this bullet note.)
+        - Add ``ValidationError`` and a set of subclasses for each possible validation
+          error.
+        - Raise ``InvalidOption`` on unknown cassette options rather than silently
+          ignoring extra options.
+        - Raise a subclass of ``ValidationError`` when a particular cassette option is
+          invalid, rather than silently ignoring the validation failure.
+        
+        0.7.2 - 2016-08-04
+        ------------------
+        
+        - Fix bug with query string matcher where query-strings without values (e.g.,
+          ``?foo&bar`` as opposed to ``?foo=1&bar=2``) were treated as if there were
+          no query string.
+        
         0.7.1 - 2016-06-14
         ------------------
         
diff --git a/betamax.egg-info/SOURCES.txt b/betamax.egg-info/SOURCES.txt
index 9122c30..5c57da5 100644
--- a/betamax.egg-info/SOURCES.txt
+++ b/betamax.egg-info/SOURCES.txt
@@ -58,6 +58,7 @@ docs/third_party_packages.rst
 docs/usage_patterns.rst
 tests/__init__.py
 tests/conftest.py
+tests/cassettes/FakeBetamaxTestCase.test_fake.json
 tests/cassettes/GitHub_create_issue.json
 tests/cassettes/GitHub_emojis.json
 tests/cassettes/global_preserve_exact_body_bytes.json
@@ -70,6 +71,7 @@ tests/cassettes/test-multiple-cookies-regression.json
 tests/cassettes/test.json
 tests/cassettes/test_replays_response_on_right_order.json
 tests/cassettes/tests.integration.test_fixtures.TestPyTestFixtures.test_pytest_fixture.json
+tests/cassettes/tests.integration.test_fixtures.TestPyTestParametrizedFixtures.test_pytest_fixture[https:-httpbin.org-get].json
 tests/integration/__init__.py
 tests/integration/helper.py
 tests/integration/test_allow_playback_repeats.py
@@ -85,12 +87,14 @@ tests/regression/test_can_replay_interactions_multiple_times.py
 tests/regression/test_cassettes_retain_global_configuration.py
 tests/regression/test_gzip_compression.py
 tests/regression/test_once_prevents_new_interactions.py
+tests/regression/test_requests_2_11_body_matcher.py
 tests/regression/test_works_with_digest_auth.py
 tests/unit/test_adapter.py
 tests/unit/test_betamax.py
 tests/unit/test_cassette.py
 tests/unit/test_configure.py
 tests/unit/test_decorator.py
+tests/unit/test_exceptions.py
 tests/unit/test_fixtures.py
 tests/unit/test_matchers.py
 tests/unit/test_options.py
diff --git a/betamax/__init__.py b/betamax/__init__.py
index 729eb93..d294cf5 100644
--- a/betamax/__init__.py
+++ b/betamax/__init__.py
@@ -22,5 +22,5 @@ __author__ = 'Ian Cordasco'
 __copyright__ = 'Copyright 2013-2014 Ian Cordasco'
 __license__ = 'Apache 2.0'
 __title__ = 'betamax'
-__version__ = '0.7.1'
+__version__ = '0.8.0'
 __version_info__ = tuple(int(i) for i in __version__.split('.'))
diff --git a/betamax/exceptions.py b/betamax/exceptions.py
index a327266..fae4b36 100644
--- a/betamax/exceptions.py
+++ b/betamax/exceptions.py
@@ -8,3 +8,51 @@ class BetamaxError(Exception):
 
 class MissingDirectoryError(BetamaxError):
     pass
+
+
+class ValidationError(BetamaxError):
+    pass
+
+
+class InvalidOption(ValidationError):
+    pass
+
+
+class BodyBytesValidationError(ValidationError):
+    pass
+
+
+class MatchersValidationError(ValidationError):
+    pass
+
+
+class RecordValidationError(ValidationError):
+    pass
+
+
+class RecordIntervalValidationError(ValidationError):
+    pass
+
+
+class PlaceholdersValidationError(ValidationError):
+    pass
+
+
+class PlaybackRepeatsValidationError(ValidationError):
+    pass
+
+
+class SerializerValidationError(ValidationError):
+    pass
+
+
+validation_error_map = {
+    'allow_playback_repeats': PlaybackRepeatsValidationError,
+    'match_requests_on': MatchersValidationError,
+    'record': RecordValidationError,
+    'placeholders': PlaceholdersValidationError,
+    'preserve_exact_body_bytes': BodyBytesValidationError,
+    're_record_interval': RecordIntervalValidationError,
+    'serialize': SerializerValidationError,  # TODO: Remove this
+    'serialize_with': SerializerValidationError
+}
diff --git a/betamax/fixtures/pytest.py b/betamax/fixtures/pytest.py
index 942b650..589d764 100644
--- a/betamax/fixtures/pytest.py
+++ b/betamax/fixtures/pytest.py
@@ -7,28 +7,30 @@
 
 from __future__ import absolute_import
 
+import re
+import warnings
+
 import pytest
 import requests
 
 from .. import recorder as betamax
 
 
- at pytest.fixture
-def betamax_recorder(request):
-    """Generate a recorder with a session that has Betamax already installed.
+def _sanitize(name):
+    """Replace whitespace and / with -"""
+    return re.sub('[\s/]+', '-', name)
 
-    This will create a new Betamax instance with a generated cassette name.
-    The cassette name is generated by first using the module name from where
-    the test is collected, then the class name (if it exists), and then the
-    test function name. For example, if your test is in ``test_stuff.py`` and
-    is the method ``TestStuffClass.test_stuff`` then your cassette name will be
-    ``test_stuff_TestStuffClass_test_stuff``.
+
+def _casette_name(request, parametrized):
+    """Determine a cassette name from request.
 
     :param request:
         A request object from pytest giving us context information for the
         fixture.
+    :param parametrized:
+        Whether the name should consider parametrized tests.
     :returns:
-        An instantiated recorder.
+        A cassette name.
     """
     cassette_name = ''
 
@@ -38,8 +40,24 @@ def betamax_recorder(request):
     if request.cls is not None:
         cassette_name += request.cls.__name__ + '.'
 
-    cassette_name += request.function.__name__
+    if parametrized:
+        cassette_name += _sanitize(request.node.name)
+    else:
+        cassette_name += request.function.__name__
+        if request.node.name != request.function.__name__:
+            warnings.warn(
+                "betamax_recorder and betamax_session currently don't include "
+                "parameters in the cassette name. "
+                "Use betamax_parametrized_recorder/_session to include "
+                "parameters. "
+                "This behavior will be the default in betamax 1.0",
+                FutureWarning, stacklevel=3)
+
+    return cassette_name
 
+
+def _betamax_recorder(request, parametrized=True):
+    cassette_name = _casette_name(request, parametrized=parametrized)
     session = requests.Session()
     recorder = betamax.Betamax(session)
     recorder.use_cassette(cassette_name)
@@ -49,6 +67,29 @@ def betamax_recorder(request):
 
 
 @pytest.fixture
+def betamax_recorder(request):
+    """Generate a recorder with a session that has Betamax already installed.
+
+    This will create a new Betamax instance with a generated cassette name.
+    The cassette name is generated by first using the module name from where
+    the test is collected, then the class name (if it exists), and then the
+    test function name. For example, if your test is in ``test_stuff.py`` and
+    is the method ``TestStuffClass.test_stuff`` then your cassette name will be
+    ``test_stuff_TestStuffClass_test_stuff``. If the test is parametrized,
+    the parameters will not be included in the name. In case you need that,
+    use betamax_parametrized_recorder instead. This will change in 1.0.0,
+    where parameters will be included by default.
+
+    :param request:
+        A request object from pytest giving us context information for the
+        fixture.
+    :returns:
+        An instantiated recorder.
+    """
+    return _betamax_recorder(request, parametrized=False)
+
+
+ at pytest.fixture
 def betamax_session(betamax_recorder):
     """Generate a session that has Betamax already installed.
 
@@ -61,3 +102,45 @@ def betamax_session(betamax_recorder):
     """
 
     return betamax_recorder.session
+
+
+ at pytest.fixture
+def betamax_parametrized_recorder(request):
+    """Generate a recorder with a session that has Betamax already installed.
+
+    This will create a new Betamax instance with a generated cassette name.
+    The cassette name is generated by first using the module name from where
+    the test is collected, then the class name (if it exists), and then the
+    test function name with parameters if parametrized.
+    For example, if your test is in ``test_stuff.py`` and
+    the method is ``TestStuffClass.test_stuff`` with parameter ``True`` then
+    your cassette name will be
+    ``test_stuff_TestStuffClass_test_stuff[True]``.
+
+    :param request:
+        A request object from pytest giving us context information for the
+        fixture.
+    :returns:
+        An instantiated recorder.
+    """
+    warnings.warn(
+        "betamax_parametrized_recorder and betamax_parametrized_session "
+        "will be removed in betamax 1.0. Their behavior will be the "
+        "default.",
+        DeprecationWarning)
+    return _betamax_recorder(request, parametrized=True)
+
+
+ at pytest.fixture
+def betamax_parametrized_session(betamax_parametrized_recorder):
+    """Generate a session that has Betamax already installed.
+
+    See `betamax_parametrized_recorder` fixture.
+
+    :param betamax_parametrized_recorder:
+        A recorder fixture with a configured request session.
+    :returns:
+        An instantiated requests Session wrapped by Betamax.
+    """
+
+    return betamax_parametrized_recorder.session
diff --git a/betamax/matchers/body.py b/betamax/matchers/body.py
index 2fa1fc8..e3f6d81 100644
--- a/betamax/matchers/body.py
+++ b/betamax/matchers/body.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 from .base import BaseMatcher
-from betamax.util import deserialize_prepared_request
+
+from betamax import util
 
 
 class BodyMatcher(BaseMatcher):
@@ -8,14 +9,14 @@ class BodyMatcher(BaseMatcher):
     name = 'body'
 
     def match(self, request, recorded_request):
-        recorded_request = deserialize_prepared_request(recorded_request)
+        recorded_request = util.deserialize_prepared_request(recorded_request)
 
+        request_body = b''
         if request.body:
-            if isinstance(recorded_request.body, type(request.body)):
-                request_body = request.body
-            else:
-                request_body = request.body.encode('utf-8')
-        else:
-            request_body = b''
+            request_body = util.coerce_content(request.body)
+
+        recorded_body = b''
+        if recorded_request.body:
+            recorded_body = util.coerce_content(recorded_request.body)
 
-        return recorded_request.body == request_body
+        return recorded_body == request_body
diff --git a/betamax/matchers/query.py b/betamax/matchers/query.py
index adf628d..432104c 100644
--- a/betamax/matchers/query.py
+++ b/betamax/matchers/query.py
@@ -18,7 +18,10 @@ class QueryMatcher(BaseMatcher):
 
     def to_dict(self, query):
         """Turn the query string into a dictionary."""
-        return parse_qs(query or '')  # Protect against None
+        return parse_qs(
+            query or '',  # Protect against None
+            keep_blank_values=True,
+        )
 
     def match(self, request, recorded_request):
         request_query_dict = self.to_dict(urlparse(request.url).query)
diff --git a/betamax/options.py b/betamax/options.py
index f4479c7..c2bcc8f 100644
--- a/betamax/options.py
+++ b/betamax/options.py
@@ -1,4 +1,5 @@
 from .cassette import Cassette
+from .exceptions import InvalidOption, validation_error_map
 
 
 def validate_record(record):
@@ -19,9 +20,10 @@ def validate_serializer(serializer):
 def validate_placeholders(placeholders):
     """Validate placeholders is a dict-like structure"""
     keys = ['placeholder', 'replace']
-    return all(
-        sorted(list(p.keys())) == keys for p in placeholders
-    )
+    try:
+        return all(sorted(list(p.keys())) == keys for p in placeholders)
+    except TypeError:
+        return False
 
 
 def translate_cassette_options():
@@ -84,8 +86,9 @@ class Options(object):
     def validate(self):
         for key, value in list(self.data.items()):
             if key not in Options.valid_options:
-                del self[key]
+                raise InvalidOption('{0} is not a valid option'.format(key))
             else:
                 is_valid = Options.valid_options[key]
                 if not is_valid(value):
-                    del self[key]
+                    raise validation_error_map[key]('{0!r} is not valid'
+                                                    .format(value))
diff --git a/docs/api.rst b/docs/api.rst
index 4af56bd..a0b9b8c 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -157,8 +157,9 @@ Forcing bytes to be preserved
 -----------------------------
 
 You may want to force betamax to preserve the exact bytes in the body of a 
-response (or request) instead of relying on the `opinions held by the library 
-<opinions>`_. In this case you have two ways of telling betamax to do this.
+response (or request) instead of relying on the :ref:`opinions held by the
+library <opinions>`. In this case you have two ways of telling betamax to do
+this.
 
 The first, is on a per-cassette basis, like so:
 
diff --git a/setup.cfg b/setup.cfg
index bd35539..6c71b61 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -2,7 +2,7 @@
 universal = 1
 
 [egg_info]
-tag_svn_revision = 0
-tag_date = 0
 tag_build = 
+tag_date = 0
+tag_svn_revision = 0
 
diff --git a/tests/cassettes/FakeBetamaxTestCase.test_fake.json b/tests/cassettes/FakeBetamaxTestCase.test_fake.json
new file mode 100644
index 0000000..e42c7ab
--- /dev/null
+++ b/tests/cassettes/FakeBetamaxTestCase.test_fake.json
@@ -0,0 +1 @@
+{"http_interactions": [], "recorded_with": "betamax/0.7.2"}
\ No newline at end of file
diff --git a/tests/cassettes/tests.integration.test_fixtures.TestPyTestParametrizedFixtures.test_pytest_fixture[https:-httpbin.org-get].json b/tests/cassettes/tests.integration.test_fixtures.TestPyTestParametrizedFixtures.test_pytest_fixture[https:-httpbin.org-get].json
new file mode 100644
index 0000000..ec3fb2a
--- /dev/null
+++ b/tests/cassettes/tests.integration.test_fixtures.TestPyTestParametrizedFixtures.test_pytest_fixture[https:-httpbin.org-get].json
@@ -0,0 +1 @@
+{"recorded_with": "betamax/0.4.2", "http_interactions": [{"recorded_at": "2015-05-25T00:46:42", "response": {"body": {"encoding": null, "string": "{\n  \"args\": {}, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"python-requests/2.6.0 CPython/3.4.2 Darwin/14.1.0\"\n  }, \n  \"origin\": \"72.160.201.47\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"}, "status": {"message": "OK", "code":  [...]
\ No newline at end of file
diff --git a/tests/integration/test_fixtures.py b/tests/integration/test_fixtures.py
index 70122de..a3a0c2d 100644
--- a/tests/integration/test_fixtures.py
+++ b/tests/integration/test_fixtures.py
@@ -24,3 +24,28 @@ class TestPyTestFixtures:
         """Exercise the fixture itself."""
         resp = betamax_session.get('https://httpbin.org/get')
         assert resp.ok
+
+
+ at pytest.mark.usefixtures('betamax_parametrized_session')
+class TestPyTestParametrizedFixtures:
+    @pytest.fixture(autouse=True)
+    def setup(self, request):
+        """After test hook to assert everything."""
+        def finalizer():
+            test_dir = os.path.abspath('.')
+            cassette_name = ('tests.integration.test_fixtures.'  # Module name
+                             'TestPyTestParametrizedFixtures.'  # Class name
+                             'test_pytest_fixture'  # Test function name
+                             '[https:-httpbin.org-get]'  # Parameter
+                             '.json')
+            file_name = os.path.join(test_dir, 'tests', 'cassettes',
+                                     cassette_name)
+            assert os.path.exists(file_name) is True
+
+        request.addfinalizer(finalizer)
+
+    @pytest.mark.parametrize('url', ('https://httpbin.org/get',))
+    def test_pytest_fixture(self, betamax_parametrized_session, url):
+        """Exercise the fixture itself."""
+        resp = betamax_parametrized_session.get(url)
+        assert resp.ok
diff --git a/tests/regression/test_requests_2_11_body_matcher.py b/tests/regression/test_requests_2_11_body_matcher.py
new file mode 100644
index 0000000..b206e5b
--- /dev/null
+++ b/tests/regression/test_requests_2_11_body_matcher.py
@@ -0,0 +1,27 @@
+import os
+import unittest
+
+import pytest
+import requests
+
+from betamax import Betamax
+
+
+class TestRequests211BodyMatcher(unittest.TestCase):
+    def tearDown(self):
+        os.unlink('tests/cassettes/requests_2_11_body_matcher.json')
+
+    @pytest.mark.skipif(requests.__build__ < 0x020401,
+                        reason="No json keyword.")
+    def test_requests_with_json_body(self):
+        s = requests.Session()
+        with Betamax(s).use_cassette('requests_2_11_body_matcher',
+                                     match_requests_on=['body']):
+            r = s.post('https://httpbin.org/post', json={'a': 2})
+            assert r.json() is not None
+
+        s = requests.Session()
+        with Betamax(s).use_cassette('requests_2_11_body_matcher',
+                                     match_requests_on=['body']):
+            r = s.post('https://httpbin.org/post', json={'a': 2})
+            assert r.json() is not None
diff --git a/tests/unit/test_cassette.py b/tests/unit/test_cassette.py
index 5207ada..0ae4c4d 100644
--- a/tests/unit/test_cassette.py
+++ b/tests/unit/test_cassette.py
@@ -3,6 +3,8 @@ import os
 import unittest
 from datetime import datetime
 
+import pytest
+
 from betamax import __version__
 from betamax.cassette import cassette
 from betamax import mock_response
@@ -310,6 +312,12 @@ class TestCassette(unittest.TestCase):
         assert i is not None
         assert self.interaction is i
 
+    def test_find_match__missing_matcher(self):
+        self.cassette.match_options = set(['uri', 'method', 'invalid'])
+        self.cassette.record_mode = 'none'
+        with pytest.raises(KeyError):
+            self.cassette.find_match(self.response.request)
+
     def test_eject(self):
         serializer = self.test_serializer
         self.cassette.eject()
diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py
new file mode 100644
index 0000000..a80f13d
--- /dev/null
+++ b/tests/unit/test_exceptions.py
@@ -0,0 +1,35 @@
+import unittest
+import inspect
+
+from betamax import exceptions
+
+
+def exception_classes():
+    for _, module_object in inspect.getmembers(exceptions):
+        if inspect.isclass(module_object):
+            yield module_object
+
+
+class TestExceptions(unittest.TestCase):
+    def test_all_exceptions_are_betamax_errors(self):
+        for exception_class in exception_classes():
+            assert isinstance(exception_class('msg'), exceptions.BetamaxError)
+
+    def test_all_validation_errors_are_in_validation_error_map(self):
+        validation_error_map_values = exceptions.validation_error_map.values()
+        for exception_class in exception_classes():
+            if exception_class.__name__ == 'ValidationError' or \
+               not exception_class.__name__.endswith('ValidationError'):
+                continue
+            assert exception_class in validation_error_map_values
+
+    def test_all_validation_errors_are_validation_errors(self):
+        for exception_class in exception_classes():
+            if not exception_class.__name__.endswith('ValidationError'):
+                continue
+            assert isinstance(exception_class('msg'),
+                              exceptions.ValidationError)
+
+    def test_invalid_option_is_validation_error(self):
+        assert isinstance(exceptions.InvalidOption('msg'),
+                          exceptions.ValidationError)
diff --git a/tests/unit/test_matchers.py b/tests/unit/test_matchers.py
index 4f3b6b3..a26fe27 100644
--- a/tests/unit/test_matchers.py
+++ b/tests/unit/test_matchers.py
@@ -140,6 +140,9 @@ class TestMatchers(unittest.TestCase):
         )
         # Regression test (no query issue)
         assert match(self.p, {'uri': 'http://example.com'}) is False
+        # Regression test (query with no value)
+        self.p.url = 'https://example.com/?foo'
+        assert match(self.p, {'uri': 'https://httpbin.org/?foo'}) is True
 
     def test_uri_matcher(self):
         match = matchers.matcher_registry['uri'].match
diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py
index 6425c31..dfe8f55 100644
--- a/tests/unit/test_options.py
+++ b/tests/unit/test_options.py
@@ -1,5 +1,9 @@
 import unittest
 from itertools import permutations
+
+import pytest
+
+from betamax import exceptions
 from betamax.options import Options, validate_record, validate_matchers
 
 
@@ -31,21 +35,50 @@ class TestOptions(unittest.TestCase):
         for key in self.data:
             assert key in self.options
 
-    def test_invalid_data_is_removed(self):
+    def test_raise_on_unknown_option(self):
         data = self.data.copy()
         data['fake'] = 'value'
-        options = Options(data)
+        with pytest.raises(exceptions.InvalidOption):
+            Options(data)
 
-        for key in self.data:
-            assert key in options
+    def test_raise_on_invalid_body_bytes(self):
+        data = self.data.copy()
+        data['preserve_exact_body_bytes'] = None
+        with pytest.raises(exceptions.BodyBytesValidationError):
+            Options(data)
+
+    def test_raise_on_invalid_matchers(self):
+        data = self.data.copy()
+        data['match_requests_on'] = ['foo', 'bar', 'bogus']
+        with pytest.raises(exceptions.MatchersValidationError):
+            Options(data)
 
-        assert 'fake' not in options
+    def test_raise_on_invalid_placeholders(self):
+        data = self.data.copy()
+        data['placeholders'] = None
+        with pytest.raises(exceptions.PlaceholdersValidationError):
+            Options(data)
 
-    def test_values_are_validated(self):
-        assert self.options['re_record_interval'] == 10000
-        assert self.options['match_requests_on'] == ['method']
+    def test_raise_on_invalid_playback_repeats(self):
+        data = self.data.copy()
+        data['allow_playback_repeats'] = None
+        with pytest.raises(exceptions.PlaybackRepeatsValidationError):
+            Options(data)
 
+    def test_raise_on_invalid_record(self):
         data = self.data.copy()
-        data['match_requests_on'] = ['foo', 'bar', 'bogus']
-        options = Options(data)
-        assert options['match_requests_on'] == ['method', 'uri']
+        data['record'] = None
+        with pytest.raises(exceptions.RecordValidationError):
+            Options(data)
+
+    def test_raise_on_invalid_record_interval(self):
+        data = self.data.copy()
+        data['re_record_interval'] = -1
+        with pytest.raises(exceptions.RecordIntervalValidationError):
+            Options(data)
+
+    def test_raise_on_invalid_serializer(self):
+        data = self.data.copy()
+        data['serialize_with'] = None
+        with pytest.raises(exceptions.SerializerValidationError):
+            Options(data)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/betamax.git



More information about the Python-modules-commits mailing list