amt.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env python3
  2. """
  3. test.modtest_d.amt: CoinAmt unit tests for the MMGen suite
  4. """
  5. from decimal import Decimal
  6. from mmgen.protocol import init_proto
  7. from mmgen.tx.new import parse_fee_spec
  8. from mmgen.cfg import Config
  9. from mmgen.amt import TokenAmt
  10. from ..include.common import cfg, vmsg
  11. def get_protos(data):
  12. return {coin: init_proto(cfg, coin, need_amt=True) for coin in set(d[0] for d in data)}
  13. def test_to_unit(data):
  14. protos = get_protos(data)
  15. for proto, amt, unit, chk in data:
  16. amt = protos[proto].coin_amt(amt)
  17. res = amt.to_unit(unit)
  18. vmsg(f' {proto.upper()} {amt.fmt(4):<24} => {res:<21} {unit}')
  19. if '.' in chk:
  20. assert res == Decimal(chk), f'{res} != {Decimal(chk)}'
  21. else:
  22. assert res == int(chk), f'{res} != {int(chk)}'
  23. return True
  24. def test_fee_spec(data):
  25. protos = get_protos(data)
  26. for proto, spec, amt, unit in data:
  27. vmsg(f' {proto.upper():6} {spec:<5} => {amt:<4} {unit}')
  28. res = parse_fee_spec(protos[proto], spec)
  29. assert res.amt == amt, f' {res.amt} != {amt}'
  30. assert res.unit == unit, f' {res.unit} != {unit}'
  31. return True
  32. def test_fmt(data):
  33. protos = get_protos(data)
  34. fs = ' {:5} {:18} {:<6} {:<5} {}'
  35. vmsg(fs.format('PROTO', 'INPUT', 'IWIDTH', 'PREC', 'FORMATTED'))
  36. for proto, amt, iwidth, prec, chk in data:
  37. amt = protos[proto].coin_amt(amt)
  38. args = (iwidth,) if iwidth else ()
  39. kwargs = {'prec': prec} if prec else {}
  40. res = amt.fmt(*args, **kwargs)
  41. vmsg(fs.format(
  42. proto.upper(),
  43. f'[{str(amt)}]',
  44. 'None' if iwidth is None else iwidth,
  45. 'None' if prec is None else prec,
  46. f'[{res}]'))
  47. assert res == chk, f'[{res}] != [{chk}]'
  48. return True
  49. class unit_tests:
  50. altcoin_deps = ('fee_spec_alt', 'to_unit_alt', 'token_amt')
  51. def to_unit(self, name, ut, desc='CoinAmt.to_unit() (BTC)'):
  52. return test_to_unit((
  53. ('btc', '0.00000001', 'satoshi', '1'),
  54. ('btc', '1.23456789', 'satoshi', '123456789')))
  55. def to_unit_alt(self, name, ut, desc='CoinAmt.to_unit() (LTC, BCH, ETH, XMR)'):
  56. return test_to_unit((
  57. ('ltc', '0.00000001', 'satoshi', '1'),
  58. ('ltc', '1.23456789', 'satoshi', '123456789'),
  59. ('bch', '0.00000001', 'satoshi', '1'),
  60. ('bch', '1.23456789', 'satoshi', '123456789'),
  61. ('eth', '1.234567890123456789', 'wei', '1234567890123456789'),
  62. ('eth', '1.234567890123456789', 'Kwei', '1234567890123456.789'),
  63. ('eth', '1.234567890123456789', 'Mwei', '1234567890123.456789'),
  64. ('eth', '1.234567890123456789', 'finney', '1234.567890123456789'),
  65. ('eth', '0.000000012345678901', 'Mwei', '12345.678901'),
  66. ('eth', '0.000000000000000001', 'Kwei', '0.001'),
  67. ('eth', '0.000000000000000001', 'Gwei', '0.000000001'),
  68. ('eth', '0.00000001', 'Gwei', '10'),
  69. ('eth', '1', 'Gwei', '1000000000'),
  70. ('eth', '1', 'finney', '1000'),
  71. ('xmr', '1', 'atomic', '1000000000000'),
  72. ('xmr', '0.000000000001', 'atomic', '1'),
  73. ('xmr', '1.234567890123', 'atomic', '1234567890123')))
  74. def fee_spec(self, name, ut, desc='fee spec parsing (BTC)'):
  75. return test_fee_spec((
  76. ('btc', '32s', '32', 'satoshi'),
  77. ('btc', '1s', '1', 'satoshi')))
  78. def fee_spec_alt(self, name, ut, desc='fee spec parsing (LTC, BCH, ETH, XMR)'):
  79. return test_fee_spec((
  80. ('ltc', '3.07s', '3.07', 'satoshi'),
  81. ('bch', '3.07s', '3.07', 'satoshi'),
  82. ('eth', '3.07G', '3.07', 'Gwei'),
  83. ('eth', '37M', '37', 'Mwei'),
  84. ('eth', '3701w', '3701', 'wei'),
  85. ('eth', '3.07M', '3.07', 'Mwei'),
  86. ('xmr', '3.07a', '3.07', 'atomic')))
  87. def fmt(self, name, ut, desc='column formatting (LTC, BCH, ETH, XMR)'):
  88. return test_fmt((
  89. ('btc', '1', None, None, '1 '),
  90. ('btc', '1.2', None, None, '1.2 '),
  91. ('btc', '1', 1, None, '1 '),
  92. ('btc', '1.2', 1, None, '1.2 '),
  93. ('btc', '12', None, None, '12 '),
  94. ('btc', '12.3', None, None, '12.3 '),
  95. ('btc', '12', 1, None, '12 '),
  96. ('btc', '12.3', 1, None, '12.3 '),
  97. ('btc', '12', 2, None, '12 '),
  98. ('btc', '12.3', 2, None, '12.3 '),
  99. ('btc', '12', 3, None, ' 12 '),
  100. ('btc', '12.3', 3, None, ' 12.3 '),
  101. ('ltc', '0', None, None, '0 '),
  102. ('ltc', '0.00000001', None, None, '0.00000001'),
  103. ('ltc', '0.00000001', 8, None, ' 0.00000001'),
  104. ('xmr', '1.234567890123', None, None, '1.234567890123'),
  105. ('xmr', '1', None, None, '1 '),
  106. ('xmr', '1', None, 4, '1 '),
  107. ('xmr', '123.456', None, None, '123.456 '),
  108. ('xmr', '123.456', 2, None, '123.456 '),
  109. ('xmr', '123.456', None, 4, '123.456 '),
  110. ('xmr', '123.456', 2, 4, '123.456 '),
  111. ('xmr', '1.234567890123', None, 4, '1.2345'),
  112. ('xmr', '1.234567890123', 8, 4, ' 1.2345'),
  113. ('xmr', '1', 8, 4, ' 1 '),
  114. ('xmr', '111', 8, 4, ' 111 ')))
  115. def token_amt(self, name, ut, desc='TokenAmt (ETH)'):
  116. for n, dec, unit, chk in (
  117. (1234567, 6, 'atomic', '1.234567'),
  118. ('1.234567', 6, None, '1.234567'),
  119. (1234567, 22, 'atomic', '0.0000000000000001234567'),
  120. ('0.0000000000000001234567', 22, None, '0.0000000000000001234567'),
  121. ):
  122. amt = TokenAmt(n, decimals=dec, from_unit=unit)
  123. amt_disp = amt.hl(color=False)
  124. vmsg(' ' + amt_disp)
  125. if unit == 'atomic':
  126. assert amt.to_unit('atomic') == n
  127. assert amt_disp == chk, f'{amt_disp} != {chk}'
  128. return True