from __future__ import annotations import importlib.util import json import sys import tempfile import unittest from decimal import Decimal from pathlib import Path REPO_DIR = Path(__file__).resolve().parents[1] SPEC = importlib.util.spec_from_file_location( "consumption_mode", REPO_DIR / "scripts/consumption_mode.py" ) cm = importlib.util.module_from_spec(SPEC) assert SPEC.loader is not None sys.modules[SPEC.name] = cm SPEC.loader.exec_module(cm) def restricted(allowance: str = "45.83") -> dict: return { "schema_version": "0.1", "record_type": "consumption_mode", "financial_entity_id": "entity:coulomb", "period": "2026-09", "consumption_mode": "restricted", "new_transfer_charges_allowed_eur": allowance, "terms_version": "0.1", } class ConsumptionModeTests(unittest.TestCase): def test_open_entity_unchanged(self) -> None: signal = restricted() signal["consumption_mode"] = "open" signal["new_transfer_charges_allowed_eur"] = None result = cm.decide( entity_id="entity:coulomb", order_class="new-order", estimate_eur=Decimal("200.00"), signal=signal, ) self.assertEqual(result["decision"], "admit") self.assertEqual(result["reason"], "open") def test_restricted_cannot_exceed_allowance(self) -> None: result = cm.decide( entity_id="entity:coulomb", order_class="new-order", estimate_eur=Decimal("45.84"), signal=restricted(), ) self.assertEqual(result["decision"], "refuse") self.assertEqual(result["reason"], "exceeds-allowance") def test_restricted_within_allowance(self) -> None: result = cm.decide( entity_id="entity:coulomb", order_class="new-order", estimate_eur=Decimal("45.83"), signal=restricted(), ) self.assertEqual(result["decision"], "admit") self.assertEqual(result["reason"], "within-allowance") def test_restricted_without_estimate_refused(self) -> None: result = cm.decide( entity_id="entity:coulomb", order_class="elastic", estimate_eur=None, signal=restricted(), ) self.assertEqual(result["decision"], "refuse") self.assertEqual(result["reason"], "restricted-estimate-required") def test_safety_admitted_as_exception(self) -> None: result = cm.decide( entity_id="entity:coulomb", order_class="safety", estimate_eur=Decimal("200.00"), signal=restricted(), ) self.assertEqual(result["decision"], "admit") self.assertTrue(result["exception"]) def test_no_signal_is_not_restricted(self) -> None: result = cm.decide( entity_id="entity:coulomb", order_class="new-order", estimate_eur=Decimal("999.00"), signal=None, ) self.assertEqual(result["decision"], "admit") self.assertEqual(result["reason"], "no-signal-not-restricted") def test_railiance_self_use_always_open(self) -> None: result = cm.decide( entity_id="entity:railiance", order_class="new-order", estimate_eur=Decimal("999.00"), signal=restricted(), ) self.assertEqual(result["decision"], "admit") self.assertEqual(result["reason"], "railiance-self-use") def test_cli_refuses_restricted_overage(self) -> None: with tempfile.TemporaryDirectory() as tmp: path = Path(tmp) / "signal.json" path.write_text(json.dumps([restricted()]), encoding="utf-8") code = cm.main( [ "check", "--entity", "entity:coulomb", "--estimate-eur", "50", "--signal", str(path), ] ) self.assertEqual(code, 2) def test_cli_admits_open(self) -> None: with tempfile.TemporaryDirectory() as tmp: path = Path(tmp) / "signal.json" path.write_text("[]", encoding="utf-8") code = cm.main( [ "check", "--entity", "entity:coulomb", "--estimate-eur", "50", "--signal", str(path), ] ) self.assertEqual(code, 0)