diff --git a/.gitignore b/.gitignore index fe51c01..a4ceecc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.py[cod] .cache .pytest_cache +__pycache__ # testing output *.xml @@ -22,3 +23,7 @@ dist # IDE /.idea .vscode + +# docs output +docs/build +docs/out diff --git a/.travis.yml b/.travis.yml index d54bbef..127e82b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ python: - 3.8 before_install: - pip install pytest-cov + - pip install requests==2.21.0 # last version that still supports py 3.4 - pip install coveralls install: - pip install . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd67a7b..05a808b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,10 +9,10 @@ Here's how: 1. Create a branch (`git checkout -b my_branch`) 1. Commit your changes (`git commit -am "added some cool feature"`) 1. Push your branch to your fork (`git push origin my_branch`) -1. Open a [Pull Request](http://github.com/ActivisionGameScience/assertpy/pulls) +1. Open a [Pull Request](http://github.com/assertpy/assertpy/pulls) 1. Respond to any questions during our review process -Read more about how pulls work on GitHub's [Using Pull Requests](https://help.github.com/articles/using-pull-requests/) page. +Read more about how pulls work on GitHub's [About pull requests](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) page. ## Running the Tests @@ -31,11 +31,11 @@ Should produce output something like this: ``` ===== test session starts ===== -collected 373 items +collected 589 items -tests/test_bool.py::TestBool::test_is_true PASSED +tests/test_bool.py::test_is_true PASSED .. -tests/test_type.py::TestType::test_is_instance_of_bad_arg_failure PASSED +tests/test_warn.py::test_failures PASSED -===== 373 passed in 0.52 seconds ===== +===== 589 passed in 1.91s ===== ``` diff --git a/README.md b/README.md index cfb8845..4cec359 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ Simple assertions library for unit testing in Python with a nice fluent API. Supports both Python 2 and 3. -[![Build Status](https://travis-ci.org/ActivisionGameScience/assertpy.svg?branch=master)](https://travis-ci.org/ActivisionGameScience/assertpy) -[![Coverage Status](https://coveralls.io/repos/ActivisionGameScience/assertpy/badge.svg?branch=master)](https://coveralls.io/github/ActivisionGameScience/assertpy) +[![Build Status](https://travis-ci.org/assertpy/assertpy.svg?branch=main)](https://travis-ci.org/assertpy/assertpy) +[![Coverage Status](https://coveralls.io/repos/github/assertpy/assertpy/badge.svg?branch=main)](https://coveralls.io/github/assertpy/assertpy?branch=main) ## Usage @@ -19,15 +19,15 @@ def test_something(): assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x') ``` -Of course, `assertpy` works best with a python test runner like [pytest](http://pytest.org/latest/contents.html) (our favorite) or [Nose](http://nose.readthedocs.org/). +Of course, `assertpy` works best with a python test runner like [pytest](http://pytest.org/) (our favorite) or [Nose](http://nose.readthedocs.org/). ## Installation ### Install via pip -[![PyPI Badge](https://badge.fury.io/py/assertpy.svg)](https://pypi.python.org/pypi/assertpy) +[![PyPI Badge](https://badge.fury.io/py/assertpy.svg)](https://pypi.org/project/assertpy/) -The `assertpy` library is available via [PyPI](https://pypi.python.org/pypi/assertpy). +The `assertpy` library is available via [PyPI](https://pypi.org/project/assertpy/). Just install with: ``` @@ -46,12 +46,16 @@ conda install assertpy --channel conda-forge ``` -## The API +## Docs The fluent API of `assertpy` is designed to create compact, yet readable tests. The API has been modeled after other fluent testing APIs, especially the awesome -[AssertJ](http://joel-costigliola.github.io/assertj/) assertion library for Java. Of course, in the `assertpy` library everything is fully pythonic and designed to take full advantage of the dynamism in the Python runtime. +[AssertJ](https://assertj.github.io/doc/) assertion library for Java. Of course, in the `assertpy` library everything is fully pythonic and designed to take full advantage of the dynamism in the Python runtime. +All assertions, with usage examples, are documented here: +https://assertpy.github.io/docs.html + +And there are hundreds of examples below. Read on... ### Strings @@ -76,8 +80,8 @@ assert_that('foo').is_equal_to('foo') assert_that('foo').is_not_equal_to('bar') assert_that('foo').is_equal_to_ignoring_case('FOO') -assert_that(u'foo').is_unicode() # on python 2 -assert_that('foo').is_unicode() # on python 3 +assert_that(u'foo').is_unicode() # on python 2 +assert_that('foo').is_unicode() # on python 3 assert_that('foo').contains('f') assert_that('foo').contains('f','oo') @@ -210,6 +214,8 @@ assert_that(['a','b']).contains_only('a','b') assert_that(['a','a']).contains_only('a') assert_that(['a','b','c']).contains_sequence('b','c') assert_that(['a','b']).is_subset_of(['a','b','c']) +assert_that(['a','b','c']).is_sorted() +assert_that(['c','b','a']).is_sorted(reverse=True) assert_that(['a','x','x']).contains_duplicates() assert_that(['a','b','c']).does_not_contain_duplicates() @@ -252,6 +258,8 @@ assert_that((1,2,3)).contains_only(1,2,3) assert_that((1,1,1)).contains_only(1) assert_that((1,2,3)).contains_sequence(2,3) assert_that((1,2,3)).is_subset_of((1,2,3,4)) +assert_that((1,2,3)).is_sorted() +assert_that((3,2,1)).is_sorted(reverse=True) assert_that((1,2,2)).contains_duplicates() assert_that((1,2,3)).does_not_contain_duplicates() @@ -863,7 +871,7 @@ forgiving behavior, you can use `soft_fail()` which is collected like any other ### Snapshot Testing -Take a snapshot of a python data structure, store it on disk in JSON format, and automatically compare the latest data to the stored data on every test run. The snapshot testing features of `assertpy` are borrowed from [Jest](https://facebook.github.io/jest/), a well-kwown and powerful Javascript testing framework. Snapshots require Python 3. +Take a snapshot of a python data structure, store it on disk in JSON format, and automatically compare the latest data to the stored data on every test run. The snapshot testing features of `assertpy` are borrowed from [Jest](https://facebook.github.io/jest/), a well-known and powerful Javascript testing framework. Snapshots require Python 3. For example, snapshot the following dict: @@ -933,7 +941,7 @@ from assertpy import add_extension def is_5(self): if self.val != 5: - self._err(f'{self.val} is NOT 5!') + return self.error(f'{self.val} is NOT 5!') return self add_extension(is_5) @@ -943,7 +951,7 @@ Once registered with `assertpy`, we can use our new assertion as expected: ```py assert_that(5).is_5() -assert_that(6).is_5() # fails! +assert_that(6).is_5() # fails! ``` Of course, `is_5()` is only available in the test file where `add_extension()` is called. If you want better control of scope of your custom extensions, such as writing extensions once and using them in any test file, you'll need to use the test setup functionality of your test runner. With [pytest](http://pytest.org/latest/contents.html), you can just use a `conftest.py` file and a _fixture_. @@ -956,7 +964,7 @@ from assertpy import add_extension def is_5(self): if self.val != 5: - self._err(f'{self.val} is NOT 5!') + return self.error(f'{self.val} is NOT 5!') return self @pytest.fixture(scope='module') @@ -971,7 +979,7 @@ from assertpy import assert_that def test_foo(my_extensions): assert_that(5).is_5() - assert_that(6).is_5() # fails! + assert_that(6).is_5() # fails! ``` where the `my_extensions` parameter must be the name of your fixture function in `conftest.py`. See the [fixture docs](https://docs.pytest.org/en/latest/fixture.html) for details. @@ -982,10 +990,10 @@ Here are some useful tips to help you write your own custom assertions: 1. Use `self` as first param (as if your function was an instance method). 2. Use `self.val` to get the _actual_ value to be tested. -2. It's better to test the negative, and then fail if true. -3. Fail by raising an `AssertionError`. -4. Always use the `self._err()` helper to fail (and print your failure message). -5. Always `return self` to allow for chaining. +3. It's better to test the negative, and then fail if true. +4. Fail by raising an `AssertionError` (the `self.error()` helper does this for you). +5. Always use the `self.error()` helper to fail (and print your failure message). +6. Always `return self` to allow for chaining. Putting it all together, here is another custom assertion example, but annotated with comments: @@ -1000,13 +1008,13 @@ def is_multiple_of(self, other): if isinstance(other, numbers.Integral) is False or other <= 0: raise TypeError('given arg must be a positive integer') - # divide and compute remainder using divmod() built-in + # calc remainder using divmod() built-in _, rem = divmod(self.val, other) # test the negative (is remainder non-zero?) if rem > 0: # non-zero remainder, so not multiple -> we fail! - self._err('Expected <%s> to be multiple of <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be multiple of <%s>, but was not.' % (self.val, other)) # success, and return self to allow chaining return self @@ -1021,24 +1029,18 @@ Here are just a few examples: ```py assert_that('foo').is_length(3).starts_with('f').ends_with('oo') -``` -```py assert_that([1,2,3]).is_type_of(list).contains(1,2).does_not_contain(4,5) -``` -```py assert_that(fred).has_first_name('Fred').has_last_name('Smith').has_shoe_size(12) -``` -```py assert_that(people).is_length(2).extracting('first_name').contains('Fred','Joe') ``` ## Future -There are always a few new features in the works...if you'd like to help, check out the [open issues](https://github.com/ActivisionGameScience/assertpy/issues?q=is%3Aopen+is%3Aissue) and see our [Contributing](CONTRIBUTING.md) doc. +There are always a few new features in the works...if you'd like to help, check out the [open issues](https://github.com/assertpy/assertpy/issues) and see our [Contributing](CONTRIBUTING.md) doc. ## License diff --git a/assertpy/assertpy.py b/assertpy/assertpy.py index 13bfe42..39abb20 100644 --- a/assertpy/assertpy.py +++ b/assertpy/assertpy.py @@ -36,31 +36,84 @@ import sys import types from .base import BaseMixin -from .contains import ContainsMixin -from .numeric import NumericMixin -from .string import StringMixin from .collection import CollectionMixin -from .dict import DictMixin +from .contains import ContainsMixin from .date import DateMixin -from .file import FileMixin +from .dict import DictMixin +from .dynamic import DynamicMixin from .extracting import ExtractingMixin -from .snapshot import SnapshotMixin from .exception import ExceptionMixin -from .dynamic import DynamicMixin +from .file import FileMixin from .helpers import HelpersMixin +from .numeric import NumericMixin +from .snapshot import SnapshotMixin +from .string import StringMixin -__version__ = '0.15' +__version__ = '1.1' -__tracebackhide__ = True # clean tracebacks via py.test integration -contextlib.__tracebackhide__ = True # monkey patch contextlib with clean py.test tracebacks +__tracebackhide__ = True # clean tracebacks via py.test integration +contextlib.__tracebackhide__ = True # monkey patch contextlib with clean py.test tracebacks +# assertpy files +ASSERTPY_FILES = [os.path.join('assertpy', file) for file in [ + 'assertpy.py', + 'base.py', + 'collection.py', + 'contains.py', + 'date.py', + 'dict.py', + 'dynamic.py', + 'exception.py', + 'extracting.py', + 'file.py', + 'helpers.py', + 'numeric.py', + 'snapshot.py', + 'string.py' +]] # soft assertions _soft_ctx = 0 _soft_err = [] + @contextlib.contextmanager def soft_assertions(): + """Create a soft assertion context. + + Normally, any assertion failure will halt test execution immediately by raising an error. + Soft assertions are way to collect assertion failures (and failure messages) together, to be + raised all at once at the end, without halting your test. + + Examples: + Create a soft assertion context, and some failing tests:: + + from assertpy import assert_that, soft_assertions + + with soft_assertions(): + assert_that('foo').is_length(4) + assert_that('foo').is_empty() + assert_that('foo').is_false() + assert_that('foo').is_digit() + assert_that('123').is_alpha() + + When the context ends, any assertion failures are collected together and a single + ``AssertionError`` is raised:: + + AssertionError: soft assertion failures: + 1. Expected to be of length <4>, but was <3>. + 2. Expected to be empty string, but was not. + 3. Expected , but was not. + 4. Expected to contain only digits, but did not. + 5. Expected <123> to contain only alphabetic chars, but did not. + + Note: + The soft assertion context only collects *assertion* failures, other errors such as + ``TypeError`` or ``ValueError`` are always raised immediately. Triggering an explicit test + failure with :meth:`fail` will similarly halt execution immediately. If you need more + forgiving behavior, use :meth:`soft_fail` to add a failure message without halting test + execution. + """ global _soft_ctx global _soft_err @@ -77,32 +130,142 @@ def soft_assertions(): if _soft_err and _soft_ctx == 0: out = 'soft assertion failures:' - for i,msg in enumerate(_soft_err): + for i, msg in enumerate(_soft_err): out += '\n%d. %s' % (i+1, msg) # reset msg, then raise _soft_err = [] raise AssertionError(out) + # factory methods def assert_that(val, description=''): - """Factory method for the assertion builder with value to be tested and optional description.""" + """Set the value to be tested, plus an optional description, and allow assertions to be called. + + This is a factory method for the :class:`AssertionBuilder`, and the single most important + method in all of assertpy. + + Args: + val: the value to be tested (aka the actual value) + description (str, optional): the extra error message description. Defaults to ``''`` + (aka empty string) + + Examples: + Just import it once at the top of your test file, and away you go...:: + + from assertpy import assert_that + + def test_something(): + assert_that(1 + 2).is_equal_to(3) + assert_that('foobar').is_length(6).starts_with('foo').ends_with('bar') + assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x') + """ global _soft_ctx if _soft_ctx: - return builder(val, description, 'soft') - return builder(val, description) + return _builder(val, description, 'soft') + return _builder(val, description) + def assert_warn(val, description='', logger=None): - """Factory method for the assertion builder with value to be tested, optional description, and - just warn on assertion failures instead of raisings exceptions.""" - return builder(val, description, 'warn', logger=logger) + """Set the value to be tested, and optional description and logger, and allow assertions to be + called, but never fail, only log warnings. + + This is a factory method for the :class:`AssertionBuilder`, but unlike :meth:`assert_that` an + `AssertionError` is never raised, and execution is never halted. Instead, any assertion failures + results in a warning message being logged. Uses the given logger, or defaults to a simple logger + that prints warnings to ``stdout``. + + + Args: + val: the value to be tested (aka the actual value) + description (str, optional): the extra error message description. Defaults to ``''`` + (aka empty string) + logger (Logger, optional): the logger for warning message on assertion failure. Defaults to ``None`` + (aka use the default simple logger that prints warnings to ``stdout``) + + Examples: + Usage:: + + from assertpy import assert_warn + + assert_warn('foo').is_length(4) + assert_warn('foo').is_empty() + assert_warn('foo').is_false() + assert_warn('foo').is_digit() + assert_warn('123').is_alpha() + + Even though all of the above assertions fail, ``AssertionError`` is never raised and + test execution is never halted. Instead, the failed assertions merely log the following + warning messages to ``stdout``:: + + 2019-10-27 20:00:35 WARNING [test_foo.py:23]: Expected to be of length <4>, but was <3>. + 2019-10-27 20:00:35 WARNING [test_foo.py:24]: Expected to be empty string, but was not. + 2019-10-27 20:00:35 WARNING [test_foo.py:25]: Expected , but was not. + 2019-10-27 20:00:35 WARNING [test_foo.py:26]: Expected to contain only digits, but did not. + 2019-10-27 20:00:35 WARNING [test_foo.py:27]: Expected <123> to contain only alphabetic chars, but did not. + + Tip: + Use :meth:`assert_warn` if and only if you have a *really* good reason to log assertion + failures instead of failing. + """ + return _builder(val, description, 'warn', logger=logger) + def fail(msg=''): - """Force test failure with the given message.""" + """Force immediate test failure with the given message. + + Args: + msg (str, optional): the failure message. Defaults to ``''`` + + Examples: + Fail a test:: + + from assertpy import assert_that, fail + + def test_fail(): + fail('forced fail!') + + If you wanted to test for a known failure, here is a useful pattern:: + + import operator + + def test_adder_bad_arg(): + try: + operator.add(1, 'bad arg') + fail('should have raised error') + except TypeError as e: + assert_that(str(e)).contains('unsupported operand') + """ raise AssertionError('Fail: %s!' % msg if msg else 'Fail!') + def soft_fail(msg=''): - """Adds error message to soft errors list if within soft assertions context. - Either just force test failure with the given message.""" + """Within a :meth:`soft_assertions` context, append the failure message to the soft error list, + but do not halt test execution. + + Otherwise, outside the context, acts identical to :meth:`fail` and forces immediate test + failure with the given message. + + Args: + msg (str, optional): the failure message. Defaults to ``''`` + + Examples: + Failing soft assertions:: + + from assertpy import assert_that, soft_assertions, soft_fail + + with soft_assertions(): + assert_that(1).is_equal_to(2) + soft_fail('my message') + assert_that('foo').is_equal_to('bar') + + Fails, and outputs the following soft error list:: + + AssertionError: soft assertion failures: + 1. Expected <1> to be equal to <2>, but was not. + 2. Fail: my message! + 3. Expected to be equal to , but was not. + + """ global _soft_ctx if _soft_ctx: global _soft_err @@ -110,41 +273,97 @@ def soft_fail(msg=''): return fail(msg) + # assertion extensions _extensions = {} + + def add_extension(func): + """Add a new user-defined custom assertion to assertpy. + + Once the assertion is registered with assertpy, use it like any other assertion. Pass val to + :meth:`assert_that`, and then call it. + + Args: + func: the assertion function (to be added) + + Examples: + Usage:: + + from assertpy import add_extension + + def is_5(self): + if self.val != 5: + return self.error(f'{self.val} is NOT 5!') + return self + + add_extension(is_5) + + def test_5(): + assert_that(5).is_5() + + def test_6(): + assert_that(6).is_5() # fails + # 6 is NOT 5! + """ if not callable(func): raise TypeError('func must be callable') _extensions[func.__name__] = func + def remove_extension(func): + """Remove a user-defined custom assertion. + + Args: + func: the assertion function (to be removed) + + Examples: + Usage:: + + from assertpy import remove_extension + + remove_extension(is_5) + """ if not callable(func): raise TypeError('func must be callable') if func.__name__ in _extensions: del _extensions[func.__name__] -def builder(val, description='', kind=None, expected=None, logger=None): + +def _builder(val, description='', kind=None, expected=None, logger=None): + """Internal helper to build a new :class:`AssertionBuilder` instance and glue on any extension methods.""" ab = AssertionBuilder(val, description, kind, expected, logger) if _extensions: # glue extension method onto new builder instance - for name,func in _extensions.items(): + for name, func in _extensions.items(): meth = types.MethodType(func, ab) setattr(ab, name, meth) return ab + # warnings class WarningLoggingAdapter(logging.LoggerAdapter): """Logging adapter to unwind the stack to get the correct callee filename and line number.""" + def process(self, msg, kwargs): - def _unwind(frame, fn='assert_warn'): - if frame and fn in frame.f_code.co_names: - return frame - return _unwind(frame.f_back, fn) + def _unwind(frame): + # walk all the frames + frames = [] + while frame: + frames.append((frame.f_code.co_filename, frame.f_lineno)) + frame = frame.f_back + + # in reverse, find the first assertpy frame (and return the previous one) + prev = None + for frame in reversed(frames): + for f in ASSERTPY_FILES: + if frame[0].endswith(f): + return prev + prev = frame + + filename, lineno = _unwind(inspect.currentframe()) + return '[%s:%d]: %s' % (os.path.basename(filename), lineno, msg), kwargs - frame = _unwind(inspect.currentframe()) - lineno = frame.f_lineno - filename = os.path.basename(frame.f_code.co_filename) - return '[%s:%d]: %s' % (filename, lineno, msg), kwargs _logger = logging.getLogger('assertpy') _handler = logging.StreamHandler(sys.stdout) @@ -155,25 +374,82 @@ def _unwind(frame, fn='assert_warn'): _default_logger = WarningLoggingAdapter(_logger, None) -class AssertionBuilder(DynamicMixin, ExceptionMixin, SnapshotMixin, ExtractingMixin, - FileMixin, DateMixin, DictMixin, CollectionMixin, StringMixin, NumericMixin, - ContainsMixin, HelpersMixin, BaseMixin, object): - """Assertion builder.""" +class AssertionBuilder( + StringMixin, + SnapshotMixin, + NumericMixin, + HelpersMixin, + FileMixin, + ExtractingMixin, + ExceptionMixin, + DynamicMixin, + DictMixin, + DateMixin, + ContainsMixin, + CollectionMixin, + BaseMixin, + object +): + """The main assertion class. Never call the constructor directly, always use the + :meth:`assert_that` helper instead. Or if you just want warning messages, use the + :meth:`assert_warn` helper. + + Args: + val: the value to be tested (aka the actual value) + description (str, optional): the extra error message description. Defaults to ``''`` + (aka empty string) + kind (str, optional): the kind of assertions, one of ``None``, ``soft``, or ``warn``. + Defaults to ``None`` + expected (Error, optional): the expected exception. Defaults to ``None`` + logger (Logger, optional): the logger for warning messages. Defaults to ``None`` + """ def __init__(self, val, description='', kind=None, expected=None, logger=None): - """Construct the assertion builder.""" + """Never call this constructor directly.""" self.val = val self.description = description self.kind = kind self.expected = expected self.logger = logger if logger else _default_logger - def _builder(self, val, description='', kind=None, expected=None, logger=None): - """Helper to build a new Builder. Only used when we don't want to chain.""" - return builder(val, description, kind, expected, logger) + def builder(self, val, description='', kind=None, expected=None, logger=None): + """Helper to build a new :class:`AssertionBuilder` instance. Use this only if not chaining to ``self``. + + Args: + val: the value to be tested (aka the actual value) + description (str, optional): the extra error message description. Defaults to ``''`` + (aka empty string) + kind (str, optional): the kind of assertions, one of ``None``, ``soft``, or ``warn``. + Defaults to ``None`` + expected (Error, optional): the expected exception. Defaults to ``None`` + logger (Logger, optional): the logger for warning messages. Defaults to ``None`` + """ + return _builder(val, description, kind, expected, logger) + + def error(self, msg): + """Helper to raise an ``AssertionError`` with the given message. + + If an error description is set by :meth:`~assertpy.base.BaseMixin.described_as`, then that + description is prepended to the error message. + + Args: + msg: the error message + + Examples: + Used to fail an assertion:: + + if self.val != other: + return self.error('Expected <%s> to be equal to <%s>, but was not.' % (self.val, other)) + + Raises: + AssertionError: always raised unless ``kind`` is ``warn`` (as set when using an + :meth:`assert_warn` assertion) or ``kind`` is ``soft`` (as set when inside a + :meth:`soft_assertions` context). - def _err(self, msg): - """Helper to raise an AssertionError, and optionally prepend custom description.""" + Returns: + AssertionBuilder: returns this instance to chain to the next assertion, but only when + ``AssertionError`` is not raised, as is the case when ``kind`` is ``warn`` or ``soft``. + """ out = '%s%s' % ('[%s] ' % self.description if len(self.description) > 0 else '', msg) if self.kind == 'warn': self.logger.warning(out) diff --git a/assertpy/base.py b/assertpy/base.py index 847a6cc..b572274 100644 --- a/assertpy/base.py +++ b/assertpy/base.py @@ -26,65 +26,296 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +__tracebackhide__ = True + + class BaseMixin(object): """Base mixin.""" def described_as(self, description): - """Describes the assertion. On failure, the description is included in the error message.""" + """Describes the assertion. On failure, the description is included in the error message. + + This is not an assertion itself. But if the any of the following chained assertions fail, + the description will be included in addition to the regular error message. + + Args: + description: the error message description + + Examples: + Usage:: + + assert_that(1).described_as('error msg desc').is_equal_to(2) # fails + # [error msg desc] Expected <1> to be equal to <2>, but was not. + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + """ self.description = str(description) return self def is_equal_to(self, other, **kwargs): - """Asserts that val is equal to other.""" + """Asserts that val is equal to other. + + Checks actual is equal to expected using the ``==`` operator. When val is *dict-like*, + optionally ignore or include keys when checking equality. + + Args: + other: the expected value + **kwargs: see below + + Keyword Args: + ignore: the dict key (or list of keys) to ignore + include: the dict key (of list of keys) to include + + Examples: + Usage:: + + assert_that(1 + 2).is_equal_to(3) + assert_that('foo').is_equal_to('foo') + assert_that(123).is_equal_to(123) + assert_that(123.4).is_equal_to(123.4) + assert_that(['a', 'b']).is_equal_to(['a', 'b']) + assert_that((1, 2, 3)).is_equal_to((1, 2, 3)) + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 2}) + assert_that({'a', 'b'}).is_equal_to({'a', 'b'}) + + When the val is *dict-like*, keys can optionally be *ignored* when checking equality:: + + # ignore a single key + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, ignore='b') + + # ignore multiple keys + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, ignore=['b', 'c']) + + # ignore nested keys + assert_that({'a': {'b': 2, 'c': 3, 'd': 4}}).is_equal_to({'a': {'d': 4}}, ignore=[('a', 'b'), ('a', 'c')]) + + When the val is *dict-like*, only certain keys can be *included* when checking equality:: + + # include a single key + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, include='a') + + # include multiple keys + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2}, include=['a', 'b']) + + Failure produces a nice error message:: + + assert_that(1).is_equal_to(2) # fails + # Expected <1> to be equal to <2>, but was not. + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if actual is **not** equal to expected + + Tip: + Using :meth:`is_equal_to` with a ``float`` val is just asking for trouble. Instead, you'll + always want to use *fuzzy* numeric assertions like :meth:`~assertpy.numeric.NumericMixin.is_close_to` + or :meth:`~assertpy.numeric.NumericMixin.is_between`. + + See Also: + :meth:`~assertpy.string.StringMixin.is_equal_to_ignoring_case` - for case-insensitive string equality + """ if self._check_dict_like(self.val, check_values=False, return_as_bool=True) and \ self._check_dict_like(other, check_values=False, return_as_bool=True): if self._dict_not_equal(self.val, other, ignore=kwargs.get('ignore'), include=kwargs.get('include')): self._dict_err(self.val, other, ignore=kwargs.get('ignore'), include=kwargs.get('include')) else: if self.val != other: - self._err('Expected <%s> to be equal to <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be equal to <%s>, but was not.' % (self.val, other)) return self def is_not_equal_to(self, other): - """Asserts that val is not equal to other.""" + """Asserts that val is not equal to other. + + Checks actual is not equal to expected using the ``!=`` operator. + + Args: + other: the expected value + + Examples: + Usage:: + + assert_that(1 + 2).is_not_equal_to(4) + assert_that('foo').is_not_equal_to('bar') + assert_that(123).is_not_equal_to(456) + assert_that(123.4).is_not_equal_to(567.8) + assert_that(['a', 'b']).is_not_equal_to(['c', 'd']) + assert_that((1, 2, 3)).is_not_equal_to((1, 2, 4)) + assert_that({'a': 1, 'b': 2}).is_not_equal_to({'a': 1, 'b': 3}) + assert_that({'a', 'b'}).is_not_equal_to({'a', 'x'}) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if actual **is** equal to expected + """ if self.val == other: - self._err('Expected <%s> to be not equal to <%s>, but was.' % (self.val, other)) + return self.error('Expected <%s> to be not equal to <%s>, but was.' % (self.val, other)) return self def is_same_as(self, other): - """Asserts that the val is identical to other, via 'is' compare.""" + """Asserts that val is identical to other. + + Checks actual is identical to expected using the ``is`` operator. + + Args: + other: the expected value + + Examples: + Basic types are identical:: + + assert_that(1).is_same_as(1) + assert_that('foo').is_same_as('foo') + assert_that(123.4).is_same_as(123.4) + + As are immutables like ``tuple``:: + + assert_that((1, 2, 3)).is_same_as((1, 2, 3)) + + But mutable collections like ``list``, ``dict``, and ``set`` are not:: + + # these all fail... + assert_that(['a', 'b']).is_same_as(['a', 'b']) # fails + assert_that({'a': 1, 'b': 2}).is_same_as({'a': 1, 'b': 2}) # fails + assert_that({'a', 'b'}).is_same_as({'a', 'b'}) # fails + + Unless they are the same object:: + + x = {'a': 1, 'b': 2} + y = x + assert_that(x).is_same_as(y) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if actual is **not** identical to expected + """ if self.val is not other: - self._err('Expected <%s> to be identical to <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be identical to <%s>, but was not.' % (self.val, other)) return self def is_not_same_as(self, other): - """Asserts that the val is not identical to other, via 'is' compare.""" + """Asserts that val is not identical to other. + + Checks actual is not identical to expected using the ``is`` operator. + + Args: + other: the expected value + + Examples: + Usage:: + + assert_that(1).is_not_same_as(2) + assert_that('foo').is_not_same_as('bar') + assert_that(123.4).is_not_same_as(567.8) + assert_that((1, 2, 3)).is_not_same_as((1, 2, 4)) + + # mutable collections, even if equal, are not identical... + assert_that(['a', 'b']).is_not_same_as(['a', 'b']) + assert_that({'a': 1, 'b': 2}).is_not_same_as({'a': 1, 'b': 2}) + assert_that({'a', 'b'}).is_not_same_as({'a', 'b'}) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if actual **is** identical to expected + """ if self.val is other: - self._err('Expected <%s> to be not identical to <%s>, but was.' % (self.val, other)) + return self.error('Expected <%s> to be not identical to <%s>, but was.' % (self.val, other)) return self def is_true(self): - """Asserts that val is true.""" + """Asserts that val is true. + + Examples: + Usage:: + + assert_that(True).is_true() + assert_that(1).is_true() + assert_that('foo').is_true() + assert_that(1.0).is_true() + assert_that(['a', 'b']).is_true() + assert_that((1, 2, 3)).is_true() + assert_that({'a': 1, 'b': 2}).is_true() + assert_that({'a', 'b'}).is_true() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** false + """ if not self.val: - self._err('Expected , but was not.') + return self.error('Expected <%s> to be , but was not.' % self.val) return self def is_false(self): - """Asserts that val is false.""" + """Asserts that val is false. + + Examples: + Usage:: + + assert_that(False).is_false() + assert_that(0).is_false() + assert_that('').is_false() + assert_that(0.0).is_false() + assert_that([]).is_false() + assert_that(()).is_false() + assert_that({}).is_false() + assert_that(set()).is_false() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** true + """ if self.val: - self._err('Expected , but was not.') + return self.error('Expected <%s> to be , but was not.' % self.val) return self def is_none(self): - """Asserts that val is none.""" + """Asserts that val is none. + + Examples: + Usage:: + + assert_that(None).is_none() + assert_that(print('hello world')).is_none() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** none + """ if self.val is not None: - self._err('Expected <%s> to be , but was not.' % self.val) + return self.error('Expected <%s> to be , but was not.' % self.val) return self def is_not_none(self): - """Asserts that val is not none.""" + """Asserts that val is not none. + + Examples: + Usage:: + + assert_that(0).is_not_none() + assert_that('foo').is_not_none() + assert_that(False).is_not_none() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** none + """ if self.val is None: - self._err('Expected not , but was.') + return self.error('Expected not , but was.') return self def _type(self, val): @@ -95,30 +326,102 @@ def _type(self, val): return 'unknown' def is_type_of(self, some_type): - """Asserts that val is of the given type.""" + """Asserts that val is of the given type. + + Args: + some_type (type): the expected type + + Examples: + Usage:: + + assert_that(1).is_type_of(int) + assert_that('foo').is_type_of(str) + assert_that(123.4).is_type_of(float) + assert_that(['a', 'b']).is_type_of(list) + assert_that((1, 2, 3)).is_type_of(tuple) + assert_that({'a': 1, 'b': 2}).is_type_of(dict) + assert_that({'a', 'b'}).is_type_of(set) + assert_that(True).is_type_of(bool) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** of the given type + """ if type(some_type) is not type and not issubclass(type(some_type), type): raise TypeError('given arg must be a type') if type(self.val) is not some_type: t = self._type(self.val) - self._err('Expected <%s:%s> to be of type <%s>, but was not.' % (self.val, t, some_type.__name__)) + return self.error('Expected <%s:%s> to be of type <%s>, but was not.' % (self.val, t, some_type.__name__)) return self def is_instance_of(self, some_class): - """Asserts that val is an instance of the given class.""" + """Asserts that val is an instance of the given class. + + Args: + some_class: the expected class + + Examples: + Usage:: + + assert_that(1).is_instance_of(int) + assert_that('foo').is_instance_of(str) + assert_that(123.4).is_instance_of(float) + assert_that(['a', 'b']).is_instance_of(list) + assert_that((1, 2, 3)).is_instance_of(tuple) + assert_that({'a': 1, 'b': 2}).is_instance_of(dict) + assert_that({'a', 'b'}).is_instance_of(set) + assert_that(True).is_instance_of(bool) + + With a user-defined class:: + + class Foo: pass + f = Foo() + assert_that(f).is_instance_of(Foo) + assert_that(f).is_instance_of(object) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** an instance of the given class + """ try: if not isinstance(self.val, some_class): t = self._type(self.val) - self._err('Expected <%s:%s> to be instance of class <%s>, but was not.' % (self.val, t, some_class.__name__)) + return self.error('Expected <%s:%s> to be instance of class <%s>, but was not.' % (self.val, t, some_class.__name__)) except TypeError: raise TypeError('given arg must be a class') return self def is_length(self, length): - """Asserts that val is the given length.""" + """Asserts that val is the given length. + + Checks val is the given length using the ``len()`` built-in. + + Args: + length (int): the expected length + + Examples: + Usage:: + + assert_that('foo').is_length(3) + assert_that(['a', 'b']).is_length(2) + assert_that((1, 2, 3)).is_length(3) + assert_that({'a': 1, 'b': 2}).is_length(2) + assert_that({'a', 'b'}).is_length(2) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** the given length + """ if type(length) is not int: raise TypeError('given arg must be an int') if length < 0: raise ValueError('given arg must be a positive int') if len(self.val) != length: - self._err('Expected <%s> to be of length <%d>, but was <%d>.' % (self.val, length, len(self.val))) - return self \ No newline at end of file + return self.error('Expected <%s> to be of length <%d>, but was <%d>.' % (self.val, length, len(self.val))) + return self diff --git a/assertpy/collection.py b/assertpy/collection.py index 5f9d906..3066ee8 100644 --- a/assertpy/collection.py +++ b/assertpy/collection.py @@ -34,24 +34,81 @@ else: Iterable = collections.Iterable +__tracebackhide__ = True + class CollectionMixin(object): """Collection assertions mixin.""" def is_iterable(self): - """Asserts that val is iterable collection.""" + """Asserts that val is iterable collection. + + Examples: + Usage:: + + assert_that('foo').is_iterable() + assert_that(['a', 'b']).is_iterable() + assert_that((1, 2, 3)).is_iterable() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** iterable + """ if not isinstance(self.val, Iterable): - self._err('Expected iterable, but was not.') + return self.error('Expected iterable, but was not.') return self def is_not_iterable(self): - """Asserts that val is not iterable collection.""" + """Asserts that val is not iterable collection. + + Examples: + Usage:: + + assert_that(1).is_not_iterable() + assert_that(123.4).is_not_iterable() + assert_that(True).is_not_iterable() + assert_that(None).is_not_iterable() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** iterable + """ if isinstance(self.val, Iterable): - self._err('Expected not iterable, but was.') + return self.error('Expected not iterable, but was.') return self def is_subset_of(self, *supersets): - """Asserts that val is iterable and a subset of the given superset or flattened superset if multiple supersets are given.""" + """Asserts that val is iterable and a subset of the given superset (or supersets). + + Args: + *supersets: the expected superset (or supersets) + + Examples: + Usage:: + + assert_that('foo').is_subset_of('abcdefghijklmnopqrstuvwxyz') + assert_that(['a', 'b']).is_subset_of(['a', 'b', 'c']) + assert_that((1, 2, 3)).is_subset_of([1, 2, 3, 4]) + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 1, 'b': 2, 'c': 3}) + assert_that({'a', 'b'}).is_subset_of({'a', 'b', 'c'}) + + # or multiple supersets (as comma-separated args) + assert_that('aBc').is_subset_of('abc', 'ABC') + assert_that((1, 2, 3)).is_subset_of([1, 3, 5], [2, 4, 6]) + + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 1, 'c': 3}) # fails + # Expected <{'a': 1, 'b': 2}> to be subset of <{'a': 1, 'c': 3}>, but <{'b': 2}> was missing. + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** subset of given superset (or supersets) + """ if not isinstance(self.val, Iterable): raise TypeError('val is not iterable') if len(supersets) == 0: @@ -61,18 +118,19 @@ def is_subset_of(self, *supersets): if hasattr(self.val, 'keys') and callable(getattr(self.val, 'keys')) and hasattr(self.val, '__getitem__'): # flatten superset dicts superdict = {} - for l,j in enumerate(supersets): + for l, j in enumerate(supersets): self._check_dict_like(j, check_values=False, name='arg #%d' % (l+1)) for k in j.keys(): superdict.update({k: j[k]}) for i in self.val.keys(): if i not in superdict: - missing.append({i: self.val[i]}) # bad key + missing.append({i: self.val[i]}) # bad key elif self.val[i] != superdict[i]: - missing.append({i: self.val[i]}) # bad val + missing.append({i: self.val[i]}) # bad val if missing: - self._err('Expected <%s> to be subset of %s, but %s %s missing.' % (self.val, self._fmt_items(superdict), self._fmt_items(missing), 'was' if len(missing) == 1 else 'were')) + return self.error('Expected <%s> to be subset of %s, but %s %s missing.' % ( + self.val, self._fmt_items(superdict), self._fmt_items(missing), 'was' if len(missing) == 1 else 'were')) else: # flatten supersets superset = set() @@ -87,6 +145,52 @@ def is_subset_of(self, *supersets): if i not in superset: missing.append(i) if missing: - self._err('Expected <%s> to be subset of %s, but %s %s missing.' % (self.val, self._fmt_items(superset), self._fmt_items(missing), 'was' if len(missing) == 1 else 'were')) + return self.error('Expected <%s> to be subset of %s, but %s %s missing.' % ( + self.val, self._fmt_items(superset), self._fmt_items(missing), 'was' if len(missing) == 1 else 'were')) + + return self + + def is_sorted(self, key=lambda x: x, reverse=False): + """Asserts that val is iterable and is sorted. + + Args: + key (function): the one-arg function to extract the sort comparison key. Defaults to + ``lambda x: x`` to just compare items directly. + reverse (bool): if ``True``, then comparison key is reversed. Defaults to ``False``. + + Examples: + Usage:: + + assert_that(['a', 'b', 'c']).is_sorted() + assert_that((1, 2, 3)).is_sorted() + + # with a key function + assert_that('aBc').is_sorted(key=str.lower) + + # reverse order + assert_that(['c', 'b', 'a']).is_sorted(reverse=True) + assert_that((3, 2, 1)).is_sorted(reverse=True) + + assert_that((1, 2, 3, 4, -5, 6)).is_sorted() # fails + # Expected <(1, 2, 3, 4, -5, 6)> to be sorted, but subset <4, -5> at index 3 is not. + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** sorted + """ + if not isinstance(self.val, Iterable): + raise TypeError('val is not iterable') + + for i, x in enumerate(self.val): + if i > 0: + if reverse: + if key(x) > key(prev): + return self.error('Expected <%s> to be sorted reverse, but subset %s at index %s is not.' % (self.val, self._fmt_items([prev, x]), i-1)) + else: + if key(x) < key(prev): + return self.error('Expected <%s> to be sorted, but subset %s at index %s is not.' % (self.val, self._fmt_items([prev, x]), i-1)) + prev = x return self diff --git a/assertpy/contains.py b/assertpy/contains.py index 1fd87d5..0f25b49 100644 --- a/assertpy/contains.py +++ b/assertpy/contains.py @@ -35,20 +35,52 @@ str_types = (basestring,) xrange = xrange +__tracebackhide__ = True + class ContainsMixin(object): """Containment assertions mixin.""" def contains(self, *items): - """Asserts that val contains the given item or items.""" + """Asserts that val contains the given item or items. + + Checks if the collection contains the given item or items using ``in`` operator. + + Args: + *items: the item or items expected to be contained + + Examples: + Usage:: + + assert_that('foo').contains('f') + assert_that('foo').contains('f', 'oo') + assert_that(['a', 'b']).contains('b', 'a') + assert_that((1, 2, 3)).contains(3, 2, 1) + assert_that({'a': 1, 'b': 2}).contains('b', 'a') # checks keys + assert_that({'a', 'b'}).contains('b', 'a') + assert_that([1, 2, 3]).is_type_of(list).contains(1, 2).does_not_contain(4, 5) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** contain the item or items + + Tip: + Use the :meth:`~assertpy.dict.DictMixin.contains_key` alias when working with + *dict-like* objects to be self-documenting. + + See Also: + :meth:`~assertpy.string.StringMixin.contains_ignoring_case` - for case-insensitive string contains + """ if len(items) == 0: raise ValueError('one or more args must be given') elif len(items) == 1: if items[0] not in self.val: if self._check_dict_like(self.val, return_as_bool=True): - self._err('Expected <%s> to contain key <%s>, but did not.' % (self.val, items[0])) + return self.error('Expected <%s> to contain key <%s>, but did not.' % (self.val, items[0])) else: - self._err('Expected <%s> to contain item <%s>, but did not.' % (self.val, items[0])) + return self.error('Expected <%s> to contain item <%s>, but did not.' % (self.val, items[0])) else: missing = [] for i in items: @@ -56,29 +88,77 @@ def contains(self, *items): missing.append(i) if missing: if self._check_dict_like(self.val, return_as_bool=True): - self._err('Expected <%s> to contain keys %s, but did not contain key%s %s.' % (self.val, self._fmt_items(items), '' if len(missing) == 0 else 's', self._fmt_items(missing))) + return self.error('Expected <%s> to contain keys %s, but did not contain key%s %s.' % ( + self.val, self._fmt_items(items), '' if len(missing) == 0 else 's', self._fmt_items(missing))) else: - self._err('Expected <%s> to contain items %s, but did not contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(missing))) + return self.error('Expected <%s> to contain items %s, but did not contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(missing))) return self def does_not_contain(self, *items): - """Asserts that val does not contain the given item or items.""" + """Asserts that val does not contain the given item or items. + + Checks if the collection excludes the given item or items using ``in`` operator. + + Args: + *items: the item or items expected to be excluded + + Examples: + Usage:: + + assert_that('foo').does_not_contain('x') + assert_that(['a', 'b']).does_not_contain('x', 'y') + assert_that((1, 2, 3)).does_not_contain(4, 5) + assert_that({'a': 1, 'b': 2}).does_not_contain('x', 'y') # checks keys + assert_that({'a', 'b'}).does_not_contain('x', 'y') + assert_that([1, 2, 3]).is_type_of(list).contains(1, 2).does_not_contain(4, 5) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **does** contain the item or items + + Tip: + Use the :meth:`~assertpy.dict.DictMixin.does_not_contain_key` alias when working with + *dict-like* objects to be self-documenting. + """ if len(items) == 0: raise ValueError('one or more args must be given') elif len(items) == 1: if items[0] in self.val: - self._err('Expected <%s> to not contain item <%s>, but did.' % (self.val, items[0])) + return self.error('Expected <%s> to not contain item <%s>, but did.' % (self.val, items[0])) else: found = [] for i in items: if i in self.val: found.append(i) if found: - self._err('Expected <%s> to not contain items %s, but did contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(found))) + return self.error('Expected <%s> to not contain items %s, but did contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(found))) return self def contains_only(self, *items): - """Asserts that val contains only the given item or items.""" + """Asserts that val contains *only* the given item or items. + + Checks if the collection contains only the given item or items using ``in`` operator. + + Args: + *items: the *only* item or items expected to be contained + + Examples: + Usage:: + + assert_that('foo').contains_only('f', 'o') + assert_that(['a', 'a', 'b']).contains_only('a', 'b') + assert_that((1, 1, 2)).contains_only(1, 2) + assert_that({'a': 1, 'a': 2, 'b': 3}).contains_only('a', 'b') + assert_that({'a', 'a', 'b'}).contains_only('a', 'b') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val contains anything **not** item or items + """ if len(items) == 0: raise ValueError('one or more args must be given') else: @@ -87,18 +167,38 @@ def contains_only(self, *items): if i not in items: extra.append(i) if extra: - self._err('Expected <%s> to contain only %s, but did contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(extra))) + return self.error('Expected <%s> to contain only %s, but did contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(extra))) missing = [] for i in items: if i not in self.val: missing.append(i) if missing: - self._err('Expected <%s> to contain only %s, but did not contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(missing))) + return self.error('Expected <%s> to contain only %s, but did not contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(missing))) return self def contains_sequence(self, *items): - """Asserts that val contains the given sequence of items in order.""" + """Asserts that val contains the given ordered sequence of items. + + Checks if the collection contains the given sequence of items using ``in`` operator. + + Args: + *items: the sequence of items expected to be contained + + Examples: + Usage:: + + assert_that('foo').contains_sequence('f', 'o') + assert_that('foo').contains_sequence('o', 'o') + assert_that(['a', 'b', 'c']).contains_sequence('b', 'c') + assert_that((1, 2, 3)).contains_sequence(1, 2) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** contains the given sequence of items + """ if len(items) == 0: raise ValueError('one or more args must be given') else: @@ -111,60 +211,152 @@ def contains_sequence(self, *items): return self except TypeError: raise TypeError('val is not iterable') - self._err('Expected <%s> to contain sequence %s, but did not.' % (self.val, self._fmt_items(items))) + return self.error('Expected <%s> to contain sequence %s, but did not.' % (self.val, self._fmt_items(items))) def contains_duplicates(self): - """Asserts that val is iterable and contains duplicate items.""" + """Asserts that val is iterable and *does* contain duplicates. + + Examples: + Usage:: + + assert_that('foo').contains_duplicates() + assert_that(['a', 'a', 'b']).contains_duplicates() + assert_that((1, 1, 2)).contains_duplicates() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** contain any duplicates + """ try: if len(self.val) != len(set(self.val)): return self except TypeError: raise TypeError('val is not iterable') - self._err('Expected <%s> to contain duplicates, but did not.' % self.val) + return self.error('Expected <%s> to contain duplicates, but did not.' % self.val) def does_not_contain_duplicates(self): - """Asserts that val is iterable and does not contain any duplicate items.""" + """Asserts that val is iterable and *does not* contain any duplicates. + + Examples: + Usage:: + + assert_that('fox').does_not_contain_duplicates() + assert_that(['a', 'b', 'c']).does_not_contain_duplicates() + assert_that((1, 2, 3)).does_not_contain_duplicates() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **does** contain duplicates + """ try: if len(self.val) == len(set(self.val)): return self except TypeError: raise TypeError('val is not iterable') - self._err('Expected <%s> to not contain duplicates, but did.' % self.val) + return self.error('Expected <%s> to not contain duplicates, but did.' % self.val) def is_empty(self): - """Asserts that val is empty.""" + """Asserts that val is empty. + + Examples: + Usage:: + + assert_that('').is_empty() + assert_that([]).is_empty() + assert_that(()).is_empty() + assert_that({}).is_empty() + assert_that(set()).is_empty() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** empty + """ if len(self.val) != 0: if isinstance(self.val, str_types): - self._err('Expected <%s> to be empty string, but was not.' % self.val) + return self.error('Expected <%s> to be empty string, but was not.' % self.val) else: - self._err('Expected <%s> to be empty, but was not.' % self.val) + return self.error('Expected <%s> to be empty, but was not.' % self.val) return self def is_not_empty(self): - """Asserts that val is not empty.""" + """Asserts that val is *not* empty. + + Examples: + Usage:: + + assert_that('foo').is_not_empty() + assert_that(['a', 'b']).is_not_empty() + assert_that((1, 2, 3)).is_not_empty() + assert_that({'a': 1, 'b': 2}).is_not_empty() + assert_that({'a', 'b'}).is_not_empty() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** empty + """ if len(self.val) == 0: if isinstance(self.val, str_types): - self._err('Expected not empty string, but was empty.') + return self.error('Expected not empty string, but was empty.') else: - self._err('Expected not empty, but was empty.') + return self.error('Expected not empty, but was empty.') return self def is_in(self, *items): - """Asserts that val is equal to one of the given items.""" + """Asserts that val is equal to one of the given items. + + Args: + *items: the items expected to contain val + + Examples: + Usage:: + + assert_that('foo').is_in('foo', 'bar', 'baz') + assert_that(1).is_in(0, 1, 2, 3) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** in the given items + """ if len(items) == 0: raise ValueError('one or more args must be given') else: for i in items: if self.val == i: return self - self._err('Expected <%s> to be in %s, but was not.' % (self.val, self._fmt_items(items))) + return self.error('Expected <%s> to be in %s, but was not.' % (self.val, self._fmt_items(items))) def is_not_in(self, *items): - """Asserts that val is not equal to one of the given items.""" + """Asserts that val is not equal to one of the given items. + + Args: + *items: the items expected to exclude val + + Examples: + Usage:: + + assert_that('foo').is_not_in('bar', 'baz', 'box') + assert_that(1).is_not_in(-1, -2, -3) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** in the given items + """ if len(items) == 0: raise ValueError('one or more args must be given') else: for i in items: if self.val == i: - self._err('Expected <%s> to not be in %s, but was.' % (self.val, self._fmt_items(items))) + return self.error('Expected <%s> to not be in %s, but was.' % (self.val, self._fmt_items(items))) return self diff --git a/assertpy/date.py b/assertpy/date.py index 2dbafbb..0cdcb29 100644 --- a/assertpy/date.py +++ b/assertpy/date.py @@ -28,54 +28,166 @@ import datetime +__tracebackhide__ = True + class DateMixin(object): """Date and time assertions mixin.""" -### datetime assertions ### def is_before(self, other): - """Asserts that val is a date and is before other date.""" + """Asserts that val is a date and is before other date. + + Args: + other: the other date, expected to be after val + + Examples: + Usage:: + + import datetime + + today = datetime.datetime.now() + yesterday = today - datetime.timedelta(days=1) + + assert_that(yesterday).is_before(today) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** before the given date + + See Also: + :meth:`~assertpy.string.NumericMixin.is_less_than` - numeric assertion, but also works with datetime BR + :meth:`~assertpy.string.NumericMixin.is_less_than_or_equal_to` - numeric assertion, but also works with datetime + """ if type(self.val) is not datetime.datetime: raise TypeError('val must be datetime, but was type <%s>' % type(self.val).__name__) if type(other) is not datetime.datetime: raise TypeError('given arg must be datetime, but was type <%s>' % type(other).__name__) if self.val >= other: - self._err('Expected <%s> to be before <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be before <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) return self def is_after(self, other): - """Asserts that val is a date and is after other date.""" + """Asserts that val is a date and is after other date. + + Args: + other: the other date, expected to be before val + + Examples: + Usage:: + + import datetime + + today = datetime.datetime.now() + yesterday = today - datetime.timedelta(days=1) + + assert_that(today).is_after(yesterday) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** after the given date + + See Also: + :meth:`~assertpy.string.NumericMixin.is_greater_than` - numeric assertion, but also works with datetime BR + :meth:`~assertpy.string.NumericMixin.is_greater_than_or_equal_to` - numeric assertion, but also works with datetime + """ if type(self.val) is not datetime.datetime: raise TypeError('val must be datetime, but was type <%s>' % type(self.val).__name__) if type(other) is not datetime.datetime: raise TypeError('given arg must be datetime, but was type <%s>' % type(other).__name__) if self.val <= other: - self._err('Expected <%s> to be after <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be after <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) return self def is_equal_to_ignoring_milliseconds(self, other): + """Asserts that val is a date and is equal to other date to the second. + + Args: + other: the other date, expected to be equal to the second + + Examples: + Usage:: + + import datetime + + d1 = datetime.datetime(2020, 1, 2, 3, 4, 5, 6) # 2020-01-02 03:04:05.000006 + d2 = datetime.datetime(2020, 1, 2, 3, 4, 5, 777777) # 2020-01-02 03:04:05.777777 + + assert_that(d1).is_equal_to_ignoring_milliseconds(d2) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** equal to the given date to the second + """ if type(self.val) is not datetime.datetime: raise TypeError('val must be datetime, but was type <%s>' % type(self.val).__name__) if type(other) is not datetime.datetime: raise TypeError('given arg must be datetime, but was type <%s>' % type(other).__name__) if self.val.date() != other.date() or self.val.hour != other.hour or self.val.minute != other.minute or self.val.second != other.second: - self._err('Expected <%s> to be equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) return self def is_equal_to_ignoring_seconds(self, other): + """Asserts that val is a date and is equal to other date to the minute. + + Args: + other: the other date, expected to be equal to the minute + + Examples: + Usage:: + + import datetime + + d1 = datetime.datetime(2020, 1, 2, 3, 4, 5) # 2020-01-02 03:04:05 + d2 = datetime.datetime(2020, 1, 2, 3, 4, 55) # 2020-01-02 03:04:55 + + assert_that(d1).is_equal_to_ignoring_seconds(d2) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** equal to the given date to the minute + """ if type(self.val) is not datetime.datetime: raise TypeError('val must be datetime, but was type <%s>' % type(self.val).__name__) if type(other) is not datetime.datetime: raise TypeError('given arg must be datetime, but was type <%s>' % type(other).__name__) if self.val.date() != other.date() or self.val.hour != other.hour or self.val.minute != other.minute: - self._err('Expected <%s> to be equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M'), other.strftime('%Y-%m-%d %H:%M'))) + return self.error('Expected <%s> to be equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M'), other.strftime('%Y-%m-%d %H:%M'))) return self def is_equal_to_ignoring_time(self, other): + """Asserts that val is a date and is equal to other date ignoring time. + + Args: + other: the other date, expected to be equal ignoring time + + Examples: + Usage:: + + import datetime + + d1 = datetime.datetime(2020, 1, 2, 3, 4, 5) # 2020-01-02 03:04:05 + d2 = datetime.datetime(2020, 1, 2, 13, 44, 55) # 2020-01-02 13:44:55 + + assert_that(d1).is_equal_to_ignoring_time(d2) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** equal to the given date ignoring time + """ if type(self.val) is not datetime.datetime: raise TypeError('val must be datetime, but was type <%s>' % type(self.val).__name__) if type(other) is not datetime.datetime: raise TypeError('given arg must be datetime, but was type <%s>' % type(other).__name__) if self.val.date() != other.date(): - self._err('Expected <%s> to be equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d'), other.strftime('%Y-%m-%d'))) + return self.error('Expected <%s> to be equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d'), other.strftime('%Y-%m-%d'))) return self diff --git a/assertpy/dict.py b/assertpy/dict.py index d1f9379..e01dce7 100644 --- a/assertpy/dict.py +++ b/assertpy/dict.py @@ -26,22 +26,78 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +__tracebackhide__ = True + class DictMixin(object): """Dict assertions mixin.""" - + def contains_key(self, *keys): - """Asserts the val is a dict and contains the given key or keys. Alias for contains().""" + """Asserts the val is a dict and contains the given key or keys. Alias for :meth:`~assertpy.contains.ContainsMixin.contains`. + + Checks if the dict contains the given key or keys using ``in`` operator. + + Args: + *keys: the key or keys expected to be contained + + Examples: + Usage:: + + assert_that({'a': 1, 'b': 2}).contains_key('a') + assert_that({'a': 1, 'b': 2}).contains_key('a', 'b') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** contain the key or keys + """ self._check_dict_like(self.val, check_values=False, check_getitem=False) return self.contains(*keys) def does_not_contain_key(self, *keys): - """Asserts the val is a dict and does not contain the given key or keys. Alias for does_not_contain().""" + """Asserts the val is a dict and does not contain the given key or keys. Alias for :meth:`~assertpy.contains.ContainsMixin.does_not_contain`. + + Checks if the dict excludes the given key or keys using ``in`` operator. + + Args: + *keys: the key or keys expected to be excluded + + Examples: + Usage:: + + assert_that({'a': 1, 'b': 2}).does_not_contain_key('x') + assert_that({'a': 1, 'b': 2}).does_not_contain_key('x', 'y') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **does** contain the key or keys + """ self._check_dict_like(self.val, check_values=False, check_getitem=False) return self.does_not_contain(*keys) def contains_value(self, *values): - """Asserts that val is a dict and contains the given value or values.""" + """Asserts that val is a dict and contains the given value or values. + + Checks if the dict contains the given value or values in *any* key. + + Args: + *values: the value or values expected to be contained + + Examples: + Usage:: + + assert_that({'a': 1, 'b': 2}).contains_value(1) + assert_that({'a': 1, 'b': 2}).contains_value(1, 2) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** contain the value or values + """ self._check_dict_like(self.val, check_getitem=False) if len(values) == 0: raise ValueError('one or more value args must be given') @@ -50,11 +106,29 @@ def contains_value(self, *values): if v not in self.val.values(): missing.append(v) if missing: - self._err('Expected <%s> to contain values %s, but did not contain %s.' % (self.val, self._fmt_items(values), self._fmt_items(missing))) + return self.error('Expected <%s> to contain values %s, but did not contain %s.' % (self.val, self._fmt_items(values), self._fmt_items(missing))) return self def does_not_contain_value(self, *values): - """Asserts that val is a dict and does not contain the given value or values.""" + """Asserts that val is a dict and does not contain the given value or values. + + Checks if the dict excludes the given value or values across *all* keys. + + Args: + *values: the value or values expected to be excluded + + Examples: + Usage:: + + assert_that({'a': 1, 'b': 2}).does_not_contain_value(3) + assert_that({'a': 1, 'b': 2}).does_not_contain_value(3, 4) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **does** contain the value or values + """ self._check_dict_like(self.val, check_getitem=False) if len(values) == 0: raise ValueError('one or more value args must be given') @@ -64,13 +138,43 @@ def does_not_contain_value(self, *values): if v in self.val.values(): found.append(v) if found: - self._err('Expected <%s> to not contain values %s, but did contain %s.' % (self.val, self._fmt_items(values), self._fmt_items(found))) + return self.error('Expected <%s> to not contain values %s, but did contain %s.' % (self.val, self._fmt_items(values), self._fmt_items(found))) return self def contains_entry(self, *args, **kwargs): - """Asserts that val is a dict and contains the given entry or entries.""" + """Asserts that val is a dict and contains the given entry or entries. + + Checks if the dict contains the given key-value pair or pairs. + + Args: + *args: the entry or entries expected to be contained (as ``{k: v}`` args) + **kwargs: the entry or entries expected to be contained (as ``k=v`` kwargs) + + Examples: + Usage:: + + # using args + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}, {'b': 2}) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}, {'b': 2}, {'c': 3}) + + # using kwargs + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry(a=1) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry(a=1, b=2) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry(a=1, b=2, c=3) + + # or args and kwargs + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'c': 3}, a=1, b=2) + + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** contain the entry or entries + """ self._check_dict_like(self.val, check_values=False) - entries = list(args) + [{k:v} for k,v in kwargs.items()] + entries = list(args) + [{k: v} for k, v in kwargs.items()] if len(entries) == 0: raise ValueError('one or more entry args must be given') missing = [] @@ -81,17 +185,41 @@ def contains_entry(self, *args, **kwargs): raise ValueError('given entry args must contain exactly one key-value pair') k = next(iter(e)) if k not in self.val: - missing.append(e) # bad key + missing.append(e) # bad key elif self.val[k] != e[k]: - missing.append(e) # bad val + missing.append(e) # bad val if missing: - self._err('Expected <%s> to contain entries %s, but did not contain %s.' % (self.val, self._fmt_items(entries), self._fmt_items(missing))) + return self.error('Expected <%s> to contain entries %s, but did not contain %s.' % (self.val, self._fmt_items(entries), self._fmt_items(missing))) return self def does_not_contain_entry(self, *args, **kwargs): - """Asserts that val is a dict and does not contain the given entry or entries.""" + """Asserts that val is a dict and does not contain the given entry or entries. + + Checks if the dict excludes the given key-value pair or pairs. + + Args: + *args: the entry or entries expected to be excluded (as ``{k: v}`` args) + **kwargs: the entry or entries expected to be excluded (as ``k=v`` kwargs) + + Examples: + Usage:: + + # using args + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'a': 2}) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'a': 2}, {'x': 4}) + + # using kwargs + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry(a=2) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry(a=2, x=4) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **does** contain the entry or entries + """ self._check_dict_like(self.val, check_values=False) - entries = list(args) + [{k:v} for k,v in kwargs.items()] + entries = list(args) + [{k: v} for k, v in kwargs.items()] if len(entries) == 0: raise ValueError('one or more entry args must be given') found = [] @@ -104,5 +232,5 @@ def does_not_contain_entry(self, *args, **kwargs): if k in self.val and e[k] == self.val[k]: found.append(e) if found: - self._err('Expected <%s> to not contain entries %s, but did contain %s.' % (self.val, self._fmt_items(entries), self._fmt_items(found))) - return self \ No newline at end of file + return self.error('Expected <%s> to not contain entries %s, but did contain %s.' % (self.val, self._fmt_items(entries), self._fmt_items(found))) + return self diff --git a/assertpy/dynamic.py b/assertpy/dynamic.py index edaa963..b2d1c2e 100644 --- a/assertpy/dynamic.py +++ b/assertpy/dynamic.py @@ -34,21 +34,56 @@ else: Iterable = collections.Iterable +__tracebackhide__ = True + class DynamicMixin(object): - """Dynamic assertions mixin.""" + """Dynamic assertions mixin. + + When testing attributes of an object (or the contents of a dict), the + :meth:`~assertpy.base.BaseMixin.is_equal_to` assertion can be a bit verbose:: + + fred = Person('Fred', 'Smith') + + assert_that(fred.first_name).is_equal_to('Fred') + assert_that(fred.name).is_equal_to('Fred Smith') + assert_that(fred.say_hello()).is_equal_to('Hello, Fred!') + + Instead, use dynamic assertions in the form of ``has_()`` where ```` is the name of + any attribute, property, or zero-argument method on the given object. Dynamic equality + assertions test if actual is equal to expected using the ``==`` operator. Using dynamic + assertions, we can rewrite the above example as:: + + assert_that(fred).has_first_name('Fred') + assert_that(fred).has_name('Fred Smith') + assert_that(fred).has_say_hello('Hello, Fred!') + + Similarly, dynamic assertions also work on any *dict-like* object:: + + fred = { + 'first_name': 'Fred', + 'last_name': 'Smith', + 'shoe_size': 12 + } + + assert_that(fred).has_first_name('Fred') + assert_that(fred).has_last_name('Smith') + assert_that(fred).has_shoe_size(12) + """ def __getattr__(self, attr): - """Asserts that val has attribute attr and that attribute's value is equal to other via a dynamic assertion of the form: has_().""" + """Asserts that val has attribute attr and that its value is equal to other via a dynamic + assertion of the form ``has_()``.""" if not attr.startswith('has_'): raise AttributeError('assertpy has no assertion <%s()>' % attr) attr_name = attr[4:] err_msg = False + is_namedtuple = isinstance(self.val, tuple) and hasattr(self.val, '_fields') is_dict = isinstance(self.val, Iterable) and hasattr(self.val, '__getitem__') if not hasattr(self.val, attr_name): - if is_dict: + if is_dict and not is_namedtuple: if attr_name not in self.val: err_msg = 'Expected key <%s>, but val has no key <%s>.' % (attr_name, attr_name) else: @@ -56,15 +91,15 @@ def __getattr__(self, attr): def _wrapper(*args, **kwargs): if err_msg: - self._err(err_msg) # ok to raise AssertionError now that we are inside wrapper + return self.error(err_msg) # ok to raise AssertionError now that we are inside wrapper else: if len(args) != 1: raise TypeError('assertion <%s()> takes exactly 1 argument (%d given)' % (attr, len(args))) - try: - val_attr = getattr(self.val, attr_name) - except AttributeError: + if is_dict and not is_namedtuple: val_attr = self.val[attr_name] + else: + val_attr = getattr(self.val, attr_name) if callable(val_attr): try: @@ -76,7 +111,7 @@ def _wrapper(*args, **kwargs): expected = args[0] if actual != expected: - self._err('Expected <%s> to be equal to <%s> on %s <%s>, but was not.' % (actual, expected, 'key' if is_dict else 'attribute', attr_name)) + return self.error('Expected <%s> to be equal to <%s> on %s <%s>, but was not.' % (actual, expected, 'key' if is_dict else 'attribute', attr_name)) return self return _wrapper diff --git a/assertpy/exception.py b/assertpy/exception.py index 6093ecf..1649985 100644 --- a/assertpy/exception.py +++ b/assertpy/exception.py @@ -34,38 +34,80 @@ else: Iterable = collections.Iterable +__tracebackhide__ = True + class ExceptionMixin(object): """Expected exception mixin.""" def raises(self, ex): - """Asserts that val is callable and that when called raises the given error.""" + """Asserts that val is callable and set the expected exception. + + Just sets the expected exception, but never calls val, and therefore never failes. You must + chain to :meth:`~when_called_with` to invoke ``val()``. + + Args: + ex: the expected exception + + Examples: + Usage:: + + assert_that(some_func).raises(RuntimeError).when_called_with('foo') + + Returns: + AssertionBuilder: returns a new instance (now with the given expected exception) to chain to the next assertion + """ if not callable(self.val): raise TypeError('val must be callable') if not issubclass(ex, BaseException): raise TypeError('given arg must be exception') - return self._builder(self.val, self.description, self.kind, ex) # don't chain! + + # chain on with ex as the expected exception + return self.builder(self.val, self.description, self.kind, ex) def when_called_with(self, *some_args, **some_kwargs): - """Asserts the val callable when invoked with the given args and kwargs raises the expected exception.""" + """Asserts that val, when invoked with the given args and kwargs, raises the expected exception. + + Invokes ``val()`` with the given args and kwargs. You must first set the expected + exception with :meth:`~raises`. + + Args: + *some_args: the args to call ``val()`` + **some_kwargs: the kwargs to call ``val()`` + + Examples: + Usage:: + + def some_func(a): + raise RuntimeError('some error!') + + assert_that(some_func).raises(RuntimeError).when_called_with('foo') + + Returns: + AssertionBuilder: returns a new instance (now with the captured exception error message as the val) to chain to the next assertion + + Raises: + AssertionError: if val does **not** raise the expected exception + TypeError: if expected exception not set via :meth:`raises` + """ if not self.expected: raise TypeError('expected exception not set, raises() must be called first') try: self.val(*some_args, **some_kwargs) except BaseException as e: if issubclass(type(e), self.expected): - # chain on with _message_ (don't chain to self!) - return self._builder(str(e), self.description, self.kind) + # chain on with error message + return self.builder(str(e), self.description, self.kind) else: # got exception, but wrong type, so raise - self._err('Expected <%s> to raise <%s> when called with (%s), but raised <%s>.' % ( + return self.error('Expected <%s> to raise <%s> when called with (%s), but raised <%s>.' % ( self.val.__name__, self.expected.__name__, self._fmt_args_kwargs(*some_args, **some_kwargs), type(e).__name__)) # didn't fail as expected, so raise - self._err('Expected <%s> to raise <%s> when called with (%s).' % ( + return self.error('Expected <%s> to raise <%s> when called with (%s).' % ( self.val.__name__, self.expected.__name__, self._fmt_args_kwargs(*some_args, **some_kwargs))) diff --git a/assertpy/extracting.py b/assertpy/extracting.py index f0a8b81..98d4ad8 100644 --- a/assertpy/extracting.py +++ b/assertpy/extracting.py @@ -36,13 +36,134 @@ str_types = (basestring,) Iterable = collections.Iterable +__tracebackhide__ = True + class ExtractingMixin(object): - """Collection flattening mixin.""" + """Collection flattening mixin. + + It is often necessary to test collections of objects. Use the ``extracting()`` helper to + reduce the collection on a given attribute. Reduce a list of objects:: + + alice = Person('Alice', 'Alpha') + bob = Person('Bob', 'Bravo') + people = [alice, bob] + + assert_that(people).extracting('first_name').is_equal_to(['Alice', 'Bob']) + assert_that(people).extracting('first_name').contains('Alice', 'Bob') + assert_that(people).extracting('first_name').does_not_contain('Charlie') + + Additionally, the ``extracting()`` helper can accept a list of attributes to be extracted, and + will flatten them into a list of tuples. Reduce a list of objects on multiple attributes:: + + assert_that(people).extracting('first_name', 'last_name').contains(('Alice', 'Alpha'), ('Bob', 'Bravo')) + + Also, ``extracting()`` works on not just attributes, but also properties, and even + zero-argument methods. Reduce a list of object on properties and zero-arg methods:: + + assert_that(people).extracting('name').contains('Alice Alpha', 'Bob Bravo') + assert_that(people).extracting('say_hello').contains('Hello, Alice!', 'Hello, Bob!') + + And ``extracting()`` even works on *dict-like* objects. Reduce a list of dicts on key:: + + alice = {'first_name': 'Alice', 'last_name': 'Alpha'} + bob = {'first_name': 'Bob', 'last_name': 'Bravo'} + people = [alice, bob] + + assert_that(people).extracting('first_name').contains('Alice', 'Bob') + + **Filtering** + + The ``extracting()`` helper can include a *filter* to keep only those items for which the given + *filter* is truthy. For example:: + + users = [ + {'user': 'Alice', 'age': 36, 'active': True}, + {'user': 'Bob', 'age': 40, 'active': False}, + {'user': 'Charlie', 'age': 13, 'active': True} + ] + + # filter the active users + assert_that(users).extracting('user', filter='active').is_equal_to(['Alice', 'Charlie']) + + The *filter* can be a *dict-like* object and the extracted items are kept if and only if all + corresponding key-value pairs are equal:: + + assert_that(users).extracting('user', filter={'active': False}).is_equal_to(['Bob']) + assert_that(users).extracting('user', filter={'age': 36, 'active': True}).is_equal_to(['Alice']) + + Or a *filter* can be any function (including an in-line ``lambda``) that accepts as its single + argument each item in the collection, and the extracted items are kept if the function + evaluates to ``True``:: + + assert_that(users).extracting('user', filter=lambda x: x['age'] > 20) + .is_equal_to(['Alice', 'Bob']) + + **Sorting** + + The ``extracting()`` helper can include a *sort* to enforce order on the extracted items. + + The *sort* can be the name of a key (or attribute, or property, or zero-argument method) and + the extracted items are ordered by the corresponding values:: + + assert_that(users).extracting('user', sort='age').is_equal_to(['Charlie', 'Alice', 'Bob']) + + The *sort* can be an ``iterable`` of names and the extracted items are ordered by + corresponding value of the first name, ties are broken by the corresponding values of the + second name, and so on:: + + assert_that(users).extracting('user', sort=['active', 'age']).is_equal_to(['Bob', 'Charlie', 'Alice']) + + The *sort* can be any function (including an in-line ``lambda``) that accepts as its single + argument each item in the collection, and the extracted items are ordered by the corresponding + function return values:: + + assert_that(users).extracting('user', sort=lambda x: -x['age']).is_equal_to(['Bob', 'Alice', 'Charlie']) + """ -### collection of objects assertions ### def extracting(self, *names, **kwargs): - """Asserts that val is collection, then extracts the named properties or named zero-arg methods into a list (or list of tuples if multiple names are given).""" + """Asserts that val is iterable, then extracts the named attributes, properties, or + zero-arg methods into a list (or list of tuples if multiple names are given). + + Args: + *names: the attribute to be extracted (or property or zero-arg method) + **kwargs: see below + + Keyword Args: + filter: extract only those items where filter is truthy + sort: order the extracted items by the sort key + + Examples: + Usage:: + + alice = User('Alice', 20, True) + bob = User('Bob', 30, False) + charlie = User('Charlie', 10, True) + users = [alice, bob, charlie] + + assert_that(users).extracting('user').contains('Alice', 'Bob', 'Charlie') + + Works with *dict-like* objects too:: + + users = [ + {'user': 'Alice', 'age': 20, 'active': True}, + {'user': 'Bob', 'age': 30, 'active': False}, + {'user': 'Charlie', 'age': 10, 'active': True} + ] + + assert_that(people).extracting('user').contains('Alice', 'Bob', 'Charlie') + + Filter:: + + assert_that(users).extracting('user', filter='active').is_equal_to(['Alice', 'Charlie']) + + Sort:: + + assert_that(users).extracting('user', sort='age').is_equal_to(['Charlie', 'Alice', 'Bob']) + + Returns: + AssertionBuilder: returns a new instance (now with the extracted list as the val) to chain to the next assertion + """ if not isinstance(self.val, Iterable): raise TypeError('val is not iterable') if isinstance(self.val, str_types): @@ -56,7 +177,12 @@ def _extract(x, name): return x[name] else: raise ValueError('item keys %s did not contain key <%s>' % (list(x.keys()), name)) - elif isinstance(x, Iterable): + elif isinstance(x, tuple) and hasattr(x, '_fields') and type(name) is str: + if name in x._fields: + return getattr(x, name) + else: #val has no attribute + raise ValueError('item attributes %s did no contain attribute <%s>' % (x._fields, name)) + elif isinstance(x, Iterable): # FIXME, this does __getitem__, but doesn't check for it... self._check_iterable(x, name='item') return x[name] elif hasattr(x, name): @@ -65,11 +191,11 @@ def _extract(x, name): try: return attr() except TypeError: - raise ValueError('val method <%s()> exists, but is not zero-arg method' % name) + raise ValueError('item method <%s()> exists, but is not zero-arg method' % name) else: return attr else: - raise ValueError('val does not have property or zero-arg method <%s>' % name) + raise ValueError('item does not have property or zero-arg method <%s>' % name) def _filter(x): if 'filter' in kwargs: @@ -105,6 +231,6 @@ def _sort(x): if _filter(i): items = [_extract(i, name) for name in names] extracted.append(tuple(items) if len(items) > 1 else items[0]) - + # chain on with _extracted_ list (don't chain to self!) - return self._builder(extracted, self.description, self.kind) + return self.builder(extracted, self.description, self.kind) diff --git a/assertpy/file.py b/assertpy/file.py index c881ee9..2c3de9a 100644 --- a/assertpy/file.py +++ b/assertpy/file.py @@ -34,22 +34,42 @@ else: str_types = (basestring,) +__tracebackhide__ = True -def contents_of(f, encoding='utf-8'): + +def contents_of(file, encoding='utf-8'): """Helper to read the contents of the given file or path into a string with the given encoding. - Encoding defaults to 'utf-8', other useful encodings are 'ascii' and 'latin-1'.""" + Args: + file: a *path-like object* (aka a file name) or a *file-like object* (aka a file) + encoding (str): the target encoding. Defaults to ``utf-8``, other useful encodings are ``ascii`` and ``latin-1``. + + Examples: + Usage:: + + from assertpy import assert_that, contents_of + + contents = contents_of('foo.txt') + assert_that(contents).starts_with('foo').ends_with('bar').contains('oob') + + Returns: + str: returns the file contents as a string + + Raises: + IOError: if file not found + TypeError: if file is not a *path-like object* or a *file-like object* + """ try: - contents = f.read() + contents = file.read() except AttributeError: try: - with open(f, 'r') as fp: + with open(file, 'r') as fp: contents = fp.read() except TypeError: - raise ValueError('val must be file or path, but was type <%s>' % type(f).__name__) + raise ValueError('val must be file or path, but was type <%s>' % type(file).__name__) except OSError: - if not isinstance(f, str_types): - raise ValueError('val must be file or path, but was type <%s>' % type(f).__name__) + if not isinstance(file, str_types): + raise ValueError('val must be file or path, but was type <%s>' % type(file).__name__) raise if sys.version_info[0] == 3 and type(contents) is bytes: @@ -72,52 +92,134 @@ class FileMixin(object): """File assertions mixin.""" def exists(self): - """Asserts that val is a path and that it exists.""" + """Asserts that val is a path and that it exists. + + Examples: + Usage:: + + assert_that('myfile.txt').exists() + assert_that('mydir').exists() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** exist + """ if not isinstance(self.val, str_types): raise TypeError('val is not a path') if not os.path.exists(self.val): - self._err('Expected <%s> to exist, but was not found.' % self.val) + return self.error('Expected <%s> to exist, but was not found.' % self.val) return self def does_not_exist(self): - """Asserts that val is a path and that it does not exist.""" + """Asserts that val is a path and that it does *not* exist. + + Examples: + Usage:: + + assert_that('missing.txt').does_not_exist() + assert_that('missing_dir').does_not_exist() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **does** exist + """ if not isinstance(self.val, str_types): raise TypeError('val is not a path') if os.path.exists(self.val): - self._err('Expected <%s> to not exist, but was found.' % self.val) + return self.error('Expected <%s> to not exist, but was found.' % self.val) return self def is_file(self): - """Asserts that val is an existing path to a file.""" + """Asserts that val is a *file* and that it exists. + + Examples: + Usage:: + + assert_that('myfile.txt').is_file() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** exist, or is **not** a file + """ self.exists() if not os.path.isfile(self.val): - self._err('Expected <%s> to be a file, but was not.' % self.val) + return self.error('Expected <%s> to be a file, but was not.' % self.val) return self def is_directory(self): - """Asserts that val is an existing path to a directory.""" + """Asserts that val is a *directory* and that it exists. + + Examples: + Usage:: + + assert_that('mydir').is_directory() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** exist, or is **not** a directory + """ self.exists() if not os.path.isdir(self.val): - self._err('Expected <%s> to be a directory, but was not.' % self.val) + return self.error('Expected <%s> to be a directory, but was not.' % self.val) return self def is_named(self, filename): - """Asserts that val is an existing path to a file and that file is named filename.""" + """Asserts that val is an existing path to a file and that file is named filename. + + Args: + filename: the expected filename + + Examples: + Usage:: + + assert_that('/path/to/mydir/myfile.txt').is_named('myfile.txt') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** exist, or is **not** a file, or is **not** named the given filename + """ self.is_file() if not isinstance(filename, str_types): raise TypeError('given filename arg must be a path') val_filename = os.path.basename(os.path.abspath(self.val)) if val_filename != filename: - self._err('Expected filename <%s> to be equal to <%s>, but was not.' % (val_filename, filename)) + return self.error('Expected filename <%s> to be equal to <%s>, but was not.' % (val_filename, filename)) return self def is_child_of(self, parent): - """Asserts that val is an existing path to a file and that file is a child of parent.""" + """Asserts that val is an existing path to a file and that file is a child of parent. + + Args: + parent: the expected parent directory + + Examples: + Usage:: + + assert_that('/path/to/mydir/myfile.txt').is_child_of('mydir') + assert_that('/path/to/mydir/myfile.txt').is_child_of('to') + assert_that('/path/to/mydir/myfile.txt').is_child_of('path') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** exist, or is **not** a file, or is **not** a child of the given directory + """ self.is_file() if not isinstance(parent, str_types): raise TypeError('given parent directory arg must be a path') val_abspath = os.path.abspath(self.val) parent_abspath = os.path.abspath(parent) if not val_abspath.startswith(parent_abspath): - self._err('Expected file <%s> to be a child of <%s>, but was not.' % (val_abspath, parent_abspath)) + return self.error('Expected file <%s> to be a child of <%s>, but was not.' % (val_abspath, parent_abspath)) return self diff --git a/assertpy/helpers.py b/assertpy/helpers.py index e5099a1..582a626 100644 --- a/assertpy/helpers.py +++ b/assertpy/helpers.py @@ -36,15 +36,18 @@ else: Iterable = collections.Iterable +__tracebackhide__ = True + class HelpersMixin(object): - """Helpers mixin.""" + """Helpers mixin. For internal use only.""" def _fmt_items(self, i): + """Helper to format the given items.""" if len(i) == 0: return '<>' elif len(i) == 1 and hasattr(i, '__getitem__'): - return '<%s>' % i[0] + return '<%s>' % (i[0],) else: return '<%s>' % str(i).lstrip('([').rstrip(',])') @@ -53,8 +56,8 @@ def _fmt_args_kwargs(self, *some_args, **some_kwargs): if some_args: out_args = str(some_args).lstrip('(').rstrip(',)') if some_kwargs: - out_kwargs = ', '.join([str(i).lstrip('(').rstrip(')').replace(', ',': ') for i in [ - (k,some_kwargs[k]) for k in sorted(some_kwargs.keys())]]) + out_kwargs = ', '.join([str(i).lstrip('(').rstrip(')').replace(', ', ': ') for i in [ + (k, some_kwargs[k]) for k in sorted(some_kwargs.keys())]]) if some_args and some_kwargs: return out_args + ', ' + out_kwargs @@ -66,13 +69,14 @@ def _fmt_args_kwargs(self, *some_args, **some_kwargs): return '' def _validate_between_args(self, val_type, low, high): + """Helper to validate given range args.""" low_type = type(low) high_type = type(high) - if val_type in self.NUMERIC_NON_COMPAREABLE: + if val_type in self._NUMERIC_NON_COMPAREABLE: raise TypeError('ordering is not defined for type <%s>' % val_type.__name__) - if val_type in self.NUMERIC_COMPAREABLE: + if val_type in self._NUMERIC_COMPAREABLE: if low_type is not val_type: raise TypeError('given low arg must be <%s>, but was <%s>' % (val_type.__name__, low_type.__name__)) if high_type is not val_type: @@ -89,6 +93,7 @@ def _validate_between_args(self, val_type, low, high): raise ValueError('given low arg must be less than given high arg') def _validate_close_to_args(self, val, other, tolerance): + """Helper for validate given arg and delta.""" if type(val) is complex or type(other) is complex or type(tolerance) is complex: raise TypeError('ordering is not defined for complex numbers') @@ -109,6 +114,7 @@ def _validate_close_to_args(self, val, other, tolerance): raise ValueError('given tolerance arg must be positive') def _check_dict_like(self, d, check_keys=True, check_values=True, check_getitem=True, name='val', return_as_bool=False): + """Helper to check if given val has various dict-like attributes.""" if not isinstance(d, Iterable): if return_as_bool: return False @@ -136,6 +142,7 @@ def _check_dict_like(self, d, check_keys=True, check_values=True, check_getitem= return True def _check_iterable(self, l, check_getitem=True, name='val'): + """Helper to check if given val has various iterable attributes.""" if not isinstance(l, Iterable): raise TypeError('%s <%s> is not iterable' % (name, type(l).__name__)) if check_getitem: @@ -143,6 +150,7 @@ def _check_iterable(self, l, check_getitem=True, name='val'): raise TypeError('%s <%s> does not have [] accessor' % (name, type(l).__name__)) def _dict_not_equal(self, val, other, ignore=None, include=None): + """Helper to compare dicts.""" if ignore or include: ignores = self._dict_ignore(ignore) includes = self._dict_include(include) @@ -154,59 +162,74 @@ def _dict_not_equal(self, val, other, ignore=None, include=None): if i not in val: missing.append(i) if missing: - self._err('Expected <%s> to include key%s %s, but did not include key%s %s.' % ( + return self.error('Expected <%s> to include key%s %s, but did not include key%s %s.' % ( val, '' if len(includes) == 1 else 's', self._fmt_items(['.'.join([str(s) for s in i]) if type(i) is tuple else i for i in includes]), '' if len(missing) == 1 else 's', self._fmt_items(missing))) + # calc val keys given ignores and includes if ignore and include: k1 = set([k for k in val if k not in ignores and k in includes]) elif ignore: k1 = set([k for k in val if k not in ignores]) - else: # include + else: # include k1 = set([k for k in val if k in includes]) + # calc other keys given ignores and includes if ignore and include: k2 = set([k for k in other if k not in ignores and k in includes]) elif ignore: k2 = set([k for k in other if k not in ignores]) - else: # include + else: # include k2 = set([k for k in other if k in includes]) if k1 != k2: + # different set of keys, so not equal return True else: for k in k1: - if self._check_dict_like(val[k], check_values=False, return_as_bool=True) and self._check_dict_like(other[k], check_values=False, return_as_bool=True): - return self._dict_not_equal(val[k], other[k], + if self._check_dict_like(val[k], check_values=False, return_as_bool=True) and \ + self._check_dict_like(other[k], check_values=False, return_as_bool=True): + subdicts_not_equal = self._dict_not_equal( + val[k], + other[k], ignore=[i[1:] for i in ignores if type(i) is tuple and i[0] == k] if ignore else None, include=[i[1:] for i in self._dict_ignore(include) if type(i) is tuple and i[0] == k] if include else None) + if subdicts_not_equal: + # fast fail inside the loop since sub-dicts are not equal + return True elif val[k] != other[k]: + # fast fail inside the loop since values are not equal return True return False else: return val != other def _dict_ignore(self, ignore): - return [i[0] if type(i) is tuple and len(i) == 1 else i \ - for i in (ignore if type(ignore) is list else [ignore])] + """Helper to make list for given ignore kwarg values.""" + return [i[0] if type(i) is tuple and len(i) == 1 else i for i in (ignore if type(ignore) is list else [ignore])] def _dict_include(self, include): - return [i[0] if type(i) is tuple else i \ - for i in (include if type(include) is list else [include])] + """Helper to make a list from given include kwarg values.""" + return [i[0] if type(i) is tuple else i for i in (include if type(include) is list else [include])] def _dict_err(self, val, other, ignore=None, include=None): + """Helper to construct error message for dict comparison.""" def _dict_repr(d, other): out = '' ellip = False - for k,v in d.items(): + for k, v in sorted(d.items()): if k not in other: out += '%s%s: %s' % (', ' if len(out) > 0 else '', repr(k), repr(v)) elif v != other[k]: - out += '%s%s: %s' % (', ' if len(out) > 0 else '', repr(k), - _dict_repr(v, other[k]) if self._check_dict_like(v, check_values=False, return_as_bool=True) and self._check_dict_like(other[k], check_values=False, return_as_bool=True) else repr(v) + out += '%s%s: %s' % ( + ', ' if len(out) > 0 else '', + repr(k), + _dict_repr(v, other[k]) if self._check_dict_like( + v, check_values=False, return_as_bool=True) and self._check_dict_like( + other[k], check_values=False, return_as_bool=True) else repr(v) ) else: ellip = True @@ -219,7 +242,7 @@ def _dict_repr(d, other): includes = self._dict_ignore(include) include_err = ' including keys %s' % self._fmt_items(['.'.join([str(s) for s in i]) if type(i) is tuple else i for i in includes]) - self._err('Expected <%s> to be equal to <%s>%s%s, but was not.' % ( + return self.error('Expected <%s> to be equal to <%s>%s%s, but was not.' % ( _dict_repr(val, other), _dict_repr(other, val), ignore_err if ignore else '', diff --git a/assertpy/numeric.py b/assertpy/numeric.py index e8721bc..0e21936 100644 --- a/assertpy/numeric.py +++ b/assertpy/numeric.py @@ -32,20 +32,22 @@ import numbers import datetime +__tracebackhide__ = True + class NumericMixin(object): """Numeric assertions mixin.""" - NUMERIC_COMPAREABLE = set([datetime.datetime, datetime.timedelta, datetime.date, datetime.time]) - NUMERIC_NON_COMPAREABLE = set([complex]) + _NUMERIC_COMPAREABLE = set([datetime.datetime, datetime.timedelta, datetime.date, datetime.time]) + _NUMERIC_NON_COMPAREABLE = set([complex]) def _validate_compareable(self, other): self_type = type(self.val) other_type = type(other) - if self_type in self.NUMERIC_NON_COMPAREABLE: + if self_type in self._NUMERIC_NON_COMPAREABLE: raise TypeError('ordering is not defined for type <%s>' % self_type.__name__) - if self_type in self.NUMERIC_COMPAREABLE: + if self_type in self._NUMERIC_COMPAREABLE: if other_type is not self_type: raise TypeError('given arg must be <%s>, but was <%s>' % (self_type.__name__, other_type.__name__)) return @@ -66,121 +68,405 @@ def _validate_real(self): raise TypeError('val is not real number') def is_zero(self): - """Asserts that val is numeric and equal to zero.""" + """Asserts that val is numeric and is zero. + + Examples: + Usage:: + + assert_that(0).is_zero() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** zero + """ self._validate_number() return self.is_equal_to(0) def is_not_zero(self): - """Asserts that val is numeric and not equal to zero.""" + """Asserts that val is numeric and is *not* zero. + + Examples: + Usage:: + + assert_that(1).is_not_zero() + assert_that(123.4).is_not_zero() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** zero + """ self._validate_number() return self.is_not_equal_to(0) def is_nan(self): - """Asserts that val is real number and NaN (not a number).""" + """Asserts that val is real number and is ``NaN`` (not a number). + + Examples: + Usage:: + + assert_that(float('nan')).is_nan() + assert_that(float('inf') * 0).is_nan() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** NaN + """ self._validate_number() self._validate_real() if not math.isnan(self.val): - self._err('Expected <%s> to be , but was not.' % self.val) + return self.error('Expected <%s> to be , but was not.' % self.val) return self def is_not_nan(self): - """Asserts that val is real number and not NaN (not a number).""" + """Asserts that val is real number and is *not* ``NaN`` (not a number). + + Examples: + Usage:: + + assert_that(0).is_not_nan() + assert_that(123.4).is_not_nan() + assert_that(float('inf')).is_not_nan() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** NaN + """ self._validate_number() self._validate_real() if math.isnan(self.val): - self._err('Expected not , but was.') + return self.error('Expected not , but was.') return self def is_inf(self): - """Asserts that val is real number and Inf (infinity).""" + """Asserts that val is real number and is ``Inf`` (infinity). + + Examples: + Usage:: + + assert_that(float('inf')).is_inf() + assert_that(float('inf') * 1).is_inf() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** Inf + """ self._validate_number() self._validate_real() if not math.isinf(self.val): - self._err('Expected <%s> to be , but was not.' % self.val) + return self.error('Expected <%s> to be , but was not.' % self.val) return self def is_not_inf(self): - """Asserts that val is real number and not Inf (infinity).""" + """Asserts that val is real number and is *not* ``Inf`` (infinity). + + Examples: + Usage:: + + assert_that(0).is_not_inf() + assert_that(123.4).is_not_inf() + assert_that(float('nan')).is_not_inf() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** Inf + """ self._validate_number() self._validate_real() if math.isinf(self.val): - self._err('Expected not , but was.') + return self.error('Expected not , but was.') return self def is_greater_than(self, other): - """Asserts that val is numeric and is greater than other.""" + """Asserts that val is numeric and is greater than other. + + Args: + other: the other date, expected to be less than val + + Examples: + Usage:: + + assert_that(1).is_greater_than(0) + assert_that(123.4).is_greater_than(111.1) + + For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_after`:: + + import datetime + + today = datetime.datetime.now() + yesterday = today - datetime.timedelta(days=1) + + assert_that(today).is_greater_than(yesterday) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** greater than other + """ self._validate_compareable(other) if self.val <= other: if type(self.val) is datetime.datetime: - self._err('Expected <%s> to be greater than <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be greater than <%s>, but was not.' % ( + self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) else: - self._err('Expected <%s> to be greater than <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be greater than <%s>, but was not.' % (self.val, other)) return self def is_greater_than_or_equal_to(self, other): - """Asserts that val is numeric and is greater than or equal to other.""" + """Asserts that val is numeric and is greater than or equal to other. + + Args: + other: the other date, expected to be less than or equal to val + + Examples: + Usage:: + + assert_that(1).is_greater_than_or_equal_to(0) + assert_that(1).is_greater_than_or_equal_to(1) + assert_that(123.4).is_greater_than_or_equal_to(111.1) + + For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_after` *except* when equal:: + + import datetime + + today = datetime.datetime.now() + yesterday = today - datetime.timedelta(days=1) + + assert_that(today).is_greater_than_or_equal_to(yesterday) + assert_that(today).is_greater_than_or_equal_to(today) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** greater than or equal to other + """ self._validate_compareable(other) if self.val < other: if type(self.val) is datetime.datetime: - self._err('Expected <%s> to be greater than or equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be greater than or equal to <%s>, but was not.' % ( + self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) else: - self._err('Expected <%s> to be greater than or equal to <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be greater than or equal to <%s>, but was not.' % (self.val, other)) return self def is_less_than(self, other): - """Asserts that val is numeric and is less than other.""" + """Asserts that val is numeric and is less than other. + + Args: + other: the other date, expected to be greater than val + + Examples: + Usage:: + + assert_that(0).is_less_than(1) + assert_that(123.4).is_less_than(555.5) + + For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_before`:: + + import datetime + + today = datetime.datetime.now() + yesterday = today - datetime.timedelta(days=1) + + assert_that(yesterday).is_less_than(today) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** less than other + """ self._validate_compareable(other) if self.val >= other: if type(self.val) is datetime.datetime: - self._err('Expected <%s> to be less than <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be less than <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) else: - self._err('Expected <%s> to be less than <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be less than <%s>, but was not.' % (self.val, other)) return self def is_less_than_or_equal_to(self, other): - """Asserts that val is numeric and is less than or equal to other.""" + """Asserts that val is numeric and is less than or equal to other. + + Args: + other: the other date, expected to be greater than or equal to val + + Examples: + Usage:: + + assert_that(1).is_less_than_or_equal_to(0) + assert_that(1).is_less_than_or_equal_to(1) + assert_that(123.4).is_less_than_or_equal_to(100.0) + + For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_before` *except* when equal:: + + import datetime + + today = datetime.datetime.now() + yesterday = today - datetime.timedelta(days=1) + + assert_that(yesterday).is_less_than_or_equal_to(today) + assert_that(today).is_less_than_or_equal_to(today) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** less than or equal to other + """ self._validate_compareable(other) if self.val > other: if type(self.val) is datetime.datetime: - self._err('Expected <%s> to be less than or equal to <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be less than or equal to <%s>, but was not.' % ( + self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'))) else: - self._err('Expected <%s> to be less than or equal to <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be less than or equal to <%s>, but was not.' % (self.val, other)) return self def is_positive(self): - """Asserts that val is numeric and greater than zero.""" + """Asserts that val is numeric and is greater than zero. + + Examples: + Usage:: + + assert_that(1).is_positive() + assert_that(123.4).is_positive() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** positive + """ return self.is_greater_than(0) def is_negative(self): - """Asserts that val is numeric and less than zero.""" + """Asserts that val is numeric and is less than zero. + + Examples: + Usage:: + + assert_that(-1).is_negative() + assert_that(-123.4).is_negative() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** negative + """ return self.is_less_than(0) def is_between(self, low, high): - """Asserts that val is numeric and is between low and high.""" + """Asserts that val is numeric and is between low and high. + + Args: + low: the low value + high: the high value + + Examples: + Usage:: + + assert_that(1).is_between(0, 2) + assert_that(123.4).is_between(111.1, 222.2) + + For dates, works as expected:: + + import datetime + + today = datetime.datetime.now() + middle = today - datetime.timedelta(hours=12) + yesterday = today - datetime.timedelta(days=1) + + assert_that(middle).is_between(yesterday, today) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** between low and high + """ val_type = type(self.val) self._validate_between_args(val_type, low, high) if self.val < low or self.val > high: if val_type is datetime.datetime: - self._err('Expected <%s> to be between <%s> and <%s>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), low.strftime('%Y-%m-%d %H:%M:%S'), high.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to be between <%s> and <%s>, but was not.' % ( + self.val.strftime('%Y-%m-%d %H:%M:%S'), low.strftime('%Y-%m-%d %H:%M:%S'), high.strftime('%Y-%m-%d %H:%M:%S'))) else: - self._err('Expected <%s> to be between <%s> and <%s>, but was not.' % (self.val, low, high)) + return self.error('Expected <%s> to be between <%s> and <%s>, but was not.' % (self.val, low, high)) return self def is_not_between(self, low, high): - """Asserts that val is numeric and is between low and high.""" + """Asserts that val is numeric and is *not* between low and high. + + Args: + low: the low value + high: the high value + + Examples: + Usage:: + + assert_that(1).is_not_between(2, 3) + assert_that(1.1).is_not_between(2.2, 3.3) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** between low and high + """ val_type = type(self.val) self._validate_between_args(val_type, low, high) if self.val >= low and self.val <= high: if val_type is datetime.datetime: - self._err('Expected <%s> to not be between <%s> and <%s>, but was.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), low.strftime('%Y-%m-%d %H:%M:%S'), high.strftime('%Y-%m-%d %H:%M:%S'))) + return self.error('Expected <%s> to not be between <%s> and <%s>, but was.' % ( + self.val.strftime('%Y-%m-%d %H:%M:%S'), low.strftime('%Y-%m-%d %H:%M:%S'), high.strftime('%Y-%m-%d %H:%M:%S'))) else: - self._err('Expected <%s> to not be between <%s> and <%s>, but was.' % (self.val, low, high)) + return self.error('Expected <%s> to not be between <%s> and <%s>, but was.' % (self.val, low, high)) return self def is_close_to(self, other, tolerance): - """Asserts that val is numeric and is close to other within tolerance.""" + """Asserts that val is numeric and is close to other within tolerance. + + Args: + other: the other value, expected to be close to val within tolerance + tolerance: the tolerance + + Examples: + Usage:: + + assert_that(123).is_close_to(100, 25) + assert_that(123.4).is_close_to(123, 0.5) + + For dates, works as expected:: + + import datetime + + today = datetime.datetime.now() + yesterday = today - datetime.timedelta(days=1) + + assert_that(today).is_close_to(yesterday, datetime.timedelta(hours=36)) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** close to other within tolerance + """ self._validate_close_to_args(self.val, other, tolerance) if self.val < (other-tolerance) or self.val > (other+tolerance): @@ -188,13 +474,31 @@ def is_close_to(self, other, tolerance): tolerance_seconds = tolerance.days * 86400 + tolerance.seconds + tolerance.microseconds / 1000000 h, rem = divmod(tolerance_seconds, 3600) m, s = divmod(rem, 60) - self._err('Expected <%s> to be close to <%s> within tolerance <%d:%02d:%02d>, but was not.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'), h, m, s)) + return self.error('Expected <%s> to be close to <%s> within tolerance <%d:%02d:%02d>, but was not.' % ( + self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'), h, m, s)) else: - self._err('Expected <%s> to be close to <%s> within tolerance <%s>, but was not.' % (self.val, other, tolerance)) + return self.error('Expected <%s> to be close to <%s> within tolerance <%s>, but was not.' % (self.val, other, tolerance)) return self def is_not_close_to(self, other, tolerance): - """Asserts that val is numeric and is not close to other within tolerance.""" + """Asserts that val is numeric and is *not* close to other within tolerance. + + Args: + other: the other value + tolerance: the tolerance + + Examples: + Usage:: + + assert_that(123).is_not_close_to(100, 22) + assert_that(123.4).is_not_close_to(123, 0.1) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **is** close to other within tolerance + """ self._validate_close_to_args(self.val, other, tolerance) if self.val >= (other-tolerance) and self.val <= (other+tolerance): @@ -202,7 +506,8 @@ def is_not_close_to(self, other, tolerance): tolerance_seconds = tolerance.days * 86400 + tolerance.seconds + tolerance.microseconds / 1000000 h, rem = divmod(tolerance_seconds, 3600) m, s = divmod(rem, 60) - self._err('Expected <%s> to not be close to <%s> within tolerance <%d:%02d:%02d>, but was.' % (self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'), h, m, s)) + return self.error('Expected <%s> to not be close to <%s> within tolerance <%d:%02d:%02d>, but was.' % ( + self.val.strftime('%Y-%m-%d %H:%M:%S'), other.strftime('%Y-%m-%d %H:%M:%S'), h, m, s)) else: - self._err('Expected <%s> to not be close to <%s> within tolerance <%s>, but was.' % (self.val, other, tolerance)) + return self.error('Expected <%s> to not be close to <%s> within tolerance <%s>, but was.' % (self.val, other, tolerance)) return self diff --git a/assertpy/snapshot.py b/assertpy/snapshot.py index 6c3ef9f..da331a8 100644 --- a/assertpy/snapshot.py +++ b/assertpy/snapshot.py @@ -32,11 +32,92 @@ import inspect import json +__tracebackhide__ = True + class SnapshotMixin(object): - """Snapshot mixin.""" + """Snapshot mixin. + + Take a snapshot of a python data structure, store it on disk in JSON format, and automatically + compare the latest data to the stored data on every test run. + + Functional testing (which snapshot testing falls under) is very much blackbox testing. When + something goes wrong, it's hard to pinpoint the issue, because functional tests typically + provide minimal *isolation* as compared to unit tests. On the plus side, snapshots typically + do provide enormous *leverage* as a few well-placed snapshot tests can strongly verify that an + application is working. Similar coverage would otherwise require dozens if not hundreds of + unit tests. + + **On-disk Format** + + Snapshots are stored in a readable JSON format. For example:: + + assert_that({'a': 1, 'b': 2, 'c': 3}).snapshot() + + Would be stored as:: + + { + "a": 1, + "b": 2, + "c": 3 + } + + The JSON formatting support most python data structures (dict, list, object, etc), but not custom + binary data. + + **Updating** + + It's easy to update your snapshots...just delete them all and re-run the test suite to regenerate all snapshots. + + Note: + Snapshots require Python 3.x + """ def snapshot(self, id=None, path='__snapshots'): + """Asserts that val is identical to the on-disk snapshot stored previously. + + On the first run of a test before the snapshot file has been saved, a snapshot is created, + stored to disk, and the test *always* passes. But on all subsequent runs, val is compared + to the on-disk snapshot, and the test fails if they don't match. + + Snapshot artifacts are stored in the ``__snapshots`` directory by default, and should be + committed to source control alongside any code changes. + + Snapshots are identified by test filename plus line number by default. + + Args: + id: the item or items expected to be contained + path: the item or items expected to be contained + + Examples: + Usage:: + + assert_that(None).snapshot() + assert_that(True).snapshot() + assert_that(1).snapshot() + assert_that(123.4).snapshot() + assert_that('foo').snapshot() + assert_that([1, 2, 3]).snapshot() + assert_that({'a': 1, 'b': 2, 'c': 3}).snapshot() + assert_that({'a', 'b', 'c'}).snapshot() + assert_that(1 + 2j).snapshot() + assert_that(someobj).snapshot() + + By default, snapshots are identified by test filename plus line number. Alternately, you can specify a custom identifier using the ``id`` arg:: + + assert_that({'a': 1, 'b': 2, 'c': 3}).snapshot(id='foo-id') + + + By default, snapshots are stored in the ``__snapshots`` directory. Alternately, you can specify a custom path using the ``path`` arg:: + + assert_that({'a': 1, 'b': 2, 'c': 3}).snapshot(path='my-custom-folder') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** equal to on-disk snapshot + """ if sys.version_info[0] < 3: raise NotImplementedError('snapshot testing requires Python 3') @@ -87,7 +168,7 @@ def _load(name): def _name(path, name): try: - return os.path.join(path, 'snap-%s.json' % name.replace(' ','_').lower()) + return os.path.join(path, 'snap-%s.json' % name.replace(' ', '_').lower()) except Exception: raise ValueError('failed to create snapshot filename, either bad path or bad name') diff --git a/assertpy/string.py b/assertpy/string.py index 7a340e2..be9c866 100644 --- a/assertpy/string.py +++ b/assertpy/string.py @@ -39,22 +39,63 @@ unicode = unicode Iterable = collections.Iterable +__tracebackhide__ = True + class StringMixin(object): """String assertions mixin.""" def is_equal_to_ignoring_case(self, other): - """Asserts that val is case-insensitive equal to other.""" + """Asserts that val is a string and is case-insensitive equal to other. + + Checks actual is equal to expected using the ``==`` operator and ``str.lower()``. + + Args: + other: the expected value + + Examples: + Usage:: + + assert_that('foo').is_equal_to_ignoring_case('FOO') + assert_that('FOO').is_equal_to_ignoring_case('foo') + assert_that('fOo').is_equal_to_ignoring_case('FoO') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if actual is **not** case-insensitive equal to expected + """ if not isinstance(self.val, str_types): raise TypeError('val is not a string') if not isinstance(other, str_types): raise TypeError('given arg must be a string') if self.val.lower() != other.lower(): - self._err('Expected <%s> to be case-insensitive equal to <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be case-insensitive equal to <%s>, but was not.' % (self.val, other)) return self def contains_ignoring_case(self, *items): - """Asserts that val is string and contains the given item or items.""" + """Asserts that val is string and contains the given item or items. + + Walks val and checks for item or items using the ``==`` operator and ``str.lower()``. + + Args: + *items: the item or items expected to be contained + + Examples: + Usage:: + + assert_that('foo').contains_ignoring_case('F', 'oO') + assert_that(['a', 'B']).contains_ignoring_case('A', 'b') + assert_that({'a': 1, 'B': 2}).contains_ignoring_case('A', 'b') + assert_that({'a', 'B'}).contains_ignoring_case('A', 'b') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** contain the case-insensitive item or items + """ if len(items) == 0: raise ValueError('one or more args must be given') if isinstance(self.val, str_types): @@ -62,7 +103,7 @@ def contains_ignoring_case(self, *items): if not isinstance(items[0], str_types): raise TypeError('given arg must be a string') if items[0].lower() not in self.val.lower(): - self._err('Expected <%s> to case-insensitive contain item <%s>, but did not.' % (self.val, items[0])) + return self.error('Expected <%s> to case-insensitive contain item <%s>, but did not.' % (self.val, items[0])) else: missing = [] for i in items: @@ -71,7 +112,8 @@ def contains_ignoring_case(self, *items): if i.lower() not in self.val.lower(): missing.append(i) if missing: - self._err('Expected <%s> to case-insensitive contain items %s, but did not contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(missing))) + return self.error('Expected <%s> to case-insensitive contain items %s, but did not contain %s.' % ( + self.val, self._fmt_items(items), self._fmt_items(missing))) elif isinstance(self.val, Iterable): missing = [] for i in items: @@ -87,13 +129,32 @@ def contains_ignoring_case(self, *items): if not found: missing.append(i) if missing: - self._err('Expected <%s> to case-insensitive contain items %s, but did not contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(missing))) + return self.error('Expected <%s> to case-insensitive contain items %s, but did not contain %s.' % ( + self.val, self._fmt_items(items), self._fmt_items(missing))) else: raise TypeError('val is not a string or iterable') return self def starts_with(self, prefix): - """Asserts that val is string or iterable and starts with prefix.""" + """Asserts that val is string or iterable and starts with prefix. + + Args: + prefix: the prefix + + Examples: + Usage:: + + assert_that('foo').starts_with('fo') + assert_that(['a', 'b', 'c']).starts_with('a') + assert_that((1, 2, 3)).starts_with(1) + assert_that(((1, 2), (3, 4), (5, 6))).starts_with((1, 2)) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** start with prefix + """ if prefix is None: raise TypeError('given prefix arg must not be none') if isinstance(self.val, str_types): @@ -102,19 +163,37 @@ def starts_with(self, prefix): if len(prefix) == 0: raise ValueError('given prefix arg must not be empty') if not self.val.startswith(prefix): - self._err('Expected <%s> to start with <%s>, but did not.' % (self.val, prefix)) + return self.error('Expected <%s> to start with <%s>, but did not.' % (self.val, prefix)) elif isinstance(self.val, Iterable): if len(self.val) == 0: raise ValueError('val must not be empty') first = next(iter(self.val)) if first != prefix: - self._err('Expected %s to start with <%s>, but did not.' % (self.val, prefix)) + return self.error('Expected %s to start with <%s>, but did not.' % (self.val, prefix)) else: raise TypeError('val is not a string or iterable') return self def ends_with(self, suffix): - """Asserts that val is string or iterable and ends with suffix.""" + """Asserts that val is string or iterable and ends with suffix. + + Args: + suffix: the suffix + + Examples: + Usage:: + + assert_that('foo').ends_with('oo') + assert_that(['a', 'b', 'c']).ends_with('c') + assert_that((1, 2, 3)).ends_with(3) + assert_that(((1, 2), (3, 4), (5, 6))).ends_with((5, 6)) + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** end with suffix + """ if suffix is None: raise TypeError('given suffix arg must not be none') if isinstance(self.val, str_types): @@ -123,7 +202,7 @@ def ends_with(self, suffix): if len(suffix) == 0: raise ValueError('given suffix arg must not be empty') if not self.val.endswith(suffix): - self._err('Expected <%s> to end with <%s>, but did not.' % (self.val, suffix)) + return self.error('Expected <%s> to end with <%s>, but did not.' % (self.val, suffix)) elif isinstance(self.val, Iterable): if len(self.val) == 0: raise ValueError('val must not be empty') @@ -131,13 +210,60 @@ def ends_with(self, suffix): for last in self.val: pass if last != suffix: - self._err('Expected %s to end with <%s>, but did not.' % (self.val, suffix)) + return self.error('Expected %s to end with <%s>, but did not.' % (self.val, suffix)) else: raise TypeError('val is not a string or iterable') return self def matches(self, pattern): - """Asserts that val is string and matches regex pattern.""" + """Asserts that val is string and matches the given regex pattern. + + Args: + pattern (str): the regular expression pattern, as raw string (aka prefixed with ``r``) + + Examples: + Usage:: + + assert_that('foo').matches(r'\\w') + assert_that('123-456-7890').matches(r'\\d{3}-\\d{3}-\\d{4}') + + Match is partial unless anchored, so these assertion pass:: + + assert_that('foo').matches(r'\\w') + assert_that('foo').matches(r'oo') + assert_that('foo').matches(r'\\w{2}') + + To match the entire string, just use an anchored regex pattern where ``^`` and ``$`` + match the start and end of line and ``\\A`` and ``\\Z`` match the start and end of string:: + + assert_that('foo').matches(r'^\\w{3}$') + assert_that('foo').matches(r'\\A\\w{3}\\Z') + + And regex flags, such as ``re.MULTILINE`` and ``re.DOTALL``, can only be applied via + *inline modifiers*, such as ``(?m)`` and ``(?s)``:: + + s = '''bar + foo + baz''' + + # using multiline (?m) + assert_that(s).matches(r'(?m)^foo$') + + # using dotall (?s) + assert_that(s).matches(r'(?s)b(.*)z') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val does **not** match pattern + + Tip: + Regular expressions are tricky. Be sure to use raw strings (aka prefixed with ``r``). + Also, note that the :meth:`matches` assertion passes for partial matches (as does the + underlying ``re.match`` method). So, if you need to match the entire string, you must + include anchors in the regex pattern. + """ if not isinstance(self.val, str_types): raise TypeError('val is not a string') if not isinstance(pattern, str_types): @@ -145,11 +271,30 @@ def matches(self, pattern): if len(pattern) == 0: raise ValueError('given pattern arg must not be empty') if re.search(pattern, self.val) is None: - self._err('Expected <%s> to match pattern <%s>, but did not.' % (self.val, pattern)) + return self.error('Expected <%s> to match pattern <%s>, but did not.' % (self.val, pattern)) return self def does_not_match(self, pattern): - """Asserts that val is string and does not match regex pattern.""" + """Asserts that val is string and does not match the given regex pattern. + + Args: + pattern (str): the regular expression pattern, as raw string (aka prefixed with ``r``) + + Examples: + Usage:: + + assert_that('foo').does_not_match(r'\\d+') + assert_that('123').does_not_match(r'\\w+') + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val **does** match pattern + + See Also: + :meth:`matches` - for more about regex patterns + """ if not isinstance(self.val, str_types): raise TypeError('val is not a string') if not isinstance(pattern, str_types): @@ -157,51 +302,112 @@ def does_not_match(self, pattern): if len(pattern) == 0: raise ValueError('given pattern arg must not be empty') if re.search(pattern, self.val) is not None: - self._err('Expected <%s> to not match pattern <%s>, but did.' % (self.val, pattern)) + return self.error('Expected <%s> to not match pattern <%s>, but did.' % (self.val, pattern)) return self def is_alpha(self): - """Asserts that val is non-empty string and all characters are alphabetic.""" + """Asserts that val is non-empty string and all characters are alphabetic (using ``str.isalpha()``). + + Examples: + Usage:: + + assert_that('foo').is_alpha() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** alphabetic + """ if not isinstance(self.val, str_types): raise TypeError('val is not a string') if len(self.val) == 0: raise ValueError('val is empty') if not self.val.isalpha(): - self._err('Expected <%s> to contain only alphabetic chars, but did not.' % self.val) + return self.error('Expected <%s> to contain only alphabetic chars, but did not.' % self.val) return self def is_digit(self): - """Asserts that val is non-empty string and all characters are digits.""" + """Asserts that val is non-empty string and all characters are digits (using ``str.isdigit()``). + + Examples: + Usage:: + + assert_that('1234567890').is_digit() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** digits + """ if not isinstance(self.val, str_types): raise TypeError('val is not a string') if len(self.val) == 0: raise ValueError('val is empty') if not self.val.isdigit(): - self._err('Expected <%s> to contain only digits, but did not.' % self.val) + return self.error('Expected <%s> to contain only digits, but did not.' % self.val) return self def is_lower(self): - """Asserts that val is non-empty string and all characters are lowercase.""" + """Asserts that val is non-empty string and all characters are lowercase (using ``str.lower()``). + + Examples: + Usage:: + + assert_that('foo').is_lower() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** lowercase + """ if not isinstance(self.val, str_types): raise TypeError('val is not a string') if len(self.val) == 0: raise ValueError('val is empty') if self.val != self.val.lower(): - self._err('Expected <%s> to contain only lowercase chars, but did not.' % self.val) + return self.error('Expected <%s> to contain only lowercase chars, but did not.' % self.val) return self def is_upper(self): - """Asserts that val is non-empty string and all characters are uppercase.""" + """Asserts that val is non-empty string and all characters are uppercase (using ``str.upper()``). + + Examples: + Usage:: + + assert_that('FOO').is_upper() + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** uppercase + """ if not isinstance(self.val, str_types): raise TypeError('val is not a string') if len(self.val) == 0: raise ValueError('val is empty') if self.val != self.val.upper(): - self._err('Expected <%s> to contain only uppercase chars, but did not.' % self.val) + return self.error('Expected <%s> to contain only uppercase chars, but did not.' % self.val) return self def is_unicode(self): - """Asserts that val is a unicode string.""" + """Asserts that val is a unicode string. + + Examples: + Usage:: + + assert_that(u'foo').is_unicode() # python 2 + assert_that('foo').is_unicode() # python 3 + + Returns: + AssertionBuilder: returns this instance to chain to the next assertion + + Raises: + AssertionError: if val is **not** a unicode string + """ if type(self.val) is not unicode: - self._err('Expected <%s> to be unicode, but was <%s>.' % (self.val, type(self.val).__name__)) + return self.error('Expected <%s> to be unicode, but was <%s>.' % (self.val, type(self.val).__name__)) return self diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..d7ce395 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,37 @@ +# assertpy docs + +Documentation is mostly written inline using Python docstrings that are in +[Google Python Style Guide](https://google.github.io/styleguide/pyguide.html) format. +[Sphinx](https://www.sphinx-doc.org/) and the +[Napoleon extension](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html) +are used to generate html. + +## Setup + +Install `sphinx` via pip... + +``` +pip install sphinx +pip install sphinxcontrib-napoleon +``` + +And checkout the [assertpy.github.io](https://github.com/assertpy/assertpy.github.io) +repo as a sibling to `assertpy`. + +``` +cd .. +git clone git@github.com:assertpy/assertpy.github.io.git +``` + +## Build + +To build the docs, run: + +``` +cd docs/ +./build.sh +``` + +This generates `docs.html` and copies is directly into the sibling +`assertpy.github.io` repo. + diff --git a/docs/assertpy.rst b/docs/assertpy.rst new file mode 100644 index 0000000..983ac11 --- /dev/null +++ b/docs/assertpy.rst @@ -0,0 +1,112 @@ +assertpy +-------- + +.. automodule:: assertpy.assertpy + :members: + :undoc-members: + :show-inheritance: + :exclude-members: WarningLoggingAdapter + +base +---- + +.. automodule:: assertpy.base + :members: + :undoc-members: + :show-inheritance: + +collection +---------- + +.. automodule:: assertpy.collection + :members: + :undoc-members: + :show-inheritance: + +contains +-------- + +.. automodule:: assertpy.contains + :members: + :undoc-members: + :show-inheritance: + +date +---- + +.. automodule:: assertpy.date + :members: + :undoc-members: + :show-inheritance: + +dict +---- + +.. automodule:: assertpy.dict + :members: + :undoc-members: + :show-inheritance: + +dynamic +------- + +.. automodule:: assertpy.dynamic + :members: + :undoc-members: + :show-inheritance: + +exception +--------- + +.. automodule:: assertpy.exception + :members: + :undoc-members: + :show-inheritance: + +extracting +---------- + +.. automodule:: assertpy.extracting + :members: + :undoc-members: + :show-inheritance: + +file +---- + +.. automodule:: assertpy.file + :members: + :undoc-members: + :show-inheritance: + +helpers +------- + +.. automodule:: assertpy.helpers + :members: + :undoc-members: + :show-inheritance: + +numeric +------- + +.. automodule:: assertpy.numeric + :members: + :undoc-members: + :show-inheritance: + +snapshot +-------- + +.. automodule:: assertpy.snapshot + :members: + :undoc-members: + :show-inheritance: + +string +------ + +.. automodule:: assertpy.string + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/build.sh b/docs/build.sh new file mode 100755 index 0000000..17ead2a --- /dev/null +++ b/docs/build.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +sphinx-build -b html . build +python fixup.py +cp out/docs.html ../../assertpy.github.io diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..5447989 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,24 @@ +# fixup path +import os +import sys +sys.path.insert(0, os.path.abspath('..')) +print('SYS.PATH=', sys.path) + +# proj info +project = 'assertpy' +copyright = '2015-2019 Activision Publishing, Inc.' +author = 'Activision' + +# extensions (for Google-style doc strings) +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon' +] + +templates_path = ['templates'] + +exclude_patterns = ['build', '.DS_Store'] + +# html_theme = 'sphinx_rtd_theme' + +add_module_names = False diff --git a/docs/fixup.py b/docs/fixup.py new file mode 100644 index 0000000..433c791 --- /dev/null +++ b/docs/fixup.py @@ -0,0 +1,70 @@ +import os +import re + + +# conf +PROJECT = 'assertpy' +SRC_DIR = os.path.join(os.getcwd(), 'build') +SRC = os.path.join(SRC_DIR, 'assertpy.html') +OUT_DIR = os.path.join(os.getcwd(), 'out') +OUT = os.path.join(OUT_DIR, 'docs.html') + + +def load(filename): + with open(filename, 'r') as fp: + return fp.read() + + +def save(target, contents): + with open(target, 'w') as fp: + fp.write(contents) + + +if __name__ == '__main__': + print('\nFIXUP') + print(f' src={SRC}') + print(f' out={OUT}') + + if not os.path.exists(OUT_DIR): + os.makedirs(OUT_DIR) + + if not os.path.isfile(SRC): + print(f'bad src filename {SRC}') + + html = load(SRC) + html = html.replace('

', '

') + + html = html.replace('"admonition-title">Tip

\n

', '"message-header">Tip

\n

') + html = html.replace('"admonition-title">Note

\n

', '"message-header">Note

\n

') + html = html.replace('"admonition-title">See also

\n

', '"message-header">See Also

\n

') + html = html.replace('"admonition tip"', '"message is-primary"') + html = html.replace('"admonition note"', '"message is-info"') + html = html.replace('"admonition seealso"', '"message is-link"') + + html = html.replace('

', '
')
+    html = html.replace('
\n
', '') + + html = html.replace('class="code">2019', + 'class="code">2019') + html = html.replace('class="code">AssertionError:', + 'class="code">AssertionError:') + html = html.replace('class="code">AssertionError: soft assertion failures', + 'class="code">AssertionError: soft assertion failures') + + html = html.replace('
Usage:

', '') + html = html.replace('BR', '
') + + margin = 'style="margin:0.2em 0;"' + html = html.replace('
Parameters
', f'
Parameters
') + html = html.replace('
Keyword Arguments
', f'
Keyword Arguments
') + html = html.replace('

Examples

', f'

Examples

') + html = html.replace('
Returns
', f'
Returns
') + html = html.replace('
Return type
', f'
Return type
') + html = html.replace('
Raises
', f'
Raises
') + + html = html.replace('
+ +assertpy docs + + + + + + + + + + + +
+
+ + +
+ +
+
+
+{% block body %} {% endblock %} +
+
+
+ +
+ + + + + \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index b88034e..d783954 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,5 @@ [metadata] -description-file = README.md +description_file = README.md + +[pep8] +max_line_length = 160 diff --git a/setup.py b/setup.py index 6139e5e..44c9d63 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,16 @@ from distutils.core import setup import assertpy -desc = """assertpy +desc = """ +assertpy ======== -Dead simple assertion library for python unit testing with a fluent API -that supports Python 2 and 3. +Simple assertions library for unit testing in Python with a nice fluent API. Supports both Python 2 and 3. Usage -''''' +----- -Just import the ``assert_that`` function, and away you go:: +Just import the ``assert_that`` function, and away you go...:: from assertpy import assert_that @@ -19,23 +19,37 @@ def test_something(): assert_that('foobar').is_length(6).starts_with('foo').ends_with('bar') assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x') -Of course, ``assertpy`` works best with a python test runner -like `pytest `_ (our favorite) -or `Nose `_.""" +Of course, assertpy works best with a python test runner like `pytest `_ (our favorite) or `Nose `_. + +Install +------- + +The assertpy library is available via `PyPI `_. +Just install with:: + + pip install assertpy + +Or, if you are a big fan of `conda `_ like we are, there is an +`assertpy-feedstock `_ for +`Conda-Forge `_ that you can use:: + + conda install assertpy --channel conda-forge + +""" setup( - name = 'assertpy', - packages = ['assertpy'], - version = assertpy.__version__, - description = 'Assertion library for python unit testing with a fluent API', - long_description = desc, - author = 'Justin Shacklette', - author_email = 'justin@saturnboy.com', - url = 'https://github.com/ActivisionGameScience/assertpy', - download_url = 'https://codeload.github.com/ActivisionGameScience/assertpy/tar.gz/%s' % assertpy.__version__, - keywords = ['test', 'testing', 'assert', 'assertion', 'assertthat', 'assert_that', 'nose', 'nosetests', 'pytest', 'unittest'], - license = 'BSD', - classifiers = [ + name='assertpy', + packages=['assertpy'], + version=assertpy.__version__, + description='Simple assertion library for unit testing in python with a fluent API', + long_description=desc, + author='Justin Shacklette', + author_email='justin@saturnboy.com', + url='https://github.com/assertpy/assertpy', + download_url='https://github.com/assertpy/assertpy/archive/%s.tar.gz' % assertpy.__version__, + keywords=['test', 'testing', 'assert', 'assertion', 'assertthat', 'assert_that', 'nose', 'nosetests', 'pytest', 'unittest'], + license='BSD', + classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', diff --git a/tests/test_bool.py b/tests/test_bool.py index ac537f5..9170392 100644 --- a/tests/test_bool.py +++ b/tests/test_bool.py @@ -26,7 +26,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_is_true(): @@ -35,14 +35,16 @@ def test_is_true(): assert_that(1).is_true() assert_that('a').is_true() assert_that([1]).is_true() - assert_that({'a':1}).is_true() + assert_that({'a': 1}).is_true() + def test_is_true_failure(): try: assert_that(False).is_true() fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).is_equal_to('Expected , but was not.') + assert_that(str(ex)).is_equal_to('Expected to be , but was not.') + def test_is_false(): assert_that(False).is_false() @@ -52,9 +54,10 @@ def test_is_false(): assert_that({}).is_false() assert_that(()).is_false() + def test_is_false_failure(): try: assert_that(True).is_false() fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).is_equal_to('Expected , but was not.') + assert_that(str(ex)).is_equal_to('Expected to be , but was not.') diff --git a/tests/test_class.py b/tests/test_class.py index 3b2f99a..547a6a2 100644 --- a/tests/test_class.py +++ b/tests/test_class.py @@ -43,12 +43,15 @@ def name(self): def say_hello(self): return 'Hello, %s!' % self.first_name + class Developer(Person): def say_hello(self): return '%s writes code.' % self.first_name + class AbstractAutomobile(object): __metaclass__ = abc.ABCMeta + def __init__(self): pass @@ -56,19 +59,21 @@ def __init__(self): def classification(self): raise NotImplementedError('This method must be overridden') + class Car(AbstractAutomobile): @property def classification(self): return 'car' + class Truck(AbstractAutomobile): @property def classification(self): return 'truck' -fred = Person('Fred','Smith') -joe = Developer('Joe','Coder') +fred = Person('Fred', 'Smith') +joe = Developer('Joe', 'Coder') people = [fred, joe] car = Car() truck = Truck() @@ -80,9 +85,11 @@ def test_is_type_of(): assert_that(car).is_type_of(Car) assert_that(truck).is_type_of(Truck) + def test_is_type_of_class(): assert_that(fred.__class__).is_type_of(Person.__class__) + def test_is_type_of_class_failure(): try: assert_that(fred.__class__).is_type_of(Person) @@ -90,6 +97,7 @@ def test_is_type_of_class_failure(): except AssertionError as ex: assert_that(str(ex)).contains('to be of type , but was not') + def test_is_instance_of(): assert_that(fred).is_instance_of(Person) assert_that(fred).is_instance_of(object) @@ -106,9 +114,11 @@ def test_is_instance_of(): assert_that(truck).is_instance_of(AbstractAutomobile) assert_that(truck).is_instance_of(object) + def test_is_instance_of_class(): assert_that(fred.__class__).is_instance_of(Person.__class__) + def test_is_instance_of_class_failure(): try: assert_that(fred.__class__).is_instance_of(Person) @@ -116,16 +126,19 @@ def test_is_instance_of_class_failure(): except AssertionError as ex: assert_that(str(ex)).contains('to be instance of class , but was not') + def test_extract_attribute(): - assert_that(people).extracting('first_name').is_equal_to(['Fred','Joe']) - assert_that(people).extracting('first_name').contains('Fred','Joe') + assert_that(people).extracting('first_name').is_equal_to(['Fred', 'Joe']) + assert_that(people).extracting('first_name').contains('Fred', 'Joe') + def test_extract_property(): - assert_that(people).extracting('name').contains('Fred Smith','Joe Coder') + assert_that(people).extracting('name').contains('Fred Smith', 'Joe Coder') + def test_extract_multiple(): - assert_that(people).extracting('first_name', 'name').contains(('Fred','Fred Smith'), ('Joe','Joe Coder')) + assert_that(people).extracting('first_name', 'name').contains(('Fred', 'Fred Smith'), ('Joe', 'Joe Coder')) + def test_extract_zero_arg_method(): assert_that(people).extracting('say_hello').contains('Hello, Fred!', 'Joe writes code.') - diff --git a/tests/test_collection.py b/tests/test_collection.py index d9bfb24..309a4f3 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -29,16 +29,17 @@ import sys import collections -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_is_iterable(): - assert_that(['a','b','c']).is_iterable() - assert_that((1,2,3)).is_iterable() + assert_that(['a', 'b', 'c']).is_iterable() + assert_that((1, 2, 3)).is_iterable() assert_that('foo').is_iterable() - assert_that({ 'a':1,'b':2,'c':3 }.keys()).is_iterable() - assert_that({ 'a':1,'b':2,'c':3 }.values()).is_iterable() - assert_that({ 'a':1,'b':2,'c':3 }.items()).is_iterable() + assert_that({'a': 1, 'b': 2, 'c': 3}.keys()).is_iterable() + assert_that({'a': 1, 'b': 2, 'c': 3}.values()).is_iterable() + assert_that({'a': 1, 'b': 2, 'c': 3}.items()).is_iterable() + def test_is_iterable_failure(): try: @@ -47,71 +48,80 @@ def test_is_iterable_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected iterable, but was not.') + def test_is_not_iterable(): assert_that(123).is_not_iterable() - assert_that({ 'a':1,'b':2,'c':3 }).is_iterable() + assert_that({'a': 1, 'b': 2, 'c': 3}).is_iterable() + def test_is_not_iterable_failure(): try: - assert_that(['a','b','c']).is_not_iterable() + assert_that(['a', 'b', 'c']).is_not_iterable() fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected not iterable, but was.') + def test_is_subset_of(): - assert_that(['a','b','c']).is_subset_of(['a','b','c']) - assert_that(['a','b','c']).is_subset_of(['a','b','c','d']) - assert_that(['a','b','c']).is_subset_of(['a'], ['b'], ['c']) - assert_that(['a','b','c']).is_subset_of('a','b','c') - assert_that(['a','b','a']).is_subset_of(['a','a','b']) - assert_that((1,2,3)).is_subset_of((1,2,3)) - assert_that((1,2,3)).is_subset_of((1,2,3,4)) - assert_that((1,2,3)).is_subset_of((1,), (2,), (3,)) - assert_that((1,2,3)).is_subset_of(1,2,3) - assert_that((1,2,1)).is_subset_of(1,1,2) + assert_that(['a', 'b', 'c']).is_subset_of(['a', 'b', 'c']) + assert_that(['a', 'b', 'c']).is_subset_of(['a', 'b', 'c', 'd']) + assert_that(['a', 'b', 'c']).is_subset_of(['a'], ['b'], ['c']) + assert_that(['a', 'b', 'c']).is_subset_of('a', 'b', 'c') + assert_that(['a', 'b', 'a']).is_subset_of(['a', 'a', 'b']) + assert_that((1, 2, 3)).is_subset_of((1, 2, 3)) + assert_that((1, 2, 3)).is_subset_of((1, 2, 3, 4)) + assert_that((1, 2, 3)).is_subset_of((1, ), (2, ), (3, )) + assert_that((1, 2, 3)).is_subset_of(1, 2, 3) + assert_that((1, 2, 1)).is_subset_of(1, 1, 2) assert_that('foo').is_subset_of('abcdefghijklmnopqrstuvwxyz') - assert_that('foo').is_subset_of('abcdef', set(['m','n','o']), ['x','y']) - assert_that(set([1,2,3])).is_subset_of(set([1,2,3,4])) - assert_that({'a':1,'b':2}).is_subset_of({'a':1,'b':2,'c':3}) - assert_that({'a':1,'b':2}).is_subset_of({'a':3}, {'b':2}, {'a':1}) + assert_that('foo').is_subset_of('abcdef', set(['m', 'n', 'o']), ['x', 'y']) + assert_that(set([1, 2, 3])).is_subset_of(set([1, 2, 3, 4])) + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 1, 'b': 2, 'c': 3}) + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 3}, {'b': 2}, {'a': 1}) + def test_is_subset_of_single_item_superset(): assert_that(['a']).is_subset_of(['a']) - assert_that((1,)).is_subset_of((1,)) + assert_that((1, )).is_subset_of((1, )) assert_that('ab').is_subset_of('ab') assert_that(set([1])).is_subset_of(set([1])) - assert_that({'a':1}).is_subset_of({'a':1}) + assert_that({'a': 1}).is_subset_of({'a': 1}) + def test_is_subset_of_failure_empty_superset(): try: - assert_that(['a','b','c']).is_subset_of([]) + assert_that(['a', 'b', 'c']).is_subset_of([]) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to be subset of <>') + def test_is_subset_of_failure_single_item_superset(): try: - assert_that(['a','b','c']).is_subset_of(['x']) + assert_that(['a', 'b', 'c']).is_subset_of(['x']) fail('should have raised error') except AssertionError as ex: if sys.version_info[0] == 3: assert_that(str(ex)).contains("to be subset of <{'x'}>") assert_that(str(ex)).contains("but <'a', 'b', 'c'> were missing.") + def test_is_subset_of_failure_array(): try: - assert_that(['a','b','c']).is_subset_of(['a','b']) + assert_that(['a', 'b', 'c']).is_subset_of(['a', 'b']) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('but was missing.') + def test_is_subset_of_failure_set(): try: - assert_that(set([1,2,3])).is_subset_of(set([1,2])) + assert_that(set([1, 2, 3])).is_subset_of(set([1, 2])) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('but <3> was missing.') + def test_is_subset_of_failure_string(): try: assert_that('abc').is_subset_of('abx') @@ -119,34 +129,39 @@ def test_is_subset_of_failure_string(): except AssertionError as ex: assert_that(str(ex)).contains('but was missing.') + def test_is_subset_of_failure_dict_key(): try: - assert_that({'a':1,'b':2}).is_subset_of({'a':1,'c':3}) + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 1, 'c': 3}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("but <{'b': 2}> was missing") + def test_is_subset_of_failure_dict_value(): try: - assert_that({'a':1,'b':2}).is_subset_of({'a':1,'b':22}) + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 1, 'b': 22}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("but <{'b': 2}> was missing.") + def test_is_subset_of_failure_bad_dict_arg1(): try: - assert_that({'a':1,'b':2}).is_subset_of('foo') + assert_that({'a': 1, 'b': 2}).is_subset_of('foo') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).contains('arg #1').contains('is not dict-like') + def test_is_subset_of_failure_bad_dict_arg2(): try: - assert_that({'a':1,'b':2}).is_subset_of({'a':1}, 'foo') + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 1}, 'foo') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).contains('arg #2').contains('is not dict-like') + def test_is_subset_of_bad_val_failure(): try: assert_that(123).is_subset_of(1234) @@ -154,13 +169,61 @@ def test_is_subset_of_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not iterable') + def test_is_subset_of_bad_arg_failure(): try: - assert_that(['a','b','c']).is_subset_of() + assert_that(['a', 'b', 'c']).is_subset_of() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more superset args must be given') -def test_chaining(): - assert_that(['a','b','c']).is_iterable().is_type_of(list).is_length(3) +def test_is_sorted(): + assert_that([1, 2, 3]).is_sorted() + assert_that((3, 2, 1)).is_sorted(reverse=True) + assert_that(['a', 'b', 'c']).is_sorted() + assert_that(['c', 'b', 'a']).is_sorted(reverse=True) + assert_that('abcdefghijklmnopqrstuvwxyz').is_sorted() + assert_that('zyxwvutsrqponmlkjihgfedcba').is_sorted(reverse=True) + assert_that([{'a': 1}, {'a': 2}, {'a': 3}]).is_sorted(key=lambda x: x['a']) + assert_that([{'a': 3}, {'a': 2}, {'a': 1}]).is_sorted(key=lambda x: x['a'], reverse=True) + assert_that([('a', 2), ('b', 1)]).is_sorted(key=lambda x: x[0]) + assert_that([('a', 2), ('b', 1)]).is_sorted(key=lambda x: x[1], reverse=True) + assert_that([1, 1, 1]).is_sorted() + assert_that([1, 1, 1]).is_sorted(reverse=True) + assert_that([]).is_sorted() + assert_that([1]).is_sorted() + + if sys.version_info[0] == 3: + import collections + ordered = collections.OrderedDict([('a', 2), ('b', 1)]) + assert_that(ordered).is_sorted() + assert_that(ordered.keys()).is_sorted() + + +def test_is_sorted_failure(): + try: + assert_that([1, 2, 3, 4, 5, 6, -1, 7, 8, 9]).is_sorted() + fail("should have raised error") + except AssertionError as ex: + assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3, 4, 5, 6, -1, 7, 8, 9]> to be sorted, but subset <6, -1> at index 5 is not.') + + +def test_is_sorted_reverse_failure(): + try: + assert_that([1, 2, 3]).is_sorted(reverse=True) + fail("should have raised error") + except AssertionError as ex: + assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3]> to be sorted reverse, but subset <1, 2> at index 0 is not.') + + +def test_is_sorted_failure_bad_val(): + try: + assert_that(123).is_sorted() + fail("should have raised error") + except TypeError as ex: + assert_that(str(ex)).is_equal_to('val is not iterable') + + +def test_chaining(): + assert_that(['a', 'b', 'c']).is_iterable().is_type_of(list).is_sorted().is_length(3) diff --git a/tests/test_core.py b/tests/test_core.py index 8079680..4d37c68 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -33,59 +33,72 @@ def test_fmt_items_empty(): ab = assert_that(None) assert_that(ab._fmt_items([])).is_equal_to('<>') + def test_fmt_items_single(): ab = assert_that(None) assert_that(ab._fmt_items([1])).is_equal_to('<1>') assert_that(ab._fmt_items(['foo'])).is_equal_to('') + assert_that(ab._fmt_items([('bar', 'baz')])).is_equal_to('<(\'bar\', \'baz\')>') + def test_fmt_items_multiple(): ab = assert_that(None) - assert_that(ab._fmt_items([1,2,3])).is_equal_to('<1, 2, 3>') - assert_that(ab._fmt_items(['a','b','c'])).is_equal_to("<'a', 'b', 'c'>") + assert_that(ab._fmt_items([1, 2, 3])).is_equal_to('<1, 2, 3>') + assert_that(ab._fmt_items(['a', 'b', 'c'])).is_equal_to("<'a', 'b', 'c'>") + def test_fmt_args_kwargs_empty(): ab = assert_that(None) assert_that(ab._fmt_args_kwargs()).is_equal_to('') + def test_fmt_args_kwargs_single_arg(): ab = assert_that(None) assert_that(ab._fmt_args_kwargs(1)).is_equal_to('1') assert_that(ab._fmt_args_kwargs('foo')).is_equal_to("'foo'") + def test_fmt_args_kwargs_multiple_args(): ab = assert_that(None) - assert_that(ab._fmt_args_kwargs(1,2,3)).is_equal_to('1, 2, 3') - assert_that(ab._fmt_args_kwargs('a','b','c')).is_equal_to("'a', 'b', 'c'") + assert_that(ab._fmt_args_kwargs(1, 2, 3)).is_equal_to('1, 2, 3') + assert_that(ab._fmt_args_kwargs('a', 'b', 'c')).is_equal_to("'a', 'b', 'c'") + def test_fmt_args_kwargs_single_kwarg(): ab = assert_that(None) assert_that(ab._fmt_args_kwargs(a=1)).is_equal_to("'a': 1") assert_that(ab._fmt_args_kwargs(f='foo')).is_equal_to("'f': 'foo'") + def test_fmt_args_kwargs_multiple_kwargs(): ab = assert_that(None) - assert_that(ab._fmt_args_kwargs(a=1,b=2,c=3)).is_equal_to("'a': 1, 'b': 2, 'c': 3") - assert_that(ab._fmt_args_kwargs(a='a',b='b',c='c')).is_equal_to("'a': 'a', 'b': 'b', 'c': 'c'") + assert_that(ab._fmt_args_kwargs(a=1, b=2, c=3)).is_equal_to("'a': 1, 'b': 2, 'c': 3") + assert_that(ab._fmt_args_kwargs(a='a', b='b', c='c')).is_equal_to("'a': 'a', 'b': 'b', 'c': 'c'") + def test_fmt_args_kwargs_multiple_both(): ab = assert_that(None) - assert_that(ab._fmt_args_kwargs(1,2,3,a=4,b=5,c=6)).is_equal_to("1, 2, 3, 'a': 4, 'b': 5, 'c': 6") - assert_that(ab._fmt_args_kwargs('a','b','c', d='g',e='h',f='i')).is_equal_to("'a', 'b', 'c', 'd': 'g', 'e': 'h', 'f': 'i'") + assert_that(ab._fmt_args_kwargs(1, 2, 3, a=4, b=5, c=6)).is_equal_to("1, 2, 3, 'a': 4, 'b': 5, 'c': 6") + assert_that(ab._fmt_args_kwargs('a', 'b', 'c', d='g', e='h', f='i')).is_equal_to("'a', 'b', 'c', 'd': 'g', 'e': 'h', 'f': 'i'") + def test_check_dict_like_empty_dict(): ab = assert_that(None) assert_that(ab._check_dict_like({})) + def test_check_dict_like_not_iterable(): ab = assert_that(None) assert_that(ab._check_dict_like).raises(TypeError).when_called_with(123)\ .is_equal_to('val is not dict-like: not iterable') + def test_check_dict_like_missing_keys(): ab = assert_that(None) assert_that(ab._check_dict_like).raises(TypeError).when_called_with('foo')\ .is_equal_to('val is not dict-like: missing keys()') + def test_check_dict_like_bool(): ab = assert_that(None) assert_that(ab._check_dict_like({}, return_as_bool=True)).is_true() diff --git a/tests/test_custom_dict.py b/tests/test_custom_dict.py index aba3dde..45b5252 100644 --- a/tests/test_custom_dict.py +++ b/tests/test_custom_dict.py @@ -45,7 +45,7 @@ def test_custom_dict(): assert_that(d).contains_value('application/json') assert_that(d['Accept']).is_equal_to('application/json') - assert_that(d).contains_entry({'Accept':'application/json'}) + assert_that(d).contains_entry({'Accept': 'application/json'}) def test_requests(): @@ -66,7 +66,7 @@ def test_requests(): assert_that(d).contains_value('application/json') assert_that(d['Accept']).is_equal_to('application/json') - assert_that(d).contains_entry({'Accept':'application/json'}) + assert_that(d).contains_entry({'Accept': 'application/json'}) except ImportError: pass @@ -74,19 +74,19 @@ def test_requests(): class CustomDict(object): def __init__(self, d): - self._dict = d - self._idx = 0 + self._dict = d + self._idx = 0 def __iter__(self): return self def __next__(self): - try: - result = self.keys()[self._idx] - except IndexError: - raise StopIteration - self._idx += 1 - return result + try: + result = self.keys()[self._idx] + except IndexError: + raise StopIteration + self._idx += 1 + return result def __contains__(self, key): return key in self.keys() @@ -180,18 +180,18 @@ def __iter__(self): return self def __next__(self): - return 1 + return 1 class CustomDictNoKeysCallable(object): def __init__(self): - self.keys = 'foo' + self.keys = 'foo' def __iter__(self): return self def __next__(self): - return 1 + return 1 class CustomDictNoValues(object): @@ -199,7 +199,7 @@ def __iter__(self): return self def __next__(self): - return 1 + return 1 def keys(self): return 'foo' @@ -207,13 +207,13 @@ def keys(self): class CustomDictNoValuesCallable(object): def __init__(self): - self.values = 'foo' + self.values = 'foo' def __iter__(self): return self def __next__(self): - return 1 + return 1 def keys(self): return 'foo' @@ -224,11 +224,10 @@ def __iter__(self): return self def __next__(self): - return 1 + return 1 def keys(self): return 'foo' def values(self): return 'bar' - diff --git a/tests/test_custom_list.py b/tests/test_custom_list.py index 1961050..1b5fa23 100644 --- a/tests/test_custom_list.py +++ b/tests/test_custom_list.py @@ -32,19 +32,19 @@ class CustomList(object): def __init__(self, s): - self._s = s - self._idx = 0 + self._s = s + self._idx = 0 def __iter__(self): return self def __next__(self): - try: - result = self._s[self._idx] - except IndexError: - raise StopIteration - self._idx += 1 - return result + try: + result = self._s[self._idx] + except IndexError: + raise StopIteration + self._idx += 1 + return result def __getitem__(self, idx): return self._s[idx] @@ -52,7 +52,7 @@ def __getitem__(self, idx): def test_custom_list(): l = CustomList('foobar') - assert_that([CustomList('foo'), CustomList('bar')]).extracting(0,-1).is_equal_to([('f','o'),('b','r')]) + assert_that([CustomList('foo'), CustomList('bar')]).extracting(0, -1).is_equal_to([('f', 'o'), ('b', 'r')]) def test_check_iterable(): diff --git a/tests/test_datetime.py b/tests/test_datetime.py index 81382a7..f0061e6 100644 --- a/tests/test_datetime.py +++ b/tests/test_datetime.py @@ -27,14 +27,16 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import datetime -from assertpy import assert_that,fail +from assertpy import assert_that, fail d1 = datetime.datetime.today() + def test_is_before(): d2 = datetime.datetime.today() assert_that(d1).is_before(d2) + def test_is_before_failure(): try: d2 = datetime.datetime.today() @@ -43,6 +45,7 @@ def test_is_before_failure(): except AssertionError as ex: assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be before <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_before_bad_val_type_failure(): try: assert_that(123).is_before(123) @@ -50,6 +53,7 @@ def test_is_before_bad_val_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be datetime, but was type ') + def test_is_before_bad_arg_type_failure(): try: assert_that(d1).is_before(123) @@ -57,10 +61,12 @@ def test_is_before_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be datetime, but was type ') + def test_is_after(): d2 = datetime.datetime.today() assert_that(d2).is_after(d1) + def test_is_after_failure(): try: d2 = datetime.datetime.today() @@ -69,6 +75,7 @@ def test_is_after_failure(): except AssertionError as ex: assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be after <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_after_bad_val_type_failure(): try: assert_that(123).is_after(123) @@ -76,6 +83,7 @@ def test_is_after_bad_val_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be datetime, but was type ') + def test_is_after_bad_arg_type_failure(): try: assert_that(d1).is_after(123) @@ -83,9 +91,11 @@ def test_is_after_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be datetime, but was type ') + def test_is_equal_to_ignoring_milliseconds(): assert_that(d1).is_equal_to_ignoring_milliseconds(d1) + def test_is_equal_to_ignoring_milliseconds_failure(): try: d2 = datetime.datetime.today() + datetime.timedelta(days=1) @@ -94,6 +104,7 @@ def test_is_equal_to_ignoring_milliseconds_failure(): except AssertionError as ex: assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be equal to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_equal_to_ignoring_milliseconds_bad_val_type_failure(): try: assert_that(123).is_equal_to_ignoring_milliseconds(123) @@ -101,6 +112,7 @@ def test_is_equal_to_ignoring_milliseconds_bad_val_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be datetime, but was type ') + def test_is_equal_to_ignoring_milliseconds_bad_arg_type_failure(): try: assert_that(d1).is_equal_to_ignoring_milliseconds(123) @@ -108,9 +120,11 @@ def test_is_equal_to_ignoring_milliseconds_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be datetime, but was type ') + def test_is_equal_to_ignoring_seconds(): assert_that(d1).is_equal_to_ignoring_seconds(d1) + def test_is_equal_to_ignoring_seconds_failure(): try: d2 = datetime.datetime.today() + datetime.timedelta(days=1) @@ -119,6 +133,7 @@ def test_is_equal_to_ignoring_seconds_failure(): except AssertionError as ex: assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}> to be equal to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}>, but was not.') + def test_is_equal_to_ignoring_seconds_bad_val_type_failure(): try: assert_that(123).is_equal_to_ignoring_seconds(123) @@ -126,6 +141,7 @@ def test_is_equal_to_ignoring_seconds_bad_val_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be datetime, but was type ') + def test_is_equal_to_ignoring_seconds_bad_arg_type_failure(): try: assert_that(d1).is_equal_to_ignoring_seconds(123) @@ -133,9 +149,11 @@ def test_is_equal_to_ignoring_seconds_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be datetime, but was type ') + def test_is_equal_to_ignoring_time(): assert_that(d1).is_equal_to_ignoring_time(d1) + def test_is_equal_to_ignoring_time_failure(): try: d2 = datetime.datetime.today() + datetime.timedelta(days=1) @@ -144,6 +162,7 @@ def test_is_equal_to_ignoring_time_failure(): except AssertionError as ex: assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2}> to be equal to <\d{4}-\d{2}-\d{2}>, but was not.') + def test_is_equal_to_ignoring_time_bad_val_type_failure(): try: assert_that(123).is_equal_to_ignoring_time(123) @@ -151,6 +170,7 @@ def test_is_equal_to_ignoring_time_bad_val_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be datetime, but was type ') + def test_is_equal_to_ignoring_time_bad_arg_type_failure(): try: assert_that(d1).is_equal_to_ignoring_time(123) @@ -158,10 +178,12 @@ def test_is_equal_to_ignoring_time_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be datetime, but was type ') + def test_is_greater_than(): d2 = datetime.datetime.today() assert_that(d2).is_greater_than(d1) + def test_is_greater_than_failure(): try: d2 = datetime.datetime.today() @@ -170,6 +192,7 @@ def test_is_greater_than_failure(): except AssertionError as ex: assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be greater than <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_greater_than_bad_arg_type_failure(): try: assert_that(d1).is_greater_than(123) @@ -177,16 +200,20 @@ def test_is_greater_than_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_greater_than_or_equal_to(): assert_that(d1).is_greater_than_or_equal_to(d1) + def test_is_greater_than_or_equal_to_failure(): try: d2 = datetime.datetime.today() assert_that(d1).is_greater_than_or_equal_to(d2) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be greater than or equal to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be greater than or equal to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_greater_than_or_equal_to_bad_arg_type_failure(): try: @@ -195,17 +222,21 @@ def test_is_greater_than_or_equal_to_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_less_than(): d2 = datetime.datetime.today() assert_that(d1).is_less_than(d2) + def test_is_less_than_failure(): try: d2 = datetime.datetime.today() assert_that(d2).is_less_than(d1) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be less than <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be less than <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_less_than_bad_arg_type_failure(): try: @@ -214,16 +245,20 @@ def test_is_less_than_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_less_than_or_equal_to(): assert_that(d1).is_less_than_or_equal_to(d1) + def test_is_less_than_or_equal_to_failure(): try: d2 = datetime.datetime.today() assert_that(d2).is_less_than_or_equal_to(d1) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be less than or equal to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be less than or equal to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_less_than_or_equal_to_bad_arg_type_failure(): try: @@ -232,11 +267,13 @@ def test_is_less_than_or_equal_to_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_between(): d2 = datetime.datetime.today() d3 = datetime.datetime.today() assert_that(d2).is_between(d1, d3) + def test_is_between_failure(): try: d2 = datetime.datetime.today() @@ -244,7 +281,10 @@ def test_is_between_failure(): assert_that(d1).is_between(d2, d3) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be between <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> and <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be between ' + + r'<\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> and <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was not.') + def test_is_between_bad_arg1_type_failure(): try: @@ -253,6 +293,7 @@ def test_is_between_bad_arg1_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given low arg must be , but was ') + def test_is_between_bad_arg2_type_failure(): try: d2 = datetime.datetime.today() @@ -261,11 +302,13 @@ def test_is_between_bad_arg2_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given high arg must be , but was ') + def test_is_not_between(): d2 = d1 + datetime.timedelta(minutes=5) d3 = d1 + datetime.timedelta(minutes=10) assert_that(d1).is_not_between(d2, d3) + def test_is_not_between_failure(): try: d2 = d1 + datetime.timedelta(minutes=5) @@ -273,7 +316,10 @@ def test_is_not_between_failure(): assert_that(d2).is_not_between(d1, d3) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to not be between <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> and <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was.') + assert_that(str(ex)).matches( + r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to not be between ' + + r'<\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> and <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}>, but was.') + def test_is_not_between_bad_arg1_type_failure(): try: @@ -282,6 +328,7 @@ def test_is_not_between_bad_arg1_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given low arg must be , but was ') + def test_is_not_between_bad_arg2_type_failure(): try: d2 = datetime.datetime.today() @@ -290,17 +337,22 @@ def test_is_not_between_bad_arg2_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given high arg must be , but was ') + def test_is_close_to(): d2 = datetime.datetime.today() assert_that(d1).is_close_to(d2, datetime.timedelta(minutes=5)) + def test_is_close_to_failure(): try: d2 = d1 + datetime.timedelta(minutes=5) assert_that(d1).is_close_to(d2, datetime.timedelta(minutes=1)) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be close to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> within tolerance <\d+:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to be close to ' + + r'<\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> within tolerance <\d+:\d+:\d+>, but was not.') + def test_is_close_to_bad_arg_type_failure(): try: @@ -309,6 +361,7 @@ def test_is_close_to_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be datetime, but was ') + def test_is_close_to_bad_tolerance_arg_type_failure(): try: d2 = datetime.datetime.today() @@ -317,17 +370,21 @@ def test_is_close_to_bad_tolerance_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given tolerance arg must be timedelta, but was ') + def test_is_not_close_to(): d2 = d1 + datetime.timedelta(minutes=5) assert_that(d1).is_not_close_to(d2, datetime.timedelta(minutes=4)) + def test_is_not_close_to_failure(): try: d2 = datetime.datetime.today() assert_that(d1).is_not_close_to(d2, datetime.timedelta(minutes=5)) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to not be close to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> within tolerance <\d+:\d{2}:\d{2}>, but was.') + assert_that(str(ex)).matches( + r'Expected <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> to not be close to <\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}> within tolerance <\d+:\d+:\d+>, but was.') + def test_is_not_close_to_bad_arg_type_failure(): try: @@ -336,6 +393,7 @@ def test_is_not_close_to_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be datetime, but was ') + def test_is_not_close_to_bad_tolerance_arg_type_failure(): try: d2 = datetime.datetime.today() @@ -347,17 +405,21 @@ def test_is_not_close_to_bad_tolerance_arg_type_failure(): t1 = datetime.timedelta(seconds=60) + def test_is_greater_than_timedelta(): d2 = datetime.timedelta(seconds=120) assert_that(d2).is_greater_than(t1) + def test_is_greater_than_timedelta_failure(): try: t2 = datetime.timedelta(seconds=90) assert_that(t1).is_greater_than(t2) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{1,2}:\d{2}:\d{2}> to be greater than <\d{1,2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{1,2}:\d{2}:\d{2}> to be greater than <\d{1,2}:\d{2}:\d{2}>, but was not.') + def test_is_greater_than_timedelta_bad_arg_type_failure(): try: @@ -366,16 +428,20 @@ def test_is_greater_than_timedelta_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_greater_than_or_equal_to_timedelta(): assert_that(t1).is_greater_than_or_equal_to(t1) + def test_is_greater_than_or_equal_to_timedelta_failure(): try: t2 = datetime.timedelta(seconds=90) assert_that(t1).is_greater_than_or_equal_to(t2) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{1,2}:\d{2}:\d{2}> to be greater than or equal to <\d{1,2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{1,2}:\d{2}:\d{2}> to be greater than or equal to <\d{1,2}:\d{2}:\d{2}>, but was not.') + def test_is_greater_than_or_equal_to_timedelta_bad_arg_type_failure(): try: @@ -384,17 +450,21 @@ def test_is_greater_than_or_equal_to_timedelta_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_less_than_timedelta(): t2 = datetime.timedelta(seconds=90) assert_that(t1).is_less_than(t2) + def test_is_less_than_timedelta_failure(): try: t2 = datetime.timedelta(seconds=90) assert_that(t2).is_less_than(t1) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{1,2}:\d{2}:\d{2}> to be less than <\d{1,2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{1,2}:\d{2}:\d{2}> to be less than <\d{1,2}:\d{2}:\d{2}>, but was not.') + def test_is_less_than_timedelta_bad_arg_type_failure(): try: @@ -403,16 +473,20 @@ def test_is_less_than_timedelta_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_less_than_or_equal_to_timedelta(): assert_that(t1).is_less_than_or_equal_to(t1) + def test_is_less_than_or_equal_to_timedelta_failure(): try: t2 = datetime.timedelta(seconds=90) assert_that(t2).is_less_than_or_equal_to(t1) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{1,2}:\d{2}:\d{2}> to be less than or equal to <\d{1,2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{1,2}:\d{2}:\d{2}> to be less than or equal to <\d{1,2}:\d{2}:\d{2}>, but was not.') + def test_is_less_than_or_equal_to_timedelta_bad_arg_type_failure(): try: @@ -421,11 +495,13 @@ def test_is_less_than_or_equal_to_timedelta_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be , but was ') + def test_is_between_timedelta(): d2 = datetime.timedelta(seconds=90) d3 = datetime.timedelta(seconds=120) assert_that(d2).is_between(t1, d3) + def test_is_between_timedelta_failure(): try: d2 = datetime.timedelta(seconds=30) @@ -433,13 +509,16 @@ def test_is_between_timedelta_failure(): assert_that(t1).is_between(d2, d3) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{1,2}:\d{2}:\d{2}> to be between <\d{1,2}:\d{2}:\d{2}> and <\d{1,2}:\d{2}:\d{2}>, but was not.') + assert_that(str(ex)).matches( + r'Expected <\d{1,2}:\d{2}:\d{2}> to be between <\d{1,2}:\d{2}:\d{2}> and <\d{1,2}:\d{2}:\d{2}>, but was not.') + def test_is_not_between_timedelta(): d2 = datetime.timedelta(seconds=90) d3 = datetime.timedelta(seconds=120) assert_that(t1).is_not_between(d2, d3) + def test_is_not_between_timedelta_failure(): try: d2 = datetime.timedelta(seconds=90) @@ -447,4 +526,5 @@ def test_is_not_between_timedelta_failure(): assert_that(d2).is_not_between(t1, d3) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).matches(r'Expected <\d{1,2}:\d{2}:\d{2}> to not be between <\d{1,2}:\d{2}:\d{2}> and <\d{1,2}:\d{2}:\d{2}>, but was.') + assert_that(str(ex)).matches( + r'Expected <\d{1,2}:\d{2}:\d{2}> to not be between <\d{1,2}:\d{2}:\d{2}> and <\d{1,2}:\d{2}:\d{2}>, but was.') diff --git a/tests/test_description.py b/tests/test_description.py index 4d33584..6c70141 100644 --- a/tests/test_description.py +++ b/tests/test_description.py @@ -26,7 +26,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_constructor(): @@ -36,6 +36,7 @@ def test_constructor(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('[extra msg] Expected <1> to be equal to <2>, but was not.') + def test_described_as(): try: assert_that(1).described_as('extra msg').is_equal_to(2) @@ -43,6 +44,7 @@ def test_described_as(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('[extra msg] Expected <1> to be equal to <2>, but was not.') + def test_described_as_double(): try: assert_that(1).described_as('extra msg').described_as('other msg').is_equal_to(2) @@ -50,10 +52,10 @@ def test_described_as_double(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('[other msg] Expected <1> to be equal to <2>, but was not.') + def test_described_as_chained(): try: assert_that(1).described_as('extra msg').is_equal_to(1).described_as('other msg').is_equal_to(1).described_as('last msg').is_equal_to(2) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('[last msg] Expected <1> to be equal to <2>, but was not.') - diff --git a/tests/test_dict.py b/tests/test_dict.py index 6f29629..9aed436 100644 --- a/tests/test_dict.py +++ b/tests/test_dict.py @@ -29,89 +29,102 @@ import sys import collections -from assertpy import assert_that,fail +from assertpy import assert_that, fail + def test_is_length(): - assert_that({ 'a':1,'b':2 }).is_length(2) + assert_that({'a': 1, 'b': 2}).is_length(2) + def test_is_length_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).is_length(4) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_length(4) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to be of length <4>, but was <3>.') + def test_contains(): - assert_that({ 'a':1,'b':2,'c':3 }).contains('a') - assert_that({ 'a':1,'b':2,'c':3 }).contains('a','b') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains('a') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains('a', 'b') if sys.version_info[0] == 3: - ordered = collections.OrderedDict([('z',9),('x',7),('y',8)]) + ordered = collections.OrderedDict([('z', 9), ('x', 7), ('y', 8)]) assert_that(ordered).contains('x') + def test_contains_empty_arg_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains() + assert_that({'a': 1, 'b': 2, 'c': 3}).contains() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') + def test_contains_single_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains('x') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains('x') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to contain key , but did not.') + def test_contains_single_item_dict_like_failure(): if sys.version_info[0] == 3: - ordered = collections.OrderedDict([('z',9),('x',7),('y',8)]) + ordered = collections.OrderedDict([('z', 9), ('x', 7), ('y', 8)]) try: assert_that(ordered).contains('a') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).ends_with('to contain key , but did not.') + def test_contains_multi_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains('a','x','z') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains('a', 'x', 'z') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain keys <'a', 'x', 'z'>, but did not contain keys <'x', 'z'>.") + def test_contains_multi_item_single_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains('a','b','z') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains('a', 'b', 'z') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain keys <'a', 'b', 'z'>, but did not contain keys .") + def test_contains_only(): - assert_that({'a':1,'b':2,'c':3}).contains_only('a','b','c') - assert_that(set(['a','b','c'])).contains_only('a','b','c') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_only('a', 'b', 'c') + assert_that(set(['a', 'b', 'c'])).contains_only('a', 'b', 'c') + def test_contains_only_failure(): try: - assert_that({'a':1,'b':2}).contains_only('a','x') + assert_that({'a': 1, 'b': 2}).contains_only('a', 'x') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain only <'a', 'x'>, but did contain .") + def test_contains_only_multi_failure(): try: - assert_that({'a':1,'b':2}).contains_only('x','y') + assert_that({'a': 1, 'b': 2}).contains_only('x', 'y') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain only <'x', 'y'>, but did contain <'") + def test_contains_key(): - assert_that({ 'a':1,'b':2,'c':3 }).contains_key('a') - assert_that({ 'a':1,'b':2,'c':3 }).contains_key('a','b') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_key('a') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_key('a', 'b') if sys.version_info[0] == 3: - ordered = collections.OrderedDict([('z',9),('x',7),('y',8)]) + ordered = collections.OrderedDict([('z', 9), ('x', 7), ('y', 8)]) assert_that(ordered).contains_key('x') + def test_contains_key_bad_val_failure(): try: assert_that(123).contains_key(1) @@ -119,9 +132,11 @@ def test_contains_key_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).contains('is not dict-like') + def test_does_not_contain_key(): - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_key('x') - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_key('x','y') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_key('x') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_key('x', 'y') + def test_does_not_contain_key_bad_val_failure(): try: @@ -130,58 +145,68 @@ def test_does_not_contain_key_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).contains('is not dict-like') + def test_contains_key_single_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_key('x') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_key('x') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).ends_with('to contain key , but did not.') + def test_contains_key_multi_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_key('a','x','z') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_key('a', 'x', 'z') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).ends_with("to contain keys <'a', 'x', 'z'>, but did not contain keys <'x', 'z'>.") + def test_does_not_contain(): - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain('x') - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain('x','y') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain('x') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain('x', 'y') + def test_does_not_contain_empty_arg_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain() + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') + def test_does_not_contain_single_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain('a') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain('a') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to not contain item , but did.') + def test_does_not_contain_list_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain('x','y','a') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain('x', 'y', 'a') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to not contain items <'x', 'y', 'a'>, but did contain .") + def test_is_empty(): assert_that({}).is_empty() + def test_is_empty_failure(): try: - assert_that({ 'a':1,'b':2 }).is_empty() + assert_that({'a': 1, 'b': 2}).is_empty() fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to be empty, but was not.') + def test_is_not_empty(): - assert_that({'a':1,'b':2}).is_not_empty() - assert_that(set(['a','b'])).is_not_empty() + assert_that({'a': 1, 'b': 2}).is_not_empty() + assert_that(set(['a', 'b'])).is_not_empty() + def test_is_not_empty_failure(): try: @@ -190,17 +215,20 @@ def test_is_not_empty_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected not empty, but was empty.') + def test_contains_value(): - assert_that({ 'a':1,'b':2,'c':3 }).contains_value(1) - assert_that({ 'a':1,'b':2,'c':3 }).contains_value(1,2) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_value(1) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_value(1, 2) + def test_contains_value_empty_arg_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_value() + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_value() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more value args must be given') + def test_contains_value_bad_val_failure(): try: assert_that('foo').contains_value('x') @@ -208,23 +236,27 @@ def test_contains_value_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).contains('is not dict-like') + def test_contains_value_single_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_value(4) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_value(4) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to contain values <4>, but did not contain <4>.') + def test_contains_value_multi_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_value(1,4,5) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_value(1, 4, 5) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to contain values <1, 4, 5>, but did not contain <4, 5>.') + def test_does_not_contain_value(): - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_value(4) - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_value(4,5) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_value(4) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_value(4, 5) + def test_does_not_contain_value_bad_val_failure(): try: @@ -233,149 +265,170 @@ def test_does_not_contain_value_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).contains('is not dict-like') + def test_does_not_contain_value_empty_arg_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_value() + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_value() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more value args must be given') + def test_does_not_contain_value_single_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_value(1) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_value(1) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to not contain values <1>, but did contain <1>.') + def test_does_not_contain_value_list_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_value(4,5,1) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_value(4, 5, 1) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to not contain values <4, 5, 1>, but did contain <1>.') + def test_does_not_contain_value_list_multi_item_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_value(4,1,2) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_value(4, 1, 2) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains('to not contain values <4, 1, 2>, but did contain <1, 2>.') + def test_contains_entry(): - assert_that({'a':1,'b':2,'c':3}).contains_entry({'a':1}) - assert_that({'a':1,'b':2,'c':3}).contains_entry({'a':1},{'b':2}) - assert_that({'a':1,'b':2,'c':3}).contains_entry({'a':1},{'b':2},{'c':3}) - assert_that({'a':1,'b':2,'c':3}).contains_entry(a=1) - assert_that({'a':1,'b':2,'c':3}).contains_entry(a=1, b=2) - assert_that({'a':1,'b':2,'c':3}).contains_entry(a=1, b=2, c=3) - assert_that({'a':1,'b':2,'c':3}).contains_entry({'a':1}, b=2) - assert_that({'a':1,'b':2,'c':3}).contains_entry({'b':2}, a=1, c=3) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}, {'b': 2}) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}, {'b': 2}, {'c': 3}) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry(a=1) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry(a=1, b=2) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry(a=1, b=2, c=3) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}, b=2) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'b': 2}, a=1, c=3) + def test_contains_entry_bad_val_failure(): try: - assert_that('foo').contains_entry({ 'a':1 }) + assert_that('foo').contains_entry({'a': 1}) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).contains('is not dict-like') + def test_contains_entry_empty_arg_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_entry() + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more entry args must be given') + def test_contains_entry_bad_arg_type_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_entry('x') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry('x') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given entry arg must be a dict') + def test_contains_entry_bad_arg_too_big_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_entry({ 'a':1, 'b':2 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1, 'b': 2}) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('given entry args must contain exactly one key-value pair') + def test_contains_entry_bad_key_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_entry({ 'x':1 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'x': 1}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain entries <{'x': 1}>, but did not contain <{'x': 1}>.") + def test_contains_entry_bad_value_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_entry({ 'a':2 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 2}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain entries <{'a': 2}>, but did not contain <{'a': 2}>.") + def test_contains_entry_bad_keys_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_entry({ 'a':1 },{ 'x':2 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}, {'x': 2}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain entries <{'a': 1}, {'x': 2}>, but did not contain <{'x': 2}>.") + def test_contains_entry_bad_values_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).contains_entry({ 'a':1 },{ 'b':4 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains_entry({'a': 1}, {'b': 4}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to contain entries <{'a': 1}, {'b': 4}>, but did not contain <{'b': 4}>.") + def test_does_not_contain_entry(): - assert_that({'a':1,'b':2,'c':3}).does_not_contain_entry({'a':2}) - assert_that({'a':1,'b':2,'c':3}).does_not_contain_entry({'a':2},{'b':1}) - assert_that({'a':1,'b':2,'c':3}).does_not_contain_entry(a=2) - assert_that({'a':1,'b':2,'c':3}).does_not_contain_entry(a=2,b=3) - assert_that({'a':1,'b':2,'c':3}).does_not_contain_entry({'x':4},y=5,z=6) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'a': 2}) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'a': 2}, {'b': 1}) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry(a=2) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry(a=2, b=3) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'x': 4}, y=5, z=6) + def test_does_not_contain_entry_bad_val_failure(): try: - assert_that('foo').does_not_contain_entry({ 'a':1 }) + assert_that('foo').does_not_contain_entry({'a': 1}) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).contains('is not dict-like') + def test_does_not_contain_entry_empty_arg_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_entry() + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more entry args must be given') + def test_does_not_contain_entry_bad_arg_type_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_entry('x') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry('x') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given entry arg must be a dict') + def test_does_not_contain_entry_bad_arg_too_big_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_entry({ 'a':1, 'b':2 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'a': 1, 'b': 2}) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('given entry args must contain exactly one key-value pair') + def test_does_not_contain_entry_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_entry({ 'a':1 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'a': 1}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to not contain entries <{'a': 1}>, but did contain <{'a': 1}>.") + def test_does_not_contain_entry_multiple_failure(): try: - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain_entry({ 'a':2 },{ 'b':2 }) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain_entry({'a': 2}, {'b': 2}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("to not contain entries <{'a': 2}, {'b': 2}>, but did contain <{'b': 2}>.") + def test_dynamic_assertion(): fred = {'first_name': 'Fred', 'last_name': 'Smith', 'shoe_size': 12} assert_that(fred).is_type_of(dict) @@ -388,6 +441,7 @@ def test_dynamic_assertion(): assert_that(fred).has_last_name('Smith') assert_that(fred).has_shoe_size(12) + def test_dynamic_assertion_failure_str(): fred = {'first_name': 'Fred', 'last_name': 'Smith', 'shoe_size': 12} @@ -397,6 +451,7 @@ def test_dynamic_assertion_failure_str(): except AssertionError as ex: assert_that(str(ex)).contains('Expected to be equal to on key , but was not.') + def test_dynamic_assertion_failure_int(): fred = {'first_name': 'Fred', 'last_name': 'Smith', 'shoe_size': 12} @@ -406,6 +461,7 @@ def test_dynamic_assertion_failure_int(): except AssertionError as ex: assert_that(str(ex)).contains('Expected <12> to be equal to <34> on key , but was not.') + def test_dynamic_assertion_bad_key_failure(): fred = {'first_name': 'Fred', 'last_name': 'Smith', 'shoe_size': 12} @@ -414,3 +470,16 @@ def test_dynamic_assertion_bad_key_failure(): fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected key , but val has no key .') + +def test_dynamic_assertion_on_reserved_word(): + fred = {'def': 'Fred'} + assert_that(fred).is_type_of(dict) + assert_that(fred['def']).is_equal_to('Fred') + assert_that(fred).has_def('Fred') + +def test_dynamic_assertion_on_dict_method(): + fred = {'update': 'Foo'} + fred.update({'update': 'Fred'}) + assert_that(fred).is_type_of(dict) + assert_that(fred['update']).is_equal_to('Fred') + assert_that(fred).has_update('Fred') diff --git a/tests/test_dict_compare.py b/tests/test_dict_compare.py index e6c1745..470b69b 100644 --- a/tests/test_dict_compare.py +++ b/tests/test_dict_compare.py @@ -29,256 +29,355 @@ import sys import collections -from assertpy import assert_that,fail +from assertpy import assert_that, fail + def test_ignore_key(): - assert_that({'a':1}).is_equal_to({}, ignore='a') - assert_that({'a':1,'b':2}).is_equal_to({'a':1}, ignore='b') - assert_that({'a':1,'b':2}).is_equal_to({'a':1,'b':2}, ignore='c') - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1}, ignore='b') + assert_that({'a': 1}).is_equal_to({}, ignore='a') + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, ignore='b') + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 2}, ignore='c') + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1}, ignore='b') + def test_ignore_list_of_keys(): - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':2,'c':3}, ignore=[]) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':2}, ignore=['c']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1}, ignore=['b','c']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({}, ignore=['a','b','c']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':2,'c':3}, ignore=['d']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'b':2}, ignore=['c','d','e','a']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2, 'c': 3}, ignore=[]) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2}, ignore=['c']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, ignore=['b', 'c']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({}, ignore=['a', 'b', 'c']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2, 'c': 3}, ignore=['d']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'b': 2}, ignore=['c', 'd', 'e', 'a']) + def test_ignore_deep_key(): - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1}, ignore=('b')) - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1}, ignore=[('b',)]) - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1,'b':{'x':2}}, ignore=('b','y')) - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1,'b':{'x':2}}, ignore=[('b','y')]) - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1,'b':{'x':2}}, ignore=[('b','y'),('b','x','j')]) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({}, ignore=[('a'),('b')]) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'a':1}, ignore=('b')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'a':1,'b':{'c':2}}, ignore=('b','d')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'a':1,'b':{'c':2,'d':{'e':3}}}, ignore=('b','d','f')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':6}}}}, ignore=('b','d','f','y')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}, ignore=('b','d','f','y','foo')) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1}, ignore=('b')) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1}, ignore=[('b', )]) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1, 'b': {'x': 2}}, ignore=('b', 'y')) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1, 'b': {'x': 2}}, ignore=[('b', 'y')]) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1, 'b': {'x': 2}}, ignore=[('b', 'y'), ('b', 'x', 'j')]) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({}, ignore=[('a'), ('b')]) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'a': 1}, ignore=('b')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'a': 1, 'b': {'c': 2}}, ignore=('b', 'd')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'a': 1, 'b': {'c': 2, 'd': {'e': 3}}}, ignore=('b', 'd', 'f')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to( + {'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 6}}}}, ignore=('b', 'd', 'f', 'y')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to( + {'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}, ignore=('b', 'd', 'f', 'y', 'foo')) + def test_ordered(): - if sys.version_info[0] == 3: - ordered = collections.OrderedDict([('a',1),('b',2)]) - assert_that(ordered).is_equal_to({'a':1,'b':2}) + if sys.version_info[0] == 3: + ordered = collections.OrderedDict([('a', 1), ('b', 2)]) + assert_that(ordered).is_equal_to({'a': 1, 'b': 2}) + def test_failure(): try: - assert_that({'a':1,'b':2}).is_equal_to({'a':1,'b':3}) + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 3}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 'b': 2}> to be equal to <{.., 'b': 3}>, but was not.") + def test_failure_single_entry(): try: - assert_that({'a':1}).is_equal_to({'a':2}) + assert_that({'a': 1}).is_equal_to({'a': 2}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to be equal to <{'a': 2}>, but was not.") + def test_failure_multi_entry(): try: - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':3,'c':3}) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 3, 'c': 3}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 'b': 2}> to be equal to <{.., 'b': 3}>, but was not.") + def test_failure_multi_entry_failure(): try: - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':3,'c':4}) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 3, 'c': 4}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).contains("'b': 2").contains("'b': 3").contains("'c': 3").contains("'c': 4").ends_with('but was not.') + def test_failure_deep_dict(): try: - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1,'b':{'x':2,'y':4}}) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1, 'b': {'x': 2, 'y': 4}}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 'b': {.., 'y': 3}}> to be equal to <{.., 'b': {.., 'y': 4}}>, but was not.") + def test_failure_deep_dict_single_key(): try: - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1,'b':{'x':2}}) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1, 'b': {'x': 2}}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 'b': {.., 'y': 3}}> to be equal to <{.., 'b': {..}}>, but was not.") + def test_failure_very_deep_dict(): try: - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':6}}}}) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 6}}}}) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).is_equal_to("Expected <{.., 'b': {.., 'd': {.., 'f': {.., 'y': 5}}}}> to be equal to <{.., 'b': {.., 'd': {.., 'f': {.., 'y': 6}}}}>, but was not.") + assert_that(str(ex)).is_equal_to( + "Expected <{.., 'b': {.., 'd': {.., 'f': {.., 'y': 5}}}}> to be equal to <{.., 'b': {.., 'd': {.., 'f': {.., 'y': 6}}}}>, but was not.") + def test_failure_ignore(): try: - assert_that({'a':1,'b':2}).is_equal_to({'a':1,'b':3}, ignore='c') + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 3}, ignore='c') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 'b': 2}> to be equal to <{.., 'b': 3}> ignoring keys , but was not.") + def test_failure_ignore_single_entry(): try: - assert_that({'a':1}).is_equal_to({'a':2}, ignore='c') + assert_that({'a': 1}).is_equal_to({'a': 2}, ignore='c') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to be equal to <{'a': 2}> ignoring keys , but was not.") + def test_failure_ignore_multi_keys(): try: - assert_that({'a':1}).is_equal_to({'a':2}, ignore=['x','y','z']) + assert_that({'a': 1}).is_equal_to({'a': 2}, ignore=['x', 'y', 'z']) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to be equal to <{'a': 2}> ignoring keys <'x', 'y', 'z'>, but was not.") + def test_failure_ignore_multi_deep_keys(): try: - assert_that({'a':1}).is_equal_to({'a':2}, ignore=[('q','r','s'),('x','y','z')]) + assert_that({'a': 1}).is_equal_to({'a': 2}, ignore=[('q', 'r', 's'), ('x', 'y', 'z')]) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to be equal to <{'a': 2}> ignoring keys <'q.r.s', 'x.y.z'>, but was not.") + def test_failure_ignore_mixed_keys(): try: - assert_that({'a':1}).is_equal_to({'a':2}, ignore=['b',('c'),('d','e'),('q','r','s'),('x','y','z')]) + assert_that({'a': 1}).is_equal_to({'a': 2}, ignore=['b', ('c'), ('d', 'e'), ('q', 'r', 's'), ('x', 'y', 'z')]) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to be equal to <{'a': 2}> ignoring keys <'b', 'c', 'd.e', 'q.r.s', 'x.y.z'>, but was not.") + def test_failure_int_keys(): try: - assert_that({1:'a',2:'b'}).is_equal_to({1:'a',3:'b'}) + assert_that({1: 'a', 2: 'b'}).is_equal_to({1: 'a', 3: 'b'}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 2: 'b'}> to be equal to <{.., 3: 'b'}>, but was not.") + def test_failure_deep_int_keys(): try: - assert_that({1:'a',2:{3:'b',4:'c'}}).is_equal_to({1:'a',2:{3:'b',5:'c'}}, ignore=(2,3)) + assert_that({1: 'a', 2: {3: 'b', 4: 'c'}}).is_equal_to({1: 'a', 2: {3: 'b', 5: 'c'}}, ignore=(2, 3)) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 2: {.., 4: 'c'}}> to be equal to <{.., 2: {.., 5: 'c'}}> ignoring keys <2.3>, but was not.") + def test_failure_tuple_keys(): try: - assert_that({(1,2):'a',(3,4):'b'}).is_equal_to({(1,2):'a',(3,4):'c'}) + assert_that({(1, 2): 'a', (3, 4): 'b'}).is_equal_to({(1, 2): 'a', (3, 4): 'c'}) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., (3, 4): 'b'}> to be equal to <{.., (3, 4): 'c'}>, but was not.") + def test_failure_tuple_keys_ignore(): try: - assert_that({(1,2):'a',(3,4):'b'}).is_equal_to({(1,2):'a',(3,4):'c'}, ignore=(1,2)) + assert_that({(1, 2): 'a', (3, 4): 'b'}).is_equal_to({(1, 2): 'a', (3, 4): 'c'}, ignore=(1, 2)) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., (3, 4): 'b'}> to be equal to <{.., (3, 4): 'c'}> ignoring keys <1.2>, but was not.") + def test_failure_deep_tuple_keys_ignore(): try: - assert_that({(1,2):'a',(3,4):{(5,6):'b',(7,8):'c'}}).is_equal_to({(1,2):'a',(3,4):{(5,6):'b',(7,8):'d'}}, ignore=((3,4),(5,6))) + assert_that({(1, 2): 'a', (3, 4): {(5, 6): 'b', (7, 8): 'c'}}).is_equal_to({(1, 2): 'a', (3, 4): {(5, 6): 'b', (7, 8): 'd'}}, ignore=((3, 4), (5, 6))) fail('should have raised error') except AssertionError as ex: - assert_that(str(ex)).is_equal_to("Expected <{.., (3, 4): {.., (7, 8): 'c'}}> to be equal to <{.., (3, 4): {.., (7, 8): 'd'}}> ignoring keys <(3, 4).(5, 6)>, but was not.") + assert_that(str(ex)).is_equal_to( + "Expected <{.., (3, 4): {.., (7, 8): 'c'}}> to be equal to <{.., (3, 4): {.., (7, 8): 'd'}}> ignoring keys <(3, 4).(5, 6)>, but was not.") + def test_failure_single_item_tuple_keys_ignore(): # due to unpacking-fu, single item tuple keys must be tupled in ignore statement, so this works: - assert_that({(1,):'a',(2,):'b'}).is_equal_to({(1,):'a',(2,):'c'}, ignore=((2,),)) + assert_that({(1,): 'a', (2,): 'b'}).is_equal_to({(1,): 'a', (2,): 'c'}, ignore=((2,), )) # but this fails: try: - assert_that({(1,):'a',(2,):'b'}).is_equal_to({(1,):'a'}, ignore=(2,)) + assert_that({(1,): 'a', (2,): 'b'}).is_equal_to({(1,): 'a'}, ignore=(2, )) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., (2,): 'b'}> to be equal to <{..}> ignoring keys <2>, but was not.") + def test_failure_single_item_tuple_keys_ignore_error_msg(): try: - assert_that({(1,):'a'}).is_equal_to({(1,):'b'}, ignore=((2,),)) + assert_that({(1,): 'a'}).is_equal_to({(1,): 'b'}, ignore=((2,), )) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{(1,): 'a'}> to be equal to <{(1,): 'b'}> ignoring keys <2>, but was not.") + def test_include_key(): - assert_that({'a':1,'b':2}).is_equal_to({'a':1}, include='a') - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'a':1}, include='a') - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'b':{'x':2,'y':3}}, include='b') + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, include='a') + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'a': 1}, include='a') + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'b': {'x': 2, 'y': 3}}, include='b') + def test_include_list_of_keys(): - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':2,'c':3}, include=['a','b','c']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':2}, include=['a','b']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1}, include=['a']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'b':2}, include=['b']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'c':3}, include=['c']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2, 'c': 3}, include=['a', 'b', 'c']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2}, include=['a', 'b']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, include=['a']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'b': 2}, include=['b']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'c': 3}, include=['c']) + def test_include_deep_key(): - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'b':{'x':2,'y':3}}, include=('b')) - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'b':{'x':2}}, include=('b','x')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}, include=('b')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'c':2}}, include=('b','c')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'d':{'e':3,'f':{'x':4,'y':5}}}}, include=('b','d')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'d':{'e':3,}}}, include=('b','d','e')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'d':{'f':{'x':4,'y':5}}}}, include=('b','d','f')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'d':{'f':{'x':4}}}}, include=('b','d','f','x')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'d':{'f':{'y':5}}}}, include=('b','d','f','y')) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'b': {'x': 2, 'y': 3}}, include=('b')) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'b': {'x': 2}}, include=('b', 'x')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}, include=('b')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'b': {'c': 2}}, include=('b', 'c')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'b': {'d': {'e': 3, 'f': {'x': 4, 'y': 5}}}}, include=('b', 'd')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'b': {'d': {'e': 3, }}}, include=('b', 'd', 'e')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'b': {'d': {'f': {'x': 4, 'y': 5}}}}, include=('b', 'd', 'f')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'b': {'d': {'f': {'x': 4}}}}, include=('b', 'd', 'f', 'x')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to({'b': {'d': {'f': {'y': 5}}}}, include=('b', 'd', 'f', 'y')) + def test_failure_include(): try: - assert_that({'a':1}).is_equal_to({'a':2}, include='a') + assert_that({'a': 1}).is_equal_to({'a': 2}, include='a') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to be equal to <{'a': 2}> including keys , but was not.") + def test_failure_include_missing(): try: - assert_that({'a':1}).is_equal_to({'a':1}, include='b') + assert_that({'a': 1}).is_equal_to({'a': 1}, include='b') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to include key , but did not include key .") + def test_failure_include_multiple_missing(): try: - assert_that({'a':1}).is_equal_to({'a':1}, include=['b','c']) + assert_that({'a': 1}).is_equal_to({'a': 1}, include=['b', 'c']) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': 1}> to include keys <'b', 'c'>, but did not include keys <'b', 'c'>.") + def test_failure_include_deep_missing(): try: - assert_that({'a':{'b':2}}).is_equal_to({'a':{'c':3}}, include=('a','c')) + assert_that({'a': {'b': 2}}).is_equal_to({'a': {'c': 3}}, include=('a', 'c')) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'b': 2}> to include key , but did not include key .") + def test_failure_include_multi_keys(): try: - assert_that({'a':1,'b':2}).is_equal_to({'a':1,'b':3}, include=['a','b']) + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 3}, include=['a', 'b']) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{.., 'b': 2}> to be equal to <{.., 'b': 3}> including keys <'a', 'b'>, but was not.") + def test_failure_include_deep_keys(): try: - assert_that({'a':{'b':1}}).is_equal_to({'a':{'b':2}}, include=('a','b')) + assert_that({'a': {'b': 1}}).is_equal_to({'a': {'b': 2}}, include=('a', 'b')) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <{'a': {'b': 1}}> to be equal to <{'a': {'b': 2}}> including keys , but was not.") + def test_ignore_and_include_key(): - assert_that({'a':1}).is_equal_to({}, ignore='a', include='a') - assert_that({'a':1,'b':2}).is_equal_to({'a':1}, ignore='b', include='a') - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'b':{'y':3}}, ignore=('b','x'), include='b') + assert_that({'a': 1}).is_equal_to({}, ignore='a', include='a') + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, ignore='b', include='a') + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'b': {'y': 3}}, ignore=('b', 'x'), include='b') + def test_ignore_and_include_list_of_keys(): - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'c':3}, ignore=['b'], include=['a','b','c']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':2}, ignore=['c'], include=['a','b']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1}, ignore=['b','c'], include=['a','b']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1}, ignore=['c'], include=['a']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'b':2}, ignore=['a'], include=['b']) - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'c':3}, ignore=['b'], include=['c']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'c': 3}, ignore=['b'], include=['a', 'b', 'c']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2}, ignore=['c'], include=['a', 'b']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, ignore=['b', 'c'], include=['a', 'b']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, ignore=['c'], include=['a']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'b': 2}, ignore=['a'], include=['b']) + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'c': 3}, ignore=['b'], include=['c']) + def test_ignore_and_include_deep_key(): - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'b':{'x':2,'y':3}}, ignore=('a'), include=('b')) - assert_that({'a':1,'b':{'x':2,'y':3}}).is_equal_to({'b':{'x':2}}, ignore=('b','y'), include=('b','x')) - assert_that({'a':1,'b':{'c':2,'d':{'e':3,'f':{'x':4,'y':5}}}}).is_equal_to({'b':{'c':2,'d':{'e':3}}}, ignore=('b','d','f'), include=('b')) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'b': {'x': 2, 'y': 3}}, ignore=('a'), include=('b')) + assert_that({'a': 1, 'b': {'x': 2, 'y': 3}}).is_equal_to({'b': {'x': 2}}, ignore=('b', 'y'), include=('b', 'x')) + assert_that({'a': 1, 'b': {'c': 2, 'd': {'e': 3, 'f': {'x': 4, 'y': 5}}}}).is_equal_to( + {'b': {'c': 2, 'd': {'e': 3}}}, ignore=('b', 'd', 'f'), include=('b')) + + +def test_ignore_deep_sibling_key(): + d1 = {'a': 1, 'b': {'c': 2, 'd': {'e': 3}}} + d2 = {'a': 1, 'b': {'c': 3, 'd': {'e': 3}}} + assert_that(d1).is_equal_to(d2, ignore=('b', 'c')) + + +def test_ignore_nested_deep_sibling_key(): + d1 = {'a': 1, 'b': {'c': 2, 'd': {'e': 3}}} + d2 = {'a': 1, 'b': {'c': 2, 'd': {'e': 4}}} + assert_that(d1).is_equal_to(d2, ignore=('b', 'd')) + + +def test_failure_deep_mismatch_when_ignoring_nested_deep_key(): + d1 = {'a': 1, 'b': {'c': 2, 'd': {'e': 3}}} + d2 = {'a': 1, 'b': {'c': 3, 'd': {'e': 4}}} + try: + assert_that(d1).is_equal_to(d2, ignore=('b', 'd')) + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to("Expected <{.., 'b': {'c': 2, 'd': {'e': 3}}}> to be equal to <{.., 'b': {'c': 3, 'd': {'e': 4}}}> ignoring keys , but was not.") + + +def test_failure_top_mismatch_when_ignoring_single_nested_key(): + d1 = {'a': 1, 'b': {'c': 2}} + d2 = {'a': 2, 'b': {'c': 3}} + try: + assert_that(d1).is_equal_to(d2, ignore=('b', 'c')) + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to("Expected <{'a': 1, 'b': {'c': 2}}> to be equal to <{'a': 2, 'b': {'c': 3}}> ignoring keys , but was not.") + + +def test_failure_top_mismatch_when_ignoring_single_nested_sibling_key(): + d1 = {'a': 1, 'b': {'c': 2, 'd': {'e': 3}}} + d2 = {'a': 2, 'b': {'c': 2, 'd': {'e': 4}}} + try: + assert_that(d1).is_equal_to(d2, ignore=('b', 'd')) + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to("Expected <{'a': 1, 'b': {.., 'd': {'e': 3}}}> to be equal to <{'a': 2, 'b': {.., 'd': {'e': 4}}}> ignoring keys , but was not.") + + +def test_failure_deep_mismatch_when_ignoring_double_nested_sibling_key(): + d1 = {'a': 1, 'b': {'c': 2, 'd': {'e': 3}, 'f': {'g': 5}}} + d2 = {'a': 1, 'b': {'c': 2, 'd': {'e': 4}, 'f': {'g': 5}}} + try: + assert_that(d1).is_equal_to(d2, ignore=('b', 'f', 'g')) + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to("Expected <{.., 'b': {.., 'd': {'e': 3}}}> to be equal to <{.., 'b': {.., 'd': {'e': 4}}}> ignoring keys , but was not.") + + +def test_ignore_all_nested_keys(): + assert_that({'a': {'b': 1}}).is_equal_to({}, ignore='a') + assert_that({'a': {'b': 1}}).is_equal_to({'a': {}}, ignore=[('a', 'b')]) + assert_that({'a': {'b': 1, 'c': 2}}).is_equal_to({'a': {}}, ignore=[('a', 'b'), ('a', 'c')]) + assert_that({'a': 1, 'b': {'c': 2}}).is_equal_to({'b': {}}, ignore=['a', ('b', 'c')]) diff --git a/tests/test_dyn.py b/tests/test_dyn.py index 09bcac0..7647342 100644 --- a/tests/test_dyn.py +++ b/tests/test_dyn.py @@ -26,7 +26,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail class Person(object): @@ -46,7 +46,8 @@ def say_goodbye(self, target): return 'Bye, %s!' % target -fred = Person('Fred','Smith',12) +fred = Person('Fred', 'Smith', 12) + def test_dynamic_assertion(): assert_that(fred).is_type_of(Person) @@ -60,14 +61,17 @@ def test_dynamic_assertion(): assert_that(fred).has_last_name('Smith') assert_that(fred).has_shoe_size(12) + def test_dynamic_assertion_on_property(): assert_that(fred.name).is_equal_to('Fred Smith') assert_that(fred).has_name('Fred Smith') + def test_dynamic_assertion_on_method(): assert_that(fred.say_hello()).is_equal_to('Hello, Fred!') assert_that(fred).has_say_hello('Hello, Fred!') + def test_dynamic_assertion_failure(): try: assert_that(fred).has_first_name('Joe') @@ -75,6 +79,7 @@ def test_dynamic_assertion_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be equal to on attribute , but was not.') + def test_dynamic_assertion_bad_name_failure(): try: assert_that(fred).foo() @@ -82,6 +87,7 @@ def test_dynamic_assertion_bad_name_failure(): except AttributeError as ex: assert_that(str(ex)).is_equal_to('assertpy has no assertion ') + def test_dynamic_assertion_unknown_attribute_failure(): try: assert_that(fred).has_foo() @@ -89,6 +95,7 @@ def test_dynamic_assertion_unknown_attribute_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected attribute , but val has no attribute .') + def test_dynamic_assertion_no_args_failure(): try: assert_that(fred).has_first_name() @@ -96,13 +103,15 @@ def test_dynamic_assertion_no_args_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('assertion takes exactly 1 argument (0 given)') + def test_dynamic_assertion_too_many_args_failure(): try: - assert_that(fred).has_first_name('Fred','Joe') + assert_that(fred).has_first_name('Fred', 'Joe') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('assertion takes exactly 1 argument (2 given)') + def test_dynamic_assertion_on_method_failure(): try: assert_that(fred).has_say_goodbye('Foo') @@ -110,6 +119,6 @@ def test_dynamic_assertion_on_method_failure(): except TypeError as ex: assert_that(str(ex)).contains('val does not have zero-arg method ') + def test_chaining(): assert_that(fred).has_first_name('Fred').has_last_name('Smith').has_shoe_size(12) - diff --git a/tests/test_equals.py b/tests/test_equals.py index d309374..36e84e4 100644 --- a/tests/test_equals.py +++ b/tests/test_equals.py @@ -26,19 +26,20 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_is_equal(): assert_that('foo').is_equal_to('foo') assert_that(123).is_equal_to(123) assert_that(0.11).is_equal_to(0.11) - assert_that(['a','b']).is_equal_to(['a','b']) - assert_that((1,2,3)).is_equal_to((1,2,3)) + assert_that(['a', 'b']).is_equal_to(['a', 'b']) + assert_that((1, 2, 3)).is_equal_to((1, 2, 3)) assert_that(1 == 1).is_equal_to(True) assert_that(1 == 2).is_equal_to(False) - assert_that(set(['a','b'])).is_equal_to(set(['b','a'])) - assert_that({ 'a':1,'b':2 }).is_equal_to({ 'b':2,'a':1 }) + assert_that(set(['a', 'b'])).is_equal_to(set(['b', 'a'])) + assert_that({'a': 1, 'b': 2}).is_equal_to({'b': 2, 'a': 1}) + def test_is_equal_failure(): try: @@ -47,6 +48,7 @@ def test_is_equal_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be equal to , but was not.') + def test_is_equal_int_failure(): try: assert_that(123).is_equal_to(234) @@ -54,26 +56,29 @@ def test_is_equal_int_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be equal to <234>, but was not.') + def test_is_equal_list_failure(): try: - assert_that(['a','b']).is_equal_to(['a','b','c']) + assert_that(['a', 'b']).is_equal_to(['a', 'b', 'c']) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b']> to be equal to <['a', 'b', 'c']>, but was not.") + def test_is_not_equal(): assert_that('foo').is_not_equal_to('bar') assert_that(123).is_not_equal_to(234) assert_that(0.11).is_not_equal_to(0.12) - assert_that(['a','b']).is_not_equal_to(['a','x']) - assert_that(['a','b']).is_not_equal_to(['a']) - assert_that(['a','b']).is_not_equal_to(['a','b','c']) - assert_that((1,2,3)).is_not_equal_to((1,2)) + assert_that(['a', 'b']).is_not_equal_to(['a', 'x']) + assert_that(['a', 'b']).is_not_equal_to(['a']) + assert_that(['a', 'b']).is_not_equal_to(['a', 'b', 'c']) + assert_that((1, 2, 3)).is_not_equal_to((1, 2)) assert_that(1 == 1).is_not_equal_to(False) assert_that(1 == 2).is_not_equal_to(True) - assert_that(set(['a','b'])).is_not_equal_to(set(['a'])) - assert_that({ 'a':1,'b':2 }).is_not_equal_to({ 'a':1,'b':3 }) - assert_that({ 'a':1,'b':2 }).is_not_equal_to({ 'a':1,'c':2 }) + assert_that(set(['a', 'b'])).is_not_equal_to(set(['a'])) + assert_that({'a': 1, 'b': 2}).is_not_equal_to({'a': 1, 'b': 3}) + assert_that({'a': 1, 'b': 2}).is_not_equal_to({'a': 1, 'c': 2}) + def test_is_not_equal_failure(): try: @@ -82,6 +87,7 @@ def test_is_not_equal_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be not equal to , but was.') + def test_is_not_equal_int_failure(): try: assert_that(123).is_not_equal_to(123) @@ -89,9 +95,10 @@ def test_is_not_equal_int_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be not equal to <123>, but was.') + def test_is_not_equal_list_failure(): try: - assert_that(['a','b']).is_not_equal_to(['a','b']) + assert_that(['a', 'b']).is_not_equal_to(['a', 'b']) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b']> to be not equal to <['a', 'b']>, but was.") diff --git a/tests/test_expected_exception.py b/tests/test_expected_exception.py index acbebe5..d5fc4f8 100644 --- a/tests/test_expected_exception.py +++ b/tests/test_expected_exception.py @@ -36,10 +36,12 @@ def test_expected_exception(): assert_that(func_kwargs).raises(RuntimeError).when_called_with(foo=1, bar=2, baz=3) assert_that(func_all).raises(RuntimeError).when_called_with('a', 'b', 3, 4, foo=1, bar=2, baz='dog') + def test_expected_exception_method(): foo = Foo() assert_that(foo.bar).raises(RuntimeError).when_called_with().is_equal_to('method err') + def test_expected_exception_chaining(): assert_that(func_no_arg).raises(RuntimeError).when_called_with()\ .is_equal_to('no arg err') @@ -52,6 +54,7 @@ def test_expected_exception_chaining(): assert_that(func_all).raises(RuntimeError).when_called_with('a', 'b', 3, 4, foo=1, bar=2, baz='dog')\ .starts_with('all err: arg1=a, arg2=b, args=(3, 4), kwargs=[') + def test_expected_exception_no_arg_failure(): try: assert_that(func_noop).raises(RuntimeError).when_called_with() @@ -60,6 +63,7 @@ def test_expected_exception_no_arg_failure(): assert_that(str(ex)).is_equal_to( 'Expected to raise when called with ().') + def test_expected_exception_no_arg_bad_func_failure(): try: assert_that(123).raises(int).when_called_with() @@ -67,6 +71,7 @@ def test_expected_exception_no_arg_bad_func_failure(): except TypeError as ex: assert_that(str(ex)).contains('val must be callable') + def test_expected_exception_no_arg_bad_exception_failure(): try: assert_that(func_noop).raises(int).when_called_with() @@ -74,6 +79,7 @@ def test_expected_exception_no_arg_bad_exception_failure(): except TypeError as ex: assert_that(str(ex)).contains('given arg must be exception') + def test_expected_exception_no_arg_wrong_exception_failure(): try: assert_that(func_no_arg).raises(TypeError).when_called_with() @@ -81,6 +87,7 @@ def test_expected_exception_no_arg_wrong_exception_failure(): except AssertionError as ex: assert_that(str(ex)).contains('Expected to raise when called with (), but raised .') + def test_expected_exception_no_arg_missing_raises_failure(): try: assert_that(func_noop).when_called_with() @@ -88,6 +95,7 @@ def test_expected_exception_no_arg_missing_raises_failure(): except TypeError as ex: assert_that(str(ex)).contains('expected exception not set, raises() must be called first') + def test_expected_exception_one_arg_failure(): try: assert_that(func_noop).raises(RuntimeError).when_called_with('foo') @@ -96,6 +104,7 @@ def test_expected_exception_one_arg_failure(): assert_that(str(ex)).is_equal_to( "Expected to raise when called with ('foo').") + def test_expected_exception_multi_args_failure(): try: assert_that(func_noop).raises(RuntimeError).when_called_with('foo', 'bar', 'baz') @@ -103,6 +112,7 @@ def test_expected_exception_multi_args_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected to raise when called with ('foo', 'bar', 'baz').") + def test_expected_exception_kwargs_failure(): try: assert_that(func_noop).raises(RuntimeError).when_called_with(foo=1, bar=2, baz=3) @@ -111,6 +121,7 @@ def test_expected_exception_kwargs_failure(): assert_that(str(ex)).is_equal_to( "Expected to raise when called with ('bar': 2, 'baz': 3, 'foo': 1).") + def test_expected_exception_all_failure(): try: assert_that(func_noop).raises(RuntimeError).when_called_with('a', 'b', 3, 4, foo=1, bar=2, baz='dog') @@ -119,28 +130,36 @@ def test_expected_exception_all_failure(): assert_that(str(ex)).is_equal_to( "Expected to raise when called with ('a', 'b', 3, 4, 'bar': 2, 'baz': 'dog', 'foo': 1).") + def test_expected_exception_arg_passing(): assert_that(func_all).raises(RuntimeError).when_called_with('a', 'b', 3, 4, foo=1, bar=2, baz='dog').is_equal_to( "all err: arg1=a, arg2=b, args=(3, 4), kwargs=[('bar', 2), ('baz', 'dog'), ('foo', 1)]") + # helpers def func_noop(*args, **kwargs): pass + def func_no_arg(): raise RuntimeError('no arg err') + def func_one_arg(arg): raise RuntimeError('one arg err') + def func_multi_args(*args): raise RuntimeError('multi args err') + def func_kwargs(**kwargs): raise RuntimeError('kwargs err') + def func_all(arg1, arg2, *args, **kwargs): - raise RuntimeError('all err: arg1=%s, arg2=%s, args=%s, kwargs=%s' % (arg1, arg2, args, [(k,kwargs[k]) for k in sorted(kwargs.keys())])) + raise RuntimeError('all err: arg1=%s, arg2=%s, args=%s, kwargs=%s' % (arg1, arg2, args, [(k, kwargs[k]) for k in sorted(kwargs.keys())])) + class Foo(object): def bar(self): diff --git a/tests/test_extensions.py b/tests/test_extensions.py index b660b37..fb1430d 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -26,46 +26,56 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that, add_extension, remove_extension, fail import numbers +from assertpy import assert_that, add_extension, remove_extension, fail def is_even(self): if isinstance(self.val, numbers.Integral) is False: raise TypeError('val must be an integer') if self.val % 2 != 0: - self._err('Expected <%s> to be even, but was not.' % (self.val)) + return self.error('Expected <%s> to be even, but was not.' % (self.val)) return self + def is_multiple_of(self, other): - # validate actual value - must be "integer" (aka int or long) if isinstance(self.val, numbers.Integral) is False or self.val <= 0: - # bad input is error, not an assertion fail, so raise error raise TypeError('val must be a positive integer') - # validate expected value if isinstance(other, numbers.Integral) is False or other <= 0: raise TypeError('given arg must be a positive integer') - # divide and compute remainder using divmod() built-in _, rem = divmod(self.val, other) + if rem > 0: + return self.error('Expected <%s> to be multiple of <%s>, but was not.' % (self.val, other)) + + return self + + +def is_factor_of(self, other): + if isinstance(self.val, numbers.Integral) is False or self.val <= 0: + raise TypeError('val must be a positive integer') - # test the negative (is remainder non-zero?) + if isinstance(other, numbers.Integral) is False or other <= 0: + raise TypeError('given arg must be a positive integer') + + _, rem = divmod(other, self.val) if rem > 0: - # non-zero remainder, so not multiple -> we fail! - self._err('Expected <%s> to be multiple of <%s>, but was not.' % (self.val, other)) + return self.error('Expected <%s> to be factor of <%s>, but was not.' % (self.val, other)) - # success, and return self to allow chaining return self + add_extension(is_even) add_extension(is_multiple_of) +add_extension(is_factor_of) def test_is_even_extension(): assert_that(124).is_even() assert_that(124).is_type_of(int).is_even().is_greater_than(123).is_less_than(125).is_equal_to(124) + def test_is_even_extension_failure(): try: assert_that(123).is_even() @@ -73,6 +83,7 @@ def test_is_even_extension_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be even, but was not.') + def test_is_even_extension_failure_not_callable(): try: add_extension('foo') @@ -80,6 +91,7 @@ def test_is_even_extension_failure_not_callable(): except TypeError as ex: assert_that(str(ex)).is_equal_to('func must be callable') + def test_is_even_extension_failure_not_integer(): try: assert_that(124.0).is_even() @@ -87,6 +99,7 @@ def test_is_even_extension_failure_not_integer(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be an integer') + def test_is_multiple_of_extension(): assert_that(24).is_multiple_of(1) assert_that(24).is_multiple_of(2) @@ -98,6 +111,7 @@ def test_is_multiple_of_extension(): assert_that(24).is_multiple_of(24) assert_that(124).is_type_of(int).is_even().is_multiple_of(31).is_equal_to(124) + def test_is_multiple_of_extension_failure(): try: assert_that(24).is_multiple_of(5) @@ -105,6 +119,7 @@ def test_is_multiple_of_extension_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <24> to be multiple of <5>, but was not.') + def test_is_multiple_of_extension_failure_bad_val(): try: assert_that(24.0).is_multiple_of(5) @@ -112,6 +127,7 @@ def test_is_multiple_of_extension_failure_bad_val(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be a positive integer') + def test_is_multiple_of_extension_failure_negative_val(): try: assert_that(-24).is_multiple_of(6) @@ -119,6 +135,7 @@ def test_is_multiple_of_extension_failure_negative_val(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must be a positive integer') + def test_is_multiple_of_extension_failure_bad_arg(): try: assert_that(24).is_multiple_of('foo') @@ -126,6 +143,7 @@ def test_is_multiple_of_extension_failure_bad_arg(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a positive integer') + def test_is_multiple_of_extension_failure_negative_arg(): try: assert_that(24).is_multiple_of(-6) @@ -133,30 +151,54 @@ def test_is_multiple_of_extension_failure_negative_arg(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a positive integer') + +def test_is_factor_of_extension(): + assert_that(1).is_factor_of(24) + assert_that(2).is_factor_of(24) + assert_that(3).is_factor_of(24) + assert_that(4).is_factor_of(24) + assert_that(6).is_factor_of(24) + assert_that(8).is_factor_of(24) + assert_that(12).is_factor_of(24) + assert_that(24).is_factor_of(24) + assert_that(31).is_type_of(int).is_factor_of(124).is_equal_to(31) + + +def test_is_factor_of_extension_failure(): + try: + assert_that(5).is_factor_of(24) + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to('Expected <5> to be factor of <24>, but was not.') + + def test_call_missing_extension(): def is_missing(): pass try: remove_extension(is_even) remove_extension(is_multiple_of) + remove_extension(is_factor_of) remove_extension(is_missing) assert_that(24).is_multiple_of(6) fail('should have raised error') except AttributeError as ex: assert_that(str(ex)).is_equal_to('assertpy has no assertion ') + def test_remove_bad_extension(): - def is_missing(): pass try: remove_extension('foo') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('func must be callable') + def is_foo(self): if self.val != 'foo': - self._err('Expected <%s> to be foo, but was not.' % (self.val)) + return self.error('Expected <%s> to be foo, but was not.' % (self.val)) return self + def dupe1(): add_extension(is_foo) assert_that('foo').is_foo() @@ -166,12 +208,13 @@ def dupe1(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be foo, but was not.') + def dupe2(): def is_foo(self): if self.val != 'FOO': - self._err('Expected <%s> to be FOO, but was not.' % (self.val)) + return self.error('Expected <%s> to be FOO, but was not.' % (self.val)) return self - + add_extension(is_foo) assert_that('FOO').is_foo() try: @@ -180,7 +223,8 @@ def is_foo(self): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be FOO, but was not.') + def test_dupe_extensions(): dupe1() dupe2() - dupe1() \ No newline at end of file + dupe1() diff --git a/tests/test_extracting.py b/tests/test_extracting.py index e5d9915..b443064 100644 --- a/tests/test_extracting.py +++ b/tests/test_extracting.py @@ -27,7 +27,8 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys -from assertpy import assert_that,fail +from assertpy import assert_that, fail + class Person(object): def __init__(self, first_name, last_name, shoe_size): @@ -48,21 +49,26 @@ def say_hello(self, name): def test_extracting_property(): - assert_that(people).extracting('first_name').contains('Fred','John') + assert_that(people).extracting('first_name').contains('Fred', 'John') + def test_extracting_multiple_properties(): - assert_that(people).extracting('first_name', 'last_name', 'shoe_size').contains(('Fred','Smith',12), ('John','Jones',9.5)) + assert_that(people).extracting('first_name', 'last_name', 'shoe_size').contains(('Fred', 'Smith', 12), ('John', 'Jones', 9.5)) + def test_extracting_zero_arg_method(): assert_that(people).extracting('full_name').contains('Fred Smith', 'John Jones') + def test_extracting_property_and_method(): - assert_that(people).extracting('first_name', 'full_name').contains(('Fred','Fred Smith'), ('John', 'John Jones')) + assert_that(people).extracting('first_name', 'full_name').contains(('Fred', 'Fred Smith'), ('John', 'John Jones')) + def test_extracting_dict(): people_as_dicts = [{'first_name': p.first_name, 'last_name': p.last_name} for p in people] - assert_that(people_as_dicts).extracting('first_name').contains('Fred','John') - assert_that(people_as_dicts).extracting('last_name').contains('Smith','Jones') + assert_that(people_as_dicts).extracting('first_name').contains('Fred', 'John') + assert_that(people_as_dicts).extracting('last_name').contains('Smith', 'Jones') + def test_extracting_bad_val_failure(): try: @@ -71,6 +77,7 @@ def test_extracting_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not iterable') + def test_extracting_bad_val_str_failure(): try: assert_that('foo').extracting('bar') @@ -78,6 +85,7 @@ def test_extracting_bad_val_str_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val must not be string') + def test_extracting_empty_args_failure(): try: assert_that(people).extracting() @@ -85,19 +93,22 @@ def test_extracting_empty_args_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more name args must be given') + def test_extracting_bad_property_failure(): try: assert_that(people).extracting('foo') fail('should have raised error') except ValueError as ex: - assert_that(str(ex)).is_equal_to('val does not have property or zero-arg method ') + assert_that(str(ex)).is_equal_to('item does not have property or zero-arg method ') + def test_extracting_too_many_args_method_failure(): try: assert_that(people).extracting('say_hello') fail('should have raised error') except ValueError as ex: - assert_that(str(ex)).is_equal_to('val method exists, but is not zero-arg method') + assert_that(str(ex)).is_equal_to('item method exists, but is not zero-arg method') + def test_extracting_dict_missing_key_failure(): people_as_dicts = [{'first_name': p.first_name, 'last_name': p.last_name} for p in people] @@ -107,38 +118,45 @@ def test_extracting_dict_missing_key_failure(): except ValueError as ex: assert_that(str(ex)).matches(r'item keys \[.*\] did not contain key ') + def test_described_as_with_extracting(): try: - assert_that(people).described_as('extra msg').extracting('first_name').contains('Fred','Bob') + assert_that(people).described_as('extra msg').extracting('first_name').contains('Fred', 'Bob') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("[extra msg] Expected <['Fred', 'John']> to contain items <'Fred', 'Bob'>, but did not contain .") + def test_described_as_with_double_extracting(): try: - assert_that(people).described_as('extra msg').extracting('first_name').described_as('other msg').contains('Fred','Bob') + assert_that(people).described_as('extra msg').extracting('first_name').described_as('other msg').contains('Fred', 'Bob') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("[other msg] Expected <['Fred', 'John']> to contain items <'Fred', 'Bob'>, but did not contain .") + users = [ {'user': 'Fred', 'age': 36, 'active': True}, {'user': 'Bob', 'age': 40, 'active': False}, {'user': 'Johnny', 'age': 13, 'active': True} ] + def test_extracting_filter(): - assert_that(users).extracting('user', filter='active').is_equal_to(['Fred','Johnny']) + assert_that(users).extracting('user', filter='active').is_equal_to(['Fred', 'Johnny']) assert_that(users).extracting('user', filter={'active': False}).is_equal_to(['Bob']) assert_that(users).extracting('user', filter={'age': 36, 'active': True}).is_equal_to(['Fred']) assert_that(users).extracting('user', filter=lambda x: x['age'] > 20).is_equal_to(['Fred', 'Bob']) assert_that(users).extracting('user', filter=lambda x: x['age'] < 10).is_empty() + def test_extracting_filter_bad_type(): assert_that(users).extracting('user', filter=123).is_equal_to([]) + def test_extracting_filter_ignore_bad_key_types(): - assert_that(users).extracting('user', filter={'active': True, 123: 'foo'}).is_equal_to(['Fred','Johnny']) + assert_that(users).extracting('user', filter={'active': True, 123: 'foo'}).is_equal_to(['Fred', 'Johnny']) + def test_extracting_filter_custom_func(): def _f(x): @@ -146,6 +164,7 @@ def _f(x): assert_that(users).extracting('user', filter=_f).is_equal_to(['Bob', 'Johnny']) + def test_extracting_filter_failure(): try: assert_that(users).extracting('user', filter='foo') @@ -153,6 +172,7 @@ def test_extracting_filter_failure(): except ValueError as ex: assert_that(str(ex)).ends_with("'] did not contain key ") + def test_extracting_filter_dict_failure(): try: assert_that(users).extracting('user', filter={'foo': 'bar'}) @@ -160,6 +180,7 @@ def test_extracting_filter_dict_failure(): except ValueError as ex: assert_that(str(ex)).ends_with("'] did not contain key ") + def test_extracting_filter_multi_item_dict_failure(): try: assert_that(users).extracting('user', filter={'age': 36, 'active': True, 'foo': 'bar'}) @@ -167,6 +188,7 @@ def test_extracting_filter_multi_item_dict_failure(): except ValueError as ex: assert_that(str(ex)).ends_with("'] did not contain key ") + def test_extracting_filter_lambda_failure(): try: assert_that(users).extracting('user', filter=lambda x: x['foo'] > 0) @@ -174,6 +196,7 @@ def test_extracting_filter_lambda_failure(): except KeyError as ex: assert_that(str(ex)).is_equal_to("'foo'") + def test_extracting_filter_custom_func_failure(): def _f(x): raise RuntimeError('foobar!') @@ -183,6 +206,7 @@ def _f(x): except RuntimeError as ex: assert_that(str(ex)).is_equal_to("foobar!") + def test_extracting_filter_bad_values(): bad = [ {'user': 'Fred', 'age': 36}, @@ -199,17 +223,21 @@ def test_extracting_filter_bad_values(): else: assert_that(str(ex)).contains("not supported between instances of 'str' and 'int'") + def test_extracting_sort(): - assert_that(users).extracting('user', sort='age').is_equal_to(['Johnny','Fred','Bob']) - assert_that(users).extracting('user', sort=['active','age']).is_equal_to(['Bob','Johnny','Fred']) - assert_that(users).extracting('user', sort=('active','age')).is_equal_to(['Bob','Johnny','Fred']) - assert_that(users).extracting('user', sort=lambda x: -x['age']).is_equal_to(['Bob','Fred','Johnny']) + assert_that(users).extracting('user', sort='age').is_equal_to(['Johnny', 'Fred', 'Bob']) + assert_that(users).extracting('user', sort=['active', 'age']).is_equal_to(['Bob', 'Johnny', 'Fred']) + assert_that(users).extracting('user', sort=('active', 'age')).is_equal_to(['Bob', 'Johnny', 'Fred']) + assert_that(users).extracting('user', sort=lambda x: -x['age']).is_equal_to(['Bob', 'Fred', 'Johnny']) + def test_extracting_sort_ignore_bad_type(): - assert_that(users).extracting('user', sort=123).is_equal_to(['Fred','Bob','Johnny']) + assert_that(users).extracting('user', sort=123).is_equal_to(['Fred', 'Bob', 'Johnny']) + def test_extracting_sort_ignore_bad_key_types(): - assert_that(users).extracting('user', sort=['active','age',123]).is_equal_to(['Bob','Johnny','Fred']) + assert_that(users).extracting('user', sort=['active', 'age', 123]).is_equal_to(['Bob', 'Johnny', 'Fred']) + def test_extracting_sort_custom_func(): def _f(x): @@ -221,6 +249,7 @@ def _f(x): assert_that(users).extracting('user', sort=_f).is_equal_to(['Johnny', 'Bob', 'Fred']) + def test_extracting_sort_failure(): try: assert_that(users).extracting('user', sort='foo') @@ -228,6 +257,7 @@ def test_extracting_sort_failure(): except ValueError as ex: assert_that(str(ex)).ends_with("'] did not contain key ") + def test_extracting_sort_list_failure(): try: assert_that(users).extracting('user', sort=['foo']) @@ -235,13 +265,15 @@ def test_extracting_sort_list_failure(): except ValueError as ex: assert_that(str(ex)).ends_with("'] did not contain key ") + def test_extracting_sort_multi_item_dict_failure(): try: - assert_that(users).extracting('user', sort=['active','age','foo']) + assert_that(users).extracting('user', sort=['active', 'age', 'foo']) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).ends_with("'] did not contain key ") + def test_extracting_sort_lambda_failure(): try: assert_that(users).extracting('user', sort=lambda x: x['foo'] > 0) @@ -249,6 +281,7 @@ def test_extracting_sort_lambda_failure(): except KeyError as ex: assert_that(str(ex)).is_equal_to("'foo'") + def test_extracting_sort_custom_func_failure(): def _f(x): raise RuntimeError('foobar!') @@ -258,6 +291,7 @@ def _f(x): except RuntimeError as ex: assert_that(str(ex)).is_equal_to("foobar!") + def test_extracting_sort_bad_values(): bad = [ {'user': 'Fred', 'age': 36}, @@ -274,47 +308,53 @@ def test_extracting_sort_bad_values(): else: assert_that(str(ex)).contains("not supported between instances of 'str' and 'int'") + def test_extracting_iterable_of_lists(): - l = [[1,2,3],[4,5,6],[7,8,9]] - assert_that(l).extracting(0).is_equal_to([1,4,7]) - assert_that(l).extracting(0,1).is_equal_to([(1,2),(4,5),(7,8)]) - assert_that(l).extracting(-1).is_equal_to([3,6,9]) - assert_that(l).extracting(-1,-2).extracting(0).is_equal_to([3,6,9]) + l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + assert_that(l).extracting(0).is_equal_to([1, 4, 7]) + assert_that(l).extracting(0, 1).is_equal_to([(1, 2), (4, 5), (7, 8)]) + assert_that(l).extracting(-1).is_equal_to([3, 6, 9]) + assert_that(l).extracting(-1, -2).extracting(0).is_equal_to([3, 6, 9]) + def test_extracting_iterable_multi_extracting(): - l = [[1,2,3],[4,5,6],[7,8,9]] - assert_that(l).extracting(-1,2).is_equal_to([(3,3),(6,6),(9,9)]) - assert_that(l).extracting(-1,1).extracting(1,0).is_equal_to([(2,3),(5,6),(8,9)]) + l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + assert_that(l).extracting(-1, 2).is_equal_to([(3, 3), (6, 6), (9, 9)]) + assert_that(l).extracting(-1, 1).extracting(1, 0).is_equal_to([(2, 3), (5, 6), (8, 9)]) + def test_extracting_iterable_of_tuples(): - t = [(1,2,3),(4,5,6),(7,8,9)] - assert_that(t).extracting(0).is_equal_to([1,4,7]) - assert_that(t).extracting(0,1).is_equal_to([(1,2),(4,5),(7,8)]) - assert_that(t).extracting(-1).is_equal_to([3,6,9]) + t = [(1, 2, 3), (4, 5, 6), (7, 8, 9)] + assert_that(t).extracting(0).is_equal_to([1, 4, 7]) + assert_that(t).extracting(0, 1).is_equal_to([(1, 2), (4, 5), (7, 8)]) + assert_that(t).extracting(-1).is_equal_to([3, 6, 9]) + def test_extracting_iterable_of_strings(): - s = ['foo','bar','baz'] + s = ['foo', 'bar', 'baz'] assert_that(s).extracting(0).is_equal_to(['f', 'b', 'b']) - assert_that(s).extracting(0,2).is_equal_to([('f','o'),('b','r'),('b','z')]) + assert_that(s).extracting(0, 2).is_equal_to([('f', 'o'), ('b', 'r'), ('b', 'z')]) + def test_extracting_iterable_failure_set(): try: - assert_that([set([1])]).extracting(0).contains(1,4,7) + assert_that([set([1])]).extracting(0).contains(1, 4, 7) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('item does not have [] accessor') + def test_extracting_iterable_failure_out_of_range(): try: - assert_that([[1],[2],[3]]).extracting(4).is_equal_to(0) + assert_that([[1], [2], [3]]).extracting(4).is_equal_to(0) fail('should have raised error') except IndexError as ex: assert_that(str(ex)).is_equal_to('list index out of range') + def test_extracting_iterable_failure_index_is_not_int(): try: - assert_that([[1],[2],[3]]).extracting('1').is_equal_to(0) + assert_that([[1], [2], [3]]).extracting('1').is_equal_to(0) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).contains('list indices must be integers') - diff --git a/tests/test_fail.py b/tests/test_fail.py index 6aeab12..cc7d041 100644 --- a/tests/test_fail.py +++ b/tests/test_fail.py @@ -26,7 +26,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_fail(): @@ -36,6 +36,7 @@ def test_fail(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Fail!') + def test_fail_msg(): try: fail('some msg') diff --git a/tests/test_file.py b/tests/test_file.py index 5284c5b..50a4acb 100644 --- a/tests/test_file.py +++ b/tests/test_file.py @@ -28,167 +28,192 @@ import sys import os -import tempfile -from assertpy import assert_that,contents_of,fail - -class TestFile(object): - - def setup(self): - self.tmp = tempfile.NamedTemporaryFile() - self.tmp.write('foobar'.encode('utf-8')) - self.tmp.seek(0) - - def teardown(self): - self.tmp.close() - - def test_contents_of_path(self): - contents = contents_of(self.tmp.name) - assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') - - def test_contents_of_path_ascii(self): - contents = contents_of(self.tmp.name, 'ascii') - assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') - - def test_contents_of_return_type(self): - if sys.version_info[0] == 3: - contents = contents_of(self.tmp.name) - assert_that(contents).is_type_of(str) - else: - contents = contents_of(self.tmp.name) - assert_that(contents).is_type_of(unicode) - - def test_contents_of_return_type_ascii(self): - if sys.version_info[0] == 3: - contents = contents_of(self.tmp.name, 'ascii') - assert_that(contents).is_type_of(str) - else: - contents = contents_of(self.tmp.name, 'ascii') - assert_that(contents).is_type_of(str) - - def test_contents_of_file(self): - contents = contents_of(self.tmp.file) - assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') - - def test_contents_of_file_ascii(self): - contents = contents_of(self.tmp.file, 'ascii') - assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') - - def test_contains_of_bad_type_failure(self): - try: - contents_of(123) - fail('should have raised error') - except ValueError as ex: - assert_that(str(ex)).is_equal_to('val must be file or path, but was type ') - - def test_contains_of_missing_file_failure(self): - try: - contents_of('missing.txt') - fail('should have raised error') - except IOError as ex: - assert_that(str(ex)).contains_ignoring_case('no such file') - - def test_exists(self): - assert_that(self.tmp.name).exists() - - def test_exists_failure(self): - try: - assert_that('missing.txt').exists() - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).is_equal_to('Expected to exist, but was not found.') - - def test_exists_bad_val_failure(self): - try: - assert_that(123).exists() - fail('should have raised error') - except TypeError as ex: - assert_that(str(ex)).is_equal_to('val is not a path') - - def test_does_not_exist(self): - assert_that('missing.txt').does_not_exist() - - def test_does_not_exist_failure(self): - try: - assert_that(self.tmp.name).does_not_exist() - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).is_equal_to('Expected <{}> to not exist, but was found.'.format(self.tmp.name)) - - def test_does_not_exist_bad_val_failure(self): - try: - assert_that(123).does_not_exist() - fail('should have raised error') - except TypeError as ex: - assert_that(str(ex)).is_equal_to('val is not a path') - - def test_is_file(self): - assert_that(self.tmp.name).is_file() - - def test_is_file_exists_failure(self): - try: - assert_that('missing.txt').is_file() - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).is_equal_to('Expected to exist, but was not found.') - - def test_is_file_directory_failure(self): - try: - dirname = os.path.dirname(self.tmp.name) - assert_that(dirname).is_file() - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).matches('Expected <.*> to be a file, but was not.') - - def test_is_directory(self): - dirname = os.path.dirname(self.tmp.name) - assert_that(dirname).is_directory() - - def test_is_directory_exists_failure(self): - try: - assert_that('missing_dir').is_directory() - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).is_equal_to('Expected to exist, but was not found.') - - def test_is_directory_file_failure(self): - try: - assert_that(self.tmp.name).is_directory() - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).matches('Expected <.*> to be a directory, but was not.') - - def test_is_named(self): - basename = os.path.basename(self.tmp.name) - assert_that(self.tmp.name).is_named(basename) - - def test_is_named_failure(self): - try: - assert_that(self.tmp.name).is_named('foo.txt') - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).matches('Expected filename <.*> to be equal to , but was not.') - - def test_is_named_bad_arg_type_failure(self): - try: - assert_that(self.tmp.name).is_named(123) - fail('should have raised error') - except TypeError as ex: - assert_that(str(ex)).matches('given filename arg must be a path') - - def test_is_child_of(self): - dirname = os.path.dirname(self.tmp.name) - assert_that(self.tmp.name).is_child_of(dirname) - - def test_is_child_of_failure(self): - try: - assert_that(self.tmp.name).is_child_of('foo_dir') - fail('should have raised error') - except AssertionError as ex: - assert_that(str(ex)).matches('Expected file <.*> to be a child of <.*/foo_dir>, but was not.') - - def test_is_child_of_bad_arg_type_failure(self): - try: - assert_that(self.tmp.name).is_child_of(123) - fail('should have raised error') - except TypeError as ex: - assert_that(str(ex)).matches('given parent directory arg must be a path') +import pytest +from assertpy import assert_that, contents_of, fail + + +@pytest.fixture() +def tmpfile(tmpdir): + tmp = tmpdir.join('test.txt') + tmp.write('foobar'.encode('utf-8')) + with tmp.open('rb') as f: + yield f + + +def test_contents_of_path(tmpfile): + contents = contents_of(tmpfile.name) + assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') + + +def test_contents_of_path_ascii(tmpfile): + contents = contents_of(tmpfile.name, 'ascii') + assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') + + +def test_contents_of_return_type(tmpfile): + if sys.version_info[0] == 3: + contents = contents_of(tmpfile.name) + assert_that(contents).is_type_of(str) + else: + contents = contents_of(tmpfile.name) + assert_that(contents).is_type_of(unicode) + + +def test_contents_of_return_type_ascii(tmpfile): + if sys.version_info[0] == 3: + contents = contents_of(tmpfile.name, 'ascii') + assert_that(contents).is_type_of(str) + else: + contents = contents_of(tmpfile.name, 'ascii') + assert_that(contents).is_type_of(str) + + +def test_contents_of_file(tmpfile): + contents = contents_of(tmpfile) + assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') + + +def test_contents_of_file_ascii(tmpfile): + contents = contents_of(tmpfile, 'ascii') + assert_that(contents).is_equal_to('foobar').starts_with('foo').ends_with('bar') + + +def test_contains_of_bad_type_failure(tmpfile): + try: + contents_of(123) + fail('should have raised error') + except ValueError as ex: + assert_that(str(ex)).is_equal_to('val must be file or path, but was type ') + + +def test_contains_of_missing_file_failure(tmpfile): + try: + contents_of('missing.txt') + fail('should have raised error') + except IOError as ex: + assert_that(str(ex)).contains_ignoring_case('no such file') + + +def test_exists(tmpfile): + assert_that(tmpfile.name).exists() + assert_that(os.path.dirname(tmpfile.name)).exists() + + +def test_exists_failure(tmpfile): + try: + assert_that('missing.txt').exists() + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to('Expected to exist, but was not found.') + + +def test_exists_bad_val_failure(tmpfile): + try: + assert_that(123).exists() + fail('should have raised error') + except TypeError as ex: + assert_that(str(ex)).is_equal_to('val is not a path') + + +def test_does_not_exist(): + assert_that('missing.txt').does_not_exist() + + +def test_does_not_exist_failure(tmpfile): + try: + assert_that(tmpfile.name).does_not_exist() + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to('Expected <{}> to not exist, but was found.'.format(tmpfile.name)) + + +def test_does_not_exist_bad_val_failure(tmpfile): + try: + assert_that(123).does_not_exist() + fail('should have raised error') + except TypeError as ex: + assert_that(str(ex)).is_equal_to('val is not a path') + + +def test_is_file(tmpfile): + assert_that(tmpfile.name).is_file() + + +def test_is_file_exists_failure(): + try: + assert_that('missing.txt').is_file() + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to('Expected to exist, but was not found.') + + +def test_is_file_directory_failure(tmpfile): + try: + dirname = os.path.dirname(tmpfile.name) + assert_that(dirname).is_file() + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).matches('Expected <.*> to be a file, but was not.') + + +def test_is_directory(tmpfile): + dirname = os.path.dirname(tmpfile.name) + assert_that(dirname).is_directory() + + +def test_is_directory_exists_failure(): + try: + assert_that('missing_dir').is_directory() + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to('Expected to exist, but was not found.') + + +def test_is_directory_file_failure(tmpfile): + try: + assert_that(tmpfile.name).is_directory() + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).matches('Expected <.*> to be a directory, but was not.') + + +def test_is_named(tmpfile): + basename = os.path.basename(tmpfile.name) + assert_that(tmpfile.name).is_named(basename) + + +def test_is_named_failure(tmpfile): + try: + assert_that(tmpfile.name).is_named('foo.txt') + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).matches('Expected filename <.*> to be equal to , but was not.') + + +def test_is_named_bad_arg_type_failure(tmpfile): + try: + assert_that(tmpfile.name).is_named(123) + fail('should have raised error') + except TypeError as ex: + assert_that(str(ex)).matches('given filename arg must be a path') + + +def test_is_child_of(tmpfile): + dirname = os.path.dirname(tmpfile.name) + assert_that(tmpfile.name).is_child_of(dirname) + + +def test_is_child_of_failure(tmpfile): + try: + assert_that(tmpfile.name).is_child_of('foo_dir') + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).matches(r'Expected file <.*> to be a child of <.*[\\/]foo_dir>, but was not.') + + +def test_is_child_of_bad_arg_type_failure(tmpfile): + try: + assert_that(tmpfile.name).is_child_of(123) + fail('should have raised error') + except TypeError as ex: + assert_that(str(ex)).matches('given parent directory arg must be a path') diff --git a/tests/test_in.py b/tests/test_in.py index 26884ad..4d72081 100644 --- a/tests/test_in.py +++ b/tests/test_in.py @@ -26,22 +26,24 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_is_in(): assert_that(1).is_in(1) - assert_that(1).is_in(1,2,3) + assert_that(1).is_in(1, 2, 3) assert_that('foo').is_in('foo', 'bar', 'baz') - assert_that([1,2,3]).is_in([1,2,3], [2,3,4], [3,4,5]) + assert_that([1, 2, 3]).is_in([1, 2, 3], [2, 3, 4], [3, 4, 5]) + def test_is_in_failure(): try: - assert_that(4).is_in(1,2,3) + assert_that(4).is_in(1, 2, 3) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <4> to be in <1, 2, 3>, but was not.') + def test_is_in_missing_arg_failure(): try: assert_that(1).is_in() @@ -49,23 +51,25 @@ def test_is_in_missing_arg_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') + def test_is_not_in(): assert_that(4).is_not_in(1) - assert_that(4).is_not_in(1,2,3) + assert_that(4).is_not_in(1, 2, 3) assert_that('fred').is_not_in('foo', 'bar', 'baz') - assert_that([4,4,4]).is_not_in([1,2,3], [2,3,4], [3,4,5]) + assert_that([4, 4, 4]).is_not_in([1, 2, 3], [2, 3, 4], [3, 4, 5]) + def test_is_not_in_failure(): try: - assert_that(1).is_not_in(1,2,3) + assert_that(1).is_not_in(1, 2, 3) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <1> to not be in <1, 2, 3>, but was.') + def test_is_not_in_missing_arg_failure(): try: assert_that(1).is_not_in() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') - diff --git a/tests/test_list.py b/tests/test_list.py index b0c66a8..2595c95 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -29,209 +29,233 @@ import sys import collections -from assertpy import assert_that,fail +from assertpy import assert_that, fail + def test_is_length(): - assert_that(['a','b','c']).is_length(3) - assert_that((1,2,3,4)).is_length(4) - assert_that({ 'a':1,'b':2 }).is_length(2) - assert_that(set(['a','b'])).is_length(2) + assert_that(['a', 'b', 'c']).is_length(3) + assert_that((1, 2, 3, 4)).is_length(4) + assert_that({'a': 1, 'b': 2}).is_length(2) + assert_that(set(['a', 'b'])).is_length(2) + def test_is_length_failure(): try: - assert_that(['a','b','c']).is_length(4) + assert_that(['a', 'b', 'c']).is_length(4) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b', 'c']> to be of length <4>, but was <3>.") + def test_is_length_bad_arg_failure(): try: - assert_that(['a','b','c']).is_length('bar') + assert_that(['a', 'b', 'c']).is_length('bar') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be an int') + def test_is_length_negative_arg_failure(): try: - assert_that(['a','b','c']).is_length(-1) + assert_that(['a', 'b', 'c']).is_length(-1) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('given arg must be a positive int') + def test_contains(): - assert_that(['a','b','c']).contains('a') - assert_that(['a','b','c']).contains('c','b','a') - assert_that((1,2,3,4)).contains(1,2,3) - assert_that((1,2,3,4)).contains(4) - assert_that({ 'a':1,'b':2,'c':3 }).contains('a') - assert_that({ 'a':1,'b':2,'c':3 }).contains('a','b') - assert_that(set(['a','b','c'])).contains('a') - assert_that(set(['a','b','c'])).contains('c','b') + assert_that(['a', 'b', 'c']).contains('a') + assert_that(['a', 'b', 'c']).contains('c', 'b', 'a') + assert_that((1, 2, 3, 4)).contains(1, 2, 3) + assert_that((1, 2, 3, 4)).contains(4) + assert_that({'a': 1, 'b': 2, 'c': 3}).contains('a') + assert_that({'a': 1, 'b': 2, 'c': 3}).contains('a', 'b') + assert_that(set(['a', 'b', 'c'])).contains('a') + assert_that(set(['a', 'b', 'c'])).contains('c', 'b') fred = Person('fred') joe = Person('joe') bob = Person('bob') - assert_that([fred,joe,bob]).contains(joe) + assert_that([fred, joe, bob]).contains(joe) + def test_contains_single_item_failure(): try: - assert_that(['a','b','c']).contains('x') + assert_that(['a', 'b', 'c']).contains('x') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b', 'c']> to contain item , but did not.") + def test_contains_multi_item_failure(): try: - assert_that(['a','b','c']).contains('a','x','z') + assert_that(['a', 'b', 'c']).contains('a', 'x', 'z') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b', 'c']> to contain items <'a', 'x', 'z'>, but did not contain <'x', 'z'>.") + def test_contains_multi_item_single_failure(): try: - assert_that(['a','b','c']).contains('a','b','z') + assert_that(['a', 'b', 'c']).contains('a', 'b', 'z') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b', 'c']> to contain items <'a', 'b', 'z'>, but did not contain .") + def test_does_not_contain(): - assert_that(['a','b','c']).does_not_contain('x') - assert_that(['a','b','c']).does_not_contain('x','y') - assert_that((1,2,3,4)).does_not_contain(5) - assert_that((1,2,3,4)).does_not_contain(5,6) - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain('x') - assert_that({ 'a':1,'b':2,'c':3 }).does_not_contain('x','y') - assert_that(set(['a','b','c'])).does_not_contain('x') - assert_that(set(['a','b','c'])).does_not_contain('x','y') + assert_that(['a', 'b', 'c']).does_not_contain('x') + assert_that(['a', 'b', 'c']).does_not_contain('x', 'y') + assert_that((1, 2, 3, 4)).does_not_contain(5) + assert_that((1, 2, 3, 4)).does_not_contain(5, 6) + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain('x') + assert_that({'a': 1, 'b': 2, 'c': 3}).does_not_contain('x', 'y') + assert_that(set(['a', 'b', 'c'])).does_not_contain('x') + assert_that(set(['a', 'b', 'c'])).does_not_contain('x', 'y') fred = Person('fred') joe = Person('joe') bob = Person('bob') - assert_that([fred,joe]).does_not_contain(bob) + assert_that([fred, joe]).does_not_contain(bob) + def test_does_not_contain_single_item_failure(): try: - assert_that(['a','b','c']).does_not_contain('a') + assert_that(['a', 'b', 'c']).does_not_contain('a') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b', 'c']> to not contain item , but did.") + def test_does_not_contain_list_item_failure(): try: - assert_that(['a','b','c']).does_not_contain('x','y','a') + assert_that(['a', 'b', 'c']).does_not_contain('x', 'y', 'a') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b', 'c']> to not contain items <'x', 'y', 'a'>, but did contain .") + def test_does_not_contain_list_multi_item_failure(): try: - assert_that(['a','b','c']).does_not_contain('x','a','b') + assert_that(['a', 'b', 'c']).does_not_contain('x', 'a', 'b') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b', 'c']> to not contain items <'x', 'a', 'b'>, but did contain <'a', 'b'>.") + def test_contains_only(): - assert_that(['a','b','c']).contains_only('a','b','c') - assert_that(['a','b','c']).contains_only('c','b','a') - assert_that(['a','a','b']).contains_only('a','b') - assert_that(['a','a','a']).contains_only('a') - assert_that((1,2,3,4)).contains_only(1,2,3,4) - assert_that((1,2,3,1)).contains_only(1,2,3) - assert_that((1,2,2,1)).contains_only(1,2) - assert_that((1,1,1,1)).contains_only(1) - assert_that('foobar').contains_only('f','o','b','a','r') + assert_that(['a', 'b', 'c']).contains_only('a', 'b', 'c') + assert_that(['a', 'b', 'c']).contains_only('c', 'b', 'a') + assert_that(['a', 'a', 'b']).contains_only('a', 'b') + assert_that(['a', 'a', 'a']).contains_only('a') + assert_that((1, 2, 3, 4)).contains_only(1, 2, 3, 4) + assert_that((1, 2, 3, 1)).contains_only(1, 2, 3) + assert_that((1, 2, 2, 1)).contains_only(1, 2) + assert_that((1, 1, 1, 1)).contains_only(1) + assert_that('foobar').contains_only('f', 'o', 'b', 'a', 'r') + def test_contains_only_no_args_failure(): try: - assert_that([1,2,3]).contains_only() + assert_that([1, 2, 3]).contains_only() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') + def test_contains_only_failure(): try: - assert_that([1,2,3]).contains_only(1,2) + assert_that([1, 2, 3]).contains_only(1, 2) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3]> to contain only <1, 2>, but did contain <3>.') + def test_contains_only_multi_failure(): try: - assert_that([1,2,3]).contains_only(1,4) + assert_that([1, 2, 3]).contains_only(1, 4) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3]> to contain only <1, 4>, but did contain <2, 3>.') + def test_contains_only_superlist_failure(): try: - assert_that([1,2,3]).contains_only(1,2,3,4) + assert_that([1, 2, 3]).contains_only(1, 2, 3, 4) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3]> to contain only <1, 2, 3, 4>, but did not contain <4>.') + def test_contains_sequence(): - assert_that(['a','b','c']).contains_sequence('a') - assert_that(['a','b','c']).contains_sequence('b') - assert_that(['a','b','c']).contains_sequence('c') - assert_that(['a','b','c']).contains_sequence('a', 'b') - assert_that(['a','b','c']).contains_sequence('b', 'c') - assert_that(['a','b','c']).contains_sequence('a', 'b', 'c') - assert_that((1,2,3,4)).contains_sequence(1) - assert_that((1,2,3,4)).contains_sequence(2) - assert_that((1,2,3,4)).contains_sequence(3) - assert_that((1,2,3,4)).contains_sequence(4) - assert_that((1,2,3,4)).contains_sequence(1,2) - assert_that((1,2,3,4)).contains_sequence(2,3) - assert_that((1,2,3,4)).contains_sequence(3,4) - assert_that((1,2,3,4)).contains_sequence(1,2,3) - assert_that((1,2,3,4)).contains_sequence(2,3,4) - assert_that((1,2,3,4)).contains_sequence(1,2,3,4) - assert_that('foobar').contains_sequence('o','o','b') + assert_that(['a', 'b', 'c']).contains_sequence('a') + assert_that(['a', 'b', 'c']).contains_sequence('b') + assert_that(['a', 'b', 'c']).contains_sequence('c') + assert_that(['a', 'b', 'c']).contains_sequence('a', 'b') + assert_that(['a', 'b', 'c']).contains_sequence('b', 'c') + assert_that(['a', 'b', 'c']).contains_sequence('a', 'b', 'c') + assert_that((1, 2, 3, 4)).contains_sequence(1) + assert_that((1, 2, 3, 4)).contains_sequence(2) + assert_that((1, 2, 3, 4)).contains_sequence(3) + assert_that((1, 2, 3, 4)).contains_sequence(4) + assert_that((1, 2, 3, 4)).contains_sequence(1, 2) + assert_that((1, 2, 3, 4)).contains_sequence(2, 3) + assert_that((1, 2, 3, 4)).contains_sequence(3, 4) + assert_that((1, 2, 3, 4)).contains_sequence(1, 2, 3) + assert_that((1, 2, 3, 4)).contains_sequence(2, 3, 4) + assert_that((1, 2, 3, 4)).contains_sequence(1, 2, 3, 4) + assert_that('foobar').contains_sequence('o', 'o', 'b') fred = Person('fred') joe = Person('joe') bob = Person('bob') - assert_that([fred,joe,bob]).contains_sequence(fred,joe) + assert_that([fred, joe, bob]).contains_sequence(fred, joe) + def test_contains_sequence_failure(): try: - assert_that([1,2,3]).contains_sequence(4,5) + assert_that([1, 2, 3]).contains_sequence(4, 5) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3]> to contain sequence <4, 5>, but did not.') + def test_contains_sequence_bad_val_failure(): try: - assert_that(123).contains_sequence(1,2) + assert_that(123).contains_sequence(1, 2) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not iterable') + def test_contains_sequence_no_args_failure(): try: - assert_that([1,2,3]).contains_sequence() + assert_that([1, 2, 3]).contains_sequence() fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') + def test_contains_duplicates(): - assert_that(['a','b','c','a']).contains_duplicates() - assert_that(('a','b','c','a')).contains_duplicates() - assert_that([1,2,3,3]).contains_duplicates() - assert_that((1,2,3,3)).contains_duplicates() + assert_that(['a', 'b', 'c', 'a']).contains_duplicates() + assert_that(('a', 'b', 'c', 'a')).contains_duplicates() + assert_that([1, 2, 3, 3]).contains_duplicates() + assert_that((1, 2, 3, 3)).contains_duplicates() assert_that('foobar').contains_duplicates() fred = Person('fred') joe = Person('joe') - assert_that([fred,joe,fred]).contains_duplicates() + assert_that([fred, joe, fred]).contains_duplicates() + def test_contains_duplicates_failure(): try: - assert_that([1,2,3]).contains_duplicates() + assert_that([1, 2, 3]).contains_duplicates() fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3]> to contain duplicates, but did not.') + def test_contains_duplicates_bad_val_failure(): try: assert_that(123).contains_duplicates() @@ -239,26 +263,29 @@ def test_contains_duplicates_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not iterable') + def test_does_not_contain_duplicates(): - assert_that(['a','b','c']).does_not_contain_duplicates() - assert_that(('a','b','c')).does_not_contain_duplicates() - assert_that(set(['a','b','c'])).does_not_contain_duplicates() - assert_that([1,2,3]).does_not_contain_duplicates() - assert_that((1,2,3)).does_not_contain_duplicates() - assert_that(set([1,2,3])).does_not_contain_duplicates() + assert_that(['a', 'b', 'c']).does_not_contain_duplicates() + assert_that(('a', 'b', 'c')).does_not_contain_duplicates() + assert_that(set(['a', 'b', 'c'])).does_not_contain_duplicates() + assert_that([1, 2, 3]).does_not_contain_duplicates() + assert_that((1, 2, 3)).does_not_contain_duplicates() + assert_that(set([1, 2, 3])).does_not_contain_duplicates() assert_that('fobar').does_not_contain_duplicates() fred = Person('fred') joe = Person('joe') - assert_that([fred,joe]).does_not_contain_duplicates() + assert_that([fred, joe]).does_not_contain_duplicates() + def test_does_not_contain_duplicates_failure(): try: - assert_that([1,2,3,3]).does_not_contain_duplicates() + assert_that([1, 2, 3, 3]).does_not_contain_duplicates() fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <[1, 2, 3, 3]> to not contain duplicates, but did.') + def test_does_not_contain_duplicates_bad_val_failure(): try: assert_that(123).does_not_contain_duplicates() @@ -266,23 +293,27 @@ def test_does_not_contain_duplicates_bad_val_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not iterable') + def test_is_empty(): assert_that([]).is_empty() assert_that(()).is_empty() assert_that({}).is_empty() + def test_is_empty_failure(): try: - assert_that(['a','b']).is_empty() + assert_that(['a', 'b']).is_empty() fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['a', 'b']> to be empty, but was not.") + def test_is_not_empty(): - assert_that(['a','b']).is_not_empty() - assert_that((1,2)).is_not_empty() - assert_that({'a':1,'b':2}).is_not_empty() - assert_that(set(['a','b'])).is_not_empty() + assert_that(['a', 'b']).is_not_empty() + assert_that((1, 2)).is_not_empty() + assert_that({'a': 1, 'b': 2}).is_not_empty() + assert_that(set(['a', 'b'])).is_not_empty() + def test_is_not_empty_failure(): try: @@ -291,23 +322,26 @@ def test_is_not_empty_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected not empty, but was empty.') + def test_starts_with(): - assert_that(['a','b','c']).starts_with('a') - assert_that((1,2,3)).starts_with(1) + assert_that(['a', 'b', 'c']).starts_with('a') + assert_that((1, 2, 3)).starts_with(1) if sys.version_info[0] == 3: - ordered = collections.OrderedDict([('z',9),('x',7),('y',8)]) + ordered = collections.OrderedDict([('z', 9), ('x', 7), ('y', 8)]) assert_that(ordered.keys()).starts_with('z') assert_that(ordered.values()).starts_with(9) - assert_that(ordered.items()).starts_with(('z',9)) + assert_that(ordered.items()).starts_with(('z', 9)) + def test_starts_with_failure(): try: - assert_that(['a','b','c']).starts_with('d') + assert_that(['a', 'b', 'c']).starts_with('d') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected ['a', 'b', 'c'] to start with , but did not.") + def test_starts_with_bad_val_failure(): try: assert_that([]).starts_with('a') @@ -315,9 +349,10 @@ def test_starts_with_bad_val_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('val must not be empty') + def test_starts_with_bad_prefix_failure(): try: - assert_that(['a','b','c']).starts_with('a', 'b') + assert_that(['a', 'b', 'c']).starts_with('a', 'b') fail('should have raised error') except TypeError as ex: if sys.version_info[0] == 3: @@ -327,22 +362,24 @@ def test_starts_with_bad_prefix_failure(): def test_ends_with(): - assert_that(['a','b','c']).ends_with('c') - assert_that((1,2,3)).ends_with(3) + assert_that(['a', 'b', 'c']).ends_with('c') + assert_that((1, 2, 3)).ends_with(3) if sys.version_info[0] == 3: - ordered = collections.OrderedDict([('z',9),('x',7),('y',8)]) + ordered = collections.OrderedDict([('z', 9), ('x', 7), ('y', 8)]) assert_that(ordered.keys()).ends_with('y') assert_that(ordered.values()).ends_with(8) - assert_that(ordered.items()).ends_with(('y',8)) + assert_that(ordered.items()).ends_with(('y', 8)) + def test_ends_with_failure(): try: - assert_that(['a','b','c']).ends_with('d') + assert_that(['a', 'b', 'c']).ends_with('d') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected ['a', 'b', 'c'] to end with , but did not.") + def test_ends_with_bad_val_failure(): try: assert_that([]).ends_with('a') @@ -350,9 +387,10 @@ def test_ends_with_bad_val_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('val must not be empty') + def test_ends_with_bad_prefix_failure(): try: - assert_that(['a','b','c']).ends_with('b', 'c') + assert_that(['a', 'b', 'c']).ends_with('b', 'c') fail('should have raised error') except TypeError as ex: if sys.version_info[0] == 3: @@ -360,28 +398,31 @@ def test_ends_with_bad_prefix_failure(): else: assert_that(str(ex)).contains('ends_with() takes exactly 2 arguments (3 given)') + def test_chaining(): - assert_that(['a','b','c']).is_type_of(list).is_length(3).contains('a').does_not_contain('x') - assert_that(['a','b','c']).is_type_of(list).is_length(3).contains('a','b').does_not_contain('x','y') + assert_that(['a', 'b', 'c']).is_type_of(list).is_length(3).contains('a').does_not_contain('x') + assert_that(['a', 'b', 'c']).is_type_of(list).is_length(3).contains('a', 'b').does_not_contain('x', 'y') + def test_list_of_lists(): - l = [[1,2,3], ['a','b','c'], (4,5,6)] + l = [[1, 2, 3], ['a', 'b', 'c'], (4, 5, 6)] assert_that(l).is_length(3) - assert_that(l).is_equal_to([[1,2,3], ['a','b','c'], (4,5,6)]) + assert_that(l).is_equal_to([[1, 2, 3], ['a', 'b', 'c'], (4, 5, 6)]) - assert_that(l).contains([1,2,3]) - assert_that(l).contains(['a','b','c']) - assert_that(l).contains((4,5,6)) + assert_that(l).contains([1, 2, 3]) + assert_that(l).contains(['a', 'b', 'c']) + assert_that(l).contains((4, 5, 6)) - assert_that(l).starts_with([1,2,3]) - assert_that(l).ends_with((4,5,6)) + assert_that(l).starts_with([1, 2, 3]) + assert_that(l).ends_with((4, 5, 6)) - assert_that(l[0]).is_equal_to([1,2,3]) - assert_that(l[2]).is_equal_to((4,5,6)) + assert_that(l[0]).is_equal_to([1, 2, 3]) + assert_that(l[2]).is_equal_to((4, 5, 6)) assert_that(l[0][0]).is_equal_to(1) assert_that(l[2][2]).is_equal_to(6) + def test_list_of_dicts(): l = [{'a': 1}, {'b': 2}, {'c': 3}] assert_that(l).is_length(3) @@ -400,7 +441,7 @@ def test_list_of_dicts(): assert_that(l[0]['a']).is_equal_to(1) assert_that(l[2]['c']).is_equal_to(3) + class Person(object): def __init__(self, name): self.name = name - diff --git a/tests/test_namedtuple.py b/tests/test_namedtuple.py new file mode 100644 index 0000000..853a4de --- /dev/null +++ b/tests/test_namedtuple.py @@ -0,0 +1,90 @@ +# Copyright (c) 2015-2021, Activision Publishing, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import collections + +from assertpy import assert_that, fail + + +Foo = collections.namedtuple('Foo', ['bar', 'baz']) +foo = Foo(bar='abc', baz=123) +foos = [foo, Foo(bar='xyz', baz=456)] + + +def test_namedtuple_equals(): + assert_that(foo).is_instance_of(Foo) + assert_that(foo).is_instance_of(tuple) + assert_that(foo).is_instance_of(object) + assert_that(foo).is_type_of(Foo) + assert_that(foo).is_equal_to(('abc', 123)) + assert_that(foo).is_equal_to(Foo(bar='abc', baz=123)) + assert_that(foo).is_not_equal_to(Foo(bar='abc', baz=124)) + assert_that(foo.bar).is_equal_to('abc') + assert_that(foo[0]).is_equal_to('abc') + assert_that(foo.baz).is_equal_to(123) + assert_that(foo[1]).is_equal_to(123) + assert_that(foo._fields).is_equal_to(('bar', 'baz')) + + +def test_namedtuple_equals_failure(): + try: + assert_that(foo).is_equal_to(Foo(bar='abc', baz=124)) + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to("Expected to be equal to , but was not.") + + +def test_namedtuple_has(): + assert_that(foo).has_bar('abc') + assert_that(foo).has_baz(123) + + +def test_namedtuple_has_failure(): + try: + assert_that(foo).has_missing('x') + fail('should have raised error') + except AssertionError as ex: + assert_that(str(ex)).is_equal_to("Expected attribute , but val has no attribute .") + + +def test_namedtuple_extracting_by_index(): + assert_that(foos).extracting(0).is_equal_to(['abc', 'xyz']) + assert_that(foos).extracting(1).is_equal_to([123, 456]) + + +def test_namedtuple_extracting_by_name(): + assert_that(foos).extracting('bar').is_equal_to(['abc', 'xyz']) + assert_that(foos).extracting('baz').is_equal_to([123, 456]) + + +def test_namedtuple_extracting_by_name_failure(): + try: + assert_that(foos).extracting('missing').is_equal_to('x') + fail('should have raised error') + except ValueError as ex: + assert_that(str(ex)).is_equal_to("item attributes ('bar', 'baz') did no contain attribute ") diff --git a/tests/test_none.py b/tests/test_none.py index 4fc2dcd..aedbb21 100644 --- a/tests/test_none.py +++ b/tests/test_none.py @@ -26,12 +26,13 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_is_none(): assert_that(None).is_none() + def test_is_none_failure(): try: assert_that('foo').is_none() @@ -39,6 +40,7 @@ def test_is_none_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be , but was not.') + def test_is_not_none(): assert_that('foo').is_not_none() assert_that(123).is_not_none() @@ -46,6 +48,7 @@ def test_is_not_none(): assert_that([]).is_not_none() assert_that({}).is_not_none() + def test_is_not_none_failure(): try: assert_that(None).is_not_none() diff --git a/tests/test_numbers.py b/tests/test_numbers.py index f20bc39..638ba48 100644 --- a/tests/test_numbers.py +++ b/tests/test_numbers.py @@ -27,15 +27,16 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import math -from assertpy import assert_that,fail +from assertpy import assert_that, fail def test_is_zero(): assert_that(0).is_zero() - #assert_that(0L).is_zero() + # assert_that(0L).is_zero() assert_that(0.0).is_zero() assert_that(0 + 0j).is_zero() + def test_is_zero_failure(): try: assert_that(1).is_zero() @@ -43,6 +44,7 @@ def test_is_zero_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <1> to be equal to <0>, but was not.') + def test_is_zero_bad_type_failure(): try: assert_that('foo').is_zero() @@ -50,12 +52,14 @@ def test_is_zero_bad_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric') + def test_is_not_zero(): assert_that(1).is_not_zero() - #assert_that(1L).is_not_zero() + # assert_that(1L).is_not_zero() assert_that(0.001).is_not_zero() assert_that(0 + 1j).is_not_zero() + def test_is_not_zero_failure(): try: assert_that(0).is_not_zero() @@ -63,6 +67,7 @@ def test_is_not_zero_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <0> to be not equal to <0>, but was.') + def test_is_not_zero_bad_type_failure(): try: assert_that('foo').is_not_zero() @@ -70,10 +75,12 @@ def test_is_not_zero_bad_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric') + def test_is_nan(): assert_that(float('NaN')).is_nan() assert_that(float('Inf')-float('Inf')).is_nan() + def test_is_nan_failure(): try: assert_that(0).is_nan() @@ -81,6 +88,7 @@ def test_is_nan_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <0> to be , but was not.') + def test_is_nan_bad_type_failure(): try: assert_that('foo').is_nan() @@ -88,6 +96,7 @@ def test_is_nan_bad_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric') + def test_is_nan_bad_type_failure_complex(): try: assert_that(1 + 2j).is_nan() @@ -95,10 +104,12 @@ def test_is_nan_bad_type_failure_complex(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not real number') + def test_is_not_nan(): assert_that(1).is_not_nan() assert_that(1.0).is_not_nan() + def test_is_not_nan_failure(): try: assert_that(float('NaN')).is_not_nan() @@ -106,6 +117,7 @@ def test_is_not_nan_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected not , but was.') + def test_is_not_nan_bad_type_failure(): try: assert_that('foo').is_not_nan() @@ -113,6 +125,7 @@ def test_is_not_nan_bad_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric') + def test_is_not_nan_bad_type_failure_complex(): try: assert_that(1 + 2j).is_not_nan() @@ -120,10 +133,12 @@ def test_is_not_nan_bad_type_failure_complex(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not real number') + def test_is_inf(): assert_that(float('Inf')).is_inf() assert_that(1e1000).is_inf() + def test_is_inf_failure(): try: assert_that(0).is_inf() @@ -131,6 +146,7 @@ def test_is_inf_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <0> to be , but was not.') + def test_is_inf_bad_type_failure(): try: assert_that('foo').is_inf() @@ -138,6 +154,7 @@ def test_is_inf_bad_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric') + def test_is_inf_bad_type_failure_complex(): try: assert_that(1 + 2j).is_inf() @@ -145,10 +162,12 @@ def test_is_inf_bad_type_failure_complex(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not real number') + def test_is_not_inf(): assert_that(1).is_not_inf() assert_that(123.456).is_not_inf() + def test_is_not_inf_failure(): try: assert_that(float('Inf')).is_not_inf() @@ -156,6 +175,7 @@ def test_is_not_inf_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected not , but was.') + def test_is_not_inf_bad_type_failure(): try: assert_that('foo').is_not_inf() @@ -163,6 +183,7 @@ def test_is_not_inf_bad_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric') + def test_is_not_inf_bad_type_failure_complex(): try: assert_that(1 + 2j).is_not_inf() @@ -170,12 +191,14 @@ def test_is_not_inf_bad_type_failure_complex(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not real number') + def test_is_greater_than(): assert_that(123).is_greater_than(100) assert_that(123).is_greater_than(0) assert_that(123).is_greater_than(-100) assert_that(123).is_greater_than(122.5) + def test_is_greater_than_failure(): try: assert_that(123).is_greater_than(123) @@ -183,6 +206,7 @@ def test_is_greater_than_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be greater than <123>, but was not.') + def test_is_greater_than_complex_failure(): try: assert_that(1 + 2j).is_greater_than(0) @@ -190,6 +214,7 @@ def test_is_greater_than_complex_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_greater_than_bad_value_type_failure(): try: assert_that('foo').is_greater_than(0) @@ -197,6 +222,7 @@ def test_is_greater_than_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_greater_than_bad_arg_type_failure(): try: assert_that(123).is_greater_than('foo') @@ -204,6 +230,7 @@ def test_is_greater_than_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a number, but was ') + def test_is_greater_than_or_equal_to(): assert_that(123).is_greater_than_or_equal_to(100) assert_that(123).is_greater_than_or_equal_to(123) @@ -211,6 +238,7 @@ def test_is_greater_than_or_equal_to(): assert_that(123).is_greater_than_or_equal_to(-100) assert_that(123).is_greater_than_or_equal_to(122.5) + def test_is_greater_than_or_equal_to_failure(): try: assert_that(123).is_greater_than_or_equal_to(1000) @@ -218,6 +246,7 @@ def test_is_greater_than_or_equal_to_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be greater than or equal to <1000>, but was not.') + def test_is_greater_than_or_equal_to_complex_failure(): try: assert_that(1 + 2j).is_greater_than_or_equal_to(0) @@ -225,6 +254,7 @@ def test_is_greater_than_or_equal_to_complex_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_greater_than_or_equal_to_bad_value_type_failure(): try: assert_that('foo').is_greater_than_or_equal_to(0) @@ -232,6 +262,7 @@ def test_is_greater_than_or_equal_to_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_greater_than_or_equal_to_bad_arg_type_failure(): try: assert_that(123).is_greater_than_or_equal_to('foo') @@ -239,12 +270,14 @@ def test_is_greater_than_or_equal_to_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a number, but was ') + def test_is_less_than(): assert_that(123).is_less_than(1000) assert_that(123).is_less_than(1e6) assert_that(-123).is_less_than(-100) assert_that(123).is_less_than(123.001) + def test_is_less_than_failure(): try: assert_that(123).is_less_than(123) @@ -252,6 +285,7 @@ def test_is_less_than_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be less than <123>, but was not.') + def test_is_less_than_complex_failure(): try: assert_that(1 + 2j).is_less_than(0) @@ -259,6 +293,7 @@ def test_is_less_than_complex_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_less_than_bad_value_type_failure(): try: assert_that('foo').is_less_than(0) @@ -266,6 +301,7 @@ def test_is_less_than_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_less_than_bad_arg_type_failure(): try: assert_that(123).is_less_than('foo') @@ -273,6 +309,7 @@ def test_is_less_than_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a number, but was ') + def test_is_less_than_or_equal_to(): assert_that(123).is_less_than_or_equal_to(1000) assert_that(123).is_less_than_or_equal_to(123) @@ -280,6 +317,7 @@ def test_is_less_than_or_equal_to(): assert_that(-123).is_less_than_or_equal_to(-100) assert_that(123).is_less_than_or_equal_to(123.001) + def test_is_less_than_or_equal_to_failure(): try: assert_that(123).is_less_than_or_equal_to(100) @@ -287,6 +325,7 @@ def test_is_less_than_or_equal_to_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be less than or equal to <100>, but was not.') + def test_is_less_than_or_equal_to_complex_failure(): try: assert_that(1 + 2j).is_less_than_or_equal_to(0) @@ -294,6 +333,7 @@ def test_is_less_than_or_equal_to_complex_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_less_than_or_equal_to_bad_value_type_failure(): try: assert_that('foo').is_less_than_or_equal_to(0) @@ -301,6 +341,7 @@ def test_is_less_than_or_equal_to_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_less_than_or_equal_to_bad_arg_type_failure(): try: assert_that(123).is_less_than_or_equal_to('foo') @@ -308,9 +349,11 @@ def test_is_less_than_or_equal_to_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a number, but was ') + def test_is_positive(): assert_that(1).is_positive() + def test_is_positive_failure(): try: assert_that(0).is_positive() @@ -318,9 +361,11 @@ def test_is_positive_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <0> to be greater than <0>, but was not.') + def test_is_negative(): assert_that(-1).is_negative() + def test_is_negative_failure(): try: assert_that(0).is_negative() @@ -328,196 +373,224 @@ def test_is_negative_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <0> to be less than <0>, but was not.') + def test_is_between(): - assert_that(123).is_between(120,125) - assert_that(123).is_between(0,1e6) - assert_that(-123).is_between(-150,-100) - assert_that(123).is_between(122.999,123.001) + assert_that(123).is_between(120, 125) + assert_that(123).is_between(0, 1e6) + assert_that(-123).is_between(-150, -100) + assert_that(123).is_between(122.999, 123.001) + def test_is_between_failure(): try: - assert_that(123).is_between(0,1) + assert_that(123).is_between(0, 1) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be between <0> and <1>, but was not.') + def test_is_between_complex_failure(): try: - assert_that(1 + 2j).is_between(0,1) + assert_that(1 + 2j).is_between(0, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_between_bad_value_type_failure(): try: - assert_that('foo').is_between(0,1) + assert_that('foo').is_between(0, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_between_low_arg_type_failure(): try: - assert_that(123).is_between('foo',1) + assert_that(123).is_between('foo', 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given low arg must be numeric, but was ') + def test_is_between_high_arg_type_failure(): try: - assert_that(123).is_between(0,'foo') + assert_that(123).is_between(0, 'foo') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given high arg must be numeric, but was ') + def test_is_between_bad_arg_delta_failure(): try: - assert_that(123).is_between(1,0) + assert_that(123).is_between(1, 0) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('given low arg must be less than given high arg') + def test_is_not_between(): - assert_that(123).is_not_between(124,125) - assert_that(123).is_not_between(1e5,1e6) - assert_that(-123).is_not_between(-1000,-150) - assert_that(123).is_not_between(122.999,122.9999) + assert_that(123).is_not_between(124, 125) + assert_that(123).is_not_between(1e5, 1e6) + assert_that(-123).is_not_between(-1000, -150) + assert_that(123).is_not_between(122.999, 122.9999) + def test_is_not_between_failure(): try: - assert_that(123).is_not_between(0,1000) + assert_that(123).is_not_between(0, 1000) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to not be between <0> and <1000>, but was.') + def test_is_not_between_complex_failure(): try: - assert_that(1 + 2j).is_not_between(0,1) + assert_that(1 + 2j).is_not_between(0, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_not_between_bad_value_type_failure(): try: - assert_that('foo').is_not_between(0,1) + assert_that('foo').is_not_between(0, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for type ') + def test_is_not_between_low_arg_type_failure(): try: - assert_that(123).is_not_between('foo',1) + assert_that(123).is_not_between('foo', 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given low arg must be numeric, but was ') + def test_is_not_between_high_arg_type_failure(): try: - assert_that(123).is_not_between(0,'foo') + assert_that(123).is_not_between(0, 'foo') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given high arg must be numeric, but was ') + def test_is_not_between_bad_arg_delta_failure(): try: - assert_that(123).is_not_between(1,0) + assert_that(123).is_not_between(1, 0) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('given low arg must be less than given high arg') + def test_is_close_to(): - assert_that(123.01).is_close_to(123,1) - assert_that(0.01).is_close_to(0,1) - assert_that(-123.01).is_close_to(-123,1) + assert_that(123.01).is_close_to(123, 1) + assert_that(0.01).is_close_to(0, 1) + assert_that(-123.01).is_close_to(-123, 1) + def test_is_close_to_failure(): try: - assert_that(123.01).is_close_to(100,1) + assert_that(123.01).is_close_to(100, 1) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123.01> to be close to <100> within tolerance <1>, but was not.') + def test_is_close_to_complex_failure(): try: - assert_that(1 + 2j).is_close_to(0,1) + assert_that(1 + 2j).is_close_to(0, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for complex numbers') + def test_is_close_to_bad_value_type_failure(): try: - assert_that('foo').is_close_to(123,1) + assert_that('foo').is_close_to(123, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric or datetime') + def test_is_close_to_bad_arg_type_failure(): try: - assert_that(123.01).is_close_to('foo',1) + assert_that(123.01).is_close_to('foo', 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be numeric') + def test_is_close_to_bad_tolerance_arg_type_failure(): try: - assert_that(123.01).is_close_to(0,'foo') + assert_that(123.01).is_close_to(0, 'foo') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given tolerance arg must be numeric') + def test_is_close_to_negative_tolerance_failure(): try: - assert_that(123.01).is_close_to(123,-1) + assert_that(123.01).is_close_to(123, -1) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('given tolerance arg must be positive') + def test_is_not_close_to(): - assert_that(123.01).is_not_close_to(122,1) - assert_that(0.01).is_not_close_to(0,0.001) - assert_that(-123.01).is_not_close_to(-122,1) + assert_that(123.01).is_not_close_to(122, 1) + assert_that(0.01).is_not_close_to(0, 0.001) + assert_that(-123.01).is_not_close_to(-122, 1) + def test_is_not_close_to_failure(): try: - assert_that(123.01).is_not_close_to(123,1) + assert_that(123.01).is_not_close_to(123, 1) fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123.01> to not be close to <123> within tolerance <1>, but was.') + def test_is_not_close_to_complex_failure(): try: - assert_that(1 + 2j).is_not_close_to(0,1) + assert_that(1 + 2j).is_not_close_to(0, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('ordering is not defined for complex numbers') + def test_is_not_close_to_bad_value_type_failure(): try: - assert_that('foo').is_not_close_to(123,1) + assert_that('foo').is_not_close_to(123, 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not numeric or datetime') + def test_is_not_close_to_bad_arg_type_failure(): try: - assert_that(123.01).is_not_close_to('foo',1) + assert_that(123.01).is_not_close_to('foo', 1) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be numeric') + def test_is_not_close_to_bad_tolerance_arg_type_failure(): try: - assert_that(123.01).is_not_close_to(0,'foo') + assert_that(123.01).is_not_close_to(0, 'foo') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given tolerance arg must be numeric') + def test_is_not_close_to_negative_tolerance_failure(): try: - assert_that(123.01).is_not_close_to(123,-1) + assert_that(123.01).is_not_close_to(123, -1) fail('should have raised error') except ValueError as ex: assert_that(str(ex)).is_equal_to('given tolerance arg must be positive') -def test_chaining(): - assert_that(123).is_greater_than(100).is_less_than(1000).is_between(120,125).is_close_to(100,25) +def test_chaining(): + assert_that(123).is_greater_than(100).is_less_than(1000).is_between(120, 125).is_close_to(100, 25) diff --git a/tests/test_readme.py b/tests/test_readme.py index 450862f..c66ed4b 100644 --- a/tests/test_readme.py +++ b/tests/test_readme.py @@ -31,452 +31,472 @@ import datetime from assertpy import assert_that, assert_warn, soft_assertions, contents_of, fail -class TestReadme(object): - - @classmethod - def setupClass(cls): - print('\nTEST test_readme.py : v%d.%d.%d' % (sys.version_info[0], sys.version_info[1], sys.version_info[2])) - - def setup(self): - with open('foo.txt', 'w') as fp: - fp.write('foobar') - - def teardown(self): - os.remove('foo.txt') - - def test_something(self): - assert_that(1 + 2).is_equal_to(3) - assert_that('foobar').is_length(6).starts_with('foo').ends_with('bar') - assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x') - - def test_strings(self): - assert_that('').is_not_none() - assert_that('').is_empty() - assert_that('').is_false() - assert_that('').is_type_of(str) - assert_that('').is_instance_of(str) - - assert_that('foo').is_length(3) - assert_that('foo').is_not_empty() - assert_that('foo').is_true() - assert_that('foo').is_alpha() - assert_that('123').is_digit() - assert_that('foo').is_lower() - assert_that('FOO').is_upper() - assert_that('foo').is_iterable() - assert_that('foo').is_equal_to('foo') - assert_that('foo').is_not_equal_to('bar') - assert_that('foo').is_equal_to_ignoring_case('FOO') - - if sys.version_info[0] == 3: - assert_that('foo').is_unicode() - else: - assert_that(u'foo').is_unicode() - - assert_that('foo').contains('f') - assert_that('foo').contains('f','oo') - assert_that('foo').contains_ignoring_case('F','oO') - assert_that('foo').does_not_contain('x') - assert_that('foo').contains_only('f','o') - assert_that('foo').contains_sequence('o','o') - - assert_that('foo').contains_duplicates() - assert_that('fox').does_not_contain_duplicates() - - assert_that('foo').is_in('foo','bar','baz') - assert_that('foo').is_not_in('boo','bar','baz') - assert_that('foo').is_subset_of('abcdefghijklmnopqrstuvwxyz') - - assert_that('foo').starts_with('f') - assert_that('foo').ends_with('oo') - - assert_that('foo').matches(r'\w') - assert_that('123-456-7890').matches(r'\d{3}-\d{3}-\d{4}') - assert_that('foo').does_not_match(r'\d+') - - # partial matches, these all pass - assert_that('foo').matches(r'\w') - assert_that('foo').matches(r'oo') - assert_that('foo').matches(r'\w{2}') - - # match the entire string with an anchored regex pattern, passes - assert_that('foo').matches(r'^\w{3}$') - - # fails - try: - assert_that('foo').matches(r'^\w{2}$') - fail('should have raised error') - except AssertionError: - pass - - def test_ints(self): - assert_that(0).is_not_none() - assert_that(0).is_false() - assert_that(0).is_type_of(int) - assert_that(0).is_instance_of(int) - - assert_that(0).is_zero() - assert_that(1).is_not_zero() - assert_that(1).is_positive() - assert_that(-1).is_negative() - - assert_that(123).is_equal_to(123) - assert_that(123).is_not_equal_to(456) - - assert_that(123).is_greater_than(100) - assert_that(123).is_greater_than_or_equal_to(123) - assert_that(123).is_less_than(200) - assert_that(123).is_less_than_or_equal_to(200) - assert_that(123).is_between(100, 200) - assert_that(123).is_close_to(100, 25) - - assert_that(1).is_in(0,1,2,3) - assert_that(1).is_not_in(-1,-2,-3) - - - def test_floats(self): - assert_that(0.0).is_not_none() - assert_that(0.0).is_false() - assert_that(0.0).is_type_of(float) - assert_that(0.0).is_instance_of(float) - - assert_that(123.4).is_equal_to(123.4) - assert_that(123.4).is_not_equal_to(456.7) - - assert_that(123.4).is_greater_than(100.1) - assert_that(123.4).is_greater_than_or_equal_to(123.4) - assert_that(123.4).is_less_than(200.2) - assert_that(123.4).is_less_than_or_equal_to(123.4) - assert_that(123.4).is_between(100.1, 200.2) - assert_that(123.4).is_close_to(123, 0.5) - - assert_that(float('NaN')).is_nan() - assert_that(123.4).is_not_nan() - assert_that(float('Inf')).is_inf() - assert_that(123.4).is_not_inf() - - def test_lists(self): - assert_that([]).is_not_none() - assert_that([]).is_empty() - assert_that([]).is_false() - assert_that([]).is_type_of(list) - assert_that([]).is_instance_of(list) - assert_that([]).is_iterable() - - assert_that(['a','b']).is_length(2) - assert_that(['a','b']).is_not_empty() - assert_that(['a','b']).is_equal_to(['a','b']) - assert_that(['a','b']).is_not_equal_to(['b','a']) - - assert_that(['a','b']).contains('a') - assert_that(['a','b']).contains('b','a') - assert_that(['a','b']).does_not_contain('x','y') - assert_that(['a','b']).contains_only('a','b') - assert_that(['a','a']).contains_only('a') - assert_that(['a','b','c']).contains_sequence('b','c') - assert_that(['a','b']).is_subset_of(['a','b','c']) - - assert_that(['a','x','x']).contains_duplicates() - assert_that(['a','b','c']).does_not_contain_duplicates() - - assert_that(['a','b','c']).starts_with('a') - assert_that(['a','b','c']).ends_with('c') - - def test_tuples(self): - assert_that(()).is_not_none() - assert_that(()).is_empty() - assert_that(()).is_false() - assert_that(()).is_type_of(tuple) - assert_that(()).is_instance_of(tuple) - assert_that(()).is_iterable() - - assert_that((1,2,3)).is_length(3) - assert_that((1,2,3)).is_not_empty() - assert_that((1,2,3)).is_equal_to((1,2,3)) - assert_that((1,2,3)).is_not_equal_to((1,2,4)) - - assert_that((1,2,3)).contains(1) - assert_that((1,2,3)).contains(3,2,1) - assert_that((1,2,3)).does_not_contain(4,5,6) - assert_that((1,2,3)).contains_only(1,2,3) - assert_that((1,1,1)).contains_only(1) - assert_that((1,2,3)).contains_sequence(2,3) - assert_that((1,2,3)).is_subset_of((1,2,3,4)) - - assert_that((1,2,2)).contains_duplicates() - assert_that((1,2,3)).does_not_contain_duplicates() - - assert_that((1,2,3)).starts_with(1) - assert_that((1,2,3)).ends_with(3) - - def test_dicts(self): - assert_that({}).is_not_none() - assert_that({}).is_empty() - assert_that({}).is_false() - assert_that({}).is_type_of(dict) - assert_that({}).is_instance_of(dict) - - assert_that({'a':1,'b':2}).is_length(2) - assert_that({'a':1,'b':2}).is_not_empty() - assert_that({'a':1,'b':2}).is_equal_to({'a':1,'b':2}) - assert_that({'a':1,'b':2}).is_equal_to({'b':2,'a':1}) - assert_that({'a':1,'b':2}).is_not_equal_to({'a':1,'b':3}) - - assert_that({'a':1,'b':2}).contains('a') - assert_that({'a':1,'b':2}).contains('b','a') - assert_that({'a':1,'b':2}).does_not_contain('x') - assert_that({'a':1,'b':2}).does_not_contain('x','y') - assert_that({'a':1,'b':2}).contains_only('a','b') - assert_that({'a':1,'b':2}).is_subset_of({'a':1,'b':2,'c':3}) - - # contains_key() is just an alias for contains() - assert_that({'a':1,'b':2}).contains_key('a') - assert_that({'a':1,'b':2}).contains_key('b','a') - - # does_not_contain_key() is just an alias for does_not_contain() - assert_that({'a':1,'b':2}).does_not_contain_key('x') - assert_that({'a':1,'b':2}).does_not_contain_key('x','y') - - assert_that({'a':1,'b':2}).contains_value(1) - assert_that({'a':1,'b':2}).contains_value(2,1) - assert_that({'a':1,'b':2}).does_not_contain_value(3) - assert_that({'a':1,'b':2}).does_not_contain_value(3,4) - - assert_that({'a':1,'b':2}).contains_entry({'a':1}) - assert_that({'a':1,'b':2}).contains_entry({'a':1},{'b':2}) - assert_that({'a':1,'b':2}).does_not_contain_entry({'a':2}) - assert_that({'a':1,'b':2}).does_not_contain_entry({'a':2},{'b':1}) - - # lists of dicts can be flattened on key - fred = {'first_name': 'Fred', 'last_name': 'Smith'} - bob = {'first_name': 'Bob', 'last_name': 'Barr'} - people = [fred, bob] - - assert_that(people).extracting('first_name').is_equal_to(['Fred','Bob']) - assert_that(people).extracting('first_name').contains('Fred','Bob') - - def test_dict_compare(self): - # ignore - assert_that({'a':1,'b':2}).is_equal_to({'a':1}, ignore='b') - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1}, ignore=['b','c']) - assert_that({'a':1,'b':{'c':2,'d':3}}).is_equal_to({'a':1,'b':{'c':2}}, ignore=('b','d')) - - # include - assert_that({'a':1,'b':2}).is_equal_to({'a':1}, include='a') - assert_that({'a':1,'b':2,'c':3}).is_equal_to({'a':1,'b':2}, include=['a','b']) - assert_that({'a':1,'b':{'c':2,'d':3}}).is_equal_to({'b':{'d':3}}, include=('b','d')) - - # both - assert_that({'a':1,'b':{'c':2,'d':3,'e':4,'f':5}}).is_equal_to( - {'b':{'d':3,'f':5}}, - ignore=[('b','c'),('b','e')], - include='b' - ) - - def test_sets(self): - assert_that(set([])).is_not_none() - assert_that(set([])).is_empty() - assert_that(set([])).is_false() - assert_that(set([])).is_type_of(set) - assert_that(set([])).is_instance_of(set) - - assert_that(set(['a','b'])).is_length(2) - assert_that(set(['a','b'])).is_not_empty() - assert_that(set(['a','b'])).is_equal_to(set(['a','b'])) - assert_that(set(['a','b'])).is_equal_to(set(['b','a'])) - assert_that(set(['a','b'])).is_not_equal_to(set(['a','x'])) - - assert_that(set(['a','b'])).contains('a') - assert_that(set(['a','b'])).contains('b','a') - assert_that(set(['a','b'])).does_not_contain('x','y') - assert_that(set(['a','b'])).contains_only('a','b') - assert_that(set(['a','b'])).is_subset_of(set(['a','b','c'])) - assert_that(set(['a','b'])).is_subset_of(set(['a']), set(['b'])) - - def test_booleans(self): - assert_that(True).is_true() - assert_that(False).is_false() - assert_that(True).is_type_of(bool) - - def test_dates(self): - today = datetime.datetime.today() - yesterday = today - datetime.timedelta(days=1) - - assert_that(yesterday).is_before(today) - assert_that(today).is_after(yesterday) - - today_0us = today - datetime.timedelta(microseconds=today.microsecond) - today_0s = today - datetime.timedelta(seconds=today.second) - today_0h = today - datetime.timedelta(hours=today.hour) - - assert_that(today).is_equal_to_ignoring_milliseconds(today_0us) - assert_that(today).is_equal_to_ignoring_seconds(today_0s) - assert_that(today).is_equal_to_ignoring_time(today_0h) - assert_that(today).is_equal_to(today) - - middle = today - datetime.timedelta(hours=12) - hours_24 = datetime.timedelta(hours=24) - - assert_that(today).is_greater_than(yesterday) - assert_that(yesterday).is_less_than(today) - assert_that(middle).is_between(yesterday, today) - - #note that the tolerance must be a datetime.timedelta object - assert_that(yesterday).is_close_to(today, hours_24) - - # 1980-01-02 03:04:05.000006 - x = datetime.datetime(1980, 1, 2, 3, 4, 5, 6) - - assert_that(x).has_year(1980) - assert_that(x).has_month(1) - assert_that(x).has_day(2) - assert_that(x).has_hour(3) - assert_that(x).has_minute(4) - assert_that(x).has_second(5) - assert_that(x).has_microsecond(6) - - def test_files(self): - assert_that('foo.txt').exists() - assert_that('missing.txt').does_not_exist() - assert_that('foo.txt').is_file() - - - #assert_that('mydir').exists() - assert_that('missing_dir').does_not_exist() - #assert_that('mydir').is_directory() - - assert_that('foo.txt').is_named('foo.txt') - #assert_that('foo.txt').is_child_of('mydir') - - contents = contents_of('foo.txt', 'ascii') - assert_that(contents).starts_with('foo').ends_with('bar').contains('oob') - - def test_objects(self): - fred = Person('Fred','Smith') - - assert_that(fred).is_not_none() - assert_that(fred).is_true() - assert_that(fred).is_type_of(Person) - assert_that(fred).is_instance_of(object) - assert_that(fred).is_same_as(fred) - - assert_that(fred.first_name).is_equal_to('Fred') - assert_that(fred.name).is_equal_to('Fred Smith') - assert_that(fred.say_hello()).is_equal_to('Hello, Fred!') - - fred = Person('Fred','Smith') - bob = Person('Bob','Barr') - people = [fred, bob] - - assert_that(people).extracting('first_name').is_equal_to(['Fred','Bob']) - assert_that(people).extracting('first_name').contains('Fred','Bob') - assert_that(people).extracting('first_name').does_not_contain('Charlie') - - fred = Person('Fred','Smith') - joe = Developer('Joe','Coder') - people = [fred, joe] - - assert_that(people).extracting('first_name').contains('Fred','Joe') - - assert_that(people).extracting('first_name', 'last_name').contains(('Fred','Smith'), ('Joe','Coder')) - - assert_that(people).extracting('name').contains('Fred Smith', 'Joe Coder') - assert_that(people).extracting('say_hello').contains('Hello, Fred!', 'Joe writes code.') - - def test_dyn(self): - fred = Person('Fred','Smith') - - assert_that(fred.first_name).is_equal_to('Fred') - assert_that(fred.name).is_equal_to('Fred Smith') - assert_that(fred.say_hello()).is_equal_to('Hello, Fred!') - - assert_that(fred).has_first_name('Fred') - assert_that(fred).has_name('Fred Smith') - assert_that(fred).has_say_hello('Hello, Fred!') - - def test_failure(self): - try: - some_func('foo') - fail('should have raised error') - except RuntimeError as e: - assert_that(str(e)).is_equal_to('some err') - - def test_expected_exceptions(self): - assert_that(some_func).raises(RuntimeError).when_called_with('foo') - assert_that(some_func).raises(RuntimeError).when_called_with('foo')\ - .is_length(8).starts_with('some').is_equal_to('some err') - - def test_custom_error_message(self): - try: - assert_that(1+2).is_equal_to(2) - fail('should have raised error') - except AssertionError as e: - assert_that(str(e)).is_equal_to('Expected <3> to be equal to <2>, but was not.') - - try: - assert_that(1+2).described_as('adding stuff').is_equal_to(2) - fail('should have raised error') - except AssertionError as e: - assert_that(str(e)).is_equal_to('[adding stuff] Expected <3> to be equal to <2>, but was not.') - - def test_assert_warn(self): - assert_warn('foo').is_length(4) - assert_warn('foo').is_empty() - assert_warn('foo').is_false() - assert_warn('foo').is_digit() - assert_warn('123').is_alpha() - assert_warn('foo').is_upper() - assert_warn('FOO').is_lower() - assert_warn('foo').is_equal_to('bar') - assert_warn('foo').is_not_equal_to('foo') - assert_warn('foo').is_equal_to_ignoring_case('BAR') - - def test_soft_assertions(self): - try: - with soft_assertions(): - assert_that('foo').is_length(4) - assert_that('foo').is_empty() - assert_that('foo').is_false() - assert_that('foo').is_digit() - assert_that('123').is_alpha() - assert_that('foo').is_upper() - assert_that('FOO').is_lower() - assert_that('foo').is_equal_to('bar') - assert_that('foo').is_not_equal_to('foo') - assert_that('foo').is_equal_to_ignoring_case('BAR') - fail('should have raised error') - except AssertionError as e: - assert_that(str(e)).contains('1. Expected to be of length <4>, but was <3>.') - assert_that(str(e)).contains('2. Expected to be empty string, but was not.') - assert_that(str(e)).contains('3. Expected , but was not.') - assert_that(str(e)).contains('4. Expected to contain only digits, but did not.') - assert_that(str(e)).contains('5. Expected <123> to contain only alphabetic chars, but did not.') - assert_that(str(e)).contains('6. Expected to contain only uppercase chars, but did not.') - assert_that(str(e)).contains('7. Expected to contain only lowercase chars, but did not.') - assert_that(str(e)).contains('8. Expected to be equal to , but was not.') - assert_that(str(e)).contains('9. Expected to be not equal to , but was.') - assert_that(str(e)).contains('10. Expected to be case-insensitive equal to , but was not.') - - def test_chaining(self): - fred = Person('Fred','Smith') - joe = Person('Joe','Jones') - people = [fred, joe] - - assert_that('foo').is_length(3).starts_with('f').ends_with('oo') - - assert_that([1,2,3]).is_type_of(list).contains(1,2).does_not_contain(4,5) - - assert_that(fred).has_first_name('Fred').has_last_name('Smith').has_shoe_size(12) - - assert_that(people).is_length(2).extracting('first_name').contains('Fred','Joe') + +def setup_module(): + print('\nTEST test_readme.py : v%d.%d.%d' % (sys.version_info[0], sys.version_info[1], sys.version_info[2])) + + +def test_something(): + assert_that(1 + 2).is_equal_to(3) + assert_that('foobar').is_length(6).starts_with('foo').ends_with('bar') + assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x') + + +def test_strings(): + assert_that('').is_not_none() + assert_that('').is_empty() + assert_that('').is_false() + assert_that('').is_type_of(str) + assert_that('').is_instance_of(str) + + assert_that('foo').is_length(3) + assert_that('foo').is_not_empty() + assert_that('foo').is_true() + assert_that('foo').is_alpha() + assert_that('123').is_digit() + assert_that('foo').is_lower() + assert_that('FOO').is_upper() + assert_that('foo').is_iterable() + assert_that('foo').is_equal_to('foo') + assert_that('foo').is_not_equal_to('bar') + assert_that('foo').is_equal_to_ignoring_case('FOO') + + if sys.version_info[0] == 3: + assert_that('foo').is_unicode() + else: + assert_that(u'foo').is_unicode() + + assert_that('foo').contains('f') + assert_that('foo').contains('f', 'oo') + assert_that('foo').contains_ignoring_case('F', 'oO') + assert_that('foo').does_not_contain('x') + assert_that('foo').contains_only('f', 'o') + assert_that('foo').contains_sequence('o', 'o') + + assert_that('foo').contains_duplicates() + assert_that('fox').does_not_contain_duplicates() + + assert_that('foo').is_in('foo', 'bar', 'baz') + assert_that('foo').is_not_in('boo', 'bar', 'baz') + assert_that('foo').is_subset_of('abcdefghijklmnopqrstuvwxyz') + + assert_that('foo').starts_with('f') + assert_that('foo').ends_with('oo') + + assert_that('foo').matches(r'\w') + assert_that('123-456-7890').matches(r'\d{3}-\d{3}-\d{4}') + assert_that('foo').does_not_match(r'\d+') + + # partial matches, these all pass + assert_that('foo').matches(r'\w') + assert_that('foo').matches(r'oo') + assert_that('foo').matches(r'\w{2}') + + # match the entire string with an anchored regex pattern, passes + assert_that('foo').matches(r'^\w{3}$') + + # fails + try: + assert_that('foo').matches(r'^\w{2}$') + fail('should have raised error') + except AssertionError: + pass + + +def test_ints(): + assert_that(0).is_not_none() + assert_that(0).is_false() + assert_that(0).is_type_of(int) + assert_that(0).is_instance_of(int) + + assert_that(0).is_zero() + assert_that(1).is_not_zero() + assert_that(1).is_positive() + assert_that(-1).is_negative() + + assert_that(123).is_equal_to(123) + assert_that(123).is_not_equal_to(456) + + assert_that(123).is_greater_than(100) + assert_that(123).is_greater_than_or_equal_to(123) + assert_that(123).is_less_than(200) + assert_that(123).is_less_than_or_equal_to(200) + assert_that(123).is_between(100, 200) + assert_that(123).is_close_to(100, 25) + + assert_that(1).is_in(0, 1, 2, 3) + assert_that(1).is_not_in(-1, -2, -3) + + +def test_floats(): + assert_that(0.0).is_not_none() + assert_that(0.0).is_false() + assert_that(0.0).is_type_of(float) + assert_that(0.0).is_instance_of(float) + + assert_that(123.4).is_equal_to(123.4) + assert_that(123.4).is_not_equal_to(456.7) + + assert_that(123.4).is_greater_than(100.1) + assert_that(123.4).is_greater_than_or_equal_to(123.4) + assert_that(123.4).is_less_than(200.2) + assert_that(123.4).is_less_than_or_equal_to(123.4) + assert_that(123.4).is_between(100.1, 200.2) + assert_that(123.4).is_close_to(123, 0.5) + + assert_that(float('NaN')).is_nan() + assert_that(123.4).is_not_nan() + assert_that(float('Inf')).is_inf() + assert_that(123.4).is_not_inf() + + +def test_lists(): + assert_that([]).is_not_none() + assert_that([]).is_empty() + assert_that([]).is_false() + assert_that([]).is_type_of(list) + assert_that([]).is_instance_of(list) + assert_that([]).is_iterable() + + assert_that(['a', 'b']).is_length(2) + assert_that(['a', 'b']).is_not_empty() + assert_that(['a', 'b']).is_equal_to(['a', 'b']) + assert_that(['a', 'b']).is_not_equal_to(['b', 'a']) + + assert_that(['a', 'b']).contains('a') + assert_that(['a', 'b']).contains('b', 'a') + assert_that(['a', 'b']).does_not_contain('x', 'y') + assert_that(['a', 'b']).contains_only('a', 'b') + assert_that(['a', 'a']).contains_only('a') + assert_that(['a', 'b', 'c']).contains_sequence('b', 'c') + assert_that(['a', 'b']).is_subset_of(['a', 'b', 'c']) + assert_that(['a', 'b', 'c']).is_sorted() + assert_that(['c', 'b', 'a']).is_sorted(reverse=True) + + assert_that(['a', 'x', 'x']).contains_duplicates() + assert_that(['a', 'b', 'c']).does_not_contain_duplicates() + + assert_that(['a', 'b', 'c']).starts_with('a') + assert_that(['a', 'b', 'c']).ends_with('c') + + +def test_tuples(): + assert_that(()).is_not_none() + assert_that(()).is_empty() + assert_that(()).is_false() + assert_that(()).is_type_of(tuple) + assert_that(()).is_instance_of(tuple) + assert_that(()).is_iterable() + + assert_that((1, 2, 3)).is_length(3) + assert_that((1, 2, 3)).is_not_empty() + assert_that((1, 2, 3)).is_equal_to((1, 2, 3)) + assert_that((1, 2, 3)).is_not_equal_to((1, 2, 4)) + + assert_that((1, 2, 3)).contains(1) + assert_that((1, 2, 3)).contains(3, 2, 1) + assert_that((1, 2, 3)).does_not_contain(4, 5, 6) + assert_that((1, 2, 3)).contains_only(1, 2, 3) + assert_that((1, 1, 1)).contains_only(1) + assert_that((1, 2, 3)).contains_sequence(2, 3) + assert_that((1, 2, 3)).is_subset_of((1, 2, 3, 4)) + assert_that((1, 2, 3)).is_sorted() + assert_that((3, 2, 1)).is_sorted(reverse=True) + + assert_that((1, 2, 2)).contains_duplicates() + assert_that((1, 2, 3)).does_not_contain_duplicates() + + assert_that((1, 2, 3)).starts_with(1) + assert_that((1, 2, 3)).ends_with(3) + + +def test_dicts(): + assert_that({}).is_not_none() + assert_that({}).is_empty() + assert_that({}).is_false() + assert_that({}).is_type_of(dict) + assert_that({}).is_instance_of(dict) + + assert_that({'a': 1, 'b': 2}).is_length(2) + assert_that({'a': 1, 'b': 2}).is_not_empty() + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 2}) + assert_that({'a': 1, 'b': 2}).is_equal_to({'b': 2, 'a': 1}) + assert_that({'a': 1, 'b': 2}).is_not_equal_to({'a': 1, 'b': 3}) + + assert_that({'a': 1, 'b': 2}).contains('a') + assert_that({'a': 1, 'b': 2}).contains('b', 'a') + assert_that({'a': 1, 'b': 2}).does_not_contain('x') + assert_that({'a': 1, 'b': 2}).does_not_contain('x', 'y') + assert_that({'a': 1, 'b': 2}).contains_only('a', 'b') + assert_that({'a': 1, 'b': 2}).is_subset_of({'a': 1, 'b': 2, 'c': 3}) + + # contains_key() is just an alias for contains() + assert_that({'a': 1, 'b': 2}).contains_key('a') + assert_that({'a': 1, 'b': 2}).contains_key('b', 'a') + + # does_not_contain_key() is just an alias for does_not_contain() + assert_that({'a': 1, 'b': 2}).does_not_contain_key('x') + assert_that({'a': 1, 'b': 2}).does_not_contain_key('x', 'y') + + assert_that({'a': 1, 'b': 2}).contains_value(1) + assert_that({'a': 1, 'b': 2}).contains_value(2, 1) + assert_that({'a': 1, 'b': 2}).does_not_contain_value(3) + assert_that({'a': 1, 'b': 2}).does_not_contain_value(3, 4) + + assert_that({'a': 1, 'b': 2}).contains_entry({'a': 1}) + assert_that({'a': 1, 'b': 2}).contains_entry({'a': 1}, {'b': 2}) + assert_that({'a': 1, 'b': 2}).does_not_contain_entry({'a': 2}) + assert_that({'a': 1, 'b': 2}).does_not_contain_entry({'a': 2}, {'b': 1}) + + # lists of dicts can be flattened on key + fred = {'first_name': 'Fred', 'last_name': 'Smith'} + bob = {'first_name': 'Bob', 'last_name': 'Barr'} + people = [fred, bob] + + assert_that(people).extracting('first_name').is_equal_to(['Fred', 'Bob']) + assert_that(people).extracting('first_name').contains('Fred', 'Bob') + + +def test_dict_compare(): + # ignore + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, ignore='b') + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, ignore=['b', 'c']) + assert_that({'a': 1, 'b': {'c': 2, 'd': 3}}).is_equal_to({'a': 1, 'b': {'c': 2}}, ignore=('b', 'd')) + + # include + assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, include='a') + assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2}, include=['a', 'b']) + assert_that({'a': 1, 'b': {'c': 2, 'd': 3}}).is_equal_to({'b': {'d': 3}}, include=('b', 'd')) + + # both + assert_that({'a': 1, 'b': {'c': 2, 'd': 3, 'e': 4, 'f': 5}}).is_equal_to( + {'b': {'d': 3, 'f': 5}}, + ignore=[('b', 'c'), ('b', 'e')], + include='b' + ) + + +def test_sets(): + assert_that(set([])).is_not_none() + assert_that(set([])).is_empty() + assert_that(set([])).is_false() + assert_that(set([])).is_type_of(set) + assert_that(set([])).is_instance_of(set) + + assert_that(set(['a', 'b'])).is_length(2) + assert_that(set(['a', 'b'])).is_not_empty() + assert_that(set(['a', 'b'])).is_equal_to(set(['a', 'b'])) + assert_that(set(['a', 'b'])).is_equal_to(set(['b', 'a'])) + assert_that(set(['a', 'b'])).is_not_equal_to(set(['a', 'x'])) + + assert_that(set(['a', 'b'])).contains('a') + assert_that(set(['a', 'b'])).contains('b', 'a') + assert_that(set(['a', 'b'])).does_not_contain('x', 'y') + assert_that(set(['a', 'b'])).contains_only('a', 'b') + assert_that(set(['a', 'b'])).is_subset_of(set(['a', 'b', 'c'])) + assert_that(set(['a', 'b'])).is_subset_of(set(['a']), set(['b'])) + + +def test_booleans(): + assert_that(True).is_true() + assert_that(False).is_false() + assert_that(True).is_type_of(bool) + + +def test_dates(): + today = datetime.datetime.today() + yesterday = today - datetime.timedelta(days=1) + + assert_that(yesterday).is_before(today) + assert_that(today).is_after(yesterday) + + today_0us = today - datetime.timedelta(microseconds=today.microsecond) + today_0s = today - datetime.timedelta(seconds=today.second) + today_0h = today - datetime.timedelta(hours=today.hour) + + assert_that(today).is_equal_to_ignoring_milliseconds(today_0us) + assert_that(today).is_equal_to_ignoring_seconds(today_0s) + assert_that(today).is_equal_to_ignoring_time(today_0h) + assert_that(today).is_equal_to(today) + + middle = today - datetime.timedelta(hours=12) + hours_24 = datetime.timedelta(hours=24) + + assert_that(today).is_greater_than(yesterday) + assert_that(yesterday).is_less_than(today) + assert_that(middle).is_between(yesterday, today) + + # note that the tolerance must be a datetime.timedelta object + assert_that(yesterday).is_close_to(today, hours_24) + + # 1980-01-02 03:04:05.000006 + x = datetime.datetime(1980, 1, 2, 3, 4, 5, 6) + + assert_that(x).has_year(1980) + assert_that(x).has_month(1) + assert_that(x).has_day(2) + assert_that(x).has_hour(3) + assert_that(x).has_minute(4) + assert_that(x).has_second(5) + assert_that(x).has_microsecond(6) + + +def test_files(): + # setup + with open('foo.txt', 'w') as fp: + fp.write('foobar') + + assert_that('foo.txt').exists() + assert_that('missing.txt').does_not_exist() + assert_that('foo.txt').is_file() + + # assert_that('mydir').exists() + assert_that('missing_dir').does_not_exist() + # assert_that('mydir').is_directory() + + assert_that('foo.txt').is_named('foo.txt') + # assert_that('foo.txt').is_child_of('mydir') + + contents = contents_of('foo.txt', 'ascii') + assert_that(contents).starts_with('foo').ends_with('bar').contains('oob') + + # teardown + os.remove('foo.txt') + + +def test_objects(): + fred = Person('Fred', 'Smith') + + assert_that(fred).is_not_none() + assert_that(fred).is_true() + assert_that(fred).is_type_of(Person) + assert_that(fred).is_instance_of(object) + assert_that(fred).is_same_as(fred) + + assert_that(fred.first_name).is_equal_to('Fred') + assert_that(fred.name).is_equal_to('Fred Smith') + assert_that(fred.say_hello()).is_equal_to('Hello, Fred!') + + fred = Person('Fred', 'Smith') + bob = Person('Bob', 'Barr') + people = [fred, bob] + + assert_that(people).extracting('first_name').is_equal_to(['Fred', 'Bob']) + assert_that(people).extracting('first_name').contains('Fred', 'Bob') + assert_that(people).extracting('first_name').does_not_contain('Charlie') + + fred = Person('Fred', 'Smith') + joe = Developer('Joe', 'Coder') + people = [fred, joe] + + assert_that(people).extracting('first_name').contains('Fred', 'Joe') + + assert_that(people).extracting('first_name', 'last_name').contains(('Fred', 'Smith'), ('Joe', 'Coder')) + + assert_that(people).extracting('name').contains('Fred Smith', 'Joe Coder') + assert_that(people).extracting('say_hello').contains('Hello, Fred!', 'Joe writes code.') + + +def test_dyn(): + fred = Person('Fred', 'Smith') + + assert_that(fred.first_name).is_equal_to('Fred') + assert_that(fred.name).is_equal_to('Fred Smith') + assert_that(fred.say_hello()).is_equal_to('Hello, Fred!') + + assert_that(fred).has_first_name('Fred') + assert_that(fred).has_name('Fred Smith') + assert_that(fred).has_say_hello('Hello, Fred!') + + +def test_failure(): + try: + some_func('foo') + fail('should have raised error') + except RuntimeError as e: + assert_that(str(e)).is_equal_to('some err') + + +def test_expected_exceptions(): + assert_that(some_func).raises(RuntimeError).when_called_with('foo') + assert_that(some_func).raises(RuntimeError).when_called_with('foo')\ + .is_length(8).starts_with('some').is_equal_to('some err') + + +def test_custom_error_message(): + try: + assert_that(1+2).is_equal_to(2) + fail('should have raised error') + except AssertionError as e: + assert_that(str(e)).is_equal_to('Expected <3> to be equal to <2>, but was not.') + + try: + assert_that(1+2).described_as('adding stuff').is_equal_to(2) + fail('should have raised error') + except AssertionError as e: + assert_that(str(e)).is_equal_to('[adding stuff] Expected <3> to be equal to <2>, but was not.') + + +def test_assert_warn(): + assert_warn('foo').is_length(4) + assert_warn('foo').is_empty() + assert_warn('foo').is_false() + assert_warn('foo').is_digit() + assert_warn('123').is_alpha() + assert_warn('foo').is_upper() + assert_warn('FOO').is_lower() + assert_warn('foo').is_equal_to('bar') + assert_warn('foo').is_not_equal_to('foo') + assert_warn('foo').is_equal_to_ignoring_case('BAR') + + +def test_soft_assertions(): + try: + with soft_assertions(): + assert_that('foo').is_length(4) + assert_that('foo').is_empty() + assert_that('foo').is_false() + assert_that('foo').is_digit() + assert_that('123').is_alpha() + assert_that('foo').is_upper() + assert_that('FOO').is_lower() + assert_that('foo').is_equal_to('bar') + assert_that('foo').is_not_equal_to('foo') + assert_that('foo').is_equal_to_ignoring_case('BAR') + fail('should have raised error') + except AssertionError as e: + assert_that(str(e)).contains('1. Expected to be of length <4>, but was <3>.') + assert_that(str(e)).contains('2. Expected to be empty string, but was not.') + assert_that(str(e)).contains('3. Expected to be , but was not.') + assert_that(str(e)).contains('4. Expected to contain only digits, but did not.') + assert_that(str(e)).contains('5. Expected <123> to contain only alphabetic chars, but did not.') + assert_that(str(e)).contains('6. Expected to contain only uppercase chars, but did not.') + assert_that(str(e)).contains('7. Expected to contain only lowercase chars, but did not.') + assert_that(str(e)).contains('8. Expected to be equal to , but was not.') + assert_that(str(e)).contains('9. Expected to be not equal to , but was.') + assert_that(str(e)).contains('10. Expected to be case-insensitive equal to , but was not.') + + +def test_chaining(): + fred = Person('Fred', 'Smith') + joe = Person('Joe', 'Jones') + people = [fred, joe] + + assert_that('foo').is_length(3).starts_with('f').ends_with('oo') + + assert_that([1, 2, 3]).is_type_of(list).contains(1, 2).does_not_contain(4, 5) + + assert_that(fred).has_first_name('Fred').has_last_name('Smith').has_shoe_size(12) + + assert_that(people).is_length(2).extracting('first_name').contains('Fred', 'Joe') def some_func(arg): - raise RuntimeError('some err') + raise RuntimeError('some err') class Person(object): - def __init__(self, first_name, last_name, shoe_size = 12): + def __init__(self, first_name, last_name, shoe_size=12): self.first_name = first_name self.last_name = last_name self.shoe_size = shoe_size @@ -492,4 +512,3 @@ def say_hello(self): class Developer(Person): def say_hello(self): return '%s writes code.' % self.first_name - diff --git a/tests/test_same_as.py b/tests/test_same_as.py index 06f60ba..0565467 100644 --- a/tests/test_same_as.py +++ b/tests/test_same_as.py @@ -53,13 +53,13 @@ def test_is_not_same_as(): assert_that(obj).is_not_same_as(True) assert_that(1).is_not_same_as(2) - assert_that({'a':1}).is_not_same_as({'a':1}) - assert_that([1,2,3]).is_not_same_as([1,2,3]) + assert_that({'a': 1}).is_not_same_as({'a': 1}) + assert_that([1, 2, 3]).is_not_same_as([1, 2, 3]) if sys.version_info[0] == 3 and sys.version_info[1] >= 7: - assert_that((1,2,3)).is_same_as((1,2,3)) # tuples are identical in py 3.7 + assert_that((1, 2, 3)).is_same_as((1, 2, 3)) # tuples are identical in py 3.7 else: - assert_that((1,2,3)).is_not_same_as((1,2,3)) + assert_that((1, 2, 3)).is_not_same_as((1, 2, 3)) def test_is_not_same_as_failure(): @@ -69,4 +69,3 @@ def test_is_not_same_as_failure(): fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).matches('Expected <.+> to be not identical to <.+>, but was.') - diff --git a/tests/test_snapshots.py b/tests/test_snapshots.py index 5c6bdea..7724646 100644 --- a/tests/test_snapshots.py +++ b/tests/test_snapshots.py @@ -33,7 +33,7 @@ import collections import pytest -from assertpy import assert_that,fail +from assertpy import assert_that, fail if sys.version_info[0] < 3: def test_snapshot_v2(): @@ -45,7 +45,7 @@ def test_snapshot_v2(): if sys.version_info[0] == 3: - @pytest.mark.parametrize('count', [1,2]) + @pytest.mark.parametrize('count', [1, 2]) def test_snapshot_v3(count): # test runs twice if count == 1: @@ -70,33 +70,33 @@ def test_snapshot_v3(count): assert_that('').snapshot() assert_that('foo').snapshot() - assert_that([1,2,3]).snapshot() + assert_that([1, 2, 3]).snapshot() - assert_that(['a','b','c']).snapshot() + assert_that(['a', 'b', 'c']).snapshot() - assert_that([[1,2,3],['a','b','c']]).snapshot() + assert_that([[1, 2, 3], ['a', 'b', 'c']]).snapshot() - assert_that(set(['a','b','c','a'])).snapshot() + assert_that(set(['a', 'b', 'c', 'a'])).snapshot() - assert_that({'a':1,'b':2,'c':3}).snapshot() + assert_that({'a': 1, 'b': 2, 'c': 3}).snapshot() - assert_that({'a': {'x':1},'b': {'y':2},'c': {'z':3}}).snapshot() + assert_that({'a': {'x': 1}, 'b': {'y': 2}, 'c': {'z': 3}}).snapshot() - assert_that({'a': [1,2],'b': [3,4],'c': [5,6]}).snapshot() + assert_that({'a': [1, 2], 'b': [3, 4], 'c': [5, 6]}).snapshot() - assert_that({'a': set([1,2]),'b': set([3,4]),'c': set([5,6])}).snapshot() + assert_that({'a': set([1, 2]), 'b': set([3, 4]), 'c': set([5, 6])}).snapshot() assert_that({'a': {'b': {'c': {'x': {'y': {'z': 1}}}}}}).snapshot() - assert_that(collections.OrderedDict([('a',1), ('c',3), ('b',2)])).snapshot() + assert_that(collections.OrderedDict([('a', 1), ('c', 3), ('b', 2)])).snapshot() assert_that(datetime.datetime(2000, 11, 22, 3, 44, 55)).snapshot() assert_that(1 + 2j).snapshot() - #tuples are always converted to lists...can this be fixed? - #assert_that((1,2,3)).snapshot() - #assert_that({'a': (1,2),'b': (3,4),'c': (5,6)}).snapshot() + # tuples are always converted to lists...can this be fixed? + # assert_that((1, 2, 3)).snapshot() + # assert_that({'a': (1,2), 'b': (3,4), 'c': (5,6)}).snapshot() assert_that({'custom': 'id'}).snapshot(id='mycustomid') @@ -105,9 +105,9 @@ def test_snapshot_v3(count): foo = Foo() foo2 = Foo({ 'a': 1, - 'b': [1,2,3], - 'c': {'x':1,'y':2,'z':3}, - 'd': set([-1,2,-3]), + 'b': [1, 2, 3], + 'c': {'x': 1, 'y': 2, 'z': 3}, + 'd': set([-1, 2, -3]), 'e': datetime.datetime(2000, 11, 22, 3, 44, 55), 'f': -1 - 2j }) @@ -117,7 +117,7 @@ def test_snapshot_v3(count): assert_that(foo.y).is_equal_to(1) assert_that(foo2.x['a']).is_equal_to(1) - assert_that(foo2.x['b']).is_equal_to([1,2,3]) + assert_that(foo2.x['b']).is_equal_to([1, 2, 3]) assert_that(foo2.y).is_equal_to(1) assert_that(bar.x).is_equal_to(0) @@ -143,11 +143,11 @@ def test_snapshot_v3(count): 'floatneg': -987.654, 'empty': '', 'str': 'foo', - 'list': [1,2,3], - 'liststr': ['a','b','c'], - 'listmix': [1, 'a', [2,4,6], set([1,2,3]), 3+6j], - 'set': set([1,2,3]), - 'dict': {'a':1,'b':2,'c':3}, + 'list': [1, 2, 3], + 'liststr': ['a', 'b', 'c'], + 'listmix': [1, 'a', [2, 4, 6], set([1, 2, 3]), 3+6j], + 'set': set([1, 2, 3]), + 'dict': {'a': 1, 'b': 2, 'c': 3}, 'time': datetime.datetime(2000, 11, 22, 3, 44, 55), 'complex': 1 + 2j, 'foo': foo, @@ -156,7 +156,6 @@ def test_snapshot_v3(count): assert_that({'__type__': 'foo', '__data__': 'bar'}).snapshot() - # def test_snapshot_not_serializable(): # try: # assert_that(range(5)).snapshot() @@ -178,7 +177,6 @@ def test_snapshot_custom_path_none(): except ValueError as ex: assert_that(str(ex)).starts_with('failed to create snapshot filename') - class Foo(object): def __init__(self, x=0): self.x = x diff --git a/tests/test_soft.py b/tests/test_soft.py index 0537612..a53775d 100644 --- a/tests/test_soft.py +++ b/tests/test_soft.py @@ -64,7 +64,7 @@ def test_failure(): out = str(e) assert_that(out).contains('Expected to be of length <4>, but was <3>.') assert_that(out).contains('Expected to be empty string, but was not.') - assert_that(out).contains('Expected , but was not.') + assert_that(out).contains('Expected to be , but was not.') assert_that(out).contains('Expected to contain only digits, but did not.') assert_that(out).contains('Expected <123> to contain only alphabetic chars, but did not.') assert_that(out).contains('Expected to contain only uppercase chars, but did not.') @@ -86,7 +86,7 @@ def test_failure_chain(): out = str(e) assert_that(out).contains('Expected to be of length <4>, but was <3>.') assert_that(out).contains('Expected to be empty string, but was not.') - assert_that(out).contains('Expected , but was not.') + assert_that(out).contains('Expected to be , but was not.') assert_that(out).contains('Expected to contain only digits, but did not.') assert_that(out).contains('Expected to contain only uppercase chars, but did not.') assert_that(out).contains('Expected to be equal to , but was not.') @@ -205,4 +205,3 @@ def recurs(i): assert_that(out).contains('4. Expected <4> to be equal to <7>, but was not.') assert_that(out).contains('5. Expected <5> to be equal to <7>, but was not.') assert_that(out).contains('6. Expected <6> to be equal to <7>, but was not.') - diff --git a/tests/test_soft_fail.py b/tests/test_soft_fail.py index 6833b8f..b5d510e 100644 --- a/tests/test_soft_fail.py +++ b/tests/test_soft_fail.py @@ -28,6 +28,7 @@ from assertpy import assert_that, fail, soft_fail, soft_assertions + def test_soft_fail_without_context(): try: soft_fail() @@ -37,6 +38,7 @@ def test_soft_fail_without_context(): assert_that(out).is_equal_to('Fail!') assert_that(out).does_not_contain('should have raised error') + def test_soft_fail_with_msg_without_context(): try: soft_fail('some msg') @@ -46,6 +48,7 @@ def test_soft_fail_with_msg_without_context(): assert_that(out).is_equal_to('Fail: some msg!') assert_that(out).does_not_contain('should have raised error') + def test_soft_fail(): try: with soft_assertions(): @@ -56,6 +59,7 @@ def test_soft_fail(): assert_that(out).contains('Fail!') assert_that(out).does_not_contain('should have raised error') + def test_soft_fail_with_msg(): try: with soft_assertions(): @@ -66,6 +70,7 @@ def test_soft_fail_with_msg(): assert_that(out).contains('Fail: foobar!') assert_that(out).does_not_contain('should have raised error') + def test_soft_fail_with_soft_failing_asserts(): try: with soft_assertions(): @@ -84,6 +89,7 @@ def test_soft_fail_with_soft_failing_asserts(): assert_that(out).contains('Expected to be case-insensitive equal to , but was not.') assert_that(out).does_not_contain('should have raised error') + def test_double_soft_fail(): try: with soft_assertions(): diff --git a/tests/test_string.py b/tests/test_string.py index 251a3cd..bb4ae19 100644 --- a/tests/test_string.py +++ b/tests/test_string.py @@ -26,7 +26,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail import sys @@ -39,6 +39,7 @@ def test_is_length(): assert_that('foo').is_length(3) + def test_is_length_failure(): try: assert_that('foo').is_length(4) @@ -46,12 +47,14 @@ def test_is_length_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be of length <4>, but was <3>.') + def test_contains(): assert_that('foo').contains('f') assert_that('foo').contains('o') - assert_that('foo').contains('fo','o') + assert_that('foo').contains('fo', 'o') assert_that('fred').contains('d') - assert_that('fred').contains('fr','e','d') + assert_that('fred').contains('fr', 'e', 'd') + def test_contains_single_item_failure(): try: @@ -60,26 +63,30 @@ def test_contains_single_item_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to contain item , but did not.') + def test_contains_multi_item_failure(): try: - assert_that('foo').contains('f','x','z') + assert_that('foo').contains('f', 'x', 'z') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected to contain items <'f', 'x', 'z'>, but did not contain <'x', 'z'>.") + def test_contains_multi_item_single_failure(): try: - assert_that('foo').contains('f','o', 'x') + assert_that('foo').contains('f', 'o', 'x') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected to contain items <'f', 'o', 'x'>, but did not contain .") + def test_contains_ignoring_case(): assert_that('foo').contains_ignoring_case('f') assert_that('foo').contains_ignoring_case('F') assert_that('foo').contains_ignoring_case('Oo') assert_that('foo').contains_ignoring_case('f', 'o', 'F', 'O', 'Fo', 'Oo', 'FoO') + def test_contains_ignoring_case_type_failure(): try: assert_that(123).contains_ignoring_case('f') @@ -87,6 +94,7 @@ def test_contains_ignoring_case_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string or iterable') + def test_contains_ignoring_case_missinge_item_failure(): try: assert_that('foo').contains_ignoring_case() @@ -94,6 +102,7 @@ def test_contains_ignoring_case_missinge_item_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') + def test_contains_ignoring_case_single_item_failure(): try: assert_that('foo').contains_ignoring_case('X') @@ -101,6 +110,7 @@ def test_contains_ignoring_case_single_item_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to case-insensitive contain item , but did not.') + def test_contains_ignoring_case_single_item_type_failure(): try: assert_that('foo').contains_ignoring_case(12) @@ -108,13 +118,15 @@ def test_contains_ignoring_case_single_item_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a string') + def test_contains_ignoring_case_multi_item_failure(): try: - assert_that('foo').contains_ignoring_case('F','X','Z') + assert_that('foo').contains_ignoring_case('F', 'X', 'Z') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected to case-insensitive contain items <'F', 'X', 'Z'>, but did not contain <'X', 'Z'>.") + def test_contains_ignoring_case_multi_item_type_failure(): try: assert_that('foo').contains_ignoring_case('F', 12) @@ -122,12 +134,14 @@ def test_contains_ignoring_case_multi_item_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given args must all be strings') + def test_contains_ignoring_case_list(): assert_that(['foo']).contains_ignoring_case('Foo') assert_that(['foo', 'bar', 'baz']).contains_ignoring_case('Foo') assert_that(['foo', 'bar', 'baz']).contains_ignoring_case('Foo', 'bAr') assert_that(['foo', 'bar', 'baz']).contains_ignoring_case('Foo', 'bAr', 'baZ') + def test_contains_ignoring_case_list_elem_type_failure(): try: assert_that([123]).contains_ignoring_case('f') @@ -135,6 +149,7 @@ def test_contains_ignoring_case_list_elem_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val items must all be strings') + def test_contains_ignoring_case_list_multi_elem_type_failure(): try: assert_that(['foo', 123]).contains_ignoring_case('f') @@ -142,6 +157,7 @@ def test_contains_ignoring_case_list_multi_elem_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val items must all be strings') + def test_contains_ignoring_case_list_missinge_item_failure(): try: assert_that(['foo']).contains_ignoring_case() @@ -149,6 +165,7 @@ def test_contains_ignoring_case_list_missinge_item_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('one or more args must be given') + def test_contains_ignoring_case_list_single_item_failure(): try: assert_that(['foo']).contains_ignoring_case('X') @@ -156,6 +173,7 @@ def test_contains_ignoring_case_list_single_item_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['foo']> to case-insensitive contain items , but did not contain .") + def test_contains_ignoring_case_list_single_item_type_failure(): try: assert_that(['foo']).contains_ignoring_case(12) @@ -163,23 +181,27 @@ def test_contains_ignoring_case_list_single_item_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given args must all be strings') + def test_contains_ignoring_case_list_multi_item_failure(): try: - assert_that(['foo','bar']).contains_ignoring_case('Foo','X','Y') + assert_that(['foo', 'bar']).contains_ignoring_case('Foo', 'X', 'Y') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected <['foo', 'bar']> to case-insensitive contain items <'Foo', 'X', 'Y'>, but did not contain <'X', 'Y'>.") + def test_contains_ignoring_case_list_multi_item_type_failure(): try: - assert_that(['foo','bar']).contains_ignoring_case('F', 12) + assert_that(['foo', 'bar']).contains_ignoring_case('F', 12) fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given args must all be strings') + def test_does_not_contain(): assert_that('foo').does_not_contain('x') - assert_that('foo').does_not_contain('x','y') + assert_that('foo').does_not_contain('x', 'y') + def test_does_not_contain_single_item_failure(): try: @@ -188,23 +210,27 @@ def test_does_not_contain_single_item_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to not contain item , but did.') + def test_does_not_contain_list_item_failure(): try: - assert_that('foo').does_not_contain('x','y','f') + assert_that('foo').does_not_contain('x', 'y', 'f') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected to not contain items <'x', 'y', 'f'>, but did contain .") + def test_does_not_contain_list_multi_item_failure(): try: - assert_that('foo').does_not_contain('x','f','o') + assert_that('foo').does_not_contain('x', 'f', 'o') fail('should have raised error') except AssertionError as ex: assert_that(str(ex)).is_equal_to("Expected to not contain items <'x', 'f', 'o'>, but did contain <'f', 'o'>.") + def test_is_empty(): assert_that('').is_empty() + def test_is_empty_failure(): try: assert_that('foo').is_empty() @@ -212,9 +238,11 @@ def test_is_empty_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be empty string, but was not.') + def test_is_not_empty(): assert_that('foo').is_not_empty() + def test_is_not_empty_failure(): try: assert_that('').is_not_empty() @@ -222,11 +250,13 @@ def test_is_not_empty_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected not empty string, but was empty.') + def test_is_equal_ignoring_case(): assert_that('FOO').is_equal_to_ignoring_case('foo') assert_that('foo').is_equal_to_ignoring_case('FOO') assert_that('fOO').is_equal_to_ignoring_case('foo') + def test_is_equal_ignoring_case_failure(): try: assert_that('foo').is_equal_to_ignoring_case('bar') @@ -234,6 +264,7 @@ def test_is_equal_ignoring_case_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be case-insensitive equal to , but was not.') + def test_is_equal_ignoring_case_bad_value_type_failure(): try: assert_that(123).is_equal_to_ignoring_case(12) @@ -241,6 +272,7 @@ def test_is_equal_ignoring_case_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string') + def test_is_equal_ignoring_case_bad_arg_type_failure(): try: assert_that('fred').is_equal_to_ignoring_case(12) @@ -248,11 +280,13 @@ def test_is_equal_ignoring_case_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a string') + def test_starts_with(): assert_that('fred').starts_with('f') assert_that('fred').starts_with('fr') assert_that('fred').starts_with('fred') + def test_starts_with_failure(): try: assert_that('fred').starts_with('bar') @@ -260,6 +294,7 @@ def test_starts_with_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to start with , but did not.') + def test_starts_with_bad_value_type_failure(): try: assert_that(123).starts_with(12) @@ -267,6 +302,7 @@ def test_starts_with_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string or iterable') + def test_starts_with_bad_arg_none_failure(): try: assert_that('fred').starts_with(None) @@ -274,6 +310,7 @@ def test_starts_with_bad_arg_none_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given prefix arg must not be none') + def test_starts_with_bad_arg_type_failure(): try: assert_that('fred').starts_with(123) @@ -281,6 +318,7 @@ def test_starts_with_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given prefix arg must be a string') + def test_starts_with_bad_arg_empty_failure(): try: assert_that('fred').starts_with('') @@ -288,11 +326,13 @@ def test_starts_with_bad_arg_empty_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('given prefix arg must not be empty') + def test_ends_with(): assert_that('fred').ends_with('d') assert_that('fred').ends_with('ed') assert_that('fred').ends_with('fred') + def test_ends_with_failure(): try: assert_that('fred').ends_with('bar') @@ -300,6 +340,7 @@ def test_ends_with_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to end with , but did not.') + def test_ends_with_bad_value_type_failure(): try: assert_that(123).ends_with(12) @@ -307,6 +348,7 @@ def test_ends_with_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string or iterable') + def test_ends_with_bad_arg_none_failure(): try: assert_that('fred').ends_with(None) @@ -314,6 +356,7 @@ def test_ends_with_bad_arg_none_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given suffix arg must not be none') + def test_ends_with_bad_arg_type_failure(): try: assert_that('fred').ends_with(123) @@ -321,6 +364,7 @@ def test_ends_with_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given suffix arg must be a string') + def test_ends_with_bad_arg_empty_failure(): try: assert_that('fred').ends_with('') @@ -328,6 +372,7 @@ def test_ends_with_bad_arg_empty_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('given suffix arg must not be empty') + def test_matches(): assert_that('fred').matches(r'\w') assert_that('fred').matches(r'\w{2}') @@ -336,6 +381,7 @@ def test_matches(): assert_that('fred').matches(r'^.*?$') assert_that('123-456-7890').matches(r'\d{3}-\d{3}-\d{4}') + def test_matches_failure(): try: assert_that('fred').matches(r'\d+') @@ -343,6 +389,7 @@ def test_matches_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to match pattern <\\d+>, but did not.') + def test_matches_bad_value_type_failure(): try: assert_that(123).matches(12) @@ -350,6 +397,7 @@ def test_matches_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string') + def test_matches_bad_arg_type_failure(): try: assert_that('fred').matches(123) @@ -357,6 +405,7 @@ def test_matches_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given pattern arg must be a string') + def test_matches_bad_arg_empty_failure(): try: assert_that('fred').matches('') @@ -364,11 +413,13 @@ def test_matches_bad_arg_empty_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('given pattern arg must not be empty') + def test_does_not_match(): assert_that('fred').does_not_match(r'\d+') assert_that('fred').does_not_match(r'\w{5}') assert_that('123-456-7890').does_not_match(r'^\d+$') + def test_does_not_match_failure(): try: assert_that('fred').does_not_match(r'\w+') @@ -376,6 +427,7 @@ def test_does_not_match_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to not match pattern <\\w+>, but did.') + def test_does_not_match_bad_value_type_failure(): try: assert_that(123).does_not_match(12) @@ -383,6 +435,7 @@ def test_does_not_match_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string') + def test_does_not_match_bad_arg_type_failure(): try: assert_that('fred').does_not_match(123) @@ -390,6 +443,7 @@ def test_does_not_match_bad_arg_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given pattern arg must be a string') + def test_does_not_match_bad_arg_empty_failure(): try: assert_that('fred').does_not_match('') @@ -397,9 +451,11 @@ def test_does_not_match_bad_arg_empty_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('given pattern arg must not be empty') + def test_is_alpha(): assert_that('foo').is_alpha() + def test_is_alpha_digit_failure(): try: assert_that('foo123').is_alpha() @@ -407,6 +463,7 @@ def test_is_alpha_digit_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to contain only alphabetic chars, but did not.') + def test_is_alpha_space_failure(): try: assert_that('foo bar').is_alpha() @@ -414,6 +471,7 @@ def test_is_alpha_space_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to contain only alphabetic chars, but did not.') + def test_is_alpha_punctuation_failure(): try: assert_that('foo,bar').is_alpha() @@ -421,6 +479,7 @@ def test_is_alpha_punctuation_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to contain only alphabetic chars, but did not.') + def test_is_alpha_bad_value_type_failure(): try: assert_that(123).is_alpha() @@ -428,6 +487,7 @@ def test_is_alpha_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string') + def test_is_alpha_empty_value_failure(): try: assert_that('').is_alpha() @@ -435,9 +495,11 @@ def test_is_alpha_empty_value_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('val is empty') + def test_is_digit(): assert_that('123').is_digit() + def test_is_digit_alpha_failure(): try: assert_that('foo123').is_digit() @@ -445,6 +507,7 @@ def test_is_digit_alpha_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to contain only digits, but did not.') + def test_is_digit_space_failure(): try: assert_that('1 000 000').is_digit() @@ -452,6 +515,7 @@ def test_is_digit_space_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <1 000 000> to contain only digits, but did not.') + def test_is_digit_punctuation_failure(): try: assert_that('-123').is_digit() @@ -459,6 +523,7 @@ def test_is_digit_punctuation_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <-123> to contain only digits, but did not.') + def test_is_digit_bad_value_type_failure(): try: assert_that(123).is_digit() @@ -466,6 +531,7 @@ def test_is_digit_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string') + def test_is_digit_empty_value_failure(): try: assert_that('').is_digit() @@ -473,11 +539,13 @@ def test_is_digit_empty_value_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('val is empty') + def test_is_lower(): assert_that('foo').is_lower() assert_that('foo 123').is_lower() assert_that('123 456').is_lower() + def test_is_lower_failure(): try: assert_that('FOO').is_lower() @@ -485,6 +553,7 @@ def test_is_lower_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to contain only lowercase chars, but did not.') + def test_is_lower_bad_value_type_failure(): try: assert_that(123).is_lower() @@ -492,6 +561,7 @@ def test_is_lower_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string') + def test_is_lower_empty_value_failure(): try: assert_that('').is_lower() @@ -499,11 +569,13 @@ def test_is_lower_empty_value_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('val is empty') + def test_is_upper(): assert_that('FOO').is_upper() assert_that('FOO 123').is_upper() assert_that('123 456').is_upper() + def test_is_upper_failure(): try: assert_that('foo').is_upper() @@ -511,6 +583,7 @@ def test_is_upper_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to contain only uppercase chars, but did not.') + def test_is_upper_bad_value_type_failure(): try: assert_that(123).is_upper() @@ -518,6 +591,7 @@ def test_is_upper_bad_value_type_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('val is not a string') + def test_is_upper_empty_value_failure(): try: assert_that('').is_upper() @@ -525,11 +599,13 @@ def test_is_upper_empty_value_failure(): except ValueError as ex: assert_that(str(ex)).is_equal_to('val is empty') + def test_is_unicode(): assert_that(unicode('unicorn')).is_unicode() assert_that(unicode('unicorn 123')).is_unicode() assert_that(unicode('unicorn')).is_unicode() + def test_is_unicode_failure(): try: assert_that(123).is_unicode() @@ -537,7 +613,7 @@ def test_is_unicode_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected <123> to be unicode, but was .') + def test_chaining(): assert_that('foo').is_type_of(str).is_length(3).contains('f').does_not_contain('x') assert_that('fred').starts_with('f').ends_with('d').matches(r'^f.*?d$').does_not_match(r'\d') - diff --git a/tests/test_traceback.py b/tests/test_traceback.py index 340b66c..ffdd15f 100644 --- a/tests/test_traceback.py +++ b/tests/test_traceback.py @@ -28,7 +28,8 @@ import sys import traceback -from assertpy import assert_that,fail +from assertpy import assert_that, fail + def test_traceback(): try: @@ -44,18 +45,18 @@ def test_traceback(): # walk_tb added in 3.5 if sys.version_info[0] == 3 and sys.version_info[1] >= 5: - frames = [(f.f_code.co_filename, f.f_code.co_name, lineno) for f,lineno in traceback.walk_tb(tb)] + frames = [(f.f_code.co_filename, f.f_code.co_name, lineno) for f, lineno in traceback.walk_tb(tb)] assert_that(frames).is_length(3) - + assert_that(frames[0][0]).ends_with('test_traceback.py') assert_that(frames[0][1]).is_equal_to('test_traceback') - assert_that(frames[0][2]).is_equal_to(35) + assert_that(frames[0][2]).is_equal_to(36) assert_that(frames[1][0]).ends_with('base.py') assert_that(frames[1][1]).is_equal_to('is_equal_to') assert_that(frames[1][2]).is_greater_than(40) assert_that(frames[2][0]).ends_with('assertpy.py') - assert_that(frames[2][1]).is_equal_to('_err') + assert_that(frames[2][1]).is_equal_to('error') assert_that(frames[2][2]).is_greater_than(100) diff --git a/tests/test_type.py b/tests/test_type.py index 86915c1..6623ec3 100644 --- a/tests/test_type.py +++ b/tests/test_type.py @@ -26,12 +26,13 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from assertpy import assert_that,fail +from assertpy import assert_that, fail class Foo(object): pass + class Bar(Foo): pass @@ -40,14 +41,15 @@ def test_is_type_of(): assert_that('foo').is_type_of(str) assert_that(123).is_type_of(int) assert_that(0.456).is_type_of(float) - assert_that(['a','b']).is_type_of(list) - assert_that(('a','b')).is_type_of(tuple) - assert_that({ 'a':1,'b':2 }).is_type_of(dict) - assert_that(set(['a','b'])).is_type_of(set) + assert_that(['a', 'b']).is_type_of(list) + assert_that(('a', 'b')).is_type_of(tuple) + assert_that({'a': 1, 'b': 2}).is_type_of(dict) + assert_that(set(['a', 'b'])).is_type_of(set) assert_that(None).is_type_of(type(None)) assert_that(Foo()).is_type_of(Foo) assert_that(Bar()).is_type_of(Bar) + def test_is_type_of_failure(): try: assert_that('foo').is_type_of(int) @@ -55,6 +57,7 @@ def test_is_type_of_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be of type , but was not.') + def test_is_type_of_bad_arg_failure(): try: assert_that('foo').is_type_of('bad') @@ -62,6 +65,7 @@ def test_is_type_of_bad_arg_failure(): except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a type') + def test_is_type_of_subclass_failure(): try: assert_that(Bar()).is_type_of(Foo) @@ -70,19 +74,21 @@ def test_is_type_of_subclass_failure(): assert_that(str(ex)).starts_with('Expected <') assert_that(str(ex)).ends_with(':Bar> to be of type , but was not.') + def test_is_instance_of(): assert_that('foo').is_instance_of(str) assert_that(123).is_instance_of(int) assert_that(0.456).is_instance_of(float) - assert_that(['a','b']).is_instance_of(list) - assert_that(('a','b')).is_instance_of(tuple) - assert_that({ 'a':1,'b':2 }).is_instance_of(dict) - assert_that(set(['a','b'])).is_instance_of(set) + assert_that(['a', 'b']).is_instance_of(list) + assert_that(('a', 'b')).is_instance_of(tuple) + assert_that({'a': 1, 'b': 2}).is_instance_of(dict) + assert_that(set(['a', 'b'])).is_instance_of(set) assert_that(None).is_instance_of(type(None)) assert_that(Foo()).is_instance_of(Foo) assert_that(Bar()).is_instance_of(Bar) assert_that(Bar()).is_instance_of(Foo) + def test_is_instance_of_failure(): try: assert_that('foo').is_instance_of(int) @@ -90,10 +96,10 @@ def test_is_instance_of_failure(): except AssertionError as ex: assert_that(str(ex)).is_equal_to('Expected to be instance of class , but was not.') + def test_is_instance_of_bad_arg_failure(): try: assert_that('foo').is_instance_of('bad') fail('should have raised error') except TypeError as ex: assert_that(str(ex)).is_equal_to('given arg must be a class') - diff --git a/tests/test_warn.py b/tests/test_warn.py index 074213f..d28718e 100644 --- a/tests/test_warn.py +++ b/tests/test_warn.py @@ -31,6 +31,11 @@ from assertpy import assert_that, assert_warn, fail, WarningLoggingAdapter +if sys.version_info[0] == 3: + from io import StringIO +else: + from StringIO import StringIO + def test_success(): assert_warn('foo').is_length(3) @@ -44,12 +49,8 @@ def test_success(): assert_warn('foo').is_not_equal_to('bar') assert_warn('foo').is_equal_to_ignoring_case('FOO') -def test_failures(): - if sys.version_info[0] == 3: - from io import StringIO - else: - from StringIO import StringIO +def test_failures(): # capture log capture = StringIO() logger = logging.getLogger('capture') @@ -72,14 +73,69 @@ def test_failures(): out = capture.getvalue() capture.close() - assert_that(out).contains('[test_warn.py:60]: Expected to be of length <4>, but was <3>.') - assert_that(out).contains('[test_warn.py:61]: Expected to be empty string, but was not.') - assert_that(out).contains('[test_warn.py:62]: Expected , but was not.') - assert_that(out).contains('[test_warn.py:63]: Expected to contain only digits, but did not.') - assert_that(out).contains('[test_warn.py:64]: Expected <123> to contain only alphabetic chars, but did not.') - assert_that(out).contains('[test_warn.py:65]: Expected to contain only uppercase chars, but did not.') - assert_that(out).contains('[test_warn.py:66]: Expected to contain only lowercase chars, but did not.') - assert_that(out).contains('[test_warn.py:67]: Expected to be equal to , but was not.') - assert_that(out).contains('[test_warn.py:68]: Expected to be not equal to , but was.') - assert_that(out).contains('[test_warn.py:69]: Expected to be case-insensitive equal to , but was not.') + assert_that(out).contains('[test_warn.py:61]: Expected to be of length <4>, but was <3>.') + assert_that(out).contains('[test_warn.py:62]: Expected to be empty string, but was not.') + assert_that(out).contains('[test_warn.py:63]: Expected to be , but was not.') + assert_that(out).contains('[test_warn.py:64]: Expected to contain only digits, but did not.') + assert_that(out).contains('[test_warn.py:65]: Expected <123> to contain only alphabetic chars, but did not.') + assert_that(out).contains('[test_warn.py:66]: Expected to contain only uppercase chars, but did not.') + assert_that(out).contains('[test_warn.py:67]: Expected to contain only lowercase chars, but did not.') + assert_that(out).contains('[test_warn.py:68]: Expected to be equal to , but was not.') + assert_that(out).contains('[test_warn.py:69]: Expected to be not equal to , but was.') + assert_that(out).contains('[test_warn.py:70]: Expected to be case-insensitive equal to , but was not.') + + +def test_chained_failure(): + # capture log + capture2 = StringIO() + logger = logging.getLogger('capture2') + handler = logging.StreamHandler(capture2) + logger.addHandler(handler) + adapted = WarningLoggingAdapter(logger, None) + + assert_warn('foo', logger=adapted).is_length(4).is_in('bar').does_not_contain_duplicates() + + # dump log to string + out = capture2.getvalue() + capture2.close() + + assert_that(out).contains('[test_warn.py:96]: Expected to be of length <4>, but was <3>.') + assert_that(out).contains('[test_warn.py:96]: Expected to be in , but was not.') + assert_that(out).contains('[test_warn.py:96]: Expected to not contain duplicates, but did.') + + +def test_failures_with_renamed_import(): + from assertpy import assert_warn as warn + + # capture log + capture3 = StringIO() + logger = logging.getLogger('capture3') + handler = logging.StreamHandler(capture3) + logger.addHandler(handler) + adapted = WarningLoggingAdapter(logger, None) + + warn('foo', logger=adapted).is_length(4) + warn('foo', logger=adapted).is_empty() + warn('foo', logger=adapted).is_false() + warn('foo', logger=adapted).is_digit() + warn('123', logger=adapted).is_alpha() + warn('foo', logger=adapted).is_upper() + warn('FOO', logger=adapted).is_lower() + warn('foo', logger=adapted).is_equal_to('bar') + warn('foo', logger=adapted).is_not_equal_to('foo') + warn('foo', logger=adapted).is_equal_to_ignoring_case('BAR') + + # dump log to string + out = capture3.getvalue() + capture3.close() + assert_that(out).contains('[test_warn.py:117]: Expected to be of length <4>, but was <3>.') + assert_that(out).contains('[test_warn.py:118]: Expected to be empty string, but was not.') + assert_that(out).contains('[test_warn.py:119]: Expected to be , but was not.') + assert_that(out).contains('[test_warn.py:120]: Expected to contain only digits, but did not.') + assert_that(out).contains('[test_warn.py:121]: Expected <123> to contain only alphabetic chars, but did not.') + assert_that(out).contains('[test_warn.py:122]: Expected to contain only uppercase chars, but did not.') + assert_that(out).contains('[test_warn.py:123]: Expected to contain only lowercase chars, but did not.') + assert_that(out).contains('[test_warn.py:124]: Expected to be equal to , but was not.') + assert_that(out).contains('[test_warn.py:125]: Expected to be not equal to , but was.') + assert_that(out).contains('[test_warn.py:126]: Expected to be case-insensitive equal to , but was not.')