diff --git a/LICENSE b/LICENSE index 21010cc..72d57cd 100644 --- a/LICENSE +++ b/LICENSE @@ -18,6 +18,7 @@ The testtools authors are: * Martin Pool * Vincent Ladeuil * Nikola Đipanov + * Tristan Seligmann and are collectively referred to as "testtools developers". diff --git a/NEWS b/NEWS index a3d7052..e0f15f2 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,8 @@ Improvements * ``TestResult`` objects that don't implement ``stop``/``shouldStop`` are now handled sanely. (Jonathan Lange) +* New ``Always`` and ``Never`` matchers. (Tristan Seligmann, #947026) + 2.0.0 ~~~~~ diff --git a/README.rst b/README.rst index fff3085..77534cf 100644 --- a/README.rst +++ b/README.rst @@ -91,3 +91,4 @@ Thanks * Martin Pool * Julia Varlamova * ClusterHQ Ltd + * Tristan Seligmann diff --git a/doc/for-test-authors.rst b/doc/for-test-authors.rst index 98f934c..06a107d 100644 --- a/doc/for-test-authors.rst +++ b/doc/for-test-authors.rst @@ -628,6 +628,20 @@ assertions. Below are a few of the combining matchers that come with testtools. +Always +~~~~~~ + +.. autofunction:: testtools.matchers.Always + :noindex: + + +Never +~~~~~ + +.. autofunction:: testtools.matchers.Never + :noindex: + + Not ~~~ diff --git a/testtools/matchers/__init__.py b/testtools/matchers/__init__.py index 771d814..b85016b 100644 --- a/testtools/matchers/__init__.py +++ b/testtools/matchers/__init__.py @@ -15,6 +15,7 @@ $ python -c 'import testtools.matchers; print testtools.matchers.__all__' __all__ = [ 'AfterPreprocessing', 'AllMatch', + 'Always', 'Annotate', 'AnyMatch', 'Contains', @@ -45,6 +46,7 @@ __all__ = [ 'MatchesRegex', 'MatchesSetwise', 'MatchesStructure', + 'Never', 'NotEquals', 'Not', 'PathExists', @@ -68,6 +70,10 @@ from ._basic import ( NotEquals, StartsWith, ) +from ._const import ( + Always, + Never, + ) from ._datastructures import ( ContainsAll, MatchesListwise, diff --git a/testtools/matchers/_const.py b/testtools/matchers/_const.py new file mode 100644 index 0000000..094856c --- /dev/null +++ b/testtools/matchers/_const.py @@ -0,0 +1,58 @@ +# Copyright (c) 2016 testtools developers. See LICENSE for details. + +__all__ = [ + 'Always', + 'Never', + ] + +from testtools.compat import _u +from ._impl import Mismatch + + +class _Always(object): + """Always matches.""" + + def __str__(self): + return 'Always()' + + def match(self, value): + return None + + +def Always(): + """Always match. + + That is:: + + self.assertThat(x, Always()) + + Will always match and never fail, no matter what ``x`` is. Most useful when + passed to other higher-order matchers (e.g. + :py:class:`~testtools.matchers.MatchesListwise`). + """ + return _Always() + + +class _Never(object): + """Never matches.""" + + def __str__(self): + return 'Never()' + + def match(self, value): + return Mismatch( + _u('Inevitable mismatch on %r' % (value,))) + + +def Never(): + """Never match. + + That is:: + + self.assertThat(x, Never()) + + Will never match and always fail, no matter what ``x`` is. Included for + completeness with :py:func:`.Always`, but if you find a use for this, let + us know! + """ + return _Never() diff --git a/testtools/tests/matchers/__init__.py b/testtools/tests/matchers/__init__.py index ebab308..e9e932d 100644 --- a/testtools/tests/matchers/__init__.py +++ b/testtools/tests/matchers/__init__.py @@ -7,6 +7,7 @@ from unittest import TestSuite def test_suite(): from testtools.tests.matchers import ( test_basic, + test_const, test_datastructures, test_dict, test_doctest, @@ -17,6 +18,7 @@ def test_suite(): ) modules = [ test_basic, + test_const, test_datastructures, test_dict, test_doctest, diff --git a/testtools/tests/matchers/test_const.py b/testtools/tests/matchers/test_const.py new file mode 100644 index 0000000..1627e6f --- /dev/null +++ b/testtools/tests/matchers/test_const.py @@ -0,0 +1,31 @@ +# Copyright (c) 2016 testtools developers. See LICENSE for details. + +from testtools import TestCase +from testtools.compat import _u +from testtools.matchers import Always, Never +from testtools.tests.matchers.helpers import TestMatchersInterface + + +class TestAlwaysInterface(TestMatchersInterface, TestCase): + """:py:func:`~testtools.matchers.Always` always matches.""" + matches_matcher = Always() + matches_matches = [42, object(), 'hi mom'] + matches_mismatches = [] + + str_examples = [('Always()', Always())] + describe_examples = [] + + +class TestNeverInterface(TestMatchersInterface, TestCase): + """:py:func:`~testtools.matchers.Never` never matches.""" + matches_matcher = Never() + matches_matches = [] + matches_mismatches = [42, object(), 'hi mom'] + + str_examples = [('Never()', Never())] + describe_examples = [(_u('Inevitable mismatch on 42'), 42, Never())] + + +def test_suite(): + from unittest import TestLoader + return TestLoader().loadTestsFromName(__name__)