""" Shared test fixtures for the BAL plugin test-suite. This module centralises the "plausible data" used by the mock tests: * Valid Bitcoin (regtest) addresses are read **read-only** from the ``giovanna7`` wallet so the heirs / change / will-executor addresses are genuine, well-formed addresses for the active network. * A lightweight fake wallet and a fake ``bal_plugin`` are provided so the core inheritance logic (``Heirs.buildTransactions`` / ``get_transactions``) can be exercised without a running Electrum daemon or any network access. Nothing here touches the real wallet file other than reading it; the file is opened read-only and never written back. """ import json import os from unittest.mock import MagicMock from electrum.transaction import PartialTxInput, TxOutpoint from electrum.util import bfh # Read-only path to the giovanna7 regtest wallet used to source valid addresses. GIOVANNA7_WALLET = ( "/home/steal/devel/bal/electrum2/.electrum2222/regtest/wallets.old/giovanna7" ) # Fallback regtest addresses (used if the wallet file is not available, e.g. on # CI), so the address-dependent tests can still run. These are valid regtest # bech32 addresses taken from the giovanna7 wallet. _FALLBACK_RECEIVING = [ "bcrt1qpm5utekdtmzwnlkh7jq5497vwwf6sm38tljan5", "bcrt1qazle627r46apscly8lj4q5cxfxgrtuew879jde", "bcrt1qh2c83yulvs7kgw0g6q3lkxqws4cnf0uxpcgcpt", "bcrt1qsprcgaldcn6v6l6jw0w6annv7hgkpw7ycxu6mu", "bcrt1qy02pnw9lulnnwg6m77yghn6v7ndgnjph3hrdmy", "bcrt1qrmjaxllejgqu6azftsfu2cdjyrz8wjxzsv7wvp", ] _FALLBACK_CHANGE = [ "bcrt1qzu5u0fgpxq5v42r62aefc2xjn6mehgzhtj4pld", "bcrt1qs9ya5hserz44elcpt992r0ycrmh3w3chzffawc", "bcrt1q28qtj5ugfcm4psqenq54sh55uryealeeprk6ju", ] def load_addresses(): """Return ``(receiving, change)`` address lists from the giovanna7 wallet. Falls back to a small hard-coded set of valid regtest addresses when the wallet file cannot be read, so the tests remain runnable everywhere. """ try: with open(GIOVANNA7_WALLET, "r") as f: data = json.load(f) receiving = data["addresses"]["receiving"] change = data["addresses"]["change"] if receiving and change: return receiving, change except Exception: pass return list(_FALLBACK_RECEIVING), list(_FALLBACK_CHANGE) # Module-level cached address pools. RECEIVING_ADDRESSES, CHANGE_ADDRESSES = load_addresses() def heir_addresses(n): """Return ``n`` distinct valid heir addresses from the giovanna7 wallet.""" # Use addresses further into the list so they do not collide with the # change address used by the fake wallet. return RECEIVING_ADDRESSES[10 : 10 + n] def willexecutor_addresses(n): """Return ``n`` distinct valid will-executor payout addresses.""" return RECEIVING_ADDRESSES[100 : 100 + n] def change_address(): """Return a single valid change address.""" return CHANGE_ADDRESSES[0] def make_utxo(txid_hex, value, out_idx=0): """Build a minimal spendable ``PartialTxInput`` with the given value. Only the fields required by the inheritance transaction builder are set (trusted value + ``is_mine``); this mirrors how Electrum hands UTXOs to the plugin without needing a real wallet. """ txin = PartialTxInput(prevout=TxOutpoint(txid=bfh(txid_hex), out_idx=out_idx)) txin._trusted_value_sats = value txin._TxInput__value_sats = value txin.is_mine = True return txin def make_utxos(n, value=1_000_000, prefix="a1"): """Return ``n`` synthetic UTXOs of ``value`` satoshis each.""" return [make_utxo(f"{prefix}{i:062x}", value) for i in range(n)] def fake_wallet(dust_threshold=546): """Return a MagicMock wallet sufficient for the inheritance builder. The change address comes from the real giovanna7 wallet so generated transactions carry a valid change output address. """ w = MagicMock() w.dust_threshold.return_value = dust_threshold w.get_change_addresses_for_new_transaction.return_value = [change_address()] w.get_utxos.return_value = [] w.db.get.return_value = {} w.db.get_transaction.return_value = None return w def fake_bal_plugin(willexecutors=None, no_willexecutor=False, decimal_point=8): """Return a fake ``bal_plugin`` exposing only what the builder reads. Args: willexecutors: ``{url: we_dict}`` mapping returned by ``Willexecutors.get_willexecutors`` (patched in the tests). no_willexecutor: value of the ``NO_WILLEXECUTOR`` toggle (whether a local backup transaction without will-executor is also produced). decimal_point: BTC decimal point (8 for satoshi precision). """ plugin = MagicMock() plugin.get_decimal_point.return_value = decimal_point plugin.NO_WILLEXECUTOR.get.return_value = no_willexecutor plugin._willexecutors = willexecutors or {} return plugin