Immo-Ka — agrégateur des propriétés à vendre au Québec (73 connecteurs, ~40 000 annonces, React+FastAPI)
Python 47.5%
HTML 27.9%
TypeScript 15.5%
CSS 7.2%
JavaScript 2%
1# -----------------------------------------------------------------------------2# Immo-Ka — Agrégateur de maisons à vendre (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# tests/test_mortgage_cmhc.py : assurance prêt hypothécaire (SCHL) — mise de5# fonds minimale, barème de primes, admissibilité, TVQ sur la prime.6# -----------------------------------------------------------------------------7import unittest89from immoka.mortgage import cmhc101112class TestMinDownPayment(unittest.TestCase):13 def test_tiers(self):14 self.assertEqual(cmhc.min_down_payment(400_000), 20_000) # 5 %15 self.assertEqual(cmhc.min_down_payment(500_000), 25_000)16 self.assertEqual(cmhc.min_down_payment(600_000), 35_000) # 25k + 10k17 self.assertEqual(cmhc.min_down_payment(1_000_000), 75_000)18 self.assertEqual(cmhc.min_down_payment(1_500_000), 300_000) # 20 %19 self.assertEqual(cmhc.min_down_payment(2_000_000), 400_000)2021 def test_zero(self):22 self.assertEqual(cmhc.min_down_payment(0), 0.0)232425class TestPremiumRate(unittest.TestCase):26 def test_bands(self):27 self.assertEqual(cmhc.premium_rate(0.65), 0.0060)28 self.assertEqual(cmhc.premium_rate(0.80), 0.0240)29 self.assertEqual(cmhc.premium_rate(0.90), 0.0310)30 self.assertEqual(cmhc.premium_rate(0.95), 0.0400)31 self.assertIsNone(cmhc.premium_rate(0.96)) # > 95 % : non assurable3233 def test_30y_surcharge(self):34 self.assertAlmostEqual(cmhc.premium_rate(0.95, amort_years=30), 0.0420)353637class TestInsuranceQuote(unittest.TestCase):38 def test_insured_600k_40k_down(self):39 # prêt 560 k$, RPV 93,3 % → prime 4 % = 22 400 $, TVQ 9,975 %40 q = cmhc.insurance_quote(600_000, 40_000)41 self.assertTrue(q["required"] and q["eligible"])42 self.assertEqual(q["premium"], 22_400)43 self.assertEqual(q["total_mortgage"], 582_400)44 self.assertEqual(q["qc_tax"], round(22_400 * 0.09975, 2))45 self.assertEqual(q["premium_rate"], 4.0)4647 def test_uninsured_20_pct_down(self):48 q = cmhc.insurance_quote(500_000, 100_000)49 self.assertFalse(q["required"])50 self.assertEqual(q["premium"], 0.0)51 self.assertEqual(q["total_mortgage"], 400_000)5253 def test_over_max_price_not_eligible(self):54 q = cmhc.insurance_quote(1_600_000, 200_000)55 self.assertTrue(q["required"])56 self.assertFalse(q["eligible"])57 self.assertEqual(q["premium"], 0.0)58 self.assertTrue(any("1,5 M$" in i for i in q["issues"]))5960 def test_below_min_down_not_eligible(self):61 q = cmhc.insurance_quote(600_000, 20_000) # min légal = 35 000 $62 self.assertFalse(q["eligible"])63 self.assertTrue(any("minimum légal" in i for i in q["issues"]))6465 def test_insured_30y_flagged(self):66 q = cmhc.insurance_quote(400_000, 40_000, amort_years=30)67 self.assertTrue(q["eligible"])68 self.assertTrue(any("premier acheteur" in i for i in q["issues"]))69 # surprime 0,20 % appliquée (RPV 90 % : 3,10 + 0,20 = 3,30 %)70 self.assertEqual(q["premium_rate"], 3.30)7172 def test_insured_over_30y_refused(self):73 q = cmhc.insurance_quote(400_000, 40_000, amort_years=35)74 self.assertFalse(q["eligible"])7576 def test_invalid_params(self):77 q = cmhc.insurance_quote(0, 0)78 self.assertFalse(q["eligible"])79 self.assertIn("paramètres invalides", q["issues"])808182if __name__ == "__main__":83 unittest.main()84