Initial extraction from monorepo
This commit is contained in:
commit
f7ef7ca4ab
56 changed files with 6163 additions and 0 deletions
70
tests/test_tax_base.py
Normal file
70
tests/test_tax_base.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
"""Bracket-arithmetic and breakdown invariants."""
|
||||
from decimal import Decimal
|
||||
|
||||
from hypothesis import given
|
||||
from hypothesis import strategies as st
|
||||
|
||||
from fire_planner.tax.base import TaxBreakdown, TaxInputs, apply_brackets
|
||||
|
||||
|
||||
def test_apply_brackets_zero_input() -> None:
|
||||
assert apply_brackets(Decimal("0"), [(Decimal("100"), Decimal("0.2"))]) == Decimal("0")
|
||||
|
||||
|
||||
def test_apply_brackets_negative_input() -> None:
|
||||
# Negative income shouldn't generate a refund — clamp to zero.
|
||||
assert apply_brackets(Decimal("-1000"), [(Decimal("100"), Decimal("0.2"))]) == Decimal("0")
|
||||
|
||||
|
||||
def test_apply_brackets_within_first_band() -> None:
|
||||
brackets = [(Decimal("100"), Decimal("0.2")), (Decimal("Infinity"), Decimal("0.4"))]
|
||||
assert apply_brackets(Decimal("50"), brackets) == Decimal("10")
|
||||
|
||||
|
||||
def test_apply_brackets_spans_two_bands() -> None:
|
||||
# 100 @ 20% = 20; next 50 @ 40% = 20 → total 40
|
||||
brackets = [(Decimal("100"), Decimal("0.2")), (Decimal("Infinity"), Decimal("0.4"))]
|
||||
assert apply_brackets(Decimal("150"), brackets) == Decimal("40")
|
||||
|
||||
|
||||
def test_apply_brackets_uk_paye_2026_smoke() -> None:
|
||||
# Taxable income £80,000 (gross £92,570 less £12,570 PA):
|
||||
# £37,700 @ 20% = £7,540
|
||||
# £42,300 @ 40% = £16,920
|
||||
# total = £24,460
|
||||
brackets = [
|
||||
(Decimal("37700"), Decimal("0.20")),
|
||||
(Decimal("112570"), Decimal("0.40")),
|
||||
(Decimal("Infinity"), Decimal("0.45")),
|
||||
]
|
||||
assert apply_brackets(Decimal("80000"), brackets) == Decimal("24460")
|
||||
|
||||
|
||||
@given(amount=st.decimals(min_value=0, max_value=10_000_000, allow_nan=False, allow_infinity=False))
|
||||
def test_apply_brackets_monotone_in_amount(amount: Decimal) -> None:
|
||||
"""More taxable income → never less tax."""
|
||||
brackets = [
|
||||
(Decimal("37700"), Decimal("0.20")),
|
||||
(Decimal("112570"), Decimal("0.40")),
|
||||
(Decimal("Infinity"), Decimal("0.45")),
|
||||
]
|
||||
extra = Decimal("100")
|
||||
assert apply_brackets(amount + extra, brackets) >= apply_brackets(amount, brackets)
|
||||
|
||||
|
||||
def test_breakdown_total_is_sum_of_components() -> None:
|
||||
b = TaxBreakdown(
|
||||
income_tax=Decimal("10000"),
|
||||
national_insurance=Decimal("3000"),
|
||||
capital_gains_tax=Decimal("500"),
|
||||
dividend_tax=Decimal("200"),
|
||||
healthcare_levy=Decimal("100"),
|
||||
other=Decimal("50"),
|
||||
)
|
||||
assert b.total == Decimal("13850")
|
||||
|
||||
|
||||
def test_inputs_default_to_zero() -> None:
|
||||
i = TaxInputs()
|
||||
assert i.earned_income == Decimal("0")
|
||||
assert i.years_since_uk_departure == 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue