mcp-calculator/tests/test_number_theory_units.py
2026-09-15 20:38:16 +02:00

94 lines
3.6 KiB
Python

from mcp_calculator.ops.context import MathError
from mcp_calculator.ops.number_theory import number_theory
from mcp_calculator.ops.units import convert_units
from tests.support import MathTestCase
class NumberTheoryTest(MathTestCase):
def test_operations(self):
cases = [
("gcd", [48, 180], 12),
("lcm", [4, 6, 10], 60),
("is_prime", [97], True),
("is_prime", ["2305843009213693951"], True),
("next_prime", [100], 101),
("previous_prime", [100], 97),
("nth_prime", [10], 29),
("totient", [36], 12),
("mod", [-7, 3], 2),
("mod_pow", [2, 100, 97], 16),
("mod_inverse", [3, 11], 4),
("binomial", [49, 6], 13983816),
("permutations", [5, 2], 20),
("fibonacci", [50], 12586269025),
("factorial", [10], 3628800),
]
for operation, values, expected in cases:
with self.subTest(operation=operation, values=values):
self.assertEqual(number_theory(operation, values)["result"], expected)
def test_big_results_are_strings(self):
r = number_theory("factorial", [30])
self.assertEqual(r["result"], "265252859812191058636308480000000")
self.assertEqual(r["digits"], 33)
def test_factorize(self):
r = number_theory("factorize", [360])
self.assertEqual(r["result"], {"2": 3, "3": 2, "5": 1})
self.assertEqual(r["product_form"], "2^3 * 3^2 * 5")
def test_crt(self):
self.assertEqual(number_theory("crt", [2, 3, 2], moduli=[3, 5, 7])["result"], 23)
def test_base_convert(self):
self.assertEqual(number_theory("base_convert", ["ff"], from_base=16, to_base=2)["result"], "11111111")
self.assertEqual(number_theory("base_convert", ["0x1F"], from_base=16, to_base=10)["result"], "31")
self.assertEqual(number_theory("base_convert", ["-10"], to_base=2)["result"], "-1010")
def test_continued_fraction(self):
self.assertEqual(number_theory("continued_fraction", ["415/93"])["result"], [4, 2, 6, 7])
def test_primes_in_range(self):
self.assertEqual(number_theory("primes_in_range", [10, 30])["result"], [11, 13, 17, 19, 23, 29])
def test_arity_errors(self):
with self.assertRaisesRegex(MathError, "values"):
number_theory("mod_pow", [2, 3])
def test_no_inverse(self):
with self.assertRaisesRegex(MathError, "no inverse"):
number_theory("mod_inverse", [2, 4])
def test_non_integer(self):
with self.assertRaisesRegex(MathError, "not an integer"):
number_theory("gcd", ["1.5", 3])
class UnitsTest(MathTestCase):
def test_speed(self):
self.assertApprox(convert_units("100 km/h", "m/s")["magnitude"], 27.7777777778)
def test_temperature(self):
self.assertApprox(convert_units("25 degC", "degF")["magnitude"], 77)
def test_quantity_arithmetic(self):
self.assertApprox(convert_units("5 km/h * 2 h", "m")["magnitude"], 10000)
def test_force(self):
self.assertApprox(convert_units("1.5 kg * 9.81 m/s^2", "N")["magnitude"], 14.715)
def test_base_units(self):
r = convert_units("3 kWh")
self.assertApprox(r["magnitude"], 10_800_000)
self.assertIn("note", r)
def test_data_units(self):
self.assertApprox(convert_units("1 GiB", "MB")["magnitude"], 1073.741824)
def test_incompatible(self):
with self.assertRaisesRegex(MathError, "incompatible"):
convert_units("5 kg", "m")
def test_unknown_unit(self):
with self.assertRaisesRegex(MathError, "unknown"):
convert_units("5 flurbs", "m")