diff --git a/monero/backends/jsonrpc.py b/monero/backends/jsonrpc.py index a6f9948..b64bf6a 100644 --- a/monero/backends/jsonrpc.py +++ b/monero/backends/jsonrpc.py @@ -247,7 +247,7 @@ class JSONRPCWallet(object): } if 'destinations' in data: result['destinations'] = [ - (address(x['address']), from_atomic(data['amount'])) + (address(x['address']), from_atomic(x['amount'])) for x in data.get('destinations') ] return result diff --git a/test_requirements.txt b/test_requirements.txt index 1d000ae..cc084fe 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -4,3 +4,4 @@ pip>=9 pytest-cov~=2.5 pytest-runner~=4.2 pytest~=3.6 +responses diff --git a/tests/base.py b/tests/base.py new file mode 100644 index 0000000..25b70b5 --- /dev/null +++ b/tests/base.py @@ -0,0 +1,15 @@ +import json +import os +import unittest + +class JSONTestCase(unittest.TestCase): + jsonrpc_url = 'http://127.0.0.1:18088/json_rpc' + data_subdir = None + + def _read(self, *args): + path = os.path.join(os.path.dirname(__file__), 'data') + if self.data_subdir: + path = os.path.join(path, self.data_subdir) + path = os.path.join(path, *args) + with open(path, 'r') as fh: + return json.loads(fh.read()) diff --git a/tests/data/test_jsonrpcwallet/test_multiple_destinations-accounts.json b/tests/data/test_jsonrpcwallet/test_multiple_destinations-accounts.json new file mode 100644 index 0000000..9ab0e3e --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_multiple_destinations-accounts.json @@ -0,0 +1,16 @@ +{"id": 0, + "jsonrpc": "2.0", + "result": {"subaddress_accounts": [{"account_index": 0, + "balance": 141601990026, + "base_address": "56cXYWG13YKaT9z1aEy2hb9TZNnxrW3zE9S4nTQVDux5Qq7UYsmjuux3Zstxkorj9HAufyWLU3FwHW4uERQF6tkeUVogGN3", + "label": "Primary account", + "tag": "", + "unlocked_balance": 141601990026}, + {"account_index": 1, + "balance": 1000000000000, + "base_address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN", + "label": "(Untitled account)", + "tag": "", + "unlocked_balance": 1000000000000}], + "total_balance": 1141601990026, + "total_unlocked_balance": 1141601990026}} diff --git a/tests/data/test_jsonrpcwallet/test_multiple_destinations-incoming.json b/tests/data/test_jsonrpcwallet/test_multiple_destinations-incoming.json new file mode 100644 index 0000000..8b17de6 --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_multiple_destinations-incoming.json @@ -0,0 +1,20 @@ +{"id": 0, + "jsonrpc": "2.0", + "result": {"out": [{"address": "56cXYWG13YKaT9z1aEy2hb9TZNnxrW3zE9S4nTQVDux5Qq7UYsmjuux3Zstxkorj9HAufyWLU3FwHW4uERQF6tkeUVogGN3", + "amount": 1000000000000, + "confirmations": 66, + "destinations": [{"address": "76yuj8ZcnuNhSCciBJHDzhBoGBXRoDVkeLbzD7gW2yiFc9ypd9ArzSBc2bkBHMsULU3LcXDBV681YbhLJn2bYbKq5mc2xsU", + "amount": 700000000000}, + {"address": "77LbfWj3yyhggccY2oLy2AcuBLqEvXKCSAYQUD6dfzBGcZXXBHgVrgy4VgBkZAaBnCdjwAC6koinjdxpXdfRjMT84neunYJ", + "amount": 300000000000}], + "double_spend_seen": false, + "fee": 477360000, + "height": 278441, + "note": "", + "payment_id": "0000000000000000", + "subaddr_index": {"major": 0, "minor": 0}, + "suggested_confirmations_threshold": 1, + "timestamp": 1552346064, + "txid": "f107123ae0611de2b732f4c6ad65a2c077d465a4e0708d3619dd44054b932f52", + "type": "out", + "unlock_time": 0}]}} diff --git a/tests/data/mainnet-subaddrs.json b/tests/data/test_offline/mainnet-subaddrs.json similarity index 100% rename from tests/data/mainnet-subaddrs.json rename to tests/data/test_offline/mainnet-subaddrs.json diff --git a/tests/data/stagenet-subaddrs.json b/tests/data/test_offline/stagenet-subaddrs.json similarity index 100% rename from tests/data/stagenet-subaddrs.json rename to tests/data/test_offline/stagenet-subaddrs.json diff --git a/tests/data/testnet-subaddrs.json b/tests/data/test_offline/testnet-subaddrs.json similarity index 100% rename from tests/data/testnet-subaddrs.json rename to tests/data/test_offline/testnet-subaddrs.json diff --git a/tests/test_jsonrpcwallet.py b/tests/test_jsonrpcwallet.py index d6f5bad..96ff7f7 100644 --- a/tests/test_jsonrpcwallet.py +++ b/tests/test_jsonrpcwallet.py @@ -1,11 +1,10 @@ from datetime import datetime from decimal import Decimal -import unittest +import responses try: from unittest.mock import patch, Mock except ImportError: from mock import patch, Mock -import warnings from monero.wallet import Wallet from monero.address import BaseAddress, Address @@ -13,7 +12,10 @@ from monero.seed import Seed from monero.transaction import IncomingPayment, OutgoingPayment, Transaction from monero.backends.jsonrpc import JSONRPCWallet -class SubaddrWalletTestCase(unittest.TestCase): +from .base import JSONTestCase + +class JSONRPCWalletTestCase(JSONTestCase): + data_subdir = 'test_jsonrpcwallet' accounts_result = {'id': 0, 'jsonrpc': '2.0', 'result': {'subaddress_accounts': [{'account_index': 0, @@ -925,6 +927,22 @@ class SubaddrWalletTestCase(unittest.TestCase): self.assertIsInstance(pmt.transaction.fee, Decimal) self.assertIs(pmt.transaction.height, None) + @responses.activate + def test_multiple_destinations(self): + responses.add(responses.POST, self.jsonrpc_url, + json=self._read('test_multiple_destinations-accounts.json'), + status=200) + responses.add(responses.POST, self.jsonrpc_url, + json=self._read('test_multiple_destinations-incoming.json'), + status=200) + self.wallet = Wallet(JSONRPCWallet()) + out = self.wallet.outgoing() + self.assertEqual(len(out), 1) + pmt = out[0] + self.assertEqual(pmt.amount, 1) + self.assertEqual(len(pmt.destinations), 2) + self.assertEqual(pmt.destinations[0][1] + pmt.destinations[1][1], pmt.amount) + @patch('monero.backends.jsonrpc.requests.post') def test_send_transfer(self, mock_post): mock_post.return_value.status_code = 200 diff --git a/tests/test_offline.py b/tests/test_offline.py index 6871244..15e31e8 100644 --- a/tests/test_offline.py +++ b/tests/test_offline.py @@ -1,27 +1,18 @@ -import json -import os -import unittest - from monero.backends.offline import OfflineWallet from monero.wallet import Wallet -from tests.utils import classproperty +from .base import JSONTestCase +from .utils import classproperty -class Tests(object): - @classproperty - def __test__(cls): - return issubclass(cls, unittest.TestCase) +class SubaddrTest(object): + data_subdir = 'test_offline' def setUp(self): - self.subaddresses = json.load(open(os.path.join( - os.path.dirname(__file__), - 'data', - '{}-subaddrs.json'.format(self.net)))) self.wallet = Wallet(OfflineWallet(self.addr, view_key=self.svk)) def test_subaddresses(self): major = 0 - for acc in self.subaddresses: + for acc in self._read('{}-subaddrs.json'.format(self.net)): minor = 0 for subaddr in acc: self.assertEqual( @@ -32,7 +23,7 @@ class Tests(object): major += 1 -class AddressTestCase(Tests, unittest.TestCase): +class AddressTestCase(SubaddrTest, JSONTestCase): addr = '47ewoP19TN7JEEnFKUJHAYhGxkeTRH82sf36giEp9AcNfDBfkAtRLX7A6rZz18bbNHPNV7ex6WYbMN3aKisFRJZ8Ebsmgef' ssk = 'e0fe01d5794e240a26609250c0d7e01673219eececa3f499d5cfa20a75739b0a' svk = '6d9056aa2c096bfcd2f272759555e5764ba204dd362604a983fa3e0aafd35901' @@ -45,14 +36,14 @@ class AddressTestCase(Tests, unittest.TestCase): self.assertRaises(ValueError, self.wallet.get_address, 2**32, 1) -class TestnetAddressTestCase(Tests, unittest.TestCase): +class TestnetAddressTestCase(SubaddrTest, JSONTestCase): addr = '9wuKTHsxGiwEsMp2fYzJiVahyhU2aZi1oZ6R6fK5U64uRa1Pxi8diZh2S1GJFqYXRRhcbfzfWiPD819zKEZkXTMwP7hMs5N' ssk = '4f5b7af2c1942067ba33d34318b9735cb46ab5d50b75294844c82a9dd872c201' svk = '60cf228f2bf7f6a70643afe9468fde254145dbd3aab4072ede14bf8bae914103' net = 'testnet' -class StagenetAddressTestCase(Tests, unittest.TestCase): +class StagenetAddressTestCase(SubaddrTest, JSONTestCase): addr = '52jzuBBUMty3xPL3JsQxGP74LDuV6E1LS8Zda1PbdqQjGzFmH6N9ep9McbFKMALujVT9S5mKpbEgC5VPhfoAiVj8LdAqbp6' ssk = 'a8733c61797115db4ec8a5ce39fb811f81dd4ec163b880526683e059c7e62503' svk = 'fd5c0d25f8f994268079a4f7844274dc870a7c2b88fbfc24ba318375e1d9430f'