test(req-001): tighten AC coverage and remove markdown trailing whitespace
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
co-authored by
genichin
parent
64975033e6
commit
7aa3de524a
@@ -6,6 +6,7 @@ import os
|
||||
import time
|
||||
from contextlib import ExitStack
|
||||
from datetime import UTC, datetime
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -71,6 +72,7 @@ class _FakeRepo:
|
||||
self.principal = principal or _token_principal()
|
||||
self.entries: list[LedgerEntry] = []
|
||||
self._next_id = 1
|
||||
self._dividend_amounts: dict[int, Decimal] = {}
|
||||
|
||||
def close(self) -> None:
|
||||
pass
|
||||
@@ -86,7 +88,9 @@ class _FakeRepo:
|
||||
def record_manual_ledger(self, portfolio_id: str, **kwargs: Any) -> LedgerEntry:
|
||||
self.get(portfolio_id)
|
||||
action = kwargs["action"]
|
||||
amount = float(kwargs.get("amount") or 0.0)
|
||||
amount_raw = kwargs.get("amount")
|
||||
amount_decimal = Decimal(str(amount_raw if amount_raw is not None else 0))
|
||||
amount = float(amount_decimal)
|
||||
quantity = float(kwargs.get("quantity") or 0.0)
|
||||
price = float(kwargs.get("price") or 0.0)
|
||||
fee = float(kwargs.get("fee") or 0.0)
|
||||
@@ -141,7 +145,7 @@ class _FakeRepo:
|
||||
if e.action == "DIVIDEND"
|
||||
and e.ledger_entry_id not in reversed_ids
|
||||
and e.executed_at == executed_at
|
||||
and abs(float(e.price) - amount) < 1e-9
|
||||
and self._dividend_amounts.get(e.ledger_entry_id, Decimal(str(e.price))) == amount_decimal
|
||||
and e.note == note
|
||||
),
|
||||
None,
|
||||
@@ -211,6 +215,8 @@ class _FakeRepo:
|
||||
)
|
||||
self._next_id += 1
|
||||
self.entries.append(entry)
|
||||
if action == "DIVIDEND":
|
||||
self._dividend_amounts[entry.ledger_entry_id] = amount_decimal
|
||||
return entry
|
||||
|
||||
def list_manual_ledger_entries(self, portfolio_id: str, limit: int = 50) -> list[LedgerEntry]:
|
||||
@@ -576,6 +582,42 @@ def test_dividend_requires_executed_at_and_rejects_fee_field() -> None:
|
||||
assert invalid_fee.status_code == 422
|
||||
|
||||
|
||||
def test_dividend_rejects_invalid_amount_tax_and_unrelated_fields_without_state_change() -> None:
|
||||
repo = _FakeRepo(_portfolio(cash=1000, quantity=10, price=10, buffer=500))
|
||||
client = _make_client(repo)
|
||||
baseline = (
|
||||
repo.portfolio.cash_balance,
|
||||
repo.portfolio.asset_quantity,
|
||||
repo.portfolio.profit_buffer,
|
||||
len(repo.entries),
|
||||
)
|
||||
|
||||
invalid_payloads = [
|
||||
{"action": "DIVIDEND", "amount": 0, "executed_at": "2026-09-01"},
|
||||
{"action": "DIVIDEND", "amount": -1, "executed_at": "2026-09-01"},
|
||||
{"action": "DIVIDEND", "amount": 1, "tax": -1, "executed_at": "2026-09-01"},
|
||||
{"action": "DIVIDEND", "amount": 1, "tax": "0.000000001", "executed_at": "2026-09-01"},
|
||||
{"action": "DIVIDEND", "amount": 1, "tax": "1000000000000.00000000", "executed_at": "2026-09-01"},
|
||||
{"action": "DIVIDEND", "amount": 1, "executed_at": "2026-09-01", "quantity": 1},
|
||||
{"action": "DIVIDEND", "amount": 1, "executed_at": "2026-09-01", "price": 1},
|
||||
{"action": "DIVIDEND", "amount": 1, "executed_at": "2026-09-01", "target_ledger_entry_id": 1},
|
||||
]
|
||||
|
||||
for payload in invalid_payloads:
|
||||
resp = client.post(
|
||||
f"/v1/portfolios/{_PORTFOLIO_ID}/ledger/manual",
|
||||
json=payload,
|
||||
headers=_auth(),
|
||||
)
|
||||
assert resp.status_code == 422
|
||||
assert (
|
||||
repo.portfolio.cash_balance,
|
||||
repo.portfolio.asset_quantity,
|
||||
repo.portfolio.profit_buffer,
|
||||
len(repo.entries),
|
||||
) == baseline
|
||||
|
||||
|
||||
def test_dividend_rejects_sub_minimum_numeric_precision() -> None:
|
||||
repo = _FakeRepo(_portfolio())
|
||||
client = _make_client(repo)
|
||||
@@ -653,6 +695,25 @@ def test_dividend_with_different_decimal_amount_is_not_treated_as_duplicate() ->
|
||||
assert second.status_code == 201
|
||||
|
||||
|
||||
def test_dividend_duplicate_check_does_not_collapse_decimals_that_can_alias_in_float() -> None:
|
||||
repo = _FakeRepo(_portfolio())
|
||||
client = _make_client(repo)
|
||||
|
||||
first = client.post(
|
||||
f"/v1/portfolios/{_PORTFOLIO_ID}/ledger/manual",
|
||||
json={"action": "DIVIDEND", "amount": "90000000.00000001", "executed_at": "2026-09-01", "note": "Q3"},
|
||||
headers=_auth(),
|
||||
)
|
||||
assert first.status_code == 201
|
||||
|
||||
second = client.post(
|
||||
f"/v1/portfolios/{_PORTFOLIO_ID}/ledger/manual",
|
||||
json={"action": "DIVIDEND", "amount": "90000000.00000002", "executed_at": "2026-09-01", "note": "Q3"},
|
||||
headers=_auth(),
|
||||
)
|
||||
assert second.status_code == 201
|
||||
|
||||
|
||||
def test_reversed_dividend_is_excluded_from_future_duplicate_candidate_matching() -> None:
|
||||
repo = _FakeRepo(_portfolio())
|
||||
client = _make_client(repo)
|
||||
|
||||
Reference in New Issue
Block a user