140 lines
4.3 KiB
Python
140 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from mathstream import (
|
|
StreamNumber,
|
|
add,
|
|
sub,
|
|
mul,
|
|
div,
|
|
mod,
|
|
pow,
|
|
is_even,
|
|
is_odd,
|
|
clear_logs,
|
|
collect_garbage,
|
|
DivideByZeroError,
|
|
active_streams,
|
|
tracked_files,
|
|
)
|
|
|
|
NUMBERS_DIR = Path(__file__).parent / "tests"
|
|
|
|
def write_number(name: str, digits: str) -> StreamNumber:
|
|
"""Persist digits to disk and return a streamable handle."""
|
|
NUMBERS_DIR.mkdir(parents=True, exist_ok=True)
|
|
target = NUMBERS_DIR / f"{name}.txt"
|
|
target.write_text(digits, encoding="utf-8")
|
|
return StreamNumber(target)
|
|
|
|
|
|
def read_number(num: StreamNumber) -> str:
|
|
"""Collapse streamed chunks back into a concrete string."""
|
|
return "".join(num.stream())
|
|
|
|
|
|
def check(label: str, result: StreamNumber, expected: str) -> None:
|
|
actual = read_number(result)
|
|
assert (
|
|
actual == expected
|
|
), f"{label} expected {expected}, got {actual}"
|
|
print(f"{label} = {actual}")
|
|
|
|
|
|
def check_bool(label: str, value: bool, expected: bool) -> None:
|
|
assert value is expected, f"{label} expected {expected}, got {value}"
|
|
print(f"{label} = {value}")
|
|
|
|
|
|
def main() -> None:
|
|
clear_logs()
|
|
|
|
# Build a handful of example operands on disk.
|
|
big = write_number("huge", "98765432123456789")
|
|
small = write_number("tiny", "34567")
|
|
negative = write_number("negative", "-1200")
|
|
exponent = write_number("power", "5")
|
|
negative_divisor = write_number("neg_divisor", "-34567")
|
|
literal_even = StreamNumber(literal="2000")
|
|
literal_odd = StreamNumber(literal="-3")
|
|
zero_literal = StreamNumber(literal="0")
|
|
|
|
# Showcase the core operations.
|
|
total = add(big, small)
|
|
difference = sub(big, small)
|
|
product = mul(small, negative)
|
|
quotient = div(big, small)
|
|
powered = pow(small, exponent)
|
|
modulus = mod(big, small)
|
|
neg_mod_pos = mod(negative, small)
|
|
pos_mod_neg = mod(small, negative)
|
|
neg_mod_neg = mod(negative, negative_divisor)
|
|
literal_combo = add(literal_even, literal_odd)
|
|
|
|
print("Operands stored under:", NUMBERS_DIR)
|
|
check("huge + tiny", total, "98765432123491356")
|
|
check("huge - tiny", difference, "98765432123422222")
|
|
check("tiny * negative", product, "-41480400")
|
|
check("huge // tiny", quotient, "2857217349595")
|
|
check("tiny ** power", powered, "49352419431622775997607")
|
|
check("huge % tiny", modulus, "6424")
|
|
check("negative % tiny", neg_mod_pos, "33367")
|
|
check("tiny % negative", pos_mod_neg, "-233")
|
|
check("negative % neg_divisor", neg_mod_neg, "-1200")
|
|
check("literal_even + literal_odd", literal_combo, "1997")
|
|
check_bool("is_even(negative)", is_even(negative), True)
|
|
check_bool("is_even(tiny)", is_even(small), False)
|
|
check_bool("is_odd(tiny)", is_odd(small), True)
|
|
check_bool("is_odd(negative)", is_odd(negative), False)
|
|
check_bool("is_even(literal_even)", is_even(literal_even), True)
|
|
check_bool("is_odd(literal_odd)", is_odd(literal_odd), True)
|
|
|
|
# Custom exception coverage
|
|
try:
|
|
div(literal_even, zero_literal)
|
|
except DivideByZeroError:
|
|
print("div(literal_even, zero_literal) raised DivideByZeroError as expected")
|
|
else:
|
|
raise AssertionError("div by zero did not raise DivideByZeroError")
|
|
|
|
try:
|
|
mod(literal_even, zero_literal)
|
|
except DivideByZeroError:
|
|
print("mod(literal_even, zero_literal) raised DivideByZeroError as expected")
|
|
else:
|
|
raise AssertionError("mod by zero did not raise DivideByZeroError")
|
|
|
|
# manual frees should immediately drop staged files
|
|
staged = [
|
|
total,
|
|
difference,
|
|
product,
|
|
quotient,
|
|
powered,
|
|
modulus,
|
|
neg_mod_pos,
|
|
pos_mod_neg,
|
|
neg_mod_neg,
|
|
literal_combo,
|
|
]
|
|
for stream in staged:
|
|
stream.free()
|
|
|
|
literal_even.free()
|
|
literal_odd.free()
|
|
zero_literal.free()
|
|
|
|
check_bool("total freed file gone", total.path.exists(), False)
|
|
check_bool("literal_even freed file gone", literal_even.path.exists(), False)
|
|
|
|
removed = collect_garbage(0)
|
|
print(f"collect_garbage removed {len(removed)} files after manual free")
|
|
check_bool("huge operand persists", big.path.exists(), True)
|
|
print("Active streams:", active_streams())
|
|
print("Tracked files:", tracked_files())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|