From c08d5cfd623821e5e48667c925be5e01f4629425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Falc=C3=A3o?= Date: Sat, 20 Jan 2024 08:28:39 +0000 Subject: [PATCH] bumps coverage to 99% --- docs/source/changelog.rst | 5 ++ sure/__init__.py | 34 ++------ sure/cli.py | 33 ++++---- sure/original.py | 32 -------- ...est_assertion_builder_assertion_methods.py | 67 +++++++++++++++- tests/test_original_api.py | 80 +------------------ 6 files changed, 96 insertions(+), 155 deletions(-) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index cc966ef..b4b9cdc 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -34,6 +34,11 @@ v3.0.0 decorator no longer receive a :class:`datetime.datetime` object as first argument. +- Removes methods from :class:`sure.original.AssertionHelper`: + - :meth:`sure.original.AssertionHelper.differs` + - :meth:`sure.original.AssertionHelper.has` + - :meth:`sure.original.AssertionHelper.is_a` + [v2.0.0] -------- diff --git a/sure/__init__.py b/sure/__init__.py index b469405..dd15784 100644 --- a/sure/__init__.py +++ b/sure/__init__.py @@ -737,17 +737,6 @@ def none(self): return True - def __contains__(self, expectation): - if isinstance(self.actual, dict): - items = self.actual.keys() - - if isinstance(self.actual, Iterable): - items = self.actual - else: - items = dir(self.actual) - - return expectation in items - @assertionmethod def contains(self, expectation): if expectation in self.actual: @@ -885,10 +874,8 @@ def different_of(self, expectation): def a(self, klass): if isinstance(klass, type): class_name = klass.__name__ - elif isinstance(klass, (str, )): - class_name = klass.strip() else: - class_name = str(klass) + class_name = str(klass).strip() is_vowel = class_name.lower()[0] in "aeiou" @@ -896,14 +883,8 @@ def a(self, klass): if "." in klass: items = klass.split(".") first = items.pop(0) - if not items: - items = [first] - first = "_abcoll" else: - if sys.version_info <= (3, 0, 0): - first = "__builtin__" - else: - first = "builtins" + first = "builtins" items = [klass] klass = reduce(getattr, items, __import__(first)) @@ -1023,7 +1004,7 @@ def called_with(self, *args, **kw): def throw(self, *args, **kw): if self.negative: msg = ( - "{0} called with args {1} and keyword-args {2} should " + "`{0}' called with args {1} and keyword-args {2} should " "not raise {3} but raised {4}" ) @@ -1033,7 +1014,7 @@ def throw(self, *args, **kw): return True except Exception as e: err = msg.format( - self.actual, + self.actual.__name__, self._callable_args, self._callable_kw, exc, @@ -1082,7 +1063,7 @@ def match(self, regex, *args): if not isinstance( self.actual, str ): - raise f"{repr(self.actual)} should be a string in order to compare using .match()" + raise WrongUsageError(f"{repr(self.actual)} should be a string in order to compare using .match()") matched = re.search(regex, self.actual, *args) modifiers_map = { @@ -1143,9 +1124,6 @@ def assure_identical(self, identical): def __getattr__(self, name): return getattr(self.assertion_builder, name) - def __repr__(self): - return f"" - assert_that = AssertionBuilder("assert_that") it = AssertionBuilder("it") @@ -1214,7 +1192,7 @@ def __exit__(self, exc_type, exc_value, traceback): old_dir = dir -def enable_special_syntax(): +def enable_special_syntax(): # pragma: no cover """enables :mod:`sure`'s :ref:`Special Syntax` .. danger:: Enabling the special syntax in production code may cause unintended consequences. diff --git a/sure/cli.py b/sure/cli.py index 995e325..cb5a100 100644 --- a/sure/cli.py +++ b/sure/cli.py @@ -15,27 +15,26 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import os # pragma: no cover +import sys # pragma: no cover +from glob import glob # pragma: no cover +from itertools import chain as flatten # pragma: no cover +from functools import reduce # pragma: no cover +from pathlib import Path # pragma: no cover -import os -import sys -from glob import glob -from itertools import chain as flatten -from functools import reduce -from pathlib import Path +import click # pragma: no cover +import coverage # pragma: no cover +import threading # pragma: no cover +import sure.reporters # pragma: no cover -import click -import coverage -import threading -import sure.reporters +from sure.loader import resolve_path # pragma: no cover +from sure.runner import Runner # pragma: no cover +from sure.runtime import RuntimeOptions # pragma: no cover +from sure.reporters import gather_reporter_names # pragma: no cover +from sure.errors import ExitError, ExitFailure, InternalRuntimeError, treat_error # pragma: no cover -from sure.loader import resolve_path -from sure.runner import Runner -from sure.runtime import RuntimeOptions -from sure.reporters import gather_reporter_names -from sure.errors import ExitError, ExitFailure, InternalRuntimeError, treat_error - -@click.command(no_args_is_help=True) +@click.command(no_args_is_help=True) # pragma: no cover @click.argument("paths", nargs=-1) @click.option("-c", "--with-coverage", is_flag=True) @click.option("-s", "--special-syntax", is_flag=True) diff --git a/sure/original.py b/sure/original.py index 6da963e..b26f8f8 100644 --- a/sure/original.py +++ b/sure/original.py @@ -64,26 +64,6 @@ def all_integers(obj: typing.Iterable) -> bool: return True -def explanation(msg: str) -> typing.Callable: - """Decorator for methods of :class:`~sure.original.AssertionHelper`. - - :param msg: message to be interpolated with the operands of the comparison taking place within the decorated method. - :returns: a decorator function - """ - def dec(func): - @wraps(func) - def wrap(self, expectation): - ret = func(self, expectation) - if bool(ret) is True: - return ret - else: - raise AssertionError(msg % (self.actual, expectation)) - - return wrap - - return dec - - class AssertionHelper(object): """Accompanies :class:`~sure.AssertionBuilder` in performing assertions. @@ -258,14 +238,6 @@ def every_item_is(self, expectation): return True - @explanation('%r should differ from %r, but is the same thing') - def differs(self, expectation): - return self.actual != expectation - - @explanation('%r should be a instance of %r, but is not') - def is_a(self, expectation): - return isinstance(self.actual, expectation) - def at(self, key): if not self.has(key): raise AssertionError(f"key {key} not present in {self.actual}") @@ -276,10 +248,6 @@ def at(self, key): else: return AssertionHelper(getattr(self.actual, key)) - @explanation('%r should have %r, but have not') - def has(self, that): - return that in self - def _get_int_or_length(self, obj: Union[int, typing.Iterable]): if isinstance(obj, Iterable): return len(obj) diff --git a/tests/test_assertion_builder_assertion_methods.py b/tests/test_assertion_builder_assertion_methods.py index 426c937..5c550b3 100644 --- a/tests/test_assertion_builder_assertion_methods.py +++ b/tests/test_assertion_builder_assertion_methods.py @@ -16,7 +16,8 @@ # along with this program. If not, see . """tests for :class:`sure.AssertionBuilder` properties defined with the decorator :func:`sure.assertionmethod`""" - +import re +import sys from sure import expects from sure.doubles import anything_of_type @@ -61,6 +62,68 @@ def test_within(): def test_different_of(): "expects().to.be.different_of()" - expects([]).to.be.different_of.when.called_with([]).should.have.raised( + expects("").to.be.different_of.when.called_with([]).should.have.raised( ".different_of only works for string comparison but in this case is expecting [] () instead" ) + + expects([]).to.be.different_of.when.called_with("").should.have.raised( + ".different_of only works for string comparison but in this case the actual source comparison object is [] () instead" + ) + + +def test_is_a(): + "expects().to.be.a()" + + expects(b"a").to.be.a(bytes) + expects(sys.stdout).to.be.a.when.called_with("io.StringIO").to.have.raised( + "expects(sys.stdout).to.be.a.when.called_with(\"io.StringIO\").to.have.raised( expects `<_io.TextIOWrapper name='' mode='w' encoding='utf-8'>' to be an `io.StringIO'" + ) + expects(sys.stdout).to.not_be.a.when.called_with("io.TextIOWrapper").to.have.raised( + "expects(sys.stdout).to.not_be.a.when.called_with(\"io.TextIOWrapper\").to.have.raised( expects `<_io.TextIOWrapper name='' mode='w' encoding='utf-8'>' to not be an `io.TextIOWrapper'" + ) + + +def test_to_be_below(): + "expects().to.be.below()" + + expects(b"A").to.be.below(b"a") + expects(b"a").to.below.when.called_with(b"A").should.have.raised( + "b'a' should be below b'A'" + ) + expects(70).to_not.be.below.when.called_with(83).should.have.raised( + "70 should not be below 83" + ) + expects(b"a").to.below.when.called_with(b"A").should_not.have.raised.when.called_with( + "b'a' should be below b'A'" + ).should.have.thrown.when.called_with("`below' called with args (b'A',) and keyword-args {} should not raise b'a' should be below b'A' but raised b'a' should be below b'A'").should.return_value(not False) + + +def test_to_be_above(): + "expects().to.be.above()" + + expects(b"S").to.be.above(b"B") + expects(b"D").to.be.above.when.called_with(b"S").should.have.raised( + "b'D' should be above b'S'" + ) + expects(115).to.not_be.above.when.called_with(102).to.have.raised( + "115 should not be above 102" + ) + + +def test_to_match(): + "expects().to.match() REGEX" + + expects("ROBSON").to.match(r"(^RO|.OB.{3})") + expects("robson").to.match(r"(^RO|.OB.{3})", re.I) + expects("OM").to.match(r"S?[OU][NM]") + expects("ON").to.match(r"S?[OU][NM]") + expects("SOM").to.match(r"S?[OU][NM]") + expects("SON").to.match(r"S?[OU][NM]") + expects("SUM").to.match(r"S?[OU][MN]") + expects("SUN").to.match(r"S?[OU][MN]") + expects("UM").to.match(r"S?[OU][MN]") + expects("UN").to.match(r"S?[OU][MN]") + expects("NOS").to_not.match(r"S?[OU][MN]") + expects(list("OHMS")).to.match.when.called_with("Ω").should.have.raised( + "['O', 'H', 'M', 'S'] should be a string in order to compare using .match()" + ) diff --git a/tests/test_original_api.py b/tests/test_original_api.py index c804372..17246bd 100644 --- a/tests/test_original_api.py +++ b/tests/test_original_api.py @@ -104,15 +104,6 @@ def data_structure_was_modified(context): assert not hasattr(data_structure, "modified") -def test_that_is_a(): - "that() is_a(object)" - - data_structure = "data_structure" - - assert that(data_structure).is_a(str) - assert isinstance(data_structure, str) - - def test_that_equals(): "that() equals(string)" @@ -122,69 +113,6 @@ def test_that_equals(): assert data_structure == "data_structure" -def test_that_differs(): - "that() differs(object)" - - data_structure = "data_structure" - - assert that(data_structure).differs("23123%FYTUGIHOfdf") - assert data_structure != "23123%FYTUGIHOfdf" - - -def test_that_has(): - "that() has(object)" - - class Class: - value = "some class" - - Object = Class() - dictionary = { - "value": "Value", - } - value = "value" - - assert hasattr(Class, "value") - expects(Class).has("value") - expects(Class).to.be.like("value") - assert "value" in that(Class) - - assert hasattr(Object, "value") - expects(Object).has("value") - expects(Object).to.be.like("value") - assert "value" in that(Object) - - assert "value" in dictionary - expects(dictionary).has("value") - expects(dictionary).to.be.like("value") - assert "value" in that(dictionary) - - expects(value).has("value") - expects(value).to.be.like("value") - assert "value" in that(value) - expects(value).has("va") - expects(value).to.be.like("va") - assert "val" in that(value) - expects(value).has("val") - expects(value).to.be.like("ue") - assert "ue" in that(value) - - -def test_that_at_key_equals(): - "that().at(object).equals(object)" - - class Class: - attribute = "some class" - - Object = Class() - dictionary = { - "attribute": "data_structure", - } - - assert that(Class).at("attribute").equals("some class") - assert that(Object).at("attribute").equals("some class") - assert that(dictionary).at("attribute").equals("data_structure") - - def test_that_len_is(): "that() len_is(number)" @@ -669,7 +597,7 @@ def sleepy(*a): except AssertionError as e: failed = True expects( - "sleepy [tests/test_original_api.py line 663] did not run within five miliseconds" + "sleepy [tests/test_original_api.py line 591] did not run within five miliseconds" ).to.equal(str(e)) assert failed, "within(five=miliseconds)(sleepy) did not fail" @@ -839,7 +767,7 @@ def test_depends_on_failing_due_to_lack_of_attribute_in_context(): fullpath = collapse_path(os.path.abspath(__file__)) error = ( - f'the action "variant_action" defined at {fullpath}:848 ' + f'the action "variant_action" defined at {fullpath}:776 ' 'depends on the attribute "data_structure" to be available in the' " current context" ) @@ -862,10 +790,10 @@ def test_depends_on_failing_due_not_calling_a_previous_action(): fullpath = collapse_path(os.path.abspath(__file__)) error = ( - 'the action "my_action" defined at {0}:876 ' + 'the action "my_action" defined at {0}:804 ' 'depends on the attribute "some_attr" to be available in the context.' " Perhaps one of the following actions might provide that attribute:\n" - " -> dependency_action at {0}:872".replace("{0}", fullpath) + " -> dependency_action at {0}:800".replace("{0}", fullpath) ) def with_setup(context):