Skip to content

Commit

Permalink
Add unit tests for Either monad
Browse files Browse the repository at this point in the history
  • Loading branch information
ashuping committed Aug 12, 2024
1 parent ac55f07 commit 135e167
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
Empty file added test/__init__.py
Empty file.
Empty file added test/types/__init__.py
Empty file.
135 changes: 135 additions & 0 deletions test/types/test_Either.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
from pytest import raises, fixture

from modules.types.Either import Either, Left, Right

def test_is_right():
assert not Left(12).is_right
assert Right("str").is_right

def test_val():
assert Right("str").val == "str"
with raises(TypeError):
Left(12).val

def test_lval():
assert Left(12).lval == 12
with raises(TypeError):
Right("str").lval

def test_equals():
assert Left(12) == Left(12)
assert Left(12) != Left(13)
assert Left(12) != Left("12")

assert Right(12) == Right(12)
assert Right(12) != Right(13)
assert Right(12) != Right("12")

assert Right(12) != Left(12)

def test_map_right():
transform = lambda x: f"my {x}"

assert Right("str").map(transform) == Right("my str")
assert Right(12).map(transform) == Right("my 12")

def test_map_left():
transform = lambda x: f"my {x}"

assert Left("str").map(transform) == Left("str")
assert Left(12).map(transform) == Left(12)

def test_compound_map_right():
tf_a = lambda x: f"precious {x}"
tf_b = lambda x: f"my {x}"

assert Right("str").map(tf_a).map(tf_b) == Right("my precious str")
assert Right(12).map(tf_a).map(tf_b) == Right("my precious 12")

def test_compound_map_left():
tf_a = lambda x: f"precious {x}"
tf_b = lambda x: f"my {x}"

assert Left("str").map(tf_a).map(tf_b) == Left("str")
assert Left(12).map(tf_a).map(tf_b) == Left(12)

def test_flat_map_right_to_right():
transform = lambda x: Right(f"my {x}")

assert Right("str").flat_map(transform) == Right("my str")
assert Right(12).flat_map(transform) == Right("my 12")

def test_flat_map_right_to_left():
transform = lambda x: Left(f"my {x}")

assert Right("str").flat_map(transform) == Left("my str")
assert Right(12).flat_map(transform) == Left("my 12")

def test_flat_map_left_to_left():
transform = lambda x: Left(f"my {x}")

assert Left("str").flat_map(transform) == Left("str")
assert Left(12).flat_map(transform) == Left(12)

def test_flat_map_left_to_right():
transform = lambda x: Right(f"my {x}")

assert Left("str").flat_map(transform) == Left("str")
assert Left(12).flat_map(transform) == Left(12)

def test_flat_map_long_chain():
assert Right("str").flat_map(
lambda x: Right(f"precious {x}")
).flat_map(
lambda x: Right(f"my {x}")
).flat_map(
lambda x: Right(f"wow, {x}")
) == Right("wow, my precious str")

def test_flat_map_and_map_chain():
def fn_stoi(x: str) -> Either[Exception, int]:
try:
return Right(int(x))
except Exception as e:
return Left(e)

def fn_do_invert(x: int) -> Either[Exception, float]:
try:
return Right(1/x)
except Exception as e:
return Left(e)

def fn_do_stringify(x: float) -> str:
return f"wow, it's {x:.4}!"

res = Right("12") \
.flat_map(fn_stoi) \
.flat_map(fn_do_invert) \
.map(fn_do_stringify)

print(f"Computation result: {res}")
assert res == Right("wow, it's 0.08333!")

def test_cancelled_chain():
def fn_stoi(x: str) -> Either[Exception, int]:
try:
return Right(int(x))
except Exception as e:
return Left(e)

def fn_do_invert(x: int) -> Either[Exception, float]:
try:
return Right(1/x)
except Exception as e:
return Left(e)

def fn_do_stringify(x: float) -> str:
return f"wow, it's {x:.4}!"

res = Right("0") \
.flat_map(fn_stoi) \
.flat_map(fn_do_invert) \
.map(fn_do_stringify)

assert not res.is_right
assert res.lval.__class__.__name__ == 'ZeroDivisionError'

0 comments on commit 135e167

Please sign in to comment.