From 536de45bade394932c847570ac31438e44d86eb1 Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Sun, 8 Mar 2026 20:23:45 +0100 Subject: [PATCH] Add address book test --- src/cpp/py_monero.cpp | 4 ++ src/python/monero_wallet.pyi | 9 +++ tests/test_monero_wallet_common.py | 88 +++++++++++++++++++++++++++++- tests/test_monero_wallet_keys.py | 5 ++ tests/utils/wallet_utils.py | 11 +++- 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/cpp/py_monero.cpp b/src/cpp/py_monero.cpp index b0d3e1e..a882e96 100644 --- a/src/cpp/py_monero.cpp +++ b/src/cpp/py_monero.cpp @@ -1946,6 +1946,10 @@ PYBIND11_MODULE(monero, m) { .def("get_address_book_entries", [](PyMoneroWallet& self, const std::vector& indices) { MONERO_CATCH_AND_RETHROW(self.get_address_book_entries(indices)); }, py::arg("indices")) + .def("get_address_book_entries", [](PyMoneroWallet& self) { + std::vector indices; + MONERO_CATCH_AND_RETHROW(self.get_address_book_entries(indices)); + }) .def("add_address_book_entry", [](PyMoneroWallet& self, const std::string& address, const std::string& description) { MONERO_CATCH_AND_RETHROW(self.add_address_book_entry(address, description)); }, py::arg("address"), py::arg("description")) diff --git a/src/python/monero_wallet.pyi b/src/python/monero_wallet.pyi index 65ff3cf..20f4ed8 100644 --- a/src/python/monero_wallet.pyi +++ b/src/python/monero_wallet.pyi @@ -315,6 +315,15 @@ class MoneroWallet: :return str: the receive address of the specified subaddress """ ... + @typing.overload + def get_address_book_entries(self) -> list[MoneroAddressBookEntry]: + """ + Get all address book entries. + + :return list[MoneroAddressBookEntry]: the address book entries + """ + ... + @typing.overload def get_address_book_entries(self, indices: list[int]) -> list[MoneroAddressBookEntry]: """ Get all address book entries. diff --git a/tests/test_monero_wallet_common.py b/tests/test_monero_wallet_common.py index b184132..cccbd0e 100644 --- a/tests/test_monero_wallet_common.py +++ b/tests/test_monero_wallet_common.py @@ -16,7 +16,8 @@ MoneroOutputQuery, MoneroTransfer, MoneroIncomingTransfer, MoneroOutgoingTransfer, MoneroTxWallet, MoneroOutputWallet, MoneroTx, MoneroAccount, MoneroSubaddress, MoneroMessageSignatureType, MoneroTxPriority, MoneroFeeEstimate, - MoneroIntegratedAddress, MoneroCheckTx, MoneroCheckReserve, MoneroSubmitTxResult + MoneroIntegratedAddress, MoneroCheckTx, MoneroCheckReserve, + MoneroAddressBookEntry, MoneroSubmitTxResult ) from utils import ( TestUtils, WalletEqualityUtils, @@ -2947,6 +2948,91 @@ def test_sign_and_verify_messages(self, wallet: MoneroWallet) -> None: result = wallet.verify_message(msg, WalletUtils.get_external_wallet_address(), signature) WalletUtils.test_message_signature_result(result, False) + # Has an address book + @pytest.mark.skipif(TestUtils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled") + def test_address_book(self, wallet: MoneroWallet) -> None: + # initial state + entries: list[MoneroAddressBookEntry] = wallet.get_address_book_entries() + num_entries_start: int = len(entries) + for entry in entries: + WalletUtils.test_address_book_entry(entry) + + # test adding standard addresses + NUM_ENTRIES: int = 5 + address: str = WalletUtils.get_external_wallet_address() + indices: list[int] = [] + for i in range(NUM_ENTRIES): + logger.debug(f"Adding address book entry ({i + 1})") + indices.append(wallet.add_address_book_entry(address, "hi there!")) + + entries = wallet.get_address_book_entries() + assert num_entries_start + NUM_ENTRIES == len(entries) + for idx in indices: + found: bool = False + for entry in entries: + if idx == entry.index: + WalletUtils.test_address_book_entry(entry) + assert entry.address == address + assert entry.description == "hi there!" + found = True + break + + assert found, f"Index {idx} not found in address book indices" + + # edit each address book entry + for idx in indices: + wallet.edit_address_book_entry(idx, False, '', True, "hello there!!") + + entries = wallet.get_address_book_entries(indices) + for entry in entries: + assert entry.description == "hello there!!" + + # delete entries at starting index + delete_idx: int = indices[0] + for i in range(len(indices)): + logger.debug(f"Deleting address book entry {i + 1}, delete_idx: {delete_idx}") + wallet.delete_address_book_entry(delete_idx) + entries = wallet.get_address_book_entries() + assert len(entries) == num_entries_start + + # test adding integrated addresses + indices = [] + # payment id less one character + payment_id: str = "03284e41c342f03" + integrated_addresses: dict[int, MoneroIntegratedAddress] = {} + integrated_descriptions: dict[int, str] = {} + for i in range(NUM_ENTRIES): + # create unique integrated address + integrated_address: MoneroIntegratedAddress = wallet.get_integrated_address('', f"{payment_id}{i}") + uuid: str = StringUtils.get_random_string() + idx: int = wallet.add_address_book_entry(integrated_address.integrated_address, uuid) + indices.append(idx) + integrated_addresses[idx] = integrated_address + integrated_descriptions[idx] = uuid + + entries = wallet.get_address_book_entries() + assert len(entries) == num_entries_start + NUM_ENTRIES + for idx in indices: + found: bool = False + for entry in entries: + if idx == entry.index: + WalletUtils.test_address_book_entry(entry) + assert integrated_descriptions[idx] == entry.description + assert integrated_addresses[idx].integrated_address == entry.address + assert entry.payment_id is None + found = True + break + assert found, f"Index {idx} not found in address bool indices" + + # delete entries at starting index + delete_idx = indices[0] + for i in range(len(indices)): + logger.debug(f"Deleting address book entry {i + 1}") + wallet.delete_address_book_entry(delete_idx) + + entries = wallet.get_address_book_entries() + assert num_entries_start == len(entries) + # Can get and set arbitrary key/value attributes @pytest.mark.skipif(TestUtils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled") def test_set_attributes(self, wallet: MoneroWallet) -> None: diff --git a/tests/test_monero_wallet_keys.py b/tests/test_monero_wallet_keys.py index 8e325d8..f914248 100644 --- a/tests/test_monero_wallet_keys.py +++ b/tests/test_monero_wallet_keys.py @@ -502,6 +502,11 @@ def test_sweep_wallet_by_subaddresses(self, wallet: MoneroWallet) -> None: def test_prove_unrelayed_txs(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None: return super().test_prove_unrelayed_txs(daemon, wallet) + @pytest.mark.not_supported + @override + def test_address_book(self, wallet: MoneroWallet) -> None: + return super().test_address_book(wallet) + #endregion #region Tests diff --git a/tests/utils/wallet_utils.py b/tests/utils/wallet_utils.py index 0973407..5d1df3c 100644 --- a/tests/utils/wallet_utils.py +++ b/tests/utils/wallet_utils.py @@ -8,7 +8,7 @@ MoneroSubaddress, MoneroWalletKeys, MoneroWalletConfig, MoneroMessageSignatureResult, MoneroWallet, MoneroTxWallet, MoneroWalletFull, MoneroWalletRpc, - MoneroTxConfig, MoneroDestination + MoneroTxConfig, MoneroDestination, MoneroAddressBookEntry ) from .gen_utils import GenUtils @@ -172,6 +172,15 @@ def test_message_signature_result(cls, result: Optional[MoneroMessageSignatureRe #assert result.signature_type is None assert result.version == 0 + @classmethod + def test_address_book_entry(cls, entry: Optional[MoneroAddressBookEntry]) -> None: + assert entry is not None + assert entry.index is not None + assert entry.index >= 0 + assert entry.address is not None + MoneroUtils.validate_address(entry.address, TestUtils.NETWORK_TYPE) + assert entry.description is not None + # Convenience method for single tx send tests @classmethod def test_send_to_single(cls, wallet: MoneroWallet, can_split: bool, relay: Optional[bool] = None, payment_id: Optional[str] = None) -> None: