Skip to content

Commit

Permalink
Fix failing python functional tests
Browse files Browse the repository at this point in the history
  • Loading branch information
U65535F committed Jan 31, 2025
1 parent dab6fe2 commit 20e6095
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 109 deletions.
275 changes: 171 additions & 104 deletions tests/functional_tests/uri.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class URITest():
def run_test(self):
self.create()
self.test_monero_uri()

self.test_multi_uri()

def create(self):
print('Creating wallet')
wallet = Wallet()
Expand All @@ -63,111 +64,95 @@ def test_monero_uri(self):
quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string]

ok = False
try: res = wallet.make_uri()
try: res = wallet.make_uri(payments=[{}]) # no address
except: ok = True
assert ok

ok = False
try: res = wallet.make_uri(address = '')
except: ok = True
assert ok
ok = False
try: res = wallet.make_uri(address = 'kjshdkj')
try: res = wallet.make_uri(payments=[{'address': 'kjshdkj'}]) # invalid address
except: ok = True
assert ok

# single payment tests
for address in [
'42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm',
'4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY',
'8AsN91rznfkBGTY8psSNkJBg9SZgxxGGRUhGwRptBhgr5XSQ1XzmA9m8QAnoxydecSh5aLJXdrgXwTDMMZ1AuXsN1EX5Mtm'
]:
res = wallet.make_uri(address = address)
# basic address
res = wallet.make_uri(payments=[{'address': address}])
assert res.uri == 'monero:' + address
res = wallet.parse_uri(res.uri)
assert res.uri.address == address
assert res.uri.payment_id == ''
assert res.uri.amount == 0
assert res.uri.tx_description == ''
assert res.uri.recipient_name == ''
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
res = wallet.make_uri(address = address, amount = 11000000000)
assert res.uri == 'monero:' + address + '?tx_amount=0.011' or res.uri == 'monero:' + address + '?tx_amount=0.011000000000'
res = wallet.parse_uri(res.uri)
assert res.uri.address == address
assert res.uri.payment_id == ''
assert res.uri.amount == 11000000000
assert res.uri.tx_description == ''
assert res.uri.recipient_name == ''
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
parsed = wallet.parse_uri(res.uri)
assert len(parsed.uri['payments']) == 1
assert parsed.uri['payments'][0]['address'] == address
assert parsed.uri['payments'][0]['amount'] == 0
assert parsed.uri['payment_id'] == ''
assert parsed.uri['tx_description'] == ''

# with amount
res = wallet.make_uri(payments=[{
'address': address,
'amount': 11000000000
}])
assert 'tx_amount=0.011' in res.uri or 'tx_amount=0.011000000000' in res.uri
parsed = wallet.parse_uri(res.uri)
assert parsed.uri['payments'][0]['amount'] == 11000000000

address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'

res = wallet.make_uri(address = address, tx_description = utf8string[0])
assert res.uri == 'monero:' + address + '?tx_description=' + quoted_utf8string[0]
res = wallet.parse_uri(res.uri)
assert res.uri.address == address
assert res.uri.payment_id == ''
assert res.uri.amount == 0
assert res.uri.tx_description == utf8string[0]
assert res.uri.recipient_name == ''
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0

res = wallet.make_uri(address = address, recipient_name = utf8string[0])
assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0]
res = wallet.parse_uri(res.uri)
assert res.uri.address == address
assert res.uri.payment_id == ''
assert res.uri.amount == 0
assert res.uri.tx_description == ''
assert res.uri.recipient_name == utf8string[0]
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0

res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1])
assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1]
res = wallet.parse_uri(res.uri)
assert res.uri.address == address
assert res.uri.payment_id == ''
assert res.uri.amount == 0
assert res.uri.tx_description == utf8string[1]
assert res.uri.recipient_name == utf8string[0]
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0

res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000)
assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1]
res = wallet.parse_uri(res.uri)
assert res.uri.address == address
assert res.uri.payment_id == ''
assert res.uri.amount == 1000000000000
assert res.uri.tx_description == utf8string[1]
assert res.uri.recipient_name == utf8string[0]
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
# test desc
res = wallet.make_uri(
payments=[{'address': address}],
tx_description=utf8string[0]
)
assert 'tx_description=' + quoted_utf8string[0] in res.uri
parsed = wallet.parse_uri(res.uri)
assert parsed.uri['tx_description'] == utf8string[0]

# external payment ids are not supported anymore
# test recipient name in payment entry
res = wallet.make_uri(payments=[{
'address': address,
'recipient_name': utf8string[0]
}])
assert 'recipient_name=' + quoted_utf8string[0] in res.uri
parsed = wallet.parse_uri(res.uri)
assert parsed.uri['payments'][0]['recipient_name'] == utf8string[0]

# combined parameters
res = wallet.make_uri(
payments=[{
'address': address,
'amount': 1000000000000,
'recipient_name': utf8string[0]
}],
tx_description=utf8string[1]
)
parsed = wallet.parse_uri(res.uri)
assert parsed.uri['payments'][0]['amount'] == 1000000000000
assert parsed.uri['payments'][0]['recipient_name'] == utf8string[0]
assert parsed.uri['tx_description'] == utf8string[1]

# test payment ID rejection
ok = False
try: res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000, payment_id = '1' * 64)
try:
wallet.make_uri(
payments=[{'address': address}],
payment_id='1' * 64
)
except: ok = True
assert ok

# spaces must be encoded as %20
res = wallet.make_uri(address = address, tx_description = ' ' + utf8string[1] + ' ' + utf8string[0] + ' ', amount = 1000000000000)
assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&tx_description=%20' + quoted_utf8string[1] + '%20' + quoted_utf8string[0] + '%20'
res = wallet.parse_uri(res.uri)
assert res.uri.address == address
assert res.uri.payment_id == ''
assert res.uri.amount == 1000000000000
assert res.uri.tx_description == ' ' + utf8string[1] + ' ' + utf8string[0] + ' '
assert res.uri.recipient_name == ''
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0

# the example from the docs
# notes: spaces must be encoded as %20
# external payment ids are not supported anymore
# test URI parsing from docs
res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation')
assert res.uri.address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em'
assert res.uri.amount == 239390140000000
assert res.uri.tx_description == 'donation'
assert res.uri.recipient_name == ''
assert res.uri.payment_id == ''
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0

# malformed/invalid
assert len(res.uri['payments']) == 1
assert res.uri['payments'][0]['address'] == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em'
assert res.uri['payments'][0]['amount'] == 239390140000000
assert res.uri['tx_description'] == 'donation'


# test malformed/invalid URIs
for uri in [
'',
':',
Expand Down Expand Up @@ -203,26 +188,108 @@ def test_monero_uri(self):
ok = False
try: res = wallet.parse_uri(uri)
except: ok = True
assert ok, res

# unknown parameters but otherwise valid
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar')
assert res.uri.address == address
assert res.uri.amount == 239390140000000
assert res.unknown_parameters == ['foo=bar'], res
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux')
assert res.uri.address == address
assert res.uri.amount == 239390140000000
assert res.unknown_parameters == ['foo=bar', 'baz=quux'], res
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&%20=%20')
assert res.uri.address == address
assert res.uri.amount == 239390140000000
assert res.unknown_parameters == ['%20=%20'], res
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0])
assert res.uri.address == address
assert res.uri.amount == 239390140000000
assert res.unknown_parameters == [u'unknown=' + quoted_utf8string[0]], res
assert ok, f"Failed to reject invalid URI: {uri}"

# unknown parameter tests for single URI: unknown parameters but otherwise valid
print('Testing unknown parameters in single-URI')
test_cases = [
('monero:' + address + '?tx_amount=239.39014&foo=bar', ['foo=bar']),
('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux', ['foo=bar', 'baz=quux']),
('monero:' + address + '?tx_amount=239.39014&%20=%20', ['%20=%20']),
('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0],
[u'unknown=' + quoted_utf8string[0]])
]

for uri, expected_unknown in test_cases:
res = wallet.parse_uri(uri)
assert len(res.uri['payments']) == 1, "Should have single payment"
assert res.uri['payments'][0]['address'] == address
assert res.uri['payments'][0]['amount'] == 239390140000000
assert res.unknown_parameters == expected_unknown, \
f"Unexpected unknown params: {res.unknown_parameters}"

def test_multi_uri(self):
print('Testing multi-recipient URIs')
wallet = Wallet()
address1 = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
address2 = '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY'
utf8string = [u'えんしゅう', u'あまやかす']
quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string]

# multi-URI unknown parameter tests
print('Testing unknown parameters in multi-URI')
multi_uri_cases = [
(
f'monero:{address1};{address2}?tx_amount=0.5;0.2&foo=bar',
{'addresses': [address1, address2], 'amounts': [500000000000, 200000000000]},
['foo=bar']
),
(
f'monero:{address1};{address2}?tx_amount=1.0;0&recipient_name=Alice;&unknown_param=123',
{'addresses': [address1, address2], 'amounts': [1000000000000, 0], 'names': ['Alice', '']},
['unknown_param=123']
),
(
f'monero:{address1};{address2}?tx_description=Test&unknown1=val1&unknown2=val2',
{'addresses': [address1, address2], 'description': 'Test'},
['unknown1=val1', 'unknown2=val2']
),
(
f'monero:{address1};{address2}?recipient_name=Name1;Name2&tx_amount=0.1;0.2&special=%40%24%5E',
{'addresses': [address1, address2], 'amounts': [100000000000, 200000000000], 'names': ['Name1', 'Name2']},
['special=%40%24%5E']
)
]

for uri, expected, expected_unknown in multi_uri_cases:
res = wallet.parse_uri(uri)

# verify payment count
assert len(res.uri['payments']) == len(expected['addresses']), \
f"Expected {len(expected['addresses'])} payments, got {len(res.uri['payments'])}"

# check addresses and amounts
for i, payment in enumerate(res.uri['payments']):
assert payment['address'] == expected['addresses'][i], \
f"Address mismatch at position {i}"

if 'amounts' in expected:
assert payment['amount'] == expected['amounts'][i], \
f"Amount mismatch at position {i}"

if 'names' in expected:
assert payment['recipient_name'] == expected['names'][i], \
f"Name mismatch at position {i}"

# check desc
if 'description' in expected:
assert res.uri['tx_description'] == expected['description'], \
"Description mismatch"

# verify unknown parameters
assert res.unknown_parameters == expected_unknown, \
f"Unknown params mismatch. Expected {expected_unknown}, got {res.unknown_parameters}"

# test mixed parameter positions
res = wallet.parse_uri(
f'monero:{address1};{address2}?unknown_first=123&tx_amount=0.1;0.2&unknown_last=456'
)
assert res.unknown_parameters == ['unknown_first=123', 'unknown_last=456']
assert len(res.uri['payments']) == 2
assert res.uri['payments'][0]['amount'] == 100000000000
assert res.uri['payments'][1]['amount'] == 200000000000

# test special characters in unknown params
special_uri = f'monero:{address1};{address2}?weird_param={quoted_utf8string[0]}&tx_amount=1;2'
res = wallet.parse_uri(special_uri)
assert res.unknown_parameters == [u'weird_param=' + quoted_utf8string[0]]
assert res.uri['payments'][0]['amount'] == 1000000000000
assert res.uri['payments'][1]['amount'] == 2000000000000

# test multiple unknown params with same key
res = wallet.parse_uri(f'monero:{address1}?tx_amount=1&flag=1&flag=2')
assert res.unknown_parameters == ['flag=1', 'flag=2']
assert res.uri['payments'][0]['amount'] == 1000000000000


if __name__ == '__main__':
Expand Down
20 changes: 15 additions & 5 deletions utils/python-rpc/framework/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,21 +987,31 @@ def get_attribute(self, key):
}
return self.rpc.send_json_rpc_request(get_attribute)

def make_uri(self, address = '', payment_id = '', amount = 0, tx_description = '', recipient_name = ''):
def make_uri(self, payments, payment_id='', tx_description=''):
make_uri = {
'method': 'make_uri',
'jsonrpc': '2.0',
'params': {
'address': address,
'payments': payments,
'payment_id': payment_id,
'amount': amount,
'tx_description': tx_description,
'recipient_name': recipient_name,
},
'id': '0'
}
return self.rpc.send_json_rpc_request(make_uri)


def legacy_make_uri(self, address='', payment_id='', amount=0, tx_description='', recipient_name=''):
"""For backward compatibility with single-payment URIs"""
return self.make_uri(
payments=[{
'address': address,
'amount': amount,
'recipient_name': recipient_name
}],
payment_id=payment_id,
tx_description=tx_description
)

def parse_uri(self, uri):
parse_uri = {
'method': 'parse_uri',
Expand Down

0 comments on commit 20e6095

Please sign in to comment.