SPB Git
11.6 KB · 207 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        a = cas.approximation_terme_espere(V, 65)70        assert a["n_eff"] == pytest.approx(18.36, abs=0.005) and a["n_eff"] == pytest.approx(u["esperance_vie"] + 0.5, abs=1e-9)71        assert a["part_NP"] * 100 == pytest.approx(53.7, abs=0.05)72        assert u["NP"] - a["NP"] == pytest.approx(15271, abs=TOL)73        for x in range(50, 100, 5):                                        # Jensen : NP viager ≥ NP du terme espéré74            for r in (0.03, 0.05, 0.08):75                assert cas.usufruit_viager(V, x, r)["NP"] >= cas.approximation_terme_espere(V, x, r)["NP"]7677    def test_grille_sensibilite(self):78        g = cas.grille_usufruit(V)79        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),80                   75: (76.3, 69.0, 62.8), 80: (81.2, 75.1, 69.7), 85: (85.5, 80.6, 76.1)}81        for age, vals in attendu.items():82            assert tuple(round(v * 100, 1) for v in g.loc[age]) == vals83        assert (0.654 - 0.484) * V == pytest.approx(108000, abs=600)84        assert all(g.diff().dropna().values.ravel() > 0)                  # NP/V croît avec l'âge85        assert all(g.diff(axis=1).dropna(axis=1).values.ravel() < 0)      # et décroît avec r868788class TestEmphyteose:89    def test_reference(self, noi):90        assert noi == pytest.approx(89955.75, abs=0.01)91        e = cas.emphyteose(noi, cas.RENTE_EMPH, cas.N_EMPH)92        assert e["V_pleine"] == pytest.approx(1999017, abs=TOL)93        assert e["V_emph"] == pytest.approx(1166242, abs=TOL) and e["part_emph"] * 100 == pytest.approx(58.3, abs=0.05)94        assert e["V_rentes"] == pytest.approx(388430, abs=TOL) and e["V_reprise"] == pytest.approx(444344, abs=TOL)95        assert e["V_prop"] == pytest.approx(832774, abs=TOL)96        assert e["somme"] == pytest.approx(e["V_pleine"], rel=1e-9)9798    def test_identite_toutes_durees(self, noi):99        for n in range(1, 101):100            e = cas.emphyteose(noi, cas.RENTE_EMPH, n)101            assert e["somme"] == pytest.approx(e["V_pleine"], rel=1e-9)102        g = cas.grille_emphyteose(noi, cas.RENTE_EMPH)103        assert all(g["V_emph"].diff().dropna() < 0)                       # décroît quand la durée restante baisse104105    def test_grille_citee(self, noi):106        g = cas.grille_emphyteose(noi, cas.RENTE_EMPH)107        attendu = {60: (1426059, 421175, 151782, 572958, 71.3), 50: (1351745, 414022, 233250, 647272, 67.6),108                   40: (1240623, 399951, 358443, 758394, 62.1), 20: (834713, 317820, 846483, 1164303, 41.8),109                   10: (487489, 210707, 1300820, 1511528, 24.4), 5: (263447, 123006, 1612564, 1735570, 13.2)}110        for n, (ve, vr, vp, vt, part) in attendu.items():111            assert g.loc[n, "V_emph"] == pytest.approx(ve, abs=TOL) and g.loc[n, "V_rentes"] == pytest.approx(vr, abs=TOL)112            assert g.loc[n, "V_reprise"] == pytest.approx(vp, abs=TOL) and g.loc[n, "V_prop"] == pytest.approx(vt, abs=TOL)113            assert g.loc[n, "part_emph"] * 100 == pytest.approx(part, abs=0.05)114115    def test_taux_distincts(self, noi):116        e = cas.emphyteose(noi, cas.RENTE_EMPH, cas.N_EMPH, r_prop=0.055)117        assert e["V_prop"] == pytest.approx(1190025, abs=TOL)118        assert e["somme"] == pytest.approx(2356268, abs=TOL)119        assert e["somme"] - e["V_pleine"] == pytest.approx(357251, abs=TOL)120121122class TestAutres:123    def test_indivision(self):124        assert cas.part_indivise(V, 0.5, 0.0)["valeur_part"] == pytest.approx(319000, abs=TOL)125        assert cas.part_indivise(V, 0.5, 0.10)["valeur_part"] == pytest.approx(287100, abs=TOL)126        assert cas.part_indivise(V, 0.5, 0.20)["valeur_part"] == pytest.approx(255200, abs=TOL)127128    def test_servitude(self):129        c = cas.valeur_cas1()130        assert c["elasticite_terrain"] == pytest.approx(0.0937, abs=5e-4)131        s = cas.servitude_terrain(V, c["terrain_m2"], 120, c["elasticite_terrain"])132        assert s["delta"] == pytest.approx(12725, abs=TOL) and s["delta_pct"] * 100 == pytest.approx(2.0, abs=0.05)133134    def test_rang(self):135        r = cas.rang_hypothecaire(560000, [455000, 90000, 40000])136        assert [x["recouvre"] for x in r] == [455000, 90000, 15000, 0]137        assert r[2]["taux_recouvrement"] == pytest.approx(0.375)138        assert sum(x["recouvre"] for x in r) == 560000139140    def test_mutation(self):141        m = cas.droit_mutation(V)142        assert [round(t["montant"], 2) for t in m["detail"]] == [314.50, 2521.00, 4845.00]143        assert m["total"] == pytest.approx(7680.50, abs=0.005)144        assert m["taux_effectif"] * 100 == pytest.approx(1.204, abs=0.0005)145        m2 = cas.droit_mutation(750000, taux_municipal=[(500000, 0.02)])146        assert m2["droit_base"] == pytest.approx(9360.50, abs=0.005) and m2["supplement_municipal"] == pytest.approx(1250.0, abs=0.005)147        assert cas.droit_mutation(62900)["total"] == pytest.approx(314.50, abs=0.005)148        assert cas.droit_mutation(0)["total"] == 0.0149150    def test_vice_et_registre(self):151        q = cas.quantum_vice(520000, 46000, 9000, 6500, False)152        assert q["reduction_prix"] == 37000 and q["total"] == 37000 and q["part_prix"] * 100 == pytest.approx(7.1, abs=0.05)153        assert cas.quantum_vice(520000, 46000, 9000, 6500, True)["total"] == 43500154        assert cas.budget_registre(5)["cout"] == 15.0155156157class TestExercices:158    """Chiffres des solutions (solutions/ch06.tex)."""159160    def test_ex1(self):161        assert 612000 - 6500 - 4000 == 601500162163    def test_ex3(self):164        p = cas.part_indivise(900000, 1 / 3, 0.12)165        assert p["valeur_proportionnelle"] == pytest.approx(300000, abs=1e-6) and p["valeur_part"] == pytest.approx(264000, abs=1e-6)166167    def test_ex4(self):168        paires = [(548000, 531000), (602000, 586500), (575000, 559000)]169        d = [a - b for a, b in paires]; rel = [(a - b) / a for a, b in paires]170        assert d == [17000, 15500, 16000] and np.mean(d) == pytest.approx(16166.67, abs=0.01)171        assert [round(x * 100, 2) for x in rel] == [3.10, 2.57, 2.78]172        assert np.mean(rel) * 100 == pytest.approx(2.82, abs=0.005)173        assert np.mean(rel) * 638000 == pytest.approx(17991, abs=TOL)174175    def test_ex5(self):176        assert cas.quantum_vice(520000, 46000, 9000, 6500, False)["prix_ajuste"] == 483000177178    def test_ex6(self):179        Vx, r, g, x = 455000, 0.045, 0.01, 72180        assert cas.loyer_net(Vx, r, g) == pytest.approx(15925.0, abs=1e-6)181        u = cas.usufruit_viager(Vx, x, r, g)182        assert u["U"] == pytest.approx(158934, abs=TOL) and u["NP"] == pytest.approx(296066, abs=TOL)183        assert u["part_NP"] * 100 == pytest.approx(65.1, abs=0.05) and u["esperance_vie"] == pytest.approx(13.0, abs=0.05)184        a = cas.approximation_terme_espere(Vx, x, r, g)185        assert a["n_eff"] == pytest.approx(13.49, abs=0.005)186        assert a["U"] == pytest.approx(167650, abs=TOL) and a["NP"] == pytest.approx(287350, abs=TOL)187        assert a["part_NP"] * 100 == pytest.approx(63.2, abs=0.05) and u["NP"] - a["NP"] == pytest.approx(8716, abs=TOL)188        t = cas.usufruit_terme(Vx, 13, r, g)189        assert t["NP"] == pytest.approx(292198, abs=TOL)190        assert cas.rente_viagere_equivalente(Vx, x, r, g) == pytest.approx(17038, abs=TOL)191        t30 = cas.usufruit_terme(Vx, 30, r, g)192        assert t30["U"] == pytest.approx(291257, abs=TOL) and t30["NP"] == pytest.approx(163743, abs=TOL)193194    def test_ex7(self):195        e = cas.emphyteose(142000, 24000, 28, 0.07, 0.02)196        assert e["V_pleine"] == pytest.approx(2840000, abs=1e-6)197        assert e["V_emph"] == pytest.approx(1805044, abs=TOL) and e["V_rentes"] == pytest.approx(291291, abs=TOL)198        assert e["V_reprise"] == pytest.approx(743665, abs=TOL) and e["V_prop"] == pytest.approx(1034956, abs=TOL)199        assert e["somme"] == pytest.approx(2840000, rel=1e-9)200        e2 = cas.emphyteose(142000, 24000, 68, 0.07, 0.02)201        assert e2["V_emph"] == pytest.approx(2390930, abs=TOL) and e2["V_prop"] == pytest.approx(449070, abs=TOL)202        m = cas.droit_mutation(e["V_emph"])203        assert m["total"] == pytest.approx(314.50 + 2521.00 + 0.015 * (e["V_emph"] - 315000), abs=0.01)204        assert m["total"] == pytest.approx(25186.16, abs=0.01)205        e3 = cas.emphyteose(142000, 24000, 28, 0.07, 0.02, r_prop=0.055)206        assert e3["V_prop"] == pytest.approx(1443131, abs=TOL) and e3["somme"] == pytest.approx(3248175, abs=TOL)207
Files · bc6e342882c88717d8bf4f61abdc43c1df67af90
Menu

Theme