diff --git a/README.rst b/README.rst index 994bafe..e69324e 100755 --- a/README.rst +++ b/README.rst @@ -37,68 +37,73 @@ See `documentation`_ and `getting started`_ for more examples. .. code-block:: python - from grappa import should + # should style + from grappa import should - True | should.be.true - False | should.be.false - None | should.be.none + True | should.be.true + False | should.be.false + None | should.be.none - '' | should.be.empty - [] | should.be.empty - 'foo' | should.exists + 3.14 | should.be.lower.than(4) + 3.14 | should.be.higher.than(3) + 3.14 | should.be.within(2, 4) - 3.14 | should.be.lower.than(4) - 3.14 | should.be.higher.than(3) - 3.14 | should.be.within(2, 4) + 'hello, grappa' | should.starts_with('hello') + 'hello, grappa' | should.ends_with('grappa') + [1, 2, 3, 4] | should.starts_with(1) + [1, 2, 3, 4] | should.ends_with(4) - 'bar' | should.be.equal.to('bar', msg='value is not "bar"') - [1, 2, 3] | should.be.equal.to([1, 2, 3]) + 'Hello grappa' | should.match('(\W)+ grappa$') + 'Hello grappa' | should.contain('grappa') | should.contain('he') + ['foo', 'bar'] | should.contain('foo') | should.do_not.contain('baz') - 'hello, grappa' | should.startswith('hello') - 'hello, grappa' | should.endswith('grappa') - [1, 2, 3, 4] | should.startswith(1) - [1, 2, 3, 4] | should.endswith(4) + 'foo' | should.pass_test(lambda x: x in 'foo bar') + 'foo' | should.pass_function(lambda x: len(x) > 2) - 'Hello grappa' | should.match('(\W)+ grappa$') - 'Hello grappa' | should.contain('grappa') | should.contain('he') - ['foo', 'bar'] | should.contain('foo') | should.do_not.contain('baz') + {'foo': 'bar'} | should.have.key('foo').that.should.be.equal('bar') + (1, 2, 3, 4) | should.be.a(tuple) > should.have.index.at(3) > should.be.equal.to(4) - 'foo' | should.be.a('string') - {'foo': True} | should.be.a('dict') + {'foo': True, 'bar': False} | should.all(should.have.key('foo'), should.have.key('bar')) + {'foo': True, 'bar': False} | should.any(should.have.key('foo'), should.have.key('baz')) - iter([1, 2, 3]) | should.have.length.of(3) - [1, 2, 3] | should.be.a('list') > should.have.length.of(3) + ({'bar': [1, 2, 3]} + | should.have.key('bar') + > should.be.a('list') + > should.have.length.of(3) + > should.contain.item(3) + > should.have.index.at(1) + > should.be.equal.to(2)) - (lambda x: x) | should.be.callable - (lambda x: x) | should.not_have.type.of('generator') - 'foo' | should.pass_test(lambda x: x in 'foo bar') - 'foo' | should.pass_function(lambda x: len(x) > 2) + # expect style + from grappa import expect - (lambda: x) | should.raises(NameError) - (lambda: x) | should.does_not.raises(RuntimeError) + expect('').to.be.empty + expect([]).to.be.empty + expect('foo').to.exists - {'foo': 'bar'} | should.have.key('foo').that.should.be.equal('bar') - (1, 2, 3, 4) | should.be.a(tuple) > should.have.index.at(3) > should.be.equal.to(4) + expect('bar').to.be.equal.to('bar', msg='value is not "bar"') + expect([1, 2, 3]).to.equal([1, 2, 3]) - an_object | should.have.properties('foo', 'bar', 'baz') - an_object | should.implement.methods('foo', 'bar', 'baz') + expect('foo').to.be.a('string') + expect({'foo': True}).to.be.a('dict') - {'foo': True, 'bar': False} | should.all(should.have.key('foo'), should.have.key('bar')) - {'foo': True, 'bar': False} | should.any(should.have.key('foo'), should.have.key('baz')) + expect(iter([1, 2, 3])).to.have.length.of(3) + expect([1, 2, 3]).to.be.a('list') > should.have.length.of(3) - ({'bar': [1, 2, 3]} - | should.have.key('bar') - > should.be.a('list') - > should.have.length.of(3) - > should.contain.item(3) - > should.have.index.at(1) - > should.be.equal.to(2)) + expect(lambda x: x).to.be.callable + expect(lambda x: x).to.not_have.type.of('generator') - with should('foo'): - should.be.a(str) - should.have.length.of(3) - should.be.equal.to('foo') + expect(lambda: x).to.raise_error(NameError) > expect.to.be('Invalid argument') + ecpect(lambda: x).to_not.raise_error(RuntimeError) + + expect(an_object).to.have.properties(('foo', 'bar', 'baz')) + expect(an_object).to.implement.methods(['foo', 'bar', 'baz']) + + with expect('foo'): + to.be.a(str) + to.have.length.of(3) + to.be.equal.to('foo') Let's see how the error report looks like in ``grappa`` running in ``pytest``. @@ -110,7 +115,9 @@ See `error reporting`_ documentation for more details about how ``grappa`` error ====================================================================== FAIL: tests.should_test.test_grappa_assert ====================================================================== - The following assertion was not satisfied + File "grappa/tests/should_test.py", line 16, in test_grappa_assert + x | should.be.have.length.of(4) + AssertionError: The following assertion was not satisfied subject "[1, 2, 3]" should be have length of "4" Message @@ -219,7 +226,7 @@ Or install the latest sources from Github: .. _`getting started`: http://grappa.readthedocs.io/en/latest/getting-started.html .. _`plugins`: http://grappa.readthedocs.io/en/latest/plugins.html .. _`error reporting`: http://grappa.readthedocs.io/en/latest/error-reporting.html -.. _`assertion styles`: http://grappa.readthedocs.io/en/latest/style.html +.. _`assertion styles`: http://grappa.readthedocs.io/en/latest/assertions-styles.html .. _`grappa-http`: https://github.com/grappa-py/http .. |Build Status| image:: https://travis-ci.org/grappa-py/grappa.svg?branch=master diff --git a/docs/accessors-operators.rst b/docs/accessors-operators.rst index 0260b94..b1ca112 100644 --- a/docs/accessors-operators.rst +++ b/docs/accessors-operators.rst @@ -1,27 +1,21 @@ -Accessors Operators +Accessors operators =================== -These operators do not accept expectation arguments but performs assertion logic. - -Example operators: none_, true_, false_, empty_, callable_ ... +These operators perform simple assertion logic. true ---- -Asserts if a given subject is `True` value. - -======================= ======================== - **Related operators** false_ -======================= ======================== +Asserts if a given subject is ``True`` value. .. code-block:: python + # should style 'foo' | should.be.true 'foo' | should.not_be.true -.. code-block:: python - + # expect style expect('foo').to.be.true expect('foo').to_not.be.true @@ -29,19 +23,15 @@ Asserts if a given subject is `True` value. false ----- -Asserts if a given subject is `False` value. - -======================= ======================== - **Related operators** true_ -======================= ======================== +Asserts if a given subject is ``False`` value. .. code-block:: python + # should style 'foo' | should.be.false 'foo' | should.not_be.false -.. code-block:: python - + # expect style expect('foo').to.be.false expect('foo').to_not.be.false @@ -52,17 +42,13 @@ callable Asserts if a given subject is a callable type or an object that implements ``__call__()`` magic method. -======================= ======================== - **Related operators** implements_ -======================= ======================== - .. code-block:: python + # should style (lambda x: x) | should.be.callable None | should.not_be.callable -.. code-block:: python - + # expect style expect(lambda x: x).to.be.callable expect(None).to_not.be.callable @@ -75,17 +61,13 @@ Asserts if a given subject is an empty object. A subject is considered empty if it's ``None``, ``0`` or ``len(subject)`` is equals to ``0``. -======================= ======================== - **Related operators** present_ none_ -======================= ======================== - .. code-block:: python + # should style [] | should.be.empty [1, 2, 3] | should.not_be.empty -.. code-block:: python - + # expect style expect(tuple()).to.be.empty expect((1, 2, 3)).to_not.be.empty @@ -95,17 +77,13 @@ none Asserts if a given subject is ``None``. -======================= ======================== - **Related operators** present_ empty_ -======================= ======================== - .. code-block:: python + # should style None | should.be.none 'foo' | should.not_be.none -.. code-block:: python - + # expect style expect(None).to.be.none expect('foo').to_not.be.none @@ -120,19 +98,12 @@ if evaluated via logical unary operator. This operator is the opposite of empty_. -======================= ======================== - **Related operators** none_ empty_ -======================= ======================== - .. code-block:: python + # should style 'foo' | should.be.present '' | should.not_be.present -.. code-block:: python - + # expect style expect('foo').to.be.present expect(False).to_not.be.present - - -.. _`implements`: http://grappa.readthedocs.io/en/latest/matchers-operators.html#implements diff --git a/docs/style.rst b/docs/assertions-styles.rst similarity index 99% rename from docs/style.rst rename to docs/assertions-styles.rst index 7a25a3d..253f391 100644 --- a/docs/style.rst +++ b/docs/assertions-styles.rst @@ -1,4 +1,4 @@ -Assertion Styles +Assertion styles ================ ``grappa`` is a behavior-oriented library that comes in two flavors: ``expect`` and ``should``. diff --git a/docs/attributes-operators.rst b/docs/attributes-operators.rst index 02b6a70..e6b538d 100644 --- a/docs/attributes-operators.rst +++ b/docs/attributes-operators.rst @@ -1,13 +1,13 @@ -Attributes Operators +Attributes operators ==================== -These operators provides assertion/negation logic. +These operators provide positive and negative assertion logic. -Example operators: to_, be_ not_be_, which_ ... +They semantically describe assertions to make them more expressive. -Assertion ---------- +Positive +-------- be ^^ @@ -36,26 +36,18 @@ that_is which_is ^^^^^^^^ -Semantic chainable attributes that defines non-negative assertions. - -Typically, you will use them implicitly in order to semantically describe your assertions. - -======================= ======================== - **Assertion mode** positive ------------------------ ------------------------ - **Resets context** no -======================= ======================== +Chainable semantic attributes which define positive assertions. .. code-block:: python + # should style 'foo' | should.be.equal.to('bar') 'foo' | should.have.length.of(3) {'foo': 'bar'} | should.have.key('foo').which.should.be.equal.to('bar') {'foo': 'bar'} | should.have.key('foo').that.should.have.length.of(3) -.. code-block:: python - + # expect style expect('foo').to.equal.to('bar') expect('foo').to.have.length.of(3) @@ -63,7 +55,7 @@ Typically, you will use them implicitly in order to semantically describe your a expect({'foo': 'bar'}).to.have.key('foo').which.expect.to.have.length.of(3) -Negation +Negative -------- not_be @@ -99,22 +91,14 @@ _not not_satisfy ^^^^^^^^^^^ -Semantic chainable attributes that defines negative assertions. - -Typically, you will use them implicitly in order to semantically describe your assertions. - -======================= ======================== - **Assertion mode** negation ------------------------ ------------------------ - **Resets context** no -======================= ======================== +Chainable semantic attributes which define negative assertions. .. code-block:: python + # should style 'foo' | should.not_be.equal.to('bar') 'foo' | should.have_not.length.of(3) -.. code-block:: python - + # expect style expect('foo').to_not.equal.to('bar') expect('foo').to.not_have.length.of(3) diff --git a/docs/error-reporting.rst b/docs/error-reporting.rst index 4af2101..df6885e 100644 --- a/docs/error-reporting.rst +++ b/docs/error-reporting.rst @@ -1,4 +1,4 @@ -Error Reporting +Error reporting =============== Feedback while testing is key. Seeing errors in your tests is not a nice thing @@ -59,17 +59,7 @@ Now, a ``grappa`` error report using ``nosetests``: self.test(*self.arg) File "grappa/tests/should_test.py", line 16, in test_grappa_assert x | should.be.have.length.of(4) - File "grappa/grappa/test.py", line 248, in __ror__ - return self.__overload__(value) - File "grappa/grappa/test.py", line 236, in __overload__ - return self.__call__(subject, overload=True) - File "grappa/grappa/test.py", line 108, in __call__ - return self._trigger() if overload else Test(subject) - File "grappa/grappa/test.py", line 153, in _trigger - raise err - AssertionError: Oops! Something went wrong! - - The following assertion was not satisfied + AssertionError: The following assertion was not satisfied subject "[1, 2, 3]" should be have length of "4" Reasons diff --git a/docs/index.rst b/docs/index.rst index 20c242c..23b9242 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,7 +6,7 @@ Contents intro getting-started - style + assertions-styles error-reporting attributes-operators accessors-operators diff --git a/docs/matchers-operators.rst b/docs/matchers-operators.rst index c309840..2c7de1f 100644 --- a/docs/matchers-operators.rst +++ b/docs/matchers-operators.rst @@ -1,9 +1,7 @@ -Matchers Operators +Matchers operators ================== -These operators does accept expectation arguments and therefore are callable. - -Example operators: equal_, within_, start_with_, match_, type_ ... +These operators use expectation arguments to perform their assertion logic. Generic @@ -19,40 +17,24 @@ Performs a strict equality comparison between ``x`` and ``y`` values. Uses ``==`` built-in binary operator for the comparison. ======================= ======================== - **Chained aliases** ``value`` ``to`` ``of`` ``as`` ``data`` ------------------------ ------------------------ - **Related operators** contain_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``value`` ``to`` ``of`` ``as`` ``data`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 'foo' | should.be.equal('foo') 'foo' | should.be.equal.to('foo') 'foo' | should.be.equal.to.value('foo') -.. code-block:: python - - 'foo' | expect.to.equal('foo') - 'foo' | expect.to.equal.to('foo') - 'foo' | expect.to.equal.to.value('foo') - -**Negation form**: - -.. code-block:: python - - 'foo' | should.not_be.equal('foo') - 'foo' | should.not_be.equal.to('foo') 'foo' | should.not_be.equal.to.value('foo') -.. code-block:: python - - 'foo' | expect.to_not.equal('foo') - 'foo' | expect.to_not.equal.to('foo') - 'foo' | expect.to_not.equal.to.value('foo') + # expect style + expect('foo').to.equal('foo') + expect('foo').to.equal.to('foo') + expect('foo').to.equal.to.value('foo') + + expect('foo').to_not.equal.to.value('foo') contain @@ -65,40 +47,28 @@ includes Asserts if a given value or values can be found in a another object. ======================= ======================== - **Chained aliases** ``value`` ``string`` ``text`` ``item`` ``expression`` ``data`` ------------------------ ------------------------ - **Related operators** equal_ matches_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``value`` ``string`` ``text`` ``item`` ``expression`` ``data`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 'foo bar' | should.contain('bar') ['foo', 'bar'] | should.contain('bar') ['foo', 'bar'] | should.contain('foo', 'bar') [{'foo': True}, 'bar'] | should.contain({'foo': True}) -.. code-block:: python - - 'foo bar' | expect.to.contain('bar') - ['foo', 'bar'] | expect.to.contain('bar') - ['foo', 'bar'] | expect.to.contain('foo', 'bar') - [{'foo': True}, 'bar'] | expect.to.contain({'foo': True}) - -**Negation form**: - -.. code-block:: python - 'foo bar' | should.do_not.contain('bar') ['foo', 'bar'] | should.do_not.contain('baz') -.. code-block:: python + # expect style + expect('foo bar').to.contain('bar') + expect(['foo', 'bar']).to.contain('bar') + expect(['foo', 'bar']).to.contain('foo', 'bar') + expect([{'foo': True}, 'bar']).to.contain({'foo': True}) - 'foo bar' | expect.to_not.contain('bar') - ['foo', 'bar'] | expect.to_not.contain('baz') + expect('foo bar').to_not.contain('bar') + expect(['foo', 'bar']).to_not.contain('baz') length @@ -109,40 +79,28 @@ size Asserts that a given object has exact length. ======================= ======================== - **Chained aliases** ``of`` ``equal`` ``to`` ------------------------ ------------------------ - **Related operators** matches_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``of`` ``equal`` ``to`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 'foo' | should.have.length(3) [1, 2, 3] | should.have.length.of(3) iter([1, 2, 3]) | should.have.length.equal.to(3) -.. code-block:: python - - 'foo' | expect.to.have.length(3) - [1, 2, 3] | expect.to.have.length.of(3) - iter([1, 2, 3]) | expect.to.have.length.equal.to(3) - -**Negation form**: - -.. code-block:: python - 'foobar' | should.not_have.length(3) [1, 2, 3, 4] | should.not_have.length.of(3) iter([1, 2, 3, 4]) | should.not_have.length.equal.to(3) -.. code-block:: python + # expect style + expect('foo').to.have.length(3) + expect([1, 2, 3]).to.have.length.of(3) + expect(iter([1, 2, 3])).to.have.length.equal.to(3) - 'foobar' | expect.to_not.have.length(3) - [1, 2, 3, 4] | expect.to_not.have.length.of(3) - iter([1, 2, 3, 4]) | expect.to_not.have.length.equal.to(3) + expect('foobar').to_not.have.length(3) + expect([1, 2, 3, 4]).to_not.have.length.of(3) + expect(iter([1, 2, 3, 4])).to_not.have.length.equal.to(3) start_with @@ -153,48 +111,36 @@ starts_with Asserts if a given value starts with a specific items. ======================= ======================== - **Chained aliases** ``by`` ``word`` ``number`` ``numbers`` ``item`` ``items`` ``value`` ``char`` ``letter`` ``character`` ------------------------ ------------------------ - **Related operators** ends_with_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``by`` ``word`` ``number`` ``numbers`` ``item`` ``items`` ``value`` ``char`` ``letter`` ``character`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 'foo' | should.start_with('f') 'foo' | should.start_with('fo') [1, 2, 3] | should.start_with.number(1) iter([1, 2, 3]) | should.start_with.numbers(1, 2) OrderedDict([('foo', 0), ('bar', 1)]) | should.start_with.item('foo') -.. code-block:: python - - 'foo' | expect.to.start_with('f') - 'foo' | expect.to.start_with('fo') - [1, 2, 3] | expect.to.start_with.number(1) - iter([1, 2, 3]) | expect.to.start_with.numbers(1, 2) - OrderedDict([('foo', 0), ('bar', 1)]) | expect.to.start_with('foo') - -**Negation form**: - -.. code-block:: python - 'foo' | should.do_not.start_with('o') 'foo' | should.do_not.start_with('o') [1, 2, 3] | should.do_not.start_with(2) iter([1, 2, 3]) | should.do_not.start_with.numbers(3, 4) - OrderedDict([('foo', 0), ('bar', 1)]) | should.start_with('bar') + OrderedDict([('foo', 0), ('bar', 1)]) | should._not.start_with('bar') -.. code-block:: python + # expect style + expect('foo').to.start_with('f') + expect('foo').to.start_with('fo') + expect([1, 2, 3]).to.start_with.number(1) + expect(iter([1, 2, 3])).to.start_with.numbers(1, 2) + expect(OrderedDict([('foo', 0), ('bar', 1)])).to.start_with('foo') - 'foo' | expect.to_not.start_with('f') - 'foo' | expect.to_not.start_with('fo') - [1, 2, 3] | expect.to_not.start_with.number(1) - iter([1, 2, 3]) | expect.to_not.start_with.numbers(1, 2) - OrderedDict([('foo', 0), ('bar', 1)]) | expect.to_not.start_with('foo') + expect('foo').to_not.start_with('f') + expect('foo').to_not.start_with('fo') + expect([1, 2, 3]).to_not.start_with.number(1) + expect(iter([1, 2, 3])).to_not.start_with.numbers(1, 2) + expect(OrderedDict([('foo', 0), ('bar', 1)])).to_not.start_with('foo') end_with @@ -205,48 +151,38 @@ ends_with Asserts if a given value ends with a specific items. ======================= ======================== - **Chained aliases** ``by`` ``word`` ``number`` ``numbers`` ``item`` ``items`` ``value`` ``char`` ``letter`` ``character`` ------------------------ ------------------------ - **Related operators** ends_with_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``by`` ``word`` ``number`` ``numbers`` ``item`` ``items`` ``value`` ``char`` ``letter`` ``character`` ======================= ======================== **Assertion form**: .. code-block:: python + # should style 'foo' | should.ends_with('o') 'foo' | should.ends_with('oo') [1, 2, 3] | should.ends_with.number(3) iter([1, 2, 3]) | should.ends_with.numbers(2, 3) OrderedDict([('foo', 0), ('bar', 1)]) | should.ends_with.item('bar') -.. code-block:: python - - 'foo' | expect.to.ends_with('o') - 'foo' | expect.to.ends_with('oo') - [1, 2, 3] | expect.to.ends_with.number(3) - iter([1, 2, 3]) | expect.to.ends_with.numbers(2, 3) - OrderedDict([('foo', 0), ('bar', 1)]) | expect.to.ends_with('bar') - -**Negation form**: - -.. code-block:: python - 'foo' | should.do_not.ends_with('f') 'foo' | should.do_not.ends_with('o') [1, 2, 3] | should.do_not.ends_with(2) iter([1, 2, 3]) | should.do_not.ends_with.numbers(3, 4) - OrderedDict([('foo', 0), ('bar', 1)]) | should.ends_with('foo') + OrderedDict([('foo', 0), ('bar', 1)]) | should._not.ends_with('foo') -.. code-block:: python + # expect style + expect('foo').to.ends_with('o') + expect('foo').to.ends_with('oo') + expect([1, 2, 3]).to.ends_with.number(3) + expect(iter([1, 2, 3])).to.ends_with.numbers(2, 3) + expect(OrderedDict([('foo', 0), ('bar', 1)])).to.ends_with('bar') - 'foo' | expect.to_not.ends_with('f') - 'foo' | expect.to_not.ends_with('oo') - [1, 2, 3] | expect.to_not.ends_with.number(2) - iter([1, 2, 3]) | expect.to_not.ends_with.numbers(1, 2) - OrderedDict([('foo', 0), ('bar', 1)]) | expect.to_not.ends_with('foo') + expect('foo').to_not.ends_with('f') + expect('foo').to_not.ends_with('oo') + expect([1, 2, 3]).to_not.ends_with.number(2) + expect(iter([1, 2, 3])).to_not.ends_with.numbers(1, 2) + expect(OrderedDict([('foo', 0), ('bar', 1)])).to_not.ends_with('foo') match @@ -257,40 +193,28 @@ matches Asserts if a given string matches a given regular expression. ======================= ======================== - **Chained aliases** ``value`` ``string`` ``expression``, ``token``, ``to``, ``regex``, ``regexp``, ``word``, ``phrase`` ------------------------ ------------------------ - **Related operators** matches_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``value`` ``string`` ``expression``, ``token``, ``to``, ``regex``, ``regexp``, ``word``, ``phrase`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 'hello world' | should.match(r'Hello \w+') 'hello world' | should.match(r'hello [A-Z]+', re.I)) 'hello world' | should.match.expression(r'hello [A-Z]+', re.I)) -.. code-block:: python - - 'hello world' | expect.to.match(r'Hello \w+') - 'hello world' | expect.to.match(r'hello [A-Z]+', re.I)) - 'hello world' | expect.to.match.expression(r'hello [A-Z]+', re.I)) - -**Negation form**: - -.. code-block:: python - 'hello w0rld' | should.do_not.match(r'Hello \w+') 'hello w0rld' | should.do_not.match(r'hello [A-Z]+', re.I)) 'hello world' | should.do_not.match.expression(r'hello [A-Z]+', re.I)) -.. code-block:: python + # expect style + expect('hello world').to.match(r'Hello \w+') + expect('hello world').to.match(r'hello [A-Z]+', re.I)) + expect('hello world').to.match.expression(r'hello [A-Z]+', re.I)) - 'hello w0rld' | expect.to_not.match(r'Hello \w+') - 'hello w0rld' | expect.to_not.match(r'hello [A-Z]+', re.I)) - 'hello world' | expect.to_not.match.expression(r'hello [A-Z]+', re.I)) + expect('hello w0rld').to_not.match(r'Hello \w+') + expect('hello w0rld').to_not.match(r'hello [A-Z]+', re.I)) + expect('hello world').to_not.match.expression(r'hello [A-Z]+', re.I)) Collections @@ -304,38 +228,26 @@ keys Asserts that a given dictionary has a key or keys. ======================= ======================== - **Chained aliases** ``present`` ``equal`` ``to`` ------------------------ ------------------------ - **Related operators** matches_ index_ + **Chainable aliases** ``present`` ``equal`` ``to`` ----------------------- ------------------------ **Yields subject** The key value, if present. ------------------------ ------------------------ - **Optional keywords** ``msg: str`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style {'foo': True} | should.have.key('foo') {'foo': True, 'bar': False} | should.have.keys('bar', 'foo') -.. code-block:: python - - {'foo': True} | expect.to.have.key('foo') - {'foo': True, 'bar': False} | expect.to.have.keys('bar', 'foo') - -**Negation form**: - -.. code-block:: python - {'bar': True} | should.not_have.key('foo') {'baz': True, 'bar': False} | should.not_have.keys('bar', 'foo') -.. code-block:: python + # expect style + expect({'foo': True}).to.have.key('foo') + expect({'foo': True, 'bar': False}).to.have.keys('bar', 'foo') - {'bar': True} | expect.to_not.have.key('foo') - {'baz': True, 'bar': False} | expect.to_not.have.keys('bar', 'foo') + expect({'bar': True}).to_not.have.key('foo') + expect({'baz': True, 'bar': False}).to_not.have.keys('bar', 'foo') index @@ -344,19 +256,14 @@ index Asserts that a given iterable has an item in a specific index. ======================= ======================== - **Chained aliases** ``present`` ``exists`` ``at`` ------------------------ ------------------------ - **Related operators** property_ key_ contain_ + **Chainable aliases** ``present`` ``exists`` ``at`` ----------------------- ------------------------ **Yields subject** Value at the selected index, if present. ------------------------ ------------------------ - **Optional keywords** ``msg: str`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style [1, 2, 3] | should.have.index(2) [1, 2, 3] | should.have.index(1) [1, 2, 3] | should.have.index.at(1) @@ -364,26 +271,19 @@ Asserts that a given iterable has an item in a specific index. [1, 2, 3] | should.have.index.at(1).equal.to(2) [1, 2, 3] | should.have.index.at(1) > should.be.equal.to(2) -.. code-block:: python - - [1, 2, 3] | expect.to.have.index(2) - [1, 2, 3] | expect.to.have.index.at(1) - [1, 2, 3] | expect.to.have.index.at(1).equal.to(2) - [1, 2, 3] | expect.to.have.index.at(1) > expect.be.equal.to(2) - -**Negation form**: - -.. code-block:: python - [1, 2, 3] | should.not_have.index(4) [1, 2, 3] | should.not_have.index.at(4) [1, 2, 3] | should.not_have.index.at(1).to_not.equal.to(5) -.. code-block:: python + # expect style + expect([1, 2, 3]).to.have.index(2) + expect([1, 2, 3]).to.have.index.at(1) + expect([1, 2, 3]).to.have.index.at(1).equal.to(2) + expect([1, 2, 3]).to.have.index.at(1) > expect.be.equal.to(2) - [1, 2, 3] | expect.to_not.have.index(2) - [1, 2, 3] | expect.to_not.have.index.at(1) - [1, 2, 3] | expect.to_not.have.index.at(1).equal.to(2) + expect([1, 2, 3]).to_not.have.index(2) + expect([1, 2, 3]).to_not.have.index.at(1) + expect([1, 2, 3]).to_not.have.index.at(1).equal.to(2) Numbers @@ -399,52 +299,33 @@ less Asserts if a given number is below to another number. ======================= ======================== - **Chained aliases** ``of`` ``to`` ``than`` ``number`` ------------------------ ------------------------ - **Related operators** within_ above_ above_or_equal_ below_or_equal_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``of`` ``to`` ``than`` ``number`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 3 | should.be.below(5) - 3 | should.be.below.of(5) - 3 | should.be.below.to(5) 3 | should.be.less.than(5) 3 | should.be.lower.than(5) 3 | should.be.below.to.number(5) 3 | should.be.below.than.number(5) -.. code-block:: python - - 3 | expect.to.be.below(5) - 3 | expect.to.be.below.of(5) - 3 | expect.to.be.below.to(5) - 3 | expect.to.be.less.than(5) - 3 | expect.to.be.lower.than(5) - 3 | expect.to.be.below.to.number(5) - 3 | expect.to.be.below.than.number(5) - -**Negation form**: - -.. code-block:: python - 5 | should.not_be.below(3) - 5 | should.not_be.below.of(3) - 3 | should.not_be.below.to(5) 3 | should.not_be.lower.than(5) 5 | should.not_be.below.to.number(3) -.. code-block:: python + # expect style + expect(3).to.be.below(5) + expect(3).to.be.less.than(5) + expect(3).to.be.lower.than(5) + expect(3).to.be.below.to.number(5) + expect(3).to.be.below.than.number(5) - 5 | expect.to_not.be.below(3) - 5 | expect.to_not.be.below.of(3) - 5 | expect.to_not.be.below.than(3) - 5 | expect.to_not.be.below.to.number(3) - 5 | expect.to_not.be.below.than.number(3) + expect(5).to_not.be.below(3) + expect(5).to_not.be.below.than(3) + expect(5).to_not.be.below.to.number(3) + expect(5).to_not.be.below.than.number(3) above @@ -455,52 +336,32 @@ higher Asserts if a given number is above to another number. ======================= ======================== - **Chained aliases** ``of`` ``to`` ``than`` ``number`` ------------------------ ------------------------ - **Related operators** within_ below_ below_or_equal_ above_or_equal_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``of`` ``to`` ``than`` ``number`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 5 | should.be.above(3) - 5 | should.be.above.of(3) - 5 | should.be.above.to(3) 5 | should.be.higher.than(3) 5 | should.be.above.to.number(3) 5 | should.be.above.than.number(3) -.. code-block:: python - - 5 | expect.to.be.above(3) - 5 | expect.to.be.above.of(3) - 5 | expect.to.be.above.to(3) - 5 | expect.to.be.higher.than(3) - 5 | expect.to.be.above.to.number(3) - 5 | expect.to.be.above.than.number(3) - -**Negation form**: - -.. code-block:: python - 3 | should.not_be.above(5) - 3 | should.not_be.above.of(5) - 3 | should.not_be.above.to(5) 3 | should.not_be.higher.than(5) 3 | should.not_be.above.to.number(5) 3 | should.not_be.above.than.number(5) -.. code-block:: python + # expect style + expect(5).to.be.above(3) + expect(5).to.be.higher.than(3) + expect(5).to.be.above.to.number(3) + expect(5).to.be.above.than.number(3) - 3 | expect.not_to.be.above(5) - 3 | expect.not_to.be.above.of(5) - 3 | expect.not_to.be.above.to(5) - 3 | expect.not_to.be.higher.than(5) - 3 | expect.not_to.be.above.to.number(5) - 3 | expect.not_to.be.above.than.number(5) + expect(3).not_to.be.above(5) + expect(3).not_to.be.higher.than(5) + expect(3).not_to.be.above.to.number(5) + expect(3).not_to.be.above.than.number(5) least @@ -513,56 +374,36 @@ higher_or_equal Asserts if a given number is above to another number. ======================= ======================== - **Chained aliases** ``of`` ``to`` ``than`` ``number`` ------------------------ ------------------------ - **Related operators** within_ below_ below_or_equal_ above_or_equal_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``of`` ``to`` ``than`` ``number`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 3 | should.be.least(3) 3 | should.be.above_or_equal(3) - 3 | should.be.above_or_equal.of(3) - 3 | should.be.above_or_equal.to(3) 3 | should.be.higher_or_equal.than(3) 3 | should.be.above_or_equal.to.number(3) 3 | should.be.above_or_equal.than.number(3) -.. code-block:: python - - 3 | expect.to.be.least(3) - 3 | expect.to.be.above_or_equal(3) - 3 | expect.to.be.above_or_equal.of(3) - 3 | expect.to.be.above_or_equal.to(3) - 3 | expect.to.be.higher_or_equal.than(3) - 3 | expect.to.be.above_or_equal.to.number(3) - 3 | expect.to.be.above_or_equal.than.number(3) - -**Negation form**: - -.. code-block:: python - 3 | should.not_be.least(3) 3 | should.not_be.above_or_equal(5) - 3 | should.not_be.above_or_equal.of(5) - 3 | should.not_be.above_or_equal.to(5) 3 | should.not_be.higher_or_equal.than(5) 3 | should.not_be.higher_or_equal.to.number(5) 3 | should.not_be.higher_or_equal.than.number(5) -.. code-block:: python + # expect style + expect(3).to.be.least(3) + expect(3).to.be.above_or_equal(3) + expect(3).to.be.higher_or_equal.than(3) + expect(3).to.be.above_or_equal.to.number(3) + expect(3).to.be.above_or_equal.than.number(3) - 3 | expect.not_be.least(3) - 3 | expect.not_be.above_or_equal(5) - 3 | expect.not_be.above_or_equal.of(5) - 3 | expect.not_be.above_or_equal.to(5) - 3 | expect.not_be.higher_or_equal.than(5) - 3 | expect.not_be.higher_or_equal.to.number(5) - 3 | expect.not_be.higher_or_equal.than.number(5) + expect(3).not_be.least(3) + expect(3).not_be.above_or_equal(5) + expect(3).not_be.higher_or_equal.than(5) + expect(3).not_be.higher_or_equal.to.number(5) + expect(3).not_be.higher_or_equal.than.number(5) most @@ -575,56 +416,36 @@ lower_or_equal Asserts if a given number is above to another number. ======================= ======================== - **Chained aliases** ``of`` ``to`` ``than`` ``number`` ------------------------ ------------------------ - **Related operators** within_ below_ above_ below_or_equal_ above_or_equal_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``of`` ``to`` ``than`` ``number`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 3 | should.be.most(3) 3 | should.be.below_or_equal(3) - 3 | should.be.below_or_equal.of(3) - 3 | should.be.below_or_equal.to(3) 3 | should.be.lower_or_equal.than(3) 3 | should.be.lower_or_equal.to.number(3) 3 | should.be.lower_or_equal.than.number(3) -.. code-block:: python - - 3 | expect.to.be.most(3) - 3 | expect.to.be.below_or_equal(3) - 3 | expect.to.be.below_or_equal.of(3) - 3 | expect.to.be.below_or_equal.to(3) - 3 | expect.to.be.lower_or_equal.than(3) - 3 | expect.to.be.lower_or_equal.to.number(3) - 3 | expect.to.be.lower_or_equal.than.number(3) - -**Negation form**: - -.. code-block:: python - 3 | should.not_be.most(5) 3 | should.not_be.below_or_equal(5) - 3 | should.not_be.below_or_equal.of(5) - 3 | should.not_be.below_or_equal.to(5) 3 | should.not_be.lower_or_equal.than(5) 3 | should.not_be.lower_or_equal.to.number(5) 3 | should.not_be.lower_or_equal.than.number(5) -.. code-block:: python + # expect style + expect(3).to.be.most(3) + expect(3).to.be.below_or_equal(3) + expect(3).to.be.lower_or_equal.than(3) + expect(3).to.be.lower_or_equal.to.number(3) + expect(3).to.be.lower_or_equal.than.number(3) - 3 | expect.not_be.most(5) - 3 | expect.not_be.below_or_equal(5) - 3 | expect.not_be.below_or_equal.of(5) - 3 | expect.not_be.below_or_equal.to(5) - 3 | expect.not_be.lower_or_equal.than(5) - 3 | expect.not_be.lower_or_equal.to.number(5) - 3 | expect.not_be.lower_or_equal.than.number(5) + expect(3).not_be.most(5) + expect(3).not_be.below_or_equal(5) + expect(3).not_be.lower_or_equal.than(5) + expect(3).not_be.lower_or_equal.to.number(5) + expect(3).not_be.lower_or_equal.than.number(5) within @@ -635,40 +456,28 @@ between Asserts that a number is within a range. ======================= ======================== - **Chained aliases** ``to`` ``numbers`` ``range`` ------------------------ ------------------------ - **Related operators** below_ above_ above_or_equal_ below_or_equal_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``to`` ``numbers`` ``range`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 4 | should.be.within(2, 5) 5 | should.be.between(2, 5) 4.5 | should.be.within(4, 5) -.. code-block:: python - 4 | should.not_be.within(2, 5) 5 | should.not_be.between(2, 5) 4.5 | should.not_be.within(4, 5) -**Negation form**: - -.. code-block:: python - - 4 | expect.to.be.within(2, 5) - 5 | expect.to.be.between(2, 5) - 4.5 | expect.to.be.within(4, 5) - -.. code-block:: python + # expect style + expect(4).to.be.within(2, 5) + expect(5).to.be.between(2, 5) + expect(4.5).to.be.within(4, 5) - 4 | expect.to_not.be.within(2, 5) - 5 | expect.to_not.be.between(2, 5) - 4.5 | expect.to_not.be.within(4, 5) + expect(4).to_not.be.within(2, 5) + expect(5).to_not.be.between(2, 5) + expect(4.5).to_not.be.within(4, 5) Objects @@ -718,17 +527,12 @@ Supported type aliases: - coroutinefunction ======================= ======================== - **Chained aliases** ``type`` ``types`` ``to`` ``of``, ``equal`` ------------------------ ------------------------ - **Related operators** equal_ matches_ implements_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``type`` ``types`` ``to`` ``of``, ``equal`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 1 | should.be.an('int') 1 | should.be.an('number') True | should.be.a('bool') @@ -743,26 +547,6 @@ Supported type aliases: 'foo' | should.be.instance.of('string') 'foo' | expect.be.types('string', 'int') -.. code-block:: python - - 1 | expect.to.be.an('int') - 1 | expect.to.be.an('number') - True | expect.to.be.a('bool') - True | expect.to.be.type(bool) - 'foo' | expect.to.be.a(str) - 'foo' | expect.to.be.a('string') - [1, 2, 3] | expect.to.be.a('list') - [1, 2, 3] | expect.to.have.type.of(list) - (1, 2, 3) | expect.to.be.a('tuple') - (1, 2, 3) | expect.to.have.type.of(tuple) - (lamdba x: x) | expect.to.be.a('lambda') - 'foo' | expect.to.be.instance.of('string') - 'foo' | expect.to.be.types('string', 'int') - -**Negation form**: - -.. code-block:: python - 1 | should.not_be.an('int') 1 | should.not_be.an('number') True | should.not_be.a('bool') @@ -777,21 +561,34 @@ Supported type aliases: 'foo' | should.not_to.be.instance.of('string') 'foo' | should.not_to.be.types('string', 'int') -.. code-block:: python - - 1 | expect.to_not.be.an('int') - 1 | expect.to_not.be.an('number') - True | expect.to_not.be.a('bool') - True | expect.to_not.be.type(bool) - 'foo' | expect.to_not.be.a(str) - 'foo' | expect.to_not.be.a('string') - [1, 2, 3] | expect.to_not.be.a('list') - [1, 2, 3] | expect.to_not.have.type.of(list) - (1, 2, 3) | expect.to_not.be.a('tuple') - (1, 2, 3) | expect.to_not.have.type.of(tuple) - (lamdba x: x) | expect.to_not.be.a('lambda') - 'foo' | expect.to.not_to.be.instance.of('string') - 'foo' | expect.to.not_to.be.types('string', 'int') + # expect style + expect(1).to.be.an('int') + expect(1).to.be.an('number') + expect(True).to.be.a('bool') + expect(True).to.be.type(bool) + expect('foo').to.be.a(str) + expect('foo').to.be.a('string') + expect([1, 2, 3]).to.be.a('list') + expect([1, 2, 3]).to.have.type.of(list) + expect((1, 2, 3)).to.be.a('tuple') + expect((1, 2, 3)).to.have.type.of(tuple) + expect((lamdba x: x)).to.be.a('lambda') + expect('foo').to.be.instance.of('string') + expect('foo').to.be.types('string', 'int') + + expect(1).to_not.be.an('int') + expect(1).to_not.be.an('number') + expect(True).to_not.be.a('bool') + expect(True).to_not.be.type(bool) + expect('foo').to_not.be.a(str) + expect('foo').to_not.be.a('string') + expect([1, 2, 3]).to_not.be.a('list') + expect([1, 2, 3]).to_not.have.type.of(list) + expect((1, 2, 3)).to_not.be.a('tuple') + expect((1, 2, 3)).to_not.have.type.of(tuple) + expect((lamdba x: x)).to_not.be.a('lambda') + expect('foo').to.not_to.be.instance.of('string') + expect('foo').to.not_to.be.types('string', 'int') property @@ -806,15 +603,30 @@ attributes Asserts if a given object has property or properties. ======================= ======================== - **Chained aliases** ``present`` ``equal`` ``to`` ------------------------ ------------------------ - **Related operators** matches_ + **Chainable aliases** ``present`` ``equal`` ``to`` ----------------------- ------------------------ **Yields subject** The attribute value, if present. ------------------------ ------------------------ - **Optional keywords** ``msg: str`` ======================= ======================== +.. code-block:: python + + # should style + Foo() | should.have.property('bar') + Foo() | should.have.properties('bar', 'baz') + Foo() | should.have.properties.present.equal.to('bar', 'baz') + + Foo() | should.have_not.property('bar') + Foo() | should.have_not.properties('bar', 'baz') + Foo() | should.have_not.properties.present.equal.to('bar', 'baz') + + # expect style + expect(Foo()).to_not.have.property('bar') + expect(Foo()).to_not.have.properties('bar', 'baz') + expect(Foo()).to_not.have.properties.present.equal.to('bar', 'baz') + + expect(Foo()).to_not.have.property('bar') + expect(Foo()).to_not.have.properties('bar', 'baz') + expect(Foo()).to_not.have.properties.present.equal.to('bar', 'baz') implements ^^^^^^^^^^ @@ -826,75 +638,35 @@ interface Asserts if a given object implements an interface of methods. ======================= ======================== - **Chained aliases** ``interface`` ``method`` ``methods`` ------------------------ ------------------------ - **Related operators** matches_ ------------------------ ------------------------ - **Optional keywords** ``msg: str`` + **Chainable aliases** ``interface`` ``method`` ``methods`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style Foo() | should.implements('bar') Foo() | should.implements.method('bar') Foo() | should.implement.methods('bar', 'baz') Foo() | should.implement.interface('bar', 'baz') Foo() | should.satisfies.interface('bar', 'baz') -.. code-block:: python - - Foo() | expect.to.implement('bar') - Foo() | expect.to.implement.method('bar') - Foo() | expect.to.implement.methods('bar', 'baz') - Foo() | expect.to.implement.interface('bar', 'baz') - Foo() | expect.to.satisfy.interface('bar', 'baz') - -**Negation form**: - -.. code-block:: python - Foo() | should.do_not.implements('bar') Foo() | should.do_not.implement.methods('bar', 'baz') Foo() | should.do_not.implement.interface('bar', 'baz') Foo() | should.do_not.satisfy.interface('bar', 'baz') -.. code-block:: python - - Foo() | expect.to_not.implement('bar') - Foo() | expect.to_not.implement.method('bar') - Foo() | expect.to_not.implement.methods('bar', 'baz') - Foo() | expect.to_not.implement.interface('bar', 'baz') - Foo() | expect.to_not.satisfy.interface('bar', 'baz') - -**Assertion form**: - -.. code-block:: python - - Foo() | should.have.property('bar') - Foo() | should.have.properties('bar', 'baz') - Foo() | should.have.properties.present.equal.to('bar', 'baz') - -.. code-block:: python - - Foo() | expect.to_not.have.property('bar') - Foo() | expect.to_not.have.properties('bar', 'baz') - Foo() | expect.to_not.have.properties.present.equal.to('bar', 'baz') - -**Negation form**: - -.. code-block:: python + # expect style + expect(Foo()).to.implement('bar') + expect(Foo()).to.implement.method('bar') + expect(Foo()).to.implement.methods('bar', 'baz') + expect(Foo()).to.implement.interface('bar', 'baz') + expect(Foo()).to.satisfy.interface('bar', 'baz') - Foo() | should.have_not.property('bar') - Foo() | should.have_not.properties('bar', 'baz') - Foo() | should.have_not.properties.present.equal.to('bar', 'baz') - -.. code-block:: python - - Foo() | expect.to_not.have.property('bar') - Foo() | expect.to_not.have.properties('bar', 'baz') - Foo() | expect.to_not.have.properties.present.equal.to('bar', 'baz') + expect(Foo()).to_not.implement('bar') + expect(Foo()).to_not.implement.method('bar') + expect(Foo()).to_not.implement.methods('bar', 'baz') + expect(Foo()).to_not.implement.interface('bar', 'baz') + expect(Foo()).to_not.satisfy.interface('bar', 'baz') Exceptions @@ -913,46 +685,34 @@ you can use ``functools.partial`` to create a zero arity function with your arguments ======================= ======================== - **Chained aliases** ``to`` ``that`` ``are`` ``instance`` ``of`` ------------------------ ------------------------ - **Related operators** matches_ + **Chainable aliases** ``to`` ``that`` ``are`` ``instance`` ``of`` ----------------------- ------------------------ **Yields subject** Message of the exception, if present or joined exception arguments. ------------------------ ------------------------ - **Optional keywords** ``msg: str`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style fn | should.raise_error() fn | should.raise_error(ValueError) fn | should.raise_error(AttributeError, ValueError) fn | should.raise_error(ValueError) > should.equal('File not found') fn | should.raise_error(ValueError) > should.contain('not found') -.. code-block:: python - - fn | expect.to.raise_error() - fn | expect.to.raise_error(ValueError) - fn | expect.to.raise_error(AttributeError, ValueError) - fn | expect.to.raise_error(ValueError) > should.equal('File not found') - fn | expect.to.raise_error(ValueError) > should.contain('not found') - -**Negation form**: - -.. code-block:: python - fn | should.do_not.raise_error() fn | should.do_not.raise_error(ValueError) fn | should.do_not.raise_error(AttributeError, ValueError) -.. code-block:: python + # expect style + expect(fn).to.raise_error() + expect(fn).to.raise_error(ValueError) + expect(fn).to.raise_error(AttributeError, ValueError) + expect(fn).to.raise_error(ValueError) > should.equal('File not found') + expect(fn).to.raise_error(ValueError) > should.contain('not found') - fn | expect.to_not.raise_error() - fn | expect.to_not.raise_error(ValueError) - fn | expect.to_not.raise_error(AttributeError, ValueError) + expect(fn).to_not.raise_error() + expect(fn).to_not.raise_error(ValueError) + expect(fn).to_not.raise_error(AttributeError, ValueError) Predicates @@ -966,34 +726,26 @@ pass_function Asserts if a given subject is valid when passed to a predicate function. ======================= ======================== - **Chained aliases** - + **Chainable aliases** - ----------------------- ------------------------ **Optional keywords** ``msg: str`` ======================= ======================== -**Assertion form**: - .. code-block:: python + # should style 'foo' | should.pass_test(lambda x: len(x) > 2) [1, 2, 3] | should.pass_function(lambda x: 2 in x) -.. code-block:: python - - 'foo' | expect.to.pass_test(lambda x: len(x) > 2) - [1, 2, 3] | expect.to.pass_function(lambda x: 2 in x) - -**Negation form**: - -.. code-block:: python - 'foo' | should.do_not.pass_test(lambda x: len(x) > 3) [1, 2, 3] | should.do_not.pass_function(lambda x: 5 in x) -.. code-block:: python + # expect style + expect('foo').to.pass_test(lambda x: len(x) > 2) + expect([1, 2, 3]).to.pass_function(lambda x: 2 in x) - 'foo' | expect.to_not.pass_test(lambda x: len(x) > 3) - [1, 2, 3] | expect.to_not.pass_function(lambda x: 5 in x) + expect('foo').to_not.pass_test(lambda x: len(x) > 3) + expect([1, 2, 3]).to_not.pass_function(lambda x: 5 in x) Mocks ----- @@ -1010,7 +762,7 @@ To be compatible with ``grappa``, mocks must only implement: .. warning:: - Mock matchers are not (yet) compatible with piping (|) assertion style. + Mock matchers are not (yet) compatible with piping ``|`` assertion style. been_called @@ -1018,12 +770,9 @@ been_called Asserts if a given mock subject have been called at least once. -======================= ======================== - **Optional keywords** ``msg: str`` -======================= ======================== - .. code-block:: python + # expect style expect(mock).to.have.been_called expect(mock).to.have_not.been_called @@ -1034,12 +783,9 @@ been_called_once Asserts if a given mock subject have been called only once. -======================= ======================== - **Optional keywords** ``msg: str`` -======================= ======================== - .. code-block:: python + # expect style expect(mock).to.have.been_called_once expect(mock).to.have_not.been_called_once @@ -1050,32 +796,25 @@ been_called_times Asserts if a given mock subject have been called n times. -======================= ======================== - **Optional keywords** ``msg: str`` -======================= ======================== - **Assertion form**: .. code-block:: python + # expect style expect(mock).to.have.been_called_times(0) expect(mock).to.have_not.been_called_times(3) - been_called_with ^^^^^^^^^^^^^^^^ Asserts if a given mock subject have been called at least once with specified arguments. -======================= ======================== - **Optional keywords** ``msg: str`` -======================= ======================== - .. code-block:: python + # expect style expect(mock).to.have.been_called_with('foo') expect(mock).to.have.been_called_with('foo', True, 150) @@ -1088,12 +827,9 @@ been_called_once_with Asserts if a given mock subject have been called only once with specified arguments. -======================= ======================== - **Optional keywords** ``msg: str`` -======================= ======================== - .. code-block:: python + # expect style expect(mock).to.have.been_called_once_with('foo') expect(mock).to.have.been_called_once_with('foo', True, 150) diff --git a/grappa/assertion.py b/grappa/assertion.py index a42ebde..c38e51d 100644 --- a/grappa/assertion.py +++ b/grappa/assertion.py @@ -21,6 +21,8 @@ def __call__(self, expected, *args, **kw): raise RuntimeError('grappa: operator already called') if not self._called: self._called = True + + __tracebackhide__ = True return self._fn(expected, *args, **kw) def _match_alias(self, name): diff --git a/grappa/decorators.py b/grappa/decorators.py index 71d8f48..48c6a10 100644 --- a/grappa/decorators.py +++ b/grappa/decorators.py @@ -117,7 +117,7 @@ def validate_methods(reasons, method): expected_props = ('called', 'call_count') reasons = functools.reduce(validate_props, expected_props, []) - expected_methods = ('assert_called_with', 'assert_called_once_with') + expected_methods = ('assert_any_call',) reasons = functools.reduce(validate_methods, expected_methods, reasons) if reasons: diff --git a/grappa/operators/been_called.py b/grappa/operators/been_called.py index 96f0823..e9d159d 100644 --- a/grappa/operators/been_called.py +++ b/grappa/operators/been_called.py @@ -131,7 +131,7 @@ class BeenCalledTimesOperator(Operator): kind = Operator.Type.MATCHER # Disable diff report - show_diff = True + show_diff = False # Operator keywords operators = ('been_called_times',) @@ -143,8 +143,8 @@ class BeenCalledTimesOperator(Operator): ) subject_message = Operator.Dsl.Message( - 'a mock that has been called {call_count} times', 'a mock that has not been called {call_count} times', + 'a mock that has been called {call_count} times', ) @mock_implementation_validator diff --git a/grappa/operators/been_called_with.py b/grappa/operators/been_called_with.py index 6de0903..1ae9dc2 100644 --- a/grappa/operators/been_called_with.py +++ b/grappa/operators/been_called_with.py @@ -52,7 +52,7 @@ class BeenCalledWithOperator(Operator): @mock_implementation_validator def match(self, subject, *args, **kwargs): try: - subject.assert_called_with(*args, **kwargs) + subject.assert_any_call(*args, **kwargs) return True except AssertionError as error: return False, error.args[0].splitlines() @@ -107,7 +107,7 @@ class BeenCalledOnceWithOperator(Operator): @mock_implementation_validator def match(self, subject, *args, **kwargs): try: - subject.assert_called_once_with(*args, **kwargs) - return True + subject.assert_any_call(*args, **kwargs) + return subject.call_count == 1 except AssertionError as error: return False, error.args[0].splitlines() diff --git a/grappa/operators/keys.py b/grappa/operators/keys.py index d1792f4..75e6c5a 100644 --- a/grappa/operators/keys.py +++ b/grappa/operators/keys.py @@ -67,14 +67,16 @@ class KeysOperator(Operator): LIST_TYPES = (tuple, list, set, array) def after_success(self, obj, *keys): - if not self.ctx.negate: - self.ctx.subject = [obj[x] for x in obj if x in keys] + if self.ctx.negate: + return + + if len(keys) == 1 and isinstance(keys[0], self.LIST_TYPES): + keys = list(keys[0]) + + self.ctx.subject = [obj[x] for x in obj if x in keys] if len(keys) == 1 and len(self.ctx.subject): - if isinstance(self.ctx.subject, list): - self.ctx.subject = self.ctx.subject[0] - else: - self.ctx.subject = list(self.ctx.subject.keys())[0] + self.ctx.subject = self.ctx.subject[0] def match(self, subject, *keys): if not isinstance(subject, collections_abc.Mapping): diff --git a/grappa/operators/property.py b/grappa/operators/property.py index cf44fe6..7aca534 100644 --- a/grappa/operators/property.py +++ b/grappa/operators/property.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from array import array from ..operator import Operator @@ -58,49 +59,37 @@ def baz(): 'an object of type "{type}" with data "{value}"', ) + LIST_TYPES = (tuple, list, set, array) + def after_success(self, obj, *keys): if self.ctx.negate: return - # Get attribute keys + if len(keys) == 1 and isinstance(keys[0], self.LIST_TYPES): + keys = list(keys[0]) + self.ctx.subject = [getattr(obj, x) for x in keys] if len(keys) == 1 and len(self.ctx.subject): self.ctx.subject = self.ctx.subject[0] - def match(self, subject, *args, **kwargs): - success_reasons = [] - for name in args: - has_property, reason = self._has_property(subject, name) - if not has_property: - return False, [reason] + def match(self, subject, *keys): + reasons = [] + + if len(keys) == 1 and isinstance(keys[0], self.LIST_TYPES): + keys = list(keys[0]) + + for name in keys: + if hasattr(subject, name): + has_property = True + reason = 'property {0!r} found'.format(name) else: - success_reasons.append(reason) + has_property = False + reason = 'property {0!r} not found'.format(name) - for name, value in kwargs.items(): - has_property, reason = self._has_property(subject, name, value) if not has_property: return False, [reason] - else: - success_reasons.append(reason) - return True, success_reasons + reasons.append(reason) - def _has_property(self, subject, name, *args): - if args: - try: - value = getattr(subject, name) - except AttributeError: - return False, 'property {0!r} not found'.format(name) - else: - expected_value = args[0] - result, _ = expected_value._match(value) - if not result: - return False, 'property {0!r} {1!r} not found'.format( - name, expected_value) - return True, 'property {0!r} {1!r} found'.format( - name, expected_value) - - if not hasattr(subject, name): - return False, 'property {0!r} not found'.format(name) - return True, 'property {0!r} found'.format(name) + return True, reasons diff --git a/grappa/operators/raises.py b/grappa/operators/raises.py index a60f91d..a7e9243 100644 --- a/grappa/operators/raises.py +++ b/grappa/operators/raises.py @@ -58,7 +58,7 @@ def fn(): def after_success(self, obj, *keys): message = getattr(self.value, 'message', None) - if not message: + if not message and self.value: message = ' '.join([str(item) for item in self.value.args]) self.ctx.subject = message diff --git a/grappa/resolver.py b/grappa/resolver.py index 351bb5b..f4d540b 100644 --- a/grappa/resolver.py +++ b/grappa/resolver.py @@ -32,6 +32,7 @@ def assertion(subject): # Self-trigger tests if running as global if self.ctx.chained or self.ctx.subject is not empty: + __tracebackhide__ = True self.test._trigger() return self.test @@ -58,6 +59,7 @@ def assertion(subject): # Trigger tests on function call if running as chained call if self.ctx.chained or self.ctx.subject is not empty: + __tracebackhide__ = True return self.test._trigger() return self.test @@ -147,4 +149,5 @@ def resolve(self, name): )) # Register operator assertion for lazy execution + __tracebackhide__ = True return run_operator(operator) or self.test diff --git a/grappa/template.py b/grappa/template.py index ad1d2b8..5d3b797 100644 --- a/grappa/template.py +++ b/grappa/template.py @@ -15,8 +15,6 @@ class ErrorTemplate(object): section_separator = '\n\n ' - header = 'Oops! Something went wrong!' - def __init__(self): self.sections = [] @@ -69,5 +67,5 @@ def add_section(buf, section): )) return buf - sections = functools.reduce(add_section, self.sections, [self.header]) + sections = functools.reduce(add_section, self.sections, []) return self.section_separator.join(sections) diff --git a/grappa/test.py b/grappa/test.py index 4f57791..134308f 100644 --- a/grappa/test.py +++ b/grappa/test.py @@ -70,6 +70,8 @@ def __call__(self, subject, overload=False): grappa.Test: new test instance with the given subject. """ self._ctx.subject = subject + + __tracebackhide__ = True return self._trigger() if overload else Test(subject) def __getattr__(self, name): @@ -87,6 +89,7 @@ def __getattr__(self, name): return Test(subject).__getattr__(name) # Resolve and register operator by name + __tracebackhide__ = True return OperatorResolver(self).resolve(name) def _trigger(self): @@ -110,6 +113,7 @@ def _trigger(self): # If error is present, raise it! if err: + __tracebackhide__ = True raise err return self @@ -190,27 +194,33 @@ def __overload__(self, subject): fork._ctx.chained = True fork._ctx.subject = self._ctx.subject # Trigger assertions + + __tracebackhide__ = True return fork._trigger() # Otherwise invoke the test function with a subject + __tracebackhide__ = True return self.__call__(subject, overload=True) def __or__(self, value): """ Overloads ``|`` as from left-to-right operator precedence expression. """ + __tracebackhide__ = True return self.__overload__(value) def __ror__(self, value): """ Overloads ``|`` operator. """ + __tracebackhide__ = True return self.__overload__(value) def __gt__(self, value): """ Overloads ``>`` operator. """ + __tracebackhide__ = True return self.__overload__(value) def __enter__(self): diff --git a/tests/operators/been_called_test.py b/tests/operators/been_called_test.py index 7d37067..c6bc8bc 100644 --- a/tests/operators/been_called_test.py +++ b/tests/operators/been_called_test.py @@ -51,8 +51,10 @@ def test_been_called_times(expect, mocker): def test_been_called_with(expect, mocker): mock_called = mocker.patch('os.path.join') os.path.join('home', 'log.txt') + os.path.join('root', 'config.json') expect(mock_called).to.have.been_called_with('home', 'log.txt') + expect(mock_called).to.have.been_called_with('root', 'config.json') with pytest.raises(AssertionError): expect(mock_called).to.have_not.been_called_with('home', 'log.txt') @@ -113,6 +115,11 @@ def test_been_called_once_with(expect, mocker): expect(mock_called_several_times).to.have_not.been_called_once + with pytest.raises(AssertionError): + expect(mock_called_several_times).to.have.been_called_once_with( + '/home/log.txt', '/home/log_new.txt' + ) + with pytest.raises(AssertionError): expect(mock_called_several_times).to.have.been_called_once diff --git a/tests/operators/properties_test.py b/tests/operators/properties_test.py index 914223f..db7b1f2 100644 --- a/tests/operators/properties_test.py +++ b/tests/operators/properties_test.py @@ -43,3 +43,24 @@ def bar(self): with pytest.raises(AssertionError): should(foo()).have.property('foo').which.should.be.equal.to('pepe') + + foo() | should.have.properties('foo', 'bar') + + foo() | should.have.properties(('foo', 'bar')) + + foo() | should.have.properties(['foo', 'bar']) + + foo() | should.have.properties({'foo', 'bar'}) + + +def test_not_expect_properties(should): + class foo(object): + foo = 'bar' + + class baz(object): + foo = 'bar' + + def bar(self): + pass + + foo() | should.not_have.property('fuu') diff --git a/tests/operators/raises_test.py b/tests/operators/raises_test.py index cbdf978..e1dbb13 100644 --- a/tests/operators/raises_test.py +++ b/tests/operators/raises_test.py @@ -32,6 +32,8 @@ def error_with_params(foo_param): with pytest.raises(AssertionError): no_error | should.raise_error(AssertionError) + no_error | should.do_not.raise_error(AssertionError) + def test_raises_with_message_redirection(should): def error(): @@ -41,6 +43,7 @@ def env_error(): raise EnvironmentError(3501, 'bar') error | should.raise_error(AssertionError) > should.equal('foo') + error | should.raise_error(AssertionError) > should.do_not.equal('fooed') error | should.raise_error(AssertionError) > should.contain('fo')