Source code for expects.testing
# -*- coding: utf-8 -*-
"""The :mod:`testing` module provides helpers to ease the testing
of your `custom matchers <custom-matchers.html>`_.
"""
import re
import traceback
from ._compat import with_metaclass
from .matchers.built_in import end_with as end_with_matcher
class _ContextManagerMeta(type):
def __enter__(cls):
pass
def __exit__(cls, exc_type, exc_value, exc_tb):
cls._handle_exception(exc_type, exc_value, exc_tb)
return True
[docs]class failure(with_metaclass(_ContextManagerMeta)):
"""The :class:`failure` context manager can be used to build
assertions of your expectation failures. It tests that the
code inside the context manager raises an :class:`AssertionError`
and matches the given message (whether any has been specified).
:param message: should match the failure message. If a string is
passed, the :class:`end_with` matcher will be used
by default.
:type message: an :class:`expects.matchers.Matcher` or string
:raises: :class:`AssertionError` when no *AssertionError* was
raised, the failure message didn't match or another
exception raised.
.. note::
The :class:`failure` context manager can be used without being
*called* (for example, if you don't want to specify a *failure message*).
Examples:
.. code-block:: python
>>> with failure:
... expect(object()).to(have_property('foo'))
.. code-block:: python
>>> with failure("to have property 'foo'"):
... expect(object()).to(have_property('foo'))
.. code-block:: python
>>> with failure(end_with("have property 'foo'")):
... expect(object()).to(have_property('foo'))
.. code-block:: python
>>> with failure("to have property '__class__'"):
... expect(object()).to(have_property('__class__'))
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "expects/testing.py", line 40, in __exit__
raise AssertionError('Expected AssertionError to be raised')
AssertionError: Expected AssertionError to be raised
"""
def __init__(self, message):
if not hasattr(message, '_match'):
message = end_with_matcher(message)
self._message = message
def __enter__(self):
pass
def __exit__(self, exc_type, exc_value, exc_tb):
self._handle_exception(exc_type, exc_value, exc_tb)
exc_message = str(exc_value)
if not self._message._match(exc_message):
raise AssertionError(
"Expected error message {!r} {}".format(
exc_message, self._message._description(exc_value)))
return True
@classmethod
def _handle_exception(cls, exc_type, exc_value, exc_tb):
if exc_type is None:
raise AssertionError('Expected AssertionError to be raised')
if exc_type != AssertionError:
raise AssertionError(
'Expected AssertionError to be raised but {} raised.'
'\n\n{}'.format(exc_type.__name__,
_format_exception(exc_type, exc_value, exc_tb))
)
def _format_exception(exc_type, exc_value, exc_tb):
return ''.join(traceback.format_exception(exc_type, exc_value, exc_tb))