Skip to content

Commit 2e2d319

Browse files
author
Jeff Schroeder
committed
Full coverage of PythProductAccount.update_from()
The rest will come once I've mocked out more of the SolanaClient bits.
1 parent a0fff99 commit 2e2d319

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

pythclient/pythaccounts.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@ def __str__(self) -> str:
345345
def __repr__(self) -> str:
346346
return str(self)
347347

348+
def __iter__(self):
349+
for key, val in self.__dict__.items():
350+
if not key.startswith('_'):
351+
yield key, val
352+
348353

349354
class PythPriceInfo:
350355
"""

tests/test_product_account.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import mock
2+
import pytest
3+
4+
import pythclient.pythaccounts
5+
from pythclient.solana import SolanaPublicKey, SolanaClient
6+
from pythclient.pythaccounts import (
7+
PythProductAccount,
8+
_VERSION_2,
9+
_read_attribute_string,
10+
)
11+
12+
13+
@pytest.fixture
14+
def solana_client():
15+
return SolanaClient(
16+
endpoint="https://example.com",
17+
ws_endpoint="wss://example.com",
18+
)
19+
20+
21+
@pytest.fixture
22+
def product_account_bytes():
23+
return bytes(
24+
[
25+
61, 210, 182, 54, 134, 164, 80, 236, 114, 144, 223, 58, 30,
26+
11, 88, 60, 4, 129, 246, 81, 53, 30, 223, 167, 99, 111, 57, 174,
27+
213, 92, 248, 163, 10, 97, 115, 115, 101, 116, 95, 116, 121,
28+
112, 101, 6, 67, 114, 121, 112, 116, 111, 6, 115, 121, 109, 98,
29+
111, 108, 7, 66, 67, 72, 47, 85, 83, 68, 7, 99, 111, 117, 110,
30+
116, 114, 121, 2, 85, 83, 14, 113, 117, 111, 116, 101, 95, 99,
31+
117, 114, 114, 101, 110, 99, 121, 3, 85, 83, 68, 11, 100, 101,
32+
115, 99, 114, 105, 112, 116, 105, 111, 110, 7, 66, 67, 72, 47,
33+
85, 83, 68, 5, 116, 101, 110, 111, 114, 4, 83, 112, 111, 116,
34+
14, 103, 101, 110, 101, 114, 105, 99, 95, 115, 121, 109, 98,
35+
111, 108, 6, 66, 67, 72, 85, 83, 68
36+
]
37+
)
38+
39+
40+
@pytest.fixture
41+
def product_account(solana_client):
42+
product_account = PythProductAccount(
43+
key=SolanaPublicKey("5uKdRzB3FzdmwyCHrqSGq4u2URja617jqtKkM71BVrkw"),
44+
solana=solana_client,
45+
)
46+
product_account.attrs = {
47+
"asset_type": "Crypto",
48+
"symbol": "BCH/USD",
49+
"country": "US",
50+
"quote_currency": "USD",
51+
"description": "BCH/USD",
52+
"tenor": "Spot",
53+
"generic_symbol": "BCHUSD",
54+
}
55+
product_account.first_price_account_key = SolanaPublicKey(
56+
"5ALDzwcRJfSyGdGyhP3kP628aqBNHZzLuVww7o9kdspe",
57+
)
58+
return product_account
59+
60+
61+
def test_product_account_update_from(
62+
product_account, product_account_bytes, solana_client
63+
):
64+
actual = PythProductAccount(
65+
key=product_account.key,
66+
solana=solana_client,
67+
)
68+
assert actual.attrs == {}
69+
70+
actual.update_from(buffer=product_account_bytes, version=_VERSION_2)
71+
72+
assert dict(actual) == dict(product_account)
73+
74+
75+
def test_update_from_null_first_price_account_key(
76+
product_account, product_account_bytes, solana_client
77+
):
78+
actual = PythProductAccount(
79+
key=product_account.key,
80+
solana=solana_client,
81+
)
82+
product_account.first_price_account_key = None
83+
84+
# Zero out the first price account key
85+
bad_bytes = (
86+
bytes(b"\x00" * SolanaPublicKey.LENGTH)
87+
+ product_account_bytes[SolanaPublicKey.LENGTH:]
88+
)
89+
90+
actual.update_from(buffer=bad_bytes, version=_VERSION_2)
91+
92+
assert dict(actual) == dict(product_account)
93+
94+
95+
def test_product_account_update_from_invalid_attr_key(
96+
product_account, product_account_bytes, solana_client
97+
):
98+
actual = PythProductAccount(
99+
key=product_account.key,
100+
solana=solana_client,
101+
)
102+
103+
def fake_read_attribute_string(buffer: bytes, offset: int):
104+
results = _read_attribute_string(buffer, offset)
105+
if results[0] == "generic_symbol":
106+
return (None, results[1])
107+
return results
108+
109+
with mock.patch.object(pythclient.pythaccounts, "_read_attribute_string") as mocked:
110+
mocked.side_effect = fake_read_attribute_string
111+
112+
# Call PythProductAccount.update_from()
113+
actual.update_from(buffer=product_account_bytes, version=_VERSION_2)
114+
115+
del product_account.attrs["generic_symbol"]
116+
117+
assert dict(actual) == dict(product_account)
118+
119+
120+
@pytest.mark.parametrize("func", [str, repr])
121+
def test_human_readable(func, product_account):
122+
expected = (
123+
"PythProductAccount BCH/USD (5uKdRzB3FzdmwyCHrqSGq4u2URja617jqtKkM71BVrkw)"
124+
)
125+
assert func(product_account) == expected

0 commit comments

Comments
 (0)