From 69e4a3dbaa3bd3aa42215d15a9d846cf86ea2810 Mon Sep 17 00:00:00 2001 From: Dov Benyomin Sohacheski Date: Fri, 2 Dec 2022 14:04:33 +0200 Subject: [PATCH] using expected actual wording (#21) --- src/expycted/__init__.py | 6 +- src/expycted/internals/base.py | 19 ++- src/expycted/internals/filesystem.py | 32 +++--- src/expycted/internals/function.py | 99 +++++++++------- src/expycted/internals/value.py | 165 ++++++++++++--------------- test/other_tests.py | 9 +- 6 files changed, 171 insertions(+), 159 deletions(-) diff --git a/src/expycted/__init__.py b/src/expycted/__init__.py index d66f904..9b33c08 100644 --- a/src/expycted/__init__.py +++ b/src/expycted/__init__.py @@ -17,13 +17,13 @@ def function(cls, function: Callable): return Function(function) @classmethod - def value(cls, value: Any): + def value(cls, expected: Any): """Expect a value to be something Args: - value (Any): Value to check for some sort of condition + expected (Any): Value to check for some sort of condition """ - return cls(value) + return cls(expected) @classmethod def folder(cls, path: Union[str, Path]): diff --git a/src/expycted/internals/base.py b/src/expycted/internals/base.py index 786e350..fe8de61 100644 --- a/src/expycted/internals/base.py +++ b/src/expycted/internals/base.py @@ -8,15 +8,24 @@ class BaseExpectation: _ASSERTION_MESSAGES = {} - def __init__(self, value: Any, negate=False): - self.value = value + def __init__(self, expected: Any, negate=False): + self.expected = expected self.negate = negate - def _message(self, method: str, actual: Any = _SENTINEL) -> str: - placeholders = dict(value1=self.value) + def _message( + self, + method: str, + actual: Any = _SENTINEL, + expected: Any = None, + **kwargs + ) -> str: + placeholders = dict( + expected=self.expected if expected is None else expected, + **kwargs + ) if actual is not _SENTINEL: - placeholders['value2'] = actual + placeholders["actual"] = actual return self._ASSERTION_MESSAGES[method].format(**placeholders) diff --git a/src/expycted/internals/filesystem.py b/src/expycted/internals/filesystem.py index 2cde2ab..fcfde6a 100644 --- a/src/expycted/internals/filesystem.py +++ b/src/expycted/internals/filesystem.py @@ -15,15 +15,15 @@ class Folder: class Directory(BaseExpectation): _ASSERTION_MESSAGES = { - "contain": "Expected {value1} to contain {value2}", - "contain_file": "Expected {value1} to contain file {value2}", - "contain_folder": "Expected {value1} to contain folder {value2}", - "exist": "Expected {value1} to exist", - "be_empty": "Expected {value1} to be empty", + "contain": "Expected {expected} to contain {actual}", + "contain_file": "Expected {expected} to contain file {actual}", + "contain_folder": "Expected {expected} to contain folder {actual}", + "exist": "Expected {expected} to exist", + "be_empty": "Expected {expected} to be empty", } - def __init__(self, value: Union[str, Path]): - super().__init__(self._normalize(value)) + def __init__(self, expected: Union[str, Path]): + super().__init__(self._normalize(expected)) @staticmethod def _normalize(value: Union[str, Path]) -> Path: @@ -34,10 +34,10 @@ def _normalize(value: Union[str, Path]) -> Path: def _internal_contain( self, - name: str, + actual: str, type_: Union[Type[File], Type[Folder], None, str] = None ) -> Tuple[bool, str]: - name = self.value.joinpath(self._normalize(name)) + name = self.expected.joinpath(self._normalize(actual)) if type_ == File or str(type_).lower() == "file": return name.is_file(), self._message("contain_file", name) @@ -48,15 +48,15 @@ def _internal_contain( return name.exists(), self._message("contain", name) def _internal_exist(self) -> Tuple[bool, str]: - return self.value.exists(), self._message("exist") + return self.expected.exists(), self._message("exist") def _internal_be_empty(self) -> Tuple[bool, str]: - return not any(self.value.iterdir()), self._message("be_empty") + return not any(self.expected.iterdir()), self._message("be_empty") @assertion def contain( self, - name: str, + actual: str, type_: Union[Type[File], Type[Folder], None, str] = None ) -> None: """ @@ -64,18 +64,18 @@ def contain( """ @hidetraceback - def contain_file(self, name: str) -> None: + def contain_file(self, actual: str) -> None: """ Check if folder contains file with given name """ - return self.contain(name, type_=File) + return self.contain(actual, type_=File) @hidetraceback - def contain_folder(self, name: str) -> None: + def contain_folder(self, actual: str) -> None: """ Check if folder contains folder with given name """ - return self.contain(name, type_=Folder) + return self.contain(actual, type_=Folder) @assertion def exist(self) -> None: diff --git a/src/expycted/internals/function.py b/src/expycted/internals/function.py index 6d522f2..1863014 100644 --- a/src/expycted/internals/function.py +++ b/src/expycted/internals/function.py @@ -1,25 +1,23 @@ from typing import Any, Callable, Type +from expycted.internals.base import BaseExpectation from expycted.internals.utils import hidetraceback -assertion_texts = { - "to_raise": "Expected function `{function}` to raise {exc} when called with: {arguments}", - "to_return": "Expected function {function} to return {value} when called with: {arguments}", - "to_return_type": "Expected value ({value}) returned by function {function} to be of type {type} when called with: {arguments}", -} - class Function: - def __init__(self, function: Callable): - self.function = function + def __init__(self, expected: Callable): + self.expected = expected - def to_raise(self, exception: Type[Exception] = Exception): + def to_raise(self, exception: Type[Exception] = None): """Check if the function raises the exception Args: exception (Exception): Exception to expect """ - return ToRaise(exception=exception, function=self.function) + return ToRaise( + expected=self.expected, + exception=exception if exception else Exception, + ) def to_return(self, value: Any = None, type_of_value: type = None): """Check if the function returns provided value or type @@ -35,10 +33,13 @@ def to_return(self, value: Any = None, type_of_value: type = None): raise ValueError( "You must specify either value or type_of_value in to_return function" ) - else: - return ToReturn( - value=value, type_of_value=type_of_value, function=self.function - ) + + return ToReturn( + expected=self.expected, + value=value, + type_of_value=type_of_value, + ) + def format_args_kwargs(args: Any, kwargs: Any) -> str: """Format arguments and keyword arguments to string @@ -52,16 +53,19 @@ def format_args_kwargs(args: Any, kwargs: Any) -> str: """ args_str = ", ".join(map(str, args)) kwargs_str = ", ".join( - map(lambda x: "{}={}".format(x[0], x[1]), kwargs.items()) + map(lambda x: f"{x[0]}={x[1]}", kwargs.items()) ) + return f"\n\t- arguments: {args_str} \n\t- keyword arguments: {kwargs_str}" -class ToRaise: - function: Callable - exception: Type[Exception] - def __init__(self, exception: Type[Exception], function: Callable): - self.function = function +class ToRaise(BaseExpectation): + _ASSERTION_MESSAGES = { + "to_raise": "Expected function `{expected}` to raise {actual} when called with: {arguments}", + } + + def __init__(self, expected: Callable, exception: Type[Exception]): + super().__init__(expected) self.exception = exception @hidetraceback @@ -72,12 +76,17 @@ def when_called_with(self, *args, **kwargs): AssertionError: When function doesn't raise the expected exception AssertionError is raised """ try: - self.function(*args, **kwargs) + self.expected(*args, **kwargs) except Exception as e: - assert issubclass(type(e), self.exception), assertion_texts["to_raise"].format( - function=self.function.__name__, - exc=self.exception, - arguments=format_args_kwargs(args, kwargs)) + self._assert( + issubclass(type(e), self.exception), + self._message( + "to_raise", + self.exception, + expected=self.expected.__name__, + arguments=format_args_kwargs(args, kwargs) + ) + ) else: raise AssertionError( f"Expected '{self.exception}' to be raised, but nothing was raised" @@ -86,13 +95,14 @@ def when_called_with(self, *args, **kwargs): when_called_with_args = when_called_with_arguments = when_called_with -class ToReturn: - function: Callable - value: Any - type_of_value: type +class ToReturn(BaseExpectation): + _ASSERTION_MESSAGES = { + "to_return": "Expected function {expected} to return {actual} when called with: {arguments}", + "to_return_type": "Expected value ({actual}) returned by function {expected} to be of type {type} when called with: {arguments}", + } - def __init__(self, function: Callable, value, type_of_value): - self.function = function + def __init__(self, expected: Callable, value, type_of_value): + super().__init__(expected) self.value = value self.type_of_value = type_of_value @@ -103,17 +113,24 @@ def when_called_with(self, *args, **kwargs): Raises: AssertionError: When function value or type_of_value is not matched AssertionError is raised """ - ret = self.function(*args, **kwargs) + ret = self.expected(*args, **kwargs) + + substitutions = dict( + actual=self.value, + expected=self.expected.__name__, + arguments=format_args_kwargs(args, kwargs) + ) + if self.value is not None: - assert ret == self.value, assertion_texts["to_return"].format( - function=self.function.__name__, - value=self.value, - arguments=format_args_kwargs(args, kwargs)) + self._assert( + ret == self.value, + self._message("to_return", **substitutions) + ) + if self.type_of_value is not None: - assert type(ret) == self.type_of_value, assertion_texts["to_return_type"].format( - function=self.function.__name__, - value=self.value, - arguments=format_args_kwargs(args, kwargs), - type=self.type_of_value) + self._assert( + type(ret) == self.type_of_value, + self._message("to_return", type=self.type_of_value, **substitutions) + ) when_called_with_args = when_called_with_arguments = when_called_with diff --git a/src/expycted/internals/value.py b/src/expycted/internals/value.py index 15b8b10..1b882cc 100644 --- a/src/expycted/internals/value.py +++ b/src/expycted/internals/value.py @@ -7,162 +7,159 @@ class Value(BaseExpectation): _ASSERTION_MESSAGES = { - "equal": "Expected {value1} to equal {value2}", - "be": "Expected {value1} to be {value2}", - "contain": "Expected {value1} to contain {value2}", - "be_contained_in": "Expected {value1} to be contained in {value2}", - "be_empty": "Expected {value1} to be empty", - "be_true": "Expected {value1} to be true", - "be_false": "Expected {value1} to be false", - "be_truthy": "Expected {value1} to be truthy", - "be_falsey": "Expected {value1} to be falsey", - "be_of_type": "Expected {value1} to be of type {value2}", - "inherit": "Expected {value1} to inherit {value2}", - "be_greater_than": "Expected {value1} to be greater than {value2}", - "be_lesser_than": "Expected {value1} to be less than {value2}", - "be_greater_or_equal_to": "Expected {value1} to be greater than or equal to {value2}", - "be_lesser_or_equal_to": "Expected {value1} to be less than or equal to {value2}", - "be_numeric": "Expected {value1} to be numeric", + "equal": "Expected {expected} to equal {actual}", + "be": "Expected {expected} to be {actual}", + "contain": "Expected {expected} to contain {actual}", + "be_contained_in": "Expected {expected} to be contained in {actual}", + "be_empty": "Expected {expected} to be empty", + "be_true": "Expected {expected} to be true", + "be_false": "Expected {expected} to be false", + "be_truthy": "Expected {expected} to be truthy", + "be_falsey": "Expected {expected} to be falsey", + "be_of_type": "Expected {expected} to be of type {actual}", + "inherit": "Expected {expected} to inherit {actual}", + "be_greater_than": "Expected {expected} to be greater than {actual}", + "be_lesser_than": "Expected {expected} to be less than {actual}", + "be_greater_or_equal_to": "Expected {expected} to be greater than or equal to {actual}", + "be_lesser_or_equal_to": "Expected {expected} to be less than or equal to {actual}", + "be_numeric": "Expected {expected} to be numeric", } def _internal_has_len(self: Any) -> bool: try: - len(self.value) + len(self.expected) return True except TypeError: return False - def _internal_equal(self, something: Any) -> Tuple[bool, str]: - return self.value == something, self._message("equal", something) + def _internal_equal(self, actual: Any) -> Tuple[bool, str]: + return self.expected == actual, self._message("equal", actual) - def _internal_be(self, something: Any) -> Tuple[bool, str]: + def _internal_be(self, actual: Any) -> Tuple[bool, str]: return any( [ - str(self.value) == str(something), - pickle.dumps(self.value) == pickle.dumps(something), - self.value == something, + str(self.expected) == str(actual), + pickle.dumps(self.expected) == pickle.dumps(actual), + self.expected == actual, ] - ), self._message("be", something) + ), self._message("be", actual) - def _internal_contain(self, something: Any) -> Tuple[bool, str]: + def _internal_contain(self, actual: Any) -> Tuple[bool, str]: try: - return something in self.value, self._message("contain", something) + return actual in self.expected, self._message("contain", actual) except Exception: raise AssertionError( - f'Type "{type(self.value)} cannot contain {something}"' + f'Type "{type(self.expected)} cannot contain {actual}"' ) - def _internal_be_contained_in(self, something: Collection) -> Tuple[bool, str]: + def _internal_be_contained_in(self, actual: Collection) -> Tuple[bool, str]: try: - return self.value in something, self._message("be_contained_in", something) + return self.expected in actual, self._message("be_contained_in", actual) except Exception: raise AssertionError( - f'Type "{type(something)} cannot contain {self.value}"' + f'Type "{type(actual)} cannot contain {self.expected}"' ) def _internal_be_empty(self): try: - iter(self.value) - return not self.value, self._message("be_empty") + iter(self.expected) + return not self.expected, self._message("be_empty") except TypeError: raise AssertionError( - f"Emptiness of '{type(self.value)}' object doesn't make sense" + f"Emptiness of '{type(self.expected)}' object doesn't make sense" ) def _internal_be_true(self) -> Tuple[bool, str]: - return self.value is True, self._message("be_true") + return self.expected is True, self._message("be_true") def _internal_be_false(self) -> Tuple[bool, str]: - return self.value is False, self._message("be_false") + return self.expected is False, self._message("be_false") def _internal_be_truthy(self) -> Tuple[bool, str]: - return True if self.value else False, self._message("be_truthy") + return True if self.expected else False, self._message("be_truthy") def _internal_be_falsey(self) -> Tuple[bool, str]: - return True if not self.value else False, self._message("be_falsey") + return True if not self.expected else False, self._message("be_falsey") - def _internal_be_of_type(self, something: type) -> Tuple[bool, str]: - return type(self.value) is something, self._message("be_of_type", something) + def _internal_be_of_type(self, actual: type) -> Tuple[bool, str]: + return type(self.expected) is actual, self._message("be_of_type", actual) - def _internal_inherit(self, something: type) -> Tuple[bool, str]: + def _internal_inherit(self, actual: type) -> Tuple[bool, str]: try: - return issubclass(type(self.value), something), self._message("inherit", something) + return issubclass(type(self.expected), actual), self._message("inherit", actual) except Exception: raise AssertionError("Second argument must be a class, not an instance") - def _internal_be_greater_than(self, something: Any) -> Tuple[bool, str]: - return self.value > something, self._message("be_greater_than", something) + def _internal_be_greater_than(self, actual: Any) -> Tuple[bool, str]: + return self.expected > actual, self._message("be_greater_than", actual) - def _internal_be_lesser_than(self, something: Any) -> Tuple[bool, str]: - return self.value < something, self._message("be_lesser_than", something) + def _internal_be_lesser_than(self, actual: Any) -> Tuple[bool, str]: + return self.expected < actual, self._message("be_lesser_than", actual) - def _internal_be_greater_or_equal_to(self, something: Any) -> Tuple[bool, str]: - return self.value >= something, self._message("be_greater_or_equal_to", something) + def _internal_be_greater_or_equal_to(self, actual: Any) -> Tuple[bool, str]: + return self.expected >= actual, self._message("be_greater_or_equal_to", actual) - def _internal_be_lesser_or_equal_to(self, something: Any) -> Tuple[bool, str]: - return self.value <= something, self._message("be_lesser_or_equal_to", something) + def _internal_be_lesser_or_equal_to(self, actual: Any) -> Tuple[bool, str]: + return self.expected <= actual, self._message("be_lesser_or_equal_to", actual) def _internal_be_numeric(self: Any) -> Tuple[bool, str]: assertion_text = self._message("be_numeric") - if type(self.value) in [int, float, complex]: + + if type(self.expected) in [int, float, complex]: return True, assertion_text - - if type(self.value) is str: + + if type(self.expected) is str: try: - float(self.value) - print(float(self.value)) + float(self.expected) return True, assertion_text except Exception: pass + return False, assertion_text @assertion - def equal(self, something: Any) -> None: + def equal(self, actual: Any) -> None: """Checks whether that the value is equal to something Args: - something (Any): The value to compare to + actual (Any): The value to compare to Returns: bool: Result """ - pass @assertion - def be(self, something: Any) -> None: + def be(self, actual: Any) -> None: """Checks whether the value is 'softly' equal to something Args: - something (Any): The value to compare to + actual (Any): The value to compare to Returns: bool: Result """ - pass @assertion - def contain(self, something: Any) -> None: + def contain(self, actual: Any) -> None: """Checks whether the value contains something Args: - something (Any): The value to be contained + actual (Any): The value to be contained Returns: bool: Result """ - pass @assertion - def be_contained_in(self, something: Collection) -> None: + def be_contained_in(self, actual: Collection) -> None: """Checks whether the value is contained in something Args: - something (Any): The value to contain something + actual (Any): The value to contain something Returns: bool: Result """ - pass @assertion def be_empty(self) -> None: @@ -171,7 +168,6 @@ def be_empty(self) -> None: Returns: bool: Result """ - pass @assertion def be_true(self) -> None: @@ -180,7 +176,6 @@ def be_true(self) -> None: Returns: bool: Result """ - pass @assertion def be_false(self) -> None: @@ -189,7 +184,6 @@ def be_false(self) -> None: Returns: bool: Result """ - pass @assertion def be_truthy(self) -> None: @@ -198,7 +192,6 @@ def be_truthy(self) -> None: Returns: bool: Result """ - pass @assertion def be_falsey(self) -> None: @@ -207,79 +200,72 @@ def be_falsey(self) -> None: Returns: bool: Result """ - pass @assertion - def be_of_type(self, something: type) -> None: + def be_of_type(self, actual: type) -> None: """Checks whether the value is of provided type Args: - something (type): Type to be checked against + actual (type): Type to be checked against Returns: bool: Result """ - pass @assertion - def inherit(self, something: type) -> None: + def inherit(self, actual: type) -> None: """Checks whether the value inherits from provided type Args: - something (type): Type to inherit from + actual (type): Type to inherit from Returns: bool: Result """ - pass @assertion - def be_greater_than(self, something: Any) -> None: + def be_greater_than(self, actual: Any) -> None: """Check whether the value is greater than something Args: - something (Any): Value to compare to + actual (Any): Value to compare to Returns: bool: Result """ - pass @assertion - def be_lesser_than(self, something: Any) -> None: + def be_lesser_than(self, actual: Any) -> None: """Check whether the value is lesser than something Args: - something (Any): Value to compare to + actual (Any): Value to compare to Returns: bool: Result """ - pass @assertion - def be_greater_or_equal_to(self, something: Any) -> None: + def be_greater_or_equal_to(self, actual: Any) -> None: """Check whether the value is greater than or equal to something Args: - something (Any): Value to compare to + actual (Any): Value to compare to Returns: bool: Result """ - pass @assertion - def be_lesser_or_equal_to(self, something: Any) -> None: + def be_lesser_or_equal_to(self, actual: Any) -> None: """Check whether the value is lesser than or equal to something Args: - something (Any): Value to compare to + actual (Any): Value to compare to Returns: bool: Result """ - pass @assertion def be_numeric(self) -> None: @@ -288,7 +274,6 @@ def be_numeric(self) -> None: Returns: bool: Result """ - pass # Aliases diff --git a/test/other_tests.py b/test/other_tests.py index 74974a6..874cd4a 100644 --- a/test/other_tests.py +++ b/test/other_tests.py @@ -2,7 +2,7 @@ import pytest -@pytest.mark.parametrize("v1,true", [ +@pytest.mark.parametrize('v1,true', [ (1, False), (3, False), (3.2, False), @@ -13,7 +13,7 @@ ('123', True), (lambda x: x, False), ] -) + ) def test_has_len(v1, true): assert expect(v1).to._internal_has_len() == true @@ -21,8 +21,9 @@ def test_has_len(v1, true): def test_to_expect_value(): expect_object = expect.value(1) assert isinstance(expect_object, expect) - assert expect_object.to.value == 1 - assert expect_object.to_not.value == 1 + assert expect_object.expected == 1 + assert expect_object.expected == 1 + def test_method_chaining(): expect_object = expect.value(1)