PocketAccountant / tests /test_engine.py
eldinosaur's picture
PocketAccountant: custom ledger UI + deterministic agent (engine, ledger, retrieval, classifier)
c55ab5e verified
Raw
History Blame Contribute Delete
5.82 kB
"""Gold-case tests for the deterministic engine.
Each expected value is computed by hand in the docstring so a reviewer can audit
the math without trusting the code. If a tax table changes, these break loudly —
exactly what we want for a financial product.
Run from the project root: python -m unittest discover -s tests
"""
import unittest
from decimal import Decimal
from src.engine import (
break_even_units,
cash_runway_months,
current_ratio,
federal_income_tax,
isr_provisional_monthly,
iva_monthly,
iva_on_amount,
profit_margin,
quarterly_estimated_tax,
resico_eligible,
resico_isr_monthly,
retenciones_servicios_profesionales,
schedule_c_net_profit,
self_employment_tax,
taxable_base,
)
def dec(s):
return Decimal(s)
class TestResico(unittest.TestCase):
def test_first_bracket(self):
# $20,000 ≤ $25,000 → 1.00% → $200.00
self.assertEqual(resico_isr_monthly(20000).amount, dec("200.00"))
def test_second_bracket(self):
# $40,000 ≤ $50,000 → 1.10% → $440.00
self.assertEqual(resico_isr_monthly(40000).amount, dec("440.00"))
def test_fourth_bracket(self):
# $100,000 ≤ $208,333.33 → 2.00% → $2,000.00
self.assertEqual(resico_isr_monthly(100000).amount, dec("2000.00"))
def test_zero_income(self):
self.assertEqual(resico_isr_monthly(0).amount, dec("0.00"))
def test_eligibility_cap(self):
self.assertTrue(resico_eligible(3500000))
self.assertFalse(resico_eligible(3500001))
class TestIsrGeneral(unittest.TestCase):
def test_base_20000(self):
# Base 20,000 → bracket [15,487.72–31,236.49], cuota 1,640.18, 21.36%
# excess = 4,512.28 ; 4,512.28 * 0.2136 = 963.823008
# tax = 1,640.18 + 963.823008 = 2,604.003008 → 2,604.00
self.assertEqual(isr_provisional_monthly(20000).amount, dec("2604.00"))
def test_first_bracket(self):
# Base 500 → bracket [0.01–746.04], 1.92% → 500 * 0.0192 = 9.60
self.assertEqual(isr_provisional_monthly(500).amount, dec("9.60"))
def test_zero_and_negative(self):
self.assertEqual(isr_provisional_monthly(0).amount, dec("0.00"))
self.assertEqual(isr_provisional_monthly(-100).amount, dec("0.00"))
def test_taxable_base_floor(self):
self.assertEqual(taxable_base(30000, 12000), dec("18000"))
self.assertEqual(taxable_base(10000, 12000), dec("0"))
class TestRetenciones(unittest.TestCase):
def test_professional_services(self):
# $10,000 → ISR 10% = 1,000 ; IVA 10.6667% = 1,066.67 ; total 2,066.67
r = retenciones_servicios_profesionales(10000)
self.assertEqual(r.amount, dec("2066.67"))
class TestIva(unittest.TestCase):
def test_iva_on_amount(self):
self.assertEqual(iva_on_amount(1000).amount, dec("160.00"))
def test_monthly_payable(self):
# 1,600 collected − 600 paid → 1,000 a cargo
self.assertEqual(iva_monthly(1600, 600).amount, dec("1000.00"))
def test_monthly_credit(self):
# 600 collected − 1,000 paid → −400 saldo a favor
r = iva_monthly(600, 1000)
self.assertEqual(r.amount, dec("-400.00"))
self.assertIn("favor", r.label.lower())
def test_withholdings_reduce_payable(self):
# 1,600 − 600 − 200 retained → 800
self.assertEqual(iva_monthly(1600, 600, 200).amount, dec("800.00"))
class TestRatios(unittest.TestCase):
def test_current_ratio(self):
self.assertEqual(current_ratio(150000, 100000).amount, dec("1.50"))
def test_current_ratio_no_liabilities(self):
self.assertEqual(current_ratio(150000, 0).amount, dec("0"))
def test_profit_margin(self):
self.assertEqual(profit_margin(20000, 100000).amount, dec("0.2000"))
def test_break_even(self):
# FC 10,000 / (100 − 60) = 250 units
self.assertEqual(break_even_units(10000, 100, 60).amount, dec("250.00"))
def test_break_even_impossible(self):
self.assertEqual(break_even_units(10000, 50, 60).amount, dec("0"))
def test_runway(self):
# 90,000 cash / 30,000 burn = 3.0 months
self.assertEqual(cash_runway_months(90000, 30000).amount, dec("3.0"))
class TestUsTax(unittest.TestCase):
def test_schedule_c(self):
self.assertEqual(schedule_c_net_profit(100000, 40000).amount, dec("60000.00"))
def test_self_employment_tax(self):
# 60,000 net → 55,410 net earnings
# SS 55,410 * 0.124 = 6,870.84 ; Medicare 55,410 * 0.029 = 1,606.89
# total = 8,477.73
self.assertEqual(self_employment_tax(60000).amount, dec("8477.73"))
def test_se_tax_below_minimum(self):
self.assertEqual(self_employment_tax(400).amount, dec("0.00"))
def test_federal_income_tax(self):
# 50,000 → bracket [47,150–100,525], fixed 5,426, 22%
# excess 2,850 * 0.22 = 627 ; tax = 6,053.00
self.assertEqual(federal_income_tax(50000).amount, dec("6053.00"))
def test_quarterly_estimate(self):
# (6,053 + 8,477.73) / 4 = 14,530.73 / 4 = 3,632.6825 → 3,632.68
r = quarterly_estimated_tax(dec("6053"), dec("8477.73"))
self.assertEqual(r.amount, dec("3632.68"))
class TestProvenance(unittest.TestCase):
"""Every result must carry its source — no number without a basis."""
def test_results_have_breakdown(self):
for r in [
resico_isr_monthly(20000),
isr_provisional_monthly(20000),
iva_monthly(1600, 600),
self_employment_tax(60000),
]:
self.assertTrue(r.breakdown, f"{r.label} has no breakdown")
self.assertIsNotNone(r.source, f"{r.label} has no source")
if __name__ == "__main__":
unittest.main()