import pytest # type: ignore from typing import Any, Callable, Tuple, Type from monads.list import List from monads.monoid import Monoid, String, Addition, Multiplication from monads.maybe import First, Last, Just Constructor = Tuple[Type, Callable[[Any], Any]] @pytest.fixture( scope="module", params=[ (First, lambda x: Just(x)), (Last, lambda x: Just(x)), (String, lambda x: str(x)), (Addition, lambda x: x), (Multiplication, lambda x: x), (List, lambda x: [x]), ], ) def constructor(request) -> Constructor: return request.param def construct(constructor: Constructor, value: Any) -> Monoid: cls, builder = constructor return cls(builder(value)) def test_mappend_add_operator(constructor: Constructor) -> None: a: Monoid = construct(constructor, 1) b: Monoid = construct(constructor, 2) assert a.mappend(b) == a + b def test_associative(constructor: Constructor) -> None: a: Monoid = construct(constructor, 1) b: Monoid = construct(constructor, 2) c: Monoid = construct(constructor, 3) assert (a + b) + c == a + (b + c) def test_mconcat_empty(constructor: Constructor) -> None: cls, _ = constructor zero: Monoid = cls.mzero() assert zero == cls.mconcat([]) def test_mconcat(constructor: Constructor) -> None: cls, _ = constructor a: Monoid = construct(constructor, 1) b: Monoid = construct(constructor, 2) c: Monoid = construct(constructor, 3) expected: Monoid = a.mappend(b).mappend(c) assert expected == cls.mconcat([a, b, c])