Initial extraction from monorepo
This commit is contained in:
commit
f7ef7ca4ab
56 changed files with 6163 additions and 0 deletions
113
tests/test_scenarios.py
Normal file
113
tests/test_scenarios.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
"""Cartesian scenario builder + strategy/regime factory."""
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
|
||||
from fire_planner.scenarios import (
|
||||
DEFAULT_GLIDES,
|
||||
DEFAULT_JURISDICTIONS,
|
||||
DEFAULT_LEAVE_YEARS,
|
||||
DEFAULT_STRATEGIES,
|
||||
ScenarioSpec,
|
||||
build_regime_schedule,
|
||||
build_strategy,
|
||||
cartesian_scenarios,
|
||||
)
|
||||
from fire_planner.strategies.guyton_klinger import GuytonKlingerStrategy
|
||||
from fire_planner.strategies.trinity import TrinityStrategy
|
||||
from fire_planner.strategies.vpw import VpwStrategy, VpwWithFloorStrategy
|
||||
from fire_planner.tax.bulgaria import BulgariaTaxRegime
|
||||
from fire_planner.tax.cyprus import CyprusTaxRegime
|
||||
from fire_planner.tax.uae import UaeTaxRegime
|
||||
from fire_planner.tax.uk import UkTaxRegime
|
||||
|
||||
|
||||
def test_default_cartesian_count_is_120() -> None:
|
||||
specs = cartesian_scenarios(spending_gbp=Decimal("100000"), nw_seed_gbp=Decimal("1000000"))
|
||||
expected = (len(DEFAULT_JURISDICTIONS) * len(DEFAULT_STRATEGIES) * len(DEFAULT_LEAVE_YEARS) *
|
||||
len(DEFAULT_GLIDES))
|
||||
assert expected == 120
|
||||
assert len(specs) == 120
|
||||
|
||||
|
||||
def test_external_id_format() -> None:
|
||||
spec = ScenarioSpec(
|
||||
jurisdiction="cyprus",
|
||||
strategy="vpw",
|
||||
leave_uk_year=3,
|
||||
glide_path="rising",
|
||||
spending_gbp=Decimal("100000"),
|
||||
nw_seed_gbp=Decimal("1000000"),
|
||||
)
|
||||
assert spec.external_id == "cyprus-vpw-leave-y3-glide-rising"
|
||||
|
||||
|
||||
def test_cartesian_unique_external_ids() -> None:
|
||||
specs = cartesian_scenarios(spending_gbp=Decimal("100000"), nw_seed_gbp=Decimal("1000000"))
|
||||
ids = [s.external_id for s in specs]
|
||||
assert len(ids) == len(set(ids))
|
||||
|
||||
|
||||
def test_build_strategy_dispatch() -> None:
|
||||
assert isinstance(build_strategy("trinity"), TrinityStrategy)
|
||||
assert isinstance(build_strategy("guyton_klinger"), GuytonKlingerStrategy)
|
||||
assert isinstance(build_strategy("vpw"), VpwStrategy)
|
||||
|
||||
|
||||
def test_build_strategy_vpw_floor_requires_floor() -> None:
|
||||
s = build_strategy("vpw_floor", floor=40_000.0)
|
||||
assert isinstance(s, VpwWithFloorStrategy)
|
||||
assert s.floor == 40_000.0
|
||||
|
||||
|
||||
def test_build_strategy_vpw_floor_missing_floor_raises() -> None:
|
||||
with pytest.raises(ValueError):
|
||||
build_strategy("vpw_floor")
|
||||
|
||||
|
||||
def test_build_strategy_unknown_raises() -> None:
|
||||
with pytest.raises(KeyError):
|
||||
build_strategy("walmart")
|
||||
|
||||
|
||||
def test_build_regime_schedule_uae() -> None:
|
||||
fn = build_regime_schedule("uae", leave_uk_year=2)
|
||||
assert isinstance(fn(0), UkTaxRegime)
|
||||
assert isinstance(fn(1), UkTaxRegime)
|
||||
assert isinstance(fn(2), UaeTaxRegime)
|
||||
assert isinstance(fn(50), UaeTaxRegime)
|
||||
|
||||
|
||||
def test_build_regime_schedule_uk_constant() -> None:
|
||||
fn = build_regime_schedule("uk", leave_uk_year=3)
|
||||
# All years should resolve to UK
|
||||
assert isinstance(fn(0), UkTaxRegime)
|
||||
assert isinstance(fn(50), UkTaxRegime)
|
||||
|
||||
|
||||
def test_build_regime_schedule_cyprus_switches_at_leave_year() -> None:
|
||||
fn = build_regime_schedule("cyprus", leave_uk_year=3)
|
||||
assert isinstance(fn(0), UkTaxRegime)
|
||||
assert isinstance(fn(2), UkTaxRegime)
|
||||
assert isinstance(fn(3), CyprusTaxRegime)
|
||||
assert isinstance(fn(50), CyprusTaxRegime)
|
||||
|
||||
|
||||
def test_build_regime_schedule_bulgaria() -> None:
|
||||
fn = build_regime_schedule("bulgaria", leave_uk_year=1)
|
||||
assert isinstance(fn(0), UkTaxRegime)
|
||||
assert isinstance(fn(1), BulgariaTaxRegime)
|
||||
|
||||
|
||||
def test_build_regime_schedule_unknown_raises() -> None:
|
||||
with pytest.raises(KeyError):
|
||||
build_regime_schedule("madeupistan", leave_uk_year=3)
|
||||
|
||||
|
||||
def test_cartesian_unknown_glide_raises() -> None:
|
||||
with pytest.raises(KeyError):
|
||||
cartesian_scenarios(
|
||||
spending_gbp=Decimal("100000"),
|
||||
nw_seed_gbp=Decimal("1000000"),
|
||||
glides=("staircase", ),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue