PocketAccountant: custom ledger UI + deterministic agent (engine, ledger, retrieval, classifier)
c55ab5e verified | """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() | |