Skip to content

Commit 81fbeab

Browse files
committed
test: add unit tests for BlockchainInfo API edge cases and error handling
1 parent bdfe438 commit 81fbeab

2 files changed

Lines changed: 54 additions & 1 deletion

File tree

blockapi/test/v2/api/test_blockchain_info.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,46 @@ def test_parse_only():
5555
assert result.data[0].balance == Decimal('0.00064363')
5656

5757

58+
def test_parse_zero_balance():
59+
api = BlockchainInfoApi()
60+
fetch_result = FetchResult(data={'wallet': {'final_balance': 0}})
61+
result = api.parse_balances(fetch_result)
62+
assert result.data is None
63+
64+
65+
def test_parse_empty_wallet():
66+
api = BlockchainInfoApi()
67+
fetch_result = FetchResult(data={'wallet': {}})
68+
result = api.parse_balances(fetch_result)
69+
assert result.data is None
70+
71+
72+
def test_fetch_invalid_address(requests_mock):
73+
invalid_address = 'not-a-valid-btc-address'
74+
requests_mock.get(
75+
'https://blockchain.info/multiaddr',
76+
status_code=400,
77+
reason='Bad Request',
78+
)
79+
80+
api = BlockchainInfoApi()
81+
result = api.fetch_balances(invalid_address)
82+
assert result.errors == ['Bad Request']
83+
84+
85+
def test_get_balance_invalid_address_should_raise(requests_mock):
86+
invalid_address = 'not-a-valid-btc-address'
87+
requests_mock.get(
88+
'https://blockchain.info/multiaddr',
89+
status_code=400,
90+
reason='Bad Request',
91+
)
92+
93+
api = BlockchainInfoApi()
94+
with pytest.raises(ApiException, match='Bad Request'):
95+
api.get_balance(invalid_address)
96+
97+
5898
def test_fetch_error_response(requests_mock):
5999
requests_mock.get(
60100
'https://blockchain.info/multiaddr',

blockapi/v2/api/blockchain_info.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,29 @@ def fetch_balances(self, address: str) -> FetchResult:
3535
)
3636

3737
def parse_balances(self, fetch_result: FetchResult) -> ParseResult:
38+
"""Parse balance from blockchain.info ``/multiaddr`` response.
39+
40+
Note: ``final_balance`` includes **unconfirmed** transactions (0-conf)
41+
and may therefore be higher than balances reported by Trezor/Blockbook
42+
or Haskoin for high-activity addresses. There is no blockchain.info
43+
endpoint that reliably returns confirmed-only balance (the ``/unspent``
44+
endpoint supports ``confirmations=1`` but is capped at 1 000 UTXOs
45+
with broken pagination).
46+
"""
3847
if not fetch_result.data:
3948
return ParseResult()
4049

4150
wallet = fetch_result.data.get('wallet', {})
4251
if not wallet:
4352
return ParseResult()
4453

54+
balance_raw = wallet.get('final_balance')
55+
if not balance_raw:
56+
return ParseResult()
57+
4558
balances = [
4659
BalanceItem.from_api(
47-
balance_raw=wallet.get('final_balance'),
60+
balance_raw=balance_raw,
4861
coin=self.coin,
4962
asset_type=AssetType.AVAILABLE,
5063
raw=fetch_result.data,

0 commit comments

Comments
 (0)