# Path: pymonet/utils.py
# def identity(value: T) -> T:
#     """
#     Return first argument.
# 
#     :param value:
#     :type value: Any
#     :returns:
#     :rtype: Any
#     """
#     return value
# 
# def increase(value: int) -> int:
#     """
#     Return increased by 1 argument.
# 
#     :param value:
#     :type value: Int
#     :returns:
#     :rtype: Int
#     """
#     return value + 1
# 
# def compose(value, *functions):
#     """
#     Perform right-to-left function composition.
# 
#     :param value: argument of first applied function
#     :type value: Any
#     :param functions: list of functions to applied from right-to-left
#     :type functions: List[Function]
#     :returns: result of all functions
#     :rtype: Any
#     """
#     return reduce(
#         lambda current_value, function: function(current_value),
#         functions[::-1],
#         value
#     )
# 
# @curry
# def eq(value, value1) -> bool:
#     return value == value1
# 
# def pipe(value, *functions):
#     """
#     Perform left-to-right function composition.
# 
#     :param value: argument of first applied function
#     :type value: Any
#     :param functions: list of functions to applied from left-to-right
#     :type functions: List[Function]
#     :returns: result of all functions
#     :rtype: Any
#     """
#     return reduce(
#         lambda current_value, function: function(current_value),
#         functions,
#         value
#     )
# 
# @curry
# def curried_map(mapper, collection):
#     return [mapper(item) for item in collection]
# 
# @curry
# def curried_filter(filterer, collection):
#     return [item for item in collection if filterer(item)]
# 
# @curry
# def find(collection: List[T], key: Callable[[T], bool]):
#     """
#     Return the first element of the list which matches the keys, or None if no element matches.
# 
#     :param collection: collection to search
#     :type collection: List[A]
#     :param key: function to decide witch element should be found
#     :type key: Function(A) -> Boolean
#     :returns: element of collection or None
#     :rtype: A | None
#     """
#     for item in collection:
#         if key(item):
#             return item


from hypothesis import given
from hypothesis.strategies import text, integers, lists
from pymonet.utils import \
    identity,\
    increase,\
    compose,\
    eq,\
    pipe,\
    curried_map as map,\
    curried_filter as filter,\
    find
@given(text(), integers())
def test_identity_should_return_first_argument(text, integer):
    assert identity(text) is text
    assert identity(integer) is integer


@given(integers())
def test_compose_should_applied_function_on_value_and_return_it_result(integer):
    assert compose(integer, increase) == integer + 1
    assert compose(integer, increase, increase) == integer + 2
    assert compose(integer, increase, increase, increase) == integer + 3


@given(integers())
def test_compose_should_appield_functions_from_last_to_first(integer):
    assert compose(integer, increase, lambda value: value * 2) == (integer * 2) + 1


@given(text())
def test_eq(text):
    assert eq(text, text)
    assert eq(text)(text)


def test_compose_with_collections():
    def is_odd(value): return value % 2 == 0

    assert compose(
        list(range(10)),
        map(increase),

# Path: pymonet/utils.py
# def identity(value: T) -> T:
#     """
#     Return first argument.
# 
#     :param value:
#     :type value: Any
#     :returns:
#     :rtype: Any
#     """
#     return value
# 
# def increase(value: int) -> int:
#     """
#     Return increased by 1 argument.
# 
#     :param value:
#     :type value: Int
#     :returns:
#     :rtype: Int
#     """
#     return value + 1
# 
# def compose(value, *functions):
#     """
#     Perform right-to-left function composition.
# 
#     :param value: argument of first applied function
#     :type value: Any
#     :param functions: list of functions to applied from right-to-left
#     :type functions: List[Function]
#     :returns: result of all functions
#     :rtype: Any
#     """
#     return reduce(
#         lambda current_value, function: function(current_value),
#         functions[::-1],
#         value
#     )
# 
# @curry
# def eq(value, value1) -> bool:
#     return value == value1
# 
# def pipe(value, *functions):
#     """
#     Perform left-to-right function composition.
# 
#     :param value: argument of first applied function
#     :type value: Any
#     :param functions: list of functions to applied from left-to-right
#     :type functions: List[Function]
#     :returns: result of all functions
#     :rtype: Any
#     """
#     return reduce(
#         lambda current_value, function: function(current_value),
#         functions,
#         value
#     )
# 
# @curry
# def curried_map(mapper, collection):
#     return [mapper(item) for item in collection]
# 
# @curry
# def curried_filter(filterer, collection):
#     return [item for item in collection if filterer(item)]
# 
# @curry
# def find(collection: List[T], key: Callable[[T], bool]):
#     """
#     Return the first element of the list which matches the keys, or None if no element matches.
# 
#     :param collection: collection to search
#     :type collection: List[A]
#     :param key: function to decide witch element should be found
#     :type key: Function(A) -> Boolean
#     :returns: element of collection or None
#     :rtype: A | None
#     """
#     for item in collection:
#         if key(item):
#             return item


# Path: tests/test_utils.py
from hypothesis import given
from hypothesis.strategies import text, integers, lists
from pymonet.utils import \
    identity,\
    increase,\
    compose,\
    eq,\
    pipe,\
    curried_map as map,\
    curried_filter as filter,\
    find

@given(text(), integers())
def test_identity_should_return_first_argument(text, integer):
    assert identity(text) is text
    assert identity(integer) is integer


@given(integers())
def test_compose_should_applied_function_on_value_and_return_it_result(integer):
    assert compose(integer, increase) == integer + 1
    assert compose(integer, increase, increase) == integer + 2
    assert compose(integer, increase, increase, increase) == integer + 3


@given(integers())
def test_compose_should_appield_functions_from_last_to_first(integer):
    assert compose(integer, increase, lambda value: value * 2) == (integer * 2) + 1


@given(text())
def test_eq(text):
    assert eq(text, text)
    assert eq(text)(text)


def test_compose_with_collections():
    def is_odd(value): return value % 2 == 0

    assert compose(
        list(range(10)),
        map(increase),

        filter(is_odd)