SPB Git
11.3 KB · 203 lines python
1"""Tests du chapitre 6 — démembrements et modalités du droit de propriété (DONNÉES SYNTHÉTIQUES, hypothèses déclarées).2Tolérances : 0,5 $ sur les montants arrondis cités dans le texte ; 1e-6 (relatif) sur les identités ; 0,05 point sur les3pourcentages cités ; valeurs exactes pour les droits de mutation (calcul en dollars et cents)."""4import sys, pathlib, math5import numpy as np, pytest6sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "cases"))7import ch06_demembrements as cas89TOL = 0.510V = cas.V_ARRONDI111213@pytest.fixture(scope="module")14def noi():15    return cas.rne_cas3()161718class TestMortalite:19    def test_survie_monotone_et_bornes(self):20        for x in (55, 65, 85):21            p = [cas.survie(x, t) for t in range(0, cas.OMEGA - x + 1)]22            assert p[0] == 1.0 and p[-1] == 0.023            assert all(a >= b for a, b in zip(p, p[1:]))2425    def test_esperances_citees(self):26        tm = cas.table_mortalite()27        assert tm.loc[65, "esperance_vie"] == pytest.approx(17.9, abs=0.05)28        assert tm.loc[55, "esperance_vie"] == pytest.approx(25.9, abs=0.05)29        assert tm.loc[75, "esperance_vie"] == pytest.approx(11.1, abs=0.05)30        assert tm.loc[85, "esperance_vie"] == pytest.approx(6.2, abs=0.05)31        assert tm.loc[65, "p10"] == pytest.approx(0.789, abs=5e-4) and tm.loc[65, "p20"] == pytest.approx(0.424, abs=5e-4)32        assert all(tm["esperance_vie"].diff().dropna() < 0)333435class TestUsufruit:36    def test_valeur_cas1_et_loyer(self):37        c = cas.valeur_cas1()38        assert c["prediction_hedonique"] == pytest.approx(637952.85, abs=0.01)39        assert round(c["prediction_hedonique"], -3) == V40        assert cas.loyer_net(V) == pytest.approx(22330.0, abs=1e-6)41        assert cas.loyer_net(V) / 12 == pytest.approx(1861, abs=0.5)4243    @pytest.mark.parametrize("n,U,NP,part", [(10, 183443, 454557, 71.2), (20, 314141, 323859, 50.8), (30, 407260, 230740, 36.2)])44    def test_terme_fixe(self, n, U, NP, part):45        u = cas.usufruit_terme(V, n)46        assert u["U"] == pytest.approx(U, abs=TOL) and u["NP"] == pytest.approx(NP, abs=TOL)47        assert u["NP"] == pytest.approx(u["NP_formule"], rel=1e-9)        # NP = V((1+g)/(1+r))^n48        assert u["U"] + u["NP"] == pytest.approx(V, rel=1e-12)49        assert u["part_NP"] * 100 == pytest.approx(part, abs=0.05)5051    @pytest.mark.parametrize("x,U,NP,part,ann,rente", [(55, 359836, 278164, 43.6, 16.114, 26300), (65, 280357, 357643, 56.1, 12.555, 25335),52                                                      (75, 197560, 440440, 69.0, 8.847, 24409), (85, 123863, 514137, 80.6, 5.547, 23599)])53    def test_viager(self, x, U, NP, part, ann, rente):54        u = cas.usufruit_viager(V, x)55        assert u["U"] == pytest.approx(U, abs=TOL) and u["NP"] == pytest.approx(NP, abs=TOL)56        assert u["NP_direct"] == pytest.approx(u["NP"], rel=1e-9)         # proposition : identité du partage viager57        assert u["part_NP"] * 100 == pytest.approx(part, abs=0.05)58        assert u["annuite_viagere"] == pytest.approx(ann, abs=5e-4)59        assert cas.rente_viagere_equivalente(V, x) == pytest.approx(rente, abs=TOL)6061    def test_identite_tous_ages_et_taux(self):62        for x in range(50, 100, 7):63            for r in (0.03, 0.05, 0.08):64                u = cas.usufruit_viager(V, x, r, 0.015)65                assert u["U"] + u["NP_direct"] == pytest.approx(V, rel=1e-9)6667    def test_approximation_terme_fixe_sous_estime_np(self):68        u = cas.usufruit_viager(V, 65)69        t = cas.usufruit_terme(V, 18)                                      # espérance de vie arrondie (17,9 → 18)70        assert t["part_NP"] * 100 == pytest.approx(54.3, abs=0.05)71        assert u["NP"] - t["NP"] == pytest.approx(11000, abs=600)          # « environ 11 000 $ »72        for x in (55, 65, 75, 85):                                         # Jensen : NP viager ≥ NP terme fixe e_x73            n = int(round(cas.esperance_vie(x)))74            assert cas.usufruit_viager(V, x)["NP"] >= cas.usufruit_terme(V, n)["NP"]7576    def test_grille_sensibilite(self):77        g = cas.grille_usufruit(V)78        attendu = {55: (54.4, 43.6, 35.4), 60: (59.8, 49.7, 41.6), 65: (65.4, 56.1, 48.4), 70: (71.0, 62.6, 55.6),79                   75: (76.3, 69.0, 62.8), 80: (81.2, 75.1, 69.7), 85: (85.5, 80.6, 76.1)}80        for age, vals in attendu.items():81            assert tuple(round(v * 100, 1) for v in g.loc[age]) == vals82        assert (0.654 - 0.484) * V == pytest.approx(108000, abs=600)83        assert all(g.diff().dropna().values.ravel() > 0)                  # NP/V croît avec l'âge84        assert all(g.diff(axis=1).dropna(axis=1).values.ravel() < 0)      # et décroît avec r858687class TestEmphyteose:88    def test_reference(self, noi):89        assert noi == pytest.approx(89955.75, abs=0.01)90        e = cas.emphyteose(noi, cas.RENTE_EMPH, cas.N_EMPH)91        assert e["V_pleine"] == pytest.approx(1999017, abs=TOL)92        assert e["V_emph"] == pytest.approx(1166242, abs=TOL) and e["part_emph"] * 100 == pytest.approx(58.3, abs=0.05)93        assert e["V_rentes"] == pytest.approx(388430, abs=TOL) and e["V_reprise"] == pytest.approx(444344, abs=TOL)94        assert e["V_prop"] == pytest.approx(832774, abs=TOL)95        assert e["somme"] == pytest.approx(e["V_pleine"], rel=1e-9)9697    def test_identite_toutes_durees(self, noi):98        for n in range(1, 101):99            e = cas.emphyteose(noi, cas.RENTE_EMPH, n)100            assert e["somme"] == pytest.approx(e["V_pleine"], rel=1e-9)101        g = cas.grille_emphyteose(noi, cas.RENTE_EMPH)102        assert all(g["V_emph"].diff().dropna() < 0)                       # décroît quand la durée restante baisse103104    def test_grille_citee(self, noi):105        g = cas.grille_emphyteose(noi, cas.RENTE_EMPH)106        attendu = {60: (1426059, 421175, 151782, 572958, 71.3), 50: (1351745, 414022, 233250, 647272, 67.6),107                   40: (1240623, 399951, 358443, 758394, 62.1), 20: (834713, 317820, 846483, 1164303, 41.8),108                   10: (487489, 210707, 1300820, 1511528, 24.4), 5: (263447, 123006, 1612564, 1735570, 13.2)}109        for n, (ve, vr, vp, vt, part) in attendu.items():110            assert g.loc[n, "V_emph"] == pytest.approx(ve, abs=TOL) and g.loc[n, "V_rentes"] == pytest.approx(vr, abs=TOL)111            assert g.loc[n, "V_reprise"] == pytest.approx(vp, abs=TOL) and g.loc[n, "V_prop"] == pytest.approx(vt, abs=TOL)112            assert g.loc[n, "part_emph"] * 100 == pytest.approx(part, abs=0.05)113114    def test_taux_distincts(self, noi):115        e = cas.emphyteose(noi, cas.RENTE_EMPH, cas.N_EMPH, r_prop=0.055)116        assert e["V_prop"] == pytest.approx(1190025, abs=TOL)117        assert e["somme"] == pytest.approx(2356268, abs=TOL)118        assert e["somme"] - e["V_pleine"] == pytest.approx(357251, abs=TOL)119120121class TestAutres:122    def test_indivision(self):123        assert cas.part_indivise(V, 0.5, 0.0)["valeur_part"] == pytest.approx(319000, abs=TOL)124        assert cas.part_indivise(V, 0.5, 0.10)["valeur_part"] == pytest.approx(287100, abs=TOL)125        assert cas.part_indivise(V, 0.5, 0.20)["valeur_part"] == pytest.approx(255200, abs=TOL)126127    def test_servitude(self):128        c = cas.valeur_cas1()129        assert c["elasticite_terrain"] == pytest.approx(0.0937, abs=5e-4)130        s = cas.servitude_terrain(V, c["terrain_m2"], 120, c["elasticite_terrain"])131        assert s["delta"] == pytest.approx(12725, abs=TOL) and s["delta_pct"] * 100 == pytest.approx(2.0, abs=0.05)132133    def test_rang(self):134        r = cas.rang_hypothecaire(560000, [455000, 90000, 40000])135        assert [x["recouvre"] for x in r] == [455000, 90000, 15000, 0]136        assert r[2]["taux_recouvrement"] == pytest.approx(0.375)137        assert sum(x["recouvre"] for x in r) == 560000138139    def test_mutation(self):140        m = cas.droit_mutation(V)141        assert [round(t["montant"], 2) for t in m["detail"]] == [314.50, 2521.00, 4845.00]142        assert m["total"] == pytest.approx(7680.50, abs=0.005)143        assert m["taux_effectif"] * 100 == pytest.approx(1.204, abs=0.0005)144        m2 = cas.droit_mutation(750000, taux_municipal=[(500000, 0.02)])145        assert m2["droit_base"] == pytest.approx(9360.50, abs=0.005) and m2["supplement_municipal"] == pytest.approx(1250.0, abs=0.005)146        assert cas.droit_mutation(62900)["total"] == pytest.approx(314.50, abs=0.005)147        assert cas.droit_mutation(0)["total"] == 0.0148149    def test_vice_et_registre(self):150        q = cas.quantum_vice(520000, 46000, 9000, 6500, False)151        assert q["reduction_prix"] == 37000 and q["total"] == 37000 and q["part_prix"] * 100 == pytest.approx(7.1, abs=0.05)152        assert cas.quantum_vice(520000, 46000, 9000, 6500, True)["total"] == 43500153        assert cas.budget_registre(5)["cout"] == 15.0154155156class TestExercices:157    """Chiffres des solutions (solutions/ch06.tex)."""158159    def test_ex1(self):160        assert 612000 - 6500 - 4000 == 601500161162    def test_ex3(self):163        p = cas.part_indivise(900000, 1 / 3, 0.12)164        assert p["valeur_proportionnelle"] == pytest.approx(300000, abs=1e-6) and p["valeur_part"] == pytest.approx(264000, abs=1e-6)165166    def test_ex4(self):167        paires = [(548000, 531000), (602000, 586500), (575000, 559000)]168        d = [a - b for a, b in paires]; rel = [(a - b) / a for a, b in paires]169        assert d == [17000, 15500, 16000] and np.mean(d) == pytest.approx(16166.67, abs=0.01)170        assert [round(x * 100, 2) for x in rel] == [3.10, 2.57, 2.78]171        assert np.mean(rel) * 100 == pytest.approx(2.82, abs=0.005)172        assert np.mean(rel) * 638000 == pytest.approx(17991, abs=TOL)173174    def test_ex5(self):175        assert cas.quantum_vice(520000, 46000, 9000, 6500, False)["prix_ajuste"] == 483000176177    def test_ex6(self):178        Vx, r, g, x = 455000, 0.045, 0.01, 72179        assert cas.loyer_net(Vx, r, g) == pytest.approx(15925.0, abs=1e-6)180        u = cas.usufruit_viager(Vx, x, r, g)181        assert u["U"] == pytest.approx(158934, abs=TOL) and u["NP"] == pytest.approx(296066, abs=TOL)182        assert u["part_NP"] * 100 == pytest.approx(65.1, abs=0.05) and u["esperance_vie"] == pytest.approx(13.0, abs=0.05)183        t = cas.usufruit_terme(Vx, 13, r, g)184        assert t["U"] == pytest.approx(162802, abs=TOL) and t["NP"] == pytest.approx(292198, abs=TOL)185        assert u["NP"] - t["NP"] == pytest.approx(3868, abs=TOL)186        assert cas.rente_viagere_equivalente(Vx, x, r, g) == pytest.approx(17038, abs=TOL)187        t30 = cas.usufruit_terme(Vx, 30, r, g)188        assert t30["U"] == pytest.approx(291257, abs=TOL) and t30["NP"] == pytest.approx(163743, abs=TOL)189190    def test_ex7(self):191        e = cas.emphyteose(142000, 24000, 28, 0.07, 0.02)192        assert e["V_pleine"] == pytest.approx(2840000, abs=1e-6)193        assert e["V_emph"] == pytest.approx(1805044, abs=TOL) and e["V_rentes"] == pytest.approx(291291, abs=TOL)194        assert e["V_reprise"] == pytest.approx(743665, abs=TOL) and e["V_prop"] == pytest.approx(1034956, abs=TOL)195        assert e["somme"] == pytest.approx(2840000, rel=1e-9)196        e2 = cas.emphyteose(142000, 24000, 68, 0.07, 0.02)197        assert e2["V_emph"] == pytest.approx(2390930, abs=TOL) and e2["V_prop"] == pytest.approx(449070, abs=TOL)198        m = cas.droit_mutation(e["V_emph"])199        assert m["total"] == pytest.approx(314.50 + 2521.00 + 0.015 * (e["V_emph"] - 315000), abs=0.01)200        assert m["total"] == pytest.approx(25186.16, abs=0.01)201        e3 = cas.emphyteose(142000, 24000, 28, 0.07, 0.02, r_prop=0.055)202        assert e3["V_prop"] == pytest.approx(1443131, abs=TOL) and e3["somme"] == pytest.approx(3248175, abs=TOL)203
Files · cb0963bad540f93d1e0e011172cab614d30348ad
Menu

Theme