fix(CORE-001D3A): accept decimal boundary inputs
This commit is contained in:
@@ -14,14 +14,14 @@ def alert_service(tmp_path: Path) -> AlertService:
|
||||
return AlertService(history_path=tmp_path / "alert_history.json")
|
||||
|
||||
|
||||
def test_normalize_alert_evaluation_input_coerces_numeric_boundary_values() -> None:
|
||||
def test_normalize_alert_evaluation_input_accepts_decimal_boundary_values() -> None:
|
||||
config = PortfolioConfig(gold_value=215_000.0, entry_price=215.0, loan_amount=151_000.0)
|
||||
|
||||
normalized = _normalize_alert_evaluation_input(
|
||||
config,
|
||||
{
|
||||
"ltv_ratio": "0.7023",
|
||||
"spot_price": "215.0",
|
||||
"ltv_ratio": Decimal("0.7023"),
|
||||
"spot_price": Decimal("215.0"),
|
||||
"quote_updated_at": 123,
|
||||
},
|
||||
)
|
||||
@@ -33,6 +33,38 @@ def test_normalize_alert_evaluation_input_coerces_numeric_boundary_values() -> N
|
||||
assert normalized.critical_threshold == Decimal("0.75")
|
||||
|
||||
|
||||
def test_alert_service_evaluate_accepts_string_boundary_values(alert_service: AlertService) -> None:
|
||||
config = PortfolioConfig(gold_value=215_000.0, entry_price=215.0, loan_amount=151_000.0)
|
||||
|
||||
status = alert_service.evaluate(
|
||||
config,
|
||||
{
|
||||
"ltv_ratio": "0.7023",
|
||||
"spot_price": "215.0",
|
||||
"quote_updated_at": "2026-03-24T12:00:00Z",
|
||||
},
|
||||
persist=False,
|
||||
)
|
||||
|
||||
assert status.severity == "warning"
|
||||
assert status.ltv_ratio == pytest.approx(0.7023, rel=1e-9)
|
||||
assert [event.severity for event in status.history] == ["warning"]
|
||||
|
||||
|
||||
def test_alert_service_rejects_missing_ltv_ratio(alert_service: AlertService) -> None:
|
||||
config = PortfolioConfig(gold_value=215_000.0, entry_price=215.0, loan_amount=151_000.0)
|
||||
|
||||
with pytest.raises(ValueError, match="portfolio.ltv_ratio must be present"):
|
||||
alert_service.evaluate(
|
||||
config,
|
||||
{
|
||||
"spot_price": 215.0,
|
||||
"quote_updated_at": "2026-03-24T12:00:00Z",
|
||||
},
|
||||
persist=False,
|
||||
)
|
||||
|
||||
|
||||
def test_normalize_alert_evaluation_input_rejects_bool_values() -> None:
|
||||
config = PortfolioConfig(gold_value=215_000.0, entry_price=215.0, loan_amount=151_000.0)
|
||||
|
||||
|
||||
@@ -30,8 +30,17 @@ class StringBoundaryConfig:
|
||||
margin_call_price = "193.33333333333334"
|
||||
|
||||
|
||||
def test_normalize_save_status_snapshot_coerces_numeric_boundary_values() -> None:
|
||||
snapshot = _normalize_save_status_snapshot(StringBoundaryConfig())
|
||||
class DecimalBoundaryConfig:
|
||||
entry_basis_mode = "weight"
|
||||
gold_value = Decimal("215000")
|
||||
entry_price = Decimal("215.0")
|
||||
gold_ounces = Decimal("1000")
|
||||
current_ltv = Decimal("0.6744186046511628")
|
||||
margin_call_price = Decimal("193.33333333333334")
|
||||
|
||||
|
||||
def test_normalize_save_status_snapshot_accepts_decimal_boundary_values() -> None:
|
||||
snapshot = _normalize_save_status_snapshot(DecimalBoundaryConfig())
|
||||
|
||||
assert snapshot.entry_basis_mode == "weight"
|
||||
assert snapshot.gold_value == Decimal("215000")
|
||||
@@ -41,6 +50,17 @@ def test_normalize_save_status_snapshot_coerces_numeric_boundary_values() -> Non
|
||||
assert snapshot.margin_call_price == Decimal("193.33333333333334")
|
||||
|
||||
|
||||
def test_save_status_text_accepts_string_boundary_values() -> None:
|
||||
status = save_status_text(StringBoundaryConfig())
|
||||
|
||||
assert "Saved: basis=weight" in status
|
||||
assert "start=$215,000" in status
|
||||
assert "entry=$215.00/oz" in status
|
||||
assert "weight=1,000.00 oz" in status
|
||||
assert "LTV=67.4%" in status
|
||||
assert "trigger=$193.33/oz" in status
|
||||
|
||||
|
||||
def test_normalize_save_status_snapshot_rejects_bool_values() -> None:
|
||||
class InvalidBoundaryConfig(StringBoundaryConfig):
|
||||
current_ltv = True
|
||||
|
||||
Reference in New Issue
Block a user