Files
bal-electrum-plugin/tests/test_core_plugin_base.py
2026-06-20 09:49:39 -04:00

260 lines
7.3 KiB
Python

"""
Comprehensive tests for ``bal.core.plugin_base``.
Covers BalTimestamp, BalConfig, and BalPlugin static helpers.
Run:
source electrum/env/bin/activate
python3 tests/test_core_plugin_base.py
"""
import sys
import os
import time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
from datetime import datetime, date, timedelta
from bal.core.plugin_base import BalTimestamp, BalPlugin, BalConfig
# ------------------------------------------------------------------ #
# BalTimestamp
# ------------------------------------------------------------------ #
def test_bt_create_and_str():
bt = BalTimestamp("30d")
assert bt.unit == "d"
assert bt.value == 30
bt2 = BalTimestamp("1y")
assert bt2.unit == "y"
assert bt2.value == 1
bt3 = BalTimestamp(1700000000)
assert bt3.unit is None
assert bt3.value == 1700000000
bt4 = BalTimestamp("garbage")
# fallback: value=1, unit=None
assert bt4.value == 1
assert bt4.unit is None
bt5 = BalTimestamp(0)
assert bt5.unit is None
assert bt5.value == 0
bt6 = BalTimestamp("7d")
assert str(bt6) == "7d"
bt7 = BalTimestamp("2y")
assert str(bt7) == "2y"
# absolute timestamp str -> ISO format
bt8 = BalTimestamp(1700000000)
s = str(bt8)
assert "202" in s or "197" in s # year present
def test_bt_duration_to_days():
assert BalTimestamp("30d").duration_to_days() == 30
assert BalTimestamp("1y").duration_to_days() == 365
assert BalTimestamp("0d").duration_to_days() == 0
assert BalTimestamp(1700000000).duration_to_days() == 1700000000 # unit None -> raw value
def test_bt_to_date_absolute():
bt = BalTimestamp(1700000000)
d = bt.to_date()
assert isinstance(d, datetime)
# absolute with from_date (should be ignored for absolute)
d2 = bt.to_date(from_date=datetime(2020, 1, 1))
assert d == d2
def test_bt_to_date_relative():
now = datetime.now()
# relative days from now
bt = BalTimestamp("7d")
d = bt.to_date()
assert d.hour == 0 and d.minute == 0 # normalized to midnight
assert d > now
# reverse (subtract days)
d_rev = bt.to_date(reverse=True)
assert d_rev < now
# from explicit datetime
base = datetime(2025, 6, 1, 12, 0, 0)
d = bt.to_date(from_date=base)
expected = (base + timedelta(days=7)).replace(hour=0, minute=0, second=0, microsecond=0)
assert d == expected
# from int timestamp
ts = int(base.timestamp())
d = bt.to_date(from_date=ts)
assert d == expected
def test_bt_to_date_years():
bt = BalTimestamp("1y")
d = bt.to_date()
assert d > datetime.now()
def test_bt_to_date_overflow():
"""Huge relative durations should not crash (clamp to INT32_MAX)."""
bt = BalTimestamp("999999999d")
d = bt.to_date()
# should not raise
assert d is not None
assert isinstance(d, datetime)
def test_bt_to_timestamp():
bt = BalTimestamp("7d")
ts = bt.to_timestamp()
assert ts > time.time()
assert isinstance(ts, float)
bt2 = BalTimestamp(1700000000)
assert abs(bt2.to_timestamp() - 1700000000) < 86400 # close to original
def test_bt_repr():
assert repr(BalTimestamp("7d")) == "7d"
r = repr(BalTimestamp(1700000000))
assert isinstance(r, str)
assert len(r) > 0
def test_bt_edge_values():
# zero timestamp
bt0 = BalTimestamp(0)
d = bt0.to_date()
assert d is not None
# negative? (may depend on platform)
try:
bt_neg = BalTimestamp(-1)
_ = bt_neg.to_date()
except (OSError, ValueError, OverflowError):
pass # acceptable on some platforms
# ------------------------------------------------------------------ #
# BalTimestamp._safe_fromtimestamp
# ------------------------------------------------------------------ #
def test_safe_fromtimestamp_normal():
d = BalTimestamp._safe_fromtimestamp(1700000000)
assert isinstance(d, datetime)
def test_safe_fromtimestamp_nlocktime_max():
"""NLOCKTIME_MAX (2**32-1) must not raise even on 32-bit platforms."""
d = BalTimestamp._safe_fromtimestamp(2**32 - 1)
assert d is not None
def test_safe_fromtimestamp_negative():
"""Negative timestamps should not crash."""
d = BalTimestamp._safe_fromtimestamp(-1)
assert isinstance(d, datetime)
# ------------------------------------------------------------------ #
# BalConfig
# ------------------------------------------------------------------ #
class FakeConfig:
"""Minimal mock for Electrum config."""
def __init__(self):
self._store = {}
def get(self, key, default=None):
return self._store.get(key, default)
def set_key(self, key, value, save=True):
self._store[key] = value
def test_balconfig_default():
cfg = FakeConfig()
bc = BalConfig(cfg, "test_key", "default_val")
assert bc.get() == "default_val"
assert bc.get("override") == "override"
assert bc.get(None) == "default_val"
def test_balconfig_set():
cfg = FakeConfig()
bc = BalConfig(cfg, "test_key", "default_val")
bc.set("stored_val")
assert cfg.get("test_key") == "stored_val"
assert bc.get() == "stored_val"
# ------------------------------------------------------------------ #
# BalPlugin
# ------------------------------------------------------------------ #
def test_default_will_settings_relative():
rel = BalPlugin.default_will_settings_relative()
assert rel["threshold"] == "30d"
assert rel["locktime"] == "1y"
def test_default_will_settings():
settings = BalPlugin.default_will_settings()
assert settings["baltx_fees"] == 100
assert "threshold" in settings
assert "locktime" in settings
# threshold/locktime should be absolute timestamps
assert isinstance(settings["threshold"], float)
assert isinstance(settings["locktime"], float)
def test_default_will_settings_absolute():
abs_ = BalPlugin.default_will_settings_absolute()
assert "threshold" in abs_
assert "locktime" in abs_
# should be timestamps (in the future)
today = datetime.combine(date.today(), datetime.min.time())
assert abs_["threshold"] >= today.timestamp()
assert abs_["locktime"] >= today.timestamp()
def test_validate_will_settings():
# Note: passing None triggers `will_settings = []` which then fails
# on .get(). This is a latent bug — test passing a dict directly
result = BalPlugin.validate_will_settings(None, {"baltx_fees": 0})
assert result["baltx_fees"] == 100
# normal settings unchanged
input_settings = {"baltx_fees": 50, "threshold": 1700000000, "locktime": 1800000000}
result = BalPlugin.validate_will_settings(None, input_settings)
assert result["baltx_fees"] == 50
assert result["threshold"] == 1700000000
if __name__ == "__main__":
test_bt_create_and_str()
test_bt_duration_to_days()
test_bt_to_date_absolute()
test_bt_to_date_relative()
test_bt_to_date_years()
test_bt_to_date_overflow()
test_bt_to_timestamp()
test_bt_repr()
test_bt_edge_values()
test_safe_fromtimestamp_normal()
test_safe_fromtimestamp_nlocktime_max()
test_safe_fromtimestamp_negative()
test_balconfig_default()
test_balconfig_set()
test_default_will_settings_relative()
test_default_will_settings()
test_default_will_settings_absolute()
test_validate_will_settings()
print(f"[OK] All {sum(1 for k in dir() if k.startswith('test_'))} plugin_base tests passed")