core: extract GUI-free logic into bal.core (reminders/checkalive/input_rules); fix save/sign tx RLock pickle by serializing tx; keep invalid heirs in wallet on build; tb1 testnet will-executor addresses; move tests to core modules
This commit is contained in:
165
tests/test_core_input_rules.py
Normal file
165
tests/test_core_input_rules.py
Normal file
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
Tests for ``bal.core.input_rules`` (pure, GUI-free).
|
||||
|
||||
Covers the locktime acceptance bounds, the RAW locktime sanitisation, and the
|
||||
percentage-or-amount field normalisation that the Qt editors wrap.
|
||||
|
||||
Run:
|
||||
source /home/steal/devel/bal/electrum/env/bin/activate
|
||||
python3 tests/test_core_input_rules.py
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, __file__.rsplit("/", 2)[0])
|
||||
|
||||
from bal.core.input_rules import ( # noqa: E402 (path insert above)
|
||||
LockTimeEditor,
|
||||
normalize_locktime_raw_text,
|
||||
normalize_perc_amount_text,
|
||||
parse_perc_amount,
|
||||
replace_dy_suffixes,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# LockTimeEditor
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
|
||||
def test_locktime_editor_is_acceptable():
|
||||
assert LockTimeEditor.is_acceptable_locktime(100) is True
|
||||
assert LockTimeEditor.is_acceptable_locktime(0) is True
|
||||
assert LockTimeEditor.is_acceptable_locktime(-1) is False
|
||||
assert LockTimeEditor.is_acceptable_locktime(None) is True
|
||||
|
||||
|
||||
def test_locktime_editor_is_acceptable_string():
|
||||
assert LockTimeEditor.is_acceptable_locktime("100") is True
|
||||
assert LockTimeEditor.is_acceptable_locktime("abc") is False
|
||||
assert LockTimeEditor.is_acceptable_locktime("") is True
|
||||
|
||||
|
||||
def test_locktime_editor_min_max():
|
||||
assert LockTimeEditor.min_allowed_value >= 0
|
||||
assert LockTimeEditor.max_allowed_value > LockTimeEditor.min_allowed_value
|
||||
|
||||
|
||||
def test_locktime_editor_get_max_allowed_timestamp():
|
||||
# Always a valid, fromtimestamp-able value (the Windows 2038 clamp).
|
||||
ts = LockTimeEditor.get_max_allowed_timestamp()
|
||||
import datetime
|
||||
|
||||
datetime.datetime.fromtimestamp(ts) # must not raise
|
||||
assert ts <= 2**32 - 1
|
||||
|
||||
|
||||
def test_locktime_editor_subclass_bounds():
|
||||
class Tight(LockTimeEditor):
|
||||
min_allowed_value = 1000
|
||||
max_allowed_value = 2000
|
||||
|
||||
assert Tight.is_acceptable_locktime(1500) is True
|
||||
assert Tight.is_acceptable_locktime(999) is False
|
||||
assert Tight.is_acceptable_locktime(2001) is False
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# replace_dy_suffixes / RAW locktime sanitisation
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
|
||||
def test_replace_dy_suffixes():
|
||||
# replace_str only strips the day ("d") and year ("y") suffixes. The
|
||||
# block-height suffix ("b") was removed (A1), so "b" is NOT stripped
|
||||
# anymore (locktimes are always UNIX timestamps now).
|
||||
assert replace_dy_suffixes("123d") == "123"
|
||||
assert replace_dy_suffixes("456y") == "456"
|
||||
# "b" is left untouched (no longer a recognised suffix)
|
||||
assert replace_dy_suffixes("789b") == "789b"
|
||||
# only d/y are stripped; a stray "b" remains
|
||||
assert replace_dy_suffixes("12d34y56b") == "123456b"
|
||||
|
||||
|
||||
def test_normalize_locktime_raw_empty():
|
||||
s, isdays, isyears, pos = normalize_locktime_raw_text("", 0)
|
||||
assert s == ""
|
||||
assert isdays is False
|
||||
assert isyears is False
|
||||
|
||||
|
||||
def test_normalize_locktime_raw_days():
|
||||
s, isdays, isyears, pos = normalize_locktime_raw_text("30d", 3)
|
||||
assert s == "30d"
|
||||
assert isdays is True
|
||||
assert isyears is False
|
||||
|
||||
|
||||
def test_normalize_locktime_raw_years():
|
||||
s, isdays, isyears, pos = normalize_locktime_raw_text("2y", 2)
|
||||
assert s == "2y"
|
||||
assert isdays is False
|
||||
assert isyears is True
|
||||
|
||||
|
||||
def test_normalize_locktime_raw_strips_bad_chars():
|
||||
s, isdays, isyears, pos = normalize_locktime_raw_text("12a34b56", 8)
|
||||
assert s == "123456"
|
||||
assert isdays is False
|
||||
assert isyears is False
|
||||
|
||||
|
||||
def test_normalize_locktime_raw_single_suffix():
|
||||
# "1y30d" collapses to a single suffix; "d" wins (processed first), so the
|
||||
# "y" is dropped along with all letters.
|
||||
s, isdays, isyears, pos = normalize_locktime_raw_text("1y30d", 5)
|
||||
assert isdays is True
|
||||
assert isyears is False
|
||||
assert s == "130d"
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Percentage-or-amount normalisation
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
|
||||
def test_perc_normalize_percent():
|
||||
s, is_perc = normalize_perc_amount_text("50%", ".")
|
||||
assert is_perc is True
|
||||
assert s == "50%"
|
||||
|
||||
|
||||
def test_perc_normalize_no_percent():
|
||||
s, is_perc = normalize_perc_amount_text("123", ".")
|
||||
assert is_perc is False
|
||||
assert s == "123"
|
||||
|
||||
|
||||
def test_perc_normalize_strips_invalid():
|
||||
s, is_perc = normalize_perc_amount_text("1a2b3", ".")
|
||||
assert s == "123"
|
||||
|
||||
|
||||
def test_perc_normalize_decimal_limit():
|
||||
# At most 8 decimals after the point.
|
||||
s, is_perc = normalize_perc_amount_text("1.1234567890123", ".")
|
||||
assert s == "1.12345678"
|
||||
|
||||
|
||||
def test_perc_parse():
|
||||
from decimal import Decimal
|
||||
|
||||
assert parse_perc_amount("50%", ".") == Decimal(50)
|
||||
assert parse_perc_amount("123.45", ".") == Decimal("123.45")
|
||||
assert parse_perc_amount("abc", ".") is None
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Main
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
if __name__ == "__main__":
|
||||
for name in sorted(dir()):
|
||||
if name.startswith("test_"):
|
||||
globals()[name]()
|
||||
print(f" [OK] {name}")
|
||||
print("[OK] All core input_rules tests passed")
|
||||
Reference in New Issue
Block a user