forked from hiero-ledger/hiero-sdk-python
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtoken_dissociate_transaction_test.py
More file actions
269 lines (186 loc) · 10.2 KB
/
Copy pathtoken_dissociate_transaction_test.py
File metadata and controls
269 lines (186 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
from __future__ import annotations
from unittest.mock import MagicMock, call
import pytest
from hiero_sdk_python.hapi.services import timestamp_pb2
from hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2 import (
SchedulableTransactionBody,
)
from hiero_sdk_python.tokens.token_dissociate_transaction import TokenDissociateTransaction
from hiero_sdk_python.transaction.transaction_id import TransactionId
pytestmark = pytest.mark.unit
def generate_transaction_id(account_id_proto):
"""Generate a unique transaction ID based on the account ID and the current timestamp."""
import time
current_time = time.time()
timestamp_seconds = int(current_time)
timestamp_nanos = int((current_time - timestamp_seconds) * 1e9)
tx_timestamp = timestamp_pb2.Timestamp(seconds=timestamp_seconds, nanos=timestamp_nanos)
return TransactionId(valid_start=tx_timestamp, account_id=account_id_proto)
# This test uses fixture mock_account_ids as parameter
def test_build_transaction_body(mock_account_ids):
"""Test building the token dissociate transaction body with valid account ID and token ID."""
account_id, _, node_account_id, token_id_1, _ = mock_account_ids
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
dissociate_tx.add_token_id(token_id_1)
dissociate_tx.transaction_id = generate_transaction_id(account_id)
dissociate_tx.node_account_id = node_account_id
transaction_body = dissociate_tx.build_transaction_body()
assert transaction_body.tokenDissociate.account.shardNum == account_id.shard
assert transaction_body.tokenDissociate.account.realmNum == account_id.realm
assert transaction_body.tokenDissociate.account.accountNum == account_id.num
assert len(transaction_body.tokenDissociate.tokens) == 1
assert transaction_body.tokenDissociate.tokens[0].tokenNum == token_id_1.num
# This test uses fixture mock_account_ids as parameter
def test_transaction_body_with_multiple_tokens(mock_account_ids):
"""Test building the transaction body for dissociating multiple tokens."""
account_id, operator_id, node_account_id, token_id_1, token_id_2 = mock_account_ids
token_ids = [token_id_1, token_id_2]
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
for token_id in token_ids:
dissociate_tx.add_token_id(token_id)
dissociate_tx.operator_account_id = operator_id
dissociate_tx.transaction_id = generate_transaction_id(account_id)
dissociate_tx.node_account_id = node_account_id
transaction_body = dissociate_tx.build_transaction_body()
assert transaction_body.tokenDissociate.account.shardNum == account_id.shard
assert transaction_body.tokenDissociate.account.realmNum == account_id.realm
assert transaction_body.tokenDissociate.account.accountNum == account_id.num
assert len(transaction_body.tokenDissociate.tokens) == len(token_ids)
for i, token_id in enumerate(token_ids):
assert transaction_body.tokenDissociate.tokens[i].tokenNum == token_id.num
# This test uses fixture mock_account_ids as parameter
def test_set_token_ids(mock_account_ids):
"""Test setting multiple token IDs at once for dissociation."""
account_id, _, _, token_id_1, token_id_2 = mock_account_ids
token_ids = [token_id_1, token_id_2]
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
dissociate_tx.set_token_ids(token_ids)
assert dissociate_tx.token_ids == token_ids
def test_validate_check_sum(mock_account_ids, mock_client, monkeypatch):
"""Test that validate_check_sum method correctly validates account and token IDs."""
account_id, _, _, token_id_1, token_id_2 = mock_account_ids
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
dissociate_tx.set_token_ids([token_id_1, token_id_2])
# Mock the validate_checksum methods on the classes to avoid assigning
# attributes on frozen dataclass instances.
monkeypatch.setattr(type(account_id), "validate_checksum", MagicMock())
token_cls = type(token_id_1)
monkeypatch.setattr(token_cls, "validate_checksum", MagicMock())
dissociate_tx._validate_check_sum(mock_client)
type(account_id).validate_checksum.assert_called_once_with(mock_client)
token_validate = type(token_id_1).validate_checksum
assert token_validate.call_count == 2
token_validate.assert_has_calls([call(mock_client), call(mock_client)])
def test_sign_transaction(mock_account_ids, mock_client):
"""Test signing the token dissociate transaction with a private key."""
account_id, _, _, token_id_1, _ = mock_account_ids
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
dissociate_tx.add_token_id(token_id_1)
dissociate_tx.transaction_id = generate_transaction_id(account_id)
private_key = MagicMock()
private_key.sign.return_value = b"signature"
private_key.public_key().to_bytes_raw.return_value = b"public_key"
dissociate_tx.freeze_with(mock_client)
dissociate_tx.sign(private_key)
node_id = mock_client.network.current_node._account_id
body_bytes = dissociate_tx._transaction_body_bytes[node_id]
assert len(dissociate_tx._signature_map[body_bytes].sigPair) == 1
sig_pair = dissociate_tx._signature_map[body_bytes].sigPair[0]
assert sig_pair.pubKeyPrefix == b"public_key"
assert sig_pair.ed25519 == b"signature"
def test_to_proto(mock_account_ids, mock_client):
"""Test converting the token dissociate transaction to protobuf format after signing."""
account_id, _, _, token_id_1, _ = mock_account_ids
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
dissociate_tx.add_token_id(token_id_1)
dissociate_tx.transaction_id = generate_transaction_id(account_id)
private_key = MagicMock()
private_key.sign.return_value = b"signature"
private_key.public_key().to_bytes_raw.return_value = b"public_key"
dissociate_tx.freeze_with(mock_client)
dissociate_tx.sign(private_key)
proto = dissociate_tx._to_proto()
assert proto.signedTransactionBytes
assert len(proto.signedTransactionBytes) > 0
def test_from_proto(mock_account_ids):
"""Test creating a TokenDissociateTransaction from a protobuf object."""
account_id, _, _, token_id_1, token_id_2 = mock_account_ids
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
dissociate_tx.set_token_ids([token_id_1, token_id_2])
proto_body = dissociate_tx._build_proto_body()
reconstructed_tx = TokenDissociateTransaction._from_proto(proto_body)
assert reconstructed_tx.account_id == account_id
assert len(reconstructed_tx.token_ids) == 2
assert reconstructed_tx.token_ids[0] == token_id_1
assert reconstructed_tx.token_ids[1] == token_id_2
def test_build_scheduled_body(mock_account_ids):
"""Test building a scheduled transaction body for token dissociate transaction."""
account_id, _, _, token_id_1, token_id_2 = mock_account_ids
token_ids = [token_id_1, token_id_2]
dissociate_tx = TokenDissociateTransaction()
dissociate_tx.set_account_id(account_id)
for token_id in token_ids:
dissociate_tx.add_token_id(token_id)
schedulable_body = dissociate_tx.build_scheduled_body()
# Verify the schedulable body has the correct structure and fields
assert isinstance(schedulable_body, SchedulableTransactionBody)
assert schedulable_body.HasField("tokenDissociate")
assert schedulable_body.tokenDissociate.account == account_id._to_proto()
assert len(schedulable_body.tokenDissociate.tokens) == len(token_ids)
for i, token_id in enumerate(token_ids):
assert schedulable_body.tokenDissociate.tokens[i] == token_id._to_proto()
def test_build_protobuf_body(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction."""
account_id, _, _, token_id_1, token_id_2 = mock_account_ids
token_ids = [token_id_1, token_id_2]
tx = TokenDissociateTransaction().set_account_id(account_id).set_token_ids(token_ids)
body = tx._build_proto_body()
assert body is not None
assert body.HasField("account")
assert body.account == account_id._to_proto()
assert len(body.tokens) == len(token_ids)
assert list(body.tokens) == [token._to_proto() for token in token_ids]
def test_build_protobuf_body_ignore_none_tokens(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction ignores none tokenId in list."""
account_id, _, _, token_id, _ = mock_account_ids
token_ids = [token_id, None]
tx = TokenDissociateTransaction().set_account_id(account_id).set_token_ids(token_ids)
body = tx._build_proto_body()
assert body is not None
assert body.HasField("account")
assert body.account == account_id._to_proto()
assert len(body.tokens) == 1
assert list(body.tokens) == [token_id._to_proto()]
def test_build_protobuf_body_without_account_id(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction without accountId."""
_, _, _, token_id_1, token_id_2 = mock_account_ids
token_ids = [token_id_1, token_id_2]
tx = TokenDissociateTransaction().set_token_ids(token_ids)
body = tx._build_proto_body()
assert body is not None
assert not body.HasField("account")
assert len(body.tokens) == len(token_ids)
assert list(body.tokens) == [token._to_proto() for token in token_ids]
def test_build_protobuf_body_without_token_ids(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction without tokenIds."""
account_id, _, _, _, _ = mock_account_ids
tx = TokenDissociateTransaction().set_account_id(account_id)
body = tx._build_proto_body()
assert body is not None
assert body.HasField("account")
assert body.account == account_id._to_proto()
assert len(body.tokens) == 0
def test_build_protobuf_body_missing_both_account_and_token_ids():
"""Test build protobuf body for a token dissociate transaction without accountId and tokenIds."""
tx = TokenDissociateTransaction()
body = tx._build_proto_body()
assert body is not None
assert not body.HasField("account")
assert len(body.tokens) == 0