forked from bitcoinafterlife/bal-electrum-plugin
183 lines
5.9 KiB
Python
183 lines
5.9 KiB
Python
"""
|
|
Tests for wallet/db-dependent methods in ``bal.core.heirs``.
|
|
|
|
Uses mocking to simulate Electrum wallet, db, and bitcoin module.
|
|
|
|
Run:
|
|
source electrum/env/bin/activate
|
|
QT_QPA_PLATFORM=offscreen python3 tests/test_core_heirs_extra.py
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
|
|
|
|
from bal.core.heirs import (
|
|
Heirs, create_op_return_script, reduce_outputs,
|
|
HEIR_ADDRESS, HEIR_AMOUNT, HEIR_LOCKTIME, HEIR_REAL_AMOUNT,
|
|
)
|
|
from bal.core.willexecutors import Willexecutors
|
|
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Heirs db-dependent methods
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def test_heirs_init_from_db():
|
|
wallet = MagicMock()
|
|
wallet.db.get .return_value = {"alice": ["bcrt1q087zm5m3jrhfg78zflqefhcr9heh4c98kzmvhp", 5000, "30d"]}
|
|
h = Heirs(wallet)
|
|
assert "alice" in h
|
|
|
|
|
|
def test_heirs_init_empty_db():
|
|
wallet = MagicMock()
|
|
wallet.db.get.return_value = {}
|
|
h = Heirs(wallet)
|
|
assert len(h) == 0
|
|
|
|
|
|
def test_heirs_save():
|
|
wallet = MagicMock()
|
|
wallet.db.get.return_value = {}
|
|
h = Heirs(wallet)
|
|
h["bob"] = ["bcrt1q08z5t4x74u2883sx2qwsmzk2hj8e5n7z83e4vy", 3000, "60d"]
|
|
wallet.db.put.assert_called()
|
|
|
|
|
|
def test_heirs_pop_saves():
|
|
wallet = MagicMock()
|
|
wallet.db.get.return_value = {"bob": ["bcrt1q08z5t4x74u2883sx2qwsmzk2hj8e5n7z83e4vy", 3000, "60d"]}
|
|
h = Heirs(wallet)
|
|
h.pop("bob")
|
|
wallet.db.put.assert_called()
|
|
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Heirs wallet-dependent methods
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def test_heirs_normalize_perc():
|
|
wallet = MagicMock()
|
|
wallet.dust_threshold.return_value = 500
|
|
heir_list = {"a": ["bcrt1q087zm5m3jrhfg78zflqefhcr9heh4c98kzmvhp", "50%", "30d"]}
|
|
h = Heirs.__new__(Heirs)
|
|
h._Heirs__normal_perc = True
|
|
h.update(heir_list)
|
|
h.normalize_perc(heir_list, 100000, 100000, wallet)
|
|
# "50%" of 100000 = 50000 → above dust threshold, value stays
|
|
assert h["a"][HEIR_AMOUNT] == "50%"
|
|
|
|
|
|
def test_heirs_prepare_lists():
|
|
wallet = MagicMock()
|
|
wallet.dust_threshold.return_value = 500
|
|
h = Heirs.__new__(Heirs)
|
|
h.update({"a": ["bcrt1q087zm5m3jrhfg78zflqefhcr9heh4c98kzmvhp", 5000, "30d"]})
|
|
result, onlyfixed = h.prepare_lists(100000, 100, wallet)
|
|
assert len(result) > 0
|
|
assert isinstance(result, dict)
|
|
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Heirs static methods (pure but use Electrum constants)
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def test_validate_address_valid():
|
|
with patch("bal.core.heirs.bitcoin.is_address", return_value=True):
|
|
result = Heirs.validate_address("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa")
|
|
assert result == "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
|
|
|
|
|
|
def test_validate_address_invalid():
|
|
with patch("bal.core.heirs.bitcoin.is_address", return_value=False):
|
|
from bal.core.heirs import NotAnAddress
|
|
try:
|
|
Heirs.validate_address("bad")
|
|
assert False, "should have raised"
|
|
except NotAnAddress:
|
|
pass
|
|
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# create_op_return_script (pure)
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def test_create_op_return_script():
|
|
data = "42414c" # "BAL" in hex
|
|
script = create_op_return_script(data)
|
|
assert script.startswith(b"\x6a")
|
|
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# reduce_outputs (pure)
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def test_reduce_outputs_noop():
|
|
outputs = [("bcrt1q087zm5m3jrhfg78zflqefhcr9heh4c98kzmvhp", 1000), ("bcrt1q08z5t4x74u2883sx2qwsmzk2hj8e5n7z83e4vy", 2000)]
|
|
reduce_outputs(5000, 5000, 100, outputs) # no crash, no modification
|
|
|
|
|
|
def test_reduce_outputs_reduces():
|
|
class FakeOut:
|
|
def __init__(self, v):
|
|
self.value = v
|
|
outputs = [FakeOut(1000), FakeOut(2000)]
|
|
reduce_outputs(100, 5000, 10, outputs)
|
|
assert outputs[0].value < 1000
|
|
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Willexecutors (pure / light mocking)
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def test_willexecutors_compute_id():
|
|
wid = Willexecutors.compute_id({"url": "example.com", "chain": "mainnet"})
|
|
assert isinstance(wid, str)
|
|
assert "example.com" in wid
|
|
|
|
|
|
def test_willexecutors_is_selected():
|
|
assert Willexecutors.is_selected({}) is False
|
|
data = {"url": "x"}
|
|
assert Willexecutors.is_selected(data) is False
|
|
assert Willexecutors.is_selected(data, True) is True
|
|
assert data.get("selected") is True
|
|
|
|
|
|
def test_willexecutors_get_we_url_from_response():
|
|
class FakeResp:
|
|
url = "http://example.com/willexecutor"
|
|
result = Willexecutors.get_we_url_from_response(FakeResp())
|
|
# With 4 path segments, result is first 2 segments joined
|
|
assert result == "http:/"
|
|
# More realistic: a deeper URL returns the host part
|
|
class FakeResp2:
|
|
url = "http://example.com/api/v1/endpoint"
|
|
result2 = Willexecutors.get_we_url_from_response(FakeResp2())
|
|
assert "example.com" in result2
|
|
|
|
|
|
def test_willexecutors_initialize_willexecutor():
|
|
we = {}
|
|
Willexecutors.initialize_willexecutor(we, "http://example.com")
|
|
assert len(we) > 0
|
|
|
|
|
|
def test_willexecutors_get_willexecutor_transactions_empty():
|
|
assert Willexecutors.get_willexecutor_transactions({}) == {}
|
|
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Main
|
|
# ------------------------------------------------------------------ #
|
|
|
|
if __name__ == "__main__":
|
|
for name in sorted(dir()):
|
|
if name.startswith("test_"):
|
|
globals()[name]()
|
|
print(f" [OK] {name}")
|
|
print("[OK] All heirs/willexecutors extra tests passed")
|