forked from bitcoinafterlife/bal-electrum-plugin
v0.4.8: seven UX fixes for the BAL inheritance plugin
- #04: Raw/Date selector now reappears on the WILL/HEIR tabs when switching to ADVANCED (and when a raw value is pushed from the wizard), keeping the current value/editor. New BalTimeEditWidget.apply_user_type_visibility() wired into WillSettingsWidget for both the locktime and check-alive boxes. - #3: Building Will report window minimum height 500 -> 450 px. - #5: 'User Type' setting moved to the bottom, above 'Rebroadcast transactions'. - #6: enabling ADVANCED now requires typing 'at My Risk' (case-insensitive); wrong phrase or cancel reverts to BASIC. QInputDialog added to common import. - #7a: on CHECK with an emptied wallet, an extra reassuring line is shown on 'Checking your will': 'Inheritance already executed (on blockchain)' in GREEN (CONFIRMED) or 'Inheritance in mempool (waiting confirmation)' in ORANGE (MEMPOOL). New _executed_inheritance_status() helper. - #7b: 'Balance is too low, or CheckAlive is in the past. Skipped' (space added) recoloured to ORANGE instead of red. - Reset button renamed 'Reset setting' -> 'Reset to Default Setting'. - Added tests/test_group_h_v048.py (8 tests). Version 0.4.7 -> 0.4.8. Full suite: 266 passed; ruff clean; CHANGELOG #24; memory updated (#04 done).
This commit is contained in:
127
tests/test_group_h_v048.py
Normal file
127
tests/test_group_h_v048.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
Tests for the v0.4.8 changes (Group H).
|
||||
|
||||
These tests cover the small, GUI-free DECISION LOGIC introduced in v0.4.8,
|
||||
without importing the Qt widgets (which need PyQt6 + an Electrum window). For
|
||||
each behaviour we reproduce the exact rule the production code uses, so the
|
||||
tests stay fast and headless while still pinning the contract.
|
||||
|
||||
Covered behaviour:
|
||||
|
||||
* #7a - "executed inheritance" detection used to show a reassuring note on the
|
||||
"Checking your will" row when the wallet is empty because the inheritance was
|
||||
already executed (CONFIRMED) or is on its way (MEMPOOL). The rule:
|
||||
CONFIRMED takes precedence over MEMPOOL, and only when neither is present is
|
||||
the will treated as "really changed" (None).
|
||||
* #6 - the "at My Risk" confirmation gate for enabling ADVANCED mode. The
|
||||
typed phrase is accepted case-insensitively; anything else (or a cancel)
|
||||
must keep the user in BASIC.
|
||||
|
||||
Run:
|
||||
PYTHONPATH=electrum-src python3 -m pytest tests/test_group_h_v048.py -q
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Mocks
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
class FakeWillItem:
|
||||
"""Minimal will item exposing only ``get_status`` like the real WillItem."""
|
||||
|
||||
def __init__(self, statuses):
|
||||
# ``statuses`` is a set of status names that are True for this item.
|
||||
self._statuses = set(statuses)
|
||||
|
||||
def get_status(self, status):
|
||||
return status in self._statuses
|
||||
|
||||
|
||||
def executed_inheritance_status(willitems):
|
||||
"""GUI-free copy of ``BalDialog._executed_inheritance_status``.
|
||||
|
||||
Mirrors the production rule exactly (see bal/gui/qt/dialogs.py):
|
||||
* return "CONFIRMED" as soon as any item is confirmed on-chain;
|
||||
* otherwise return "MEMPOOL" if any item is in the mempool;
|
||||
* otherwise return None.
|
||||
"""
|
||||
has_mempool = False
|
||||
for witem in willitems.values():
|
||||
if witem.get_status("CONFIRMED"):
|
||||
return "CONFIRMED"
|
||||
if witem.get_status("MEMPOOL"):
|
||||
has_mempool = True
|
||||
return "MEMPOOL" if has_mempool else None
|
||||
|
||||
|
||||
def advanced_phrase_ok(text, accepted):
|
||||
"""GUI-free copy of the ADVANCED gate check (see on_user_type_change).
|
||||
|
||||
Returns True only when ``text`` equals the confirmation phrase ignoring
|
||||
surrounding whitespace and letter case. ``accepted`` is False when the input
|
||||
dialog was cancelled, which must never enable ADVANCED.
|
||||
"""
|
||||
if not accepted:
|
||||
return False
|
||||
return text.strip().lower() == "at my risk"
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# #7a - executed-inheritance detection
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def test_executed_status_confirmed_wins():
|
||||
"""A confirmed transaction reports CONFIRMED even if a mempool one exists."""
|
||||
willitems = {
|
||||
"a": FakeWillItem({"MEMPOOL"}),
|
||||
"b": FakeWillItem({"CONFIRMED"}),
|
||||
}
|
||||
assert executed_inheritance_status(willitems) == "CONFIRMED"
|
||||
|
||||
|
||||
def test_executed_status_mempool_only():
|
||||
"""With only a mempool transaction the status is MEMPOOL."""
|
||||
willitems = {"a": FakeWillItem({"MEMPOOL"})}
|
||||
assert executed_inheritance_status(willitems) == "MEMPOOL"
|
||||
|
||||
|
||||
def test_executed_status_none_when_neither():
|
||||
"""No confirmed/mempool item -> None (the will really has to be rebuilt)."""
|
||||
willitems = {"a": FakeWillItem({"VALID"})}
|
||||
assert executed_inheritance_status(willitems) is None
|
||||
|
||||
|
||||
def test_executed_status_empty():
|
||||
"""No will items at all -> None."""
|
||||
assert executed_inheritance_status({}) is None
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# #6 - "at My Risk" ADVANCED gate
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def test_advanced_phrase_exact():
|
||||
"""The exact phrase as shown in the prompt is accepted."""
|
||||
assert advanced_phrase_ok("at My Risk", True) is True
|
||||
|
||||
|
||||
def test_advanced_phrase_case_insensitive():
|
||||
"""Any capitalisation is accepted (case-insensitive)."""
|
||||
for variant in ("at my risk", "AT MY RISK", "At My Risk", " at my risk "):
|
||||
assert advanced_phrase_ok(variant, True) is True
|
||||
|
||||
|
||||
def test_advanced_phrase_wrong_text():
|
||||
"""A wrong phrase keeps the user in BASIC."""
|
||||
assert advanced_phrase_ok("at your risk", True) is False
|
||||
assert advanced_phrase_ok("", True) is False
|
||||
|
||||
|
||||
def test_advanced_phrase_cancelled():
|
||||
"""Cancelling the dialog (accepted=False) never enables ADVANCED."""
|
||||
assert advanced_phrase_ok("at My Risk", False) is False
|
||||
Reference in New Issue
Block a user