ct_misc.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2024 The MMGen Project <mmgen@tuta.io>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. test.cmdtest_d.ct_misc: Miscellaneous test groups for the cmdtest.py test suite
  20. """
  21. import sys, re
  22. from mmgen.util import die
  23. from ..include.common import cfg, start_test_daemons, stop_test_daemons, imsg
  24. from .common import get_file_with_ext, dfl_words_file
  25. from .ct_base import CmdTestBase
  26. from .ct_main import CmdTestMain
  27. class CmdTestDev(CmdTestBase):
  28. 'developer scripts'
  29. networks = ('btc',)
  30. cmd_group = (
  31. ('compute_file_chksum', 'scripts/compute-file-chksum.py'),
  32. ('create_bip_hd_chain_params', 'scripts/create-bip-hd-chain-params.py'),
  33. )
  34. tmpdir_nums = [99]
  35. color = True
  36. def _spawn(self, script, args):
  37. return self.spawn(script, args, cmd_dir='.', no_exec_wrapper=True)
  38. def compute_file_chksum(self):
  39. t = self._spawn('scripts/compute-file-chksum.py', ['test/ref/25EFA3[2.34].testnet.rawtx'])
  40. t.expect('3df942')
  41. return t
  42. def create_bip_hd_chain_params(self):
  43. t = self._spawn('scripts/create-bip-hd-chain-params.py', ['test/ref/altcoin/slip44-mini.json'])
  44. t.expect('[defaults]')
  45. t.expect(r"secp.*0488ade4.*0488b21e.*0'\/0\/0", regex=True)
  46. t.expect('[bip-44]')
  47. t.expect('[bip-49]')
  48. t.match_expect_list(
  49. ['0', 'BTC', 'x', 'm', 'P2SH', '049d7878', '049d7cb2', '80', '05', 'x', 'Bitcoin', '1'])
  50. return t
  51. class CmdTestMisc(CmdTestBase):
  52. 'miscellaneous tests (RPC backends, xmrwallet_txview, term)'
  53. networks = ('btc',)
  54. tmpdir_nums = [99]
  55. passthru_opts = ('daemon_data_dir', 'rpc_port')
  56. cmd_group = (
  57. ('rpc_backends', 'RPC backends'),
  58. ('bch_txview_legacy1', '‘mmgen-tool --coin=bch --cashaddr=0 txview terse=0’'),
  59. ('bch_txview_legacy2', '‘mmgen-tool --coin=bch --cashaddr=0 txview terse=1’'),
  60. ('bch_txview_cashaddr1', '‘mmgen-tool --coin=bch --cashaddr=1 txview terse=0’'),
  61. ('bch_txview_cashaddr2', '‘mmgen-tool --coin=bch --cashaddr=1 txview terse=1’'),
  62. ('xmrwallet_txview', '‘mmgen-xmrwallet txview’'),
  63. ('xmrwallet_txlist', '‘mmgen-xmrwallet txlist’'),
  64. ('coin_daemon_info', '‘examples/coin-daemon-info.py’'),
  65. ('examples_bip_hd', '‘examples/bip_hd.py’'),
  66. ('term_echo', 'term.set("echo")'),
  67. ('term_cleanup', 'term.register_cleanup()'),
  68. )
  69. need_daemon = True
  70. color = True
  71. def rpc_backends(self):
  72. backends = cfg._autoset_opts['rpc_backend'][1]
  73. for b in backends:
  74. t = self.spawn_chk('mmgen-tool', [f'--rpc-backend={b}', 'daemon_version'], extra_desc=f'({b})')
  75. return t
  76. def _bch_txview(self, view_pref, terse, expect):
  77. if cfg.no_altcoin:
  78. return 'skip'
  79. tx = 'test/ref/bitcoin_cash/895108-BCH[2.65913].rawtx'
  80. t = self.spawn('mmgen-tool', ['--coin=bch', f'--cashaddr={view_pref}', 'txview', tx, f'terse={terse}'])
  81. #t = self.spawn('mmgen-tool', ['--coin=bch', '--longhelp'])
  82. t.expect(expect)
  83. return t
  84. def bch_txview_legacy1(self):
  85. return self._bch_txview(0, 0, '[qzuffa536e0eqfwz3smapckhlw9wge4p5spvx5j7h7]')
  86. def bch_txview_legacy2(self):
  87. return self._bch_txview(0, 1, '[qzuffa536e0eqfwz3smapckhlw9wge4p5spvx5j7h7]')
  88. def bch_txview_cashaddr1(self):
  89. return self._bch_txview(1, 0, '[1HpynST7vkLn8yNtdrqPfeghexZk4sdB3W]')
  90. def bch_txview_cashaddr2(self):
  91. return self._bch_txview(1, 1, '[1HpynST7vkLn8yNtdrqPfeghexZk4sdB3W]')
  92. def xmrwallet_txview(self, op='txview'):
  93. if cfg.no_altcoin:
  94. return 'skip'
  95. files = get_file_with_ext('test/ref/monero', 'tx', no_dot=True, delete=False, return_list=True)
  96. t = self.spawn('mmgen-xmrwallet', [op] + files)
  97. res = t.read(strip_color=True)
  98. if op == 'txview':
  99. for s in (
  100. 'Amount: 0.74 XMR',
  101. 'Dest: 56VQ9M6k',
  102. ):
  103. assert s in res, f'{s} not in {res}'
  104. elif op == 'txlist':
  105. assert re.search('3EBD06-.*D94583-.*8BFA29-', res, re.DOTALL)
  106. return t
  107. def xmrwallet_txlist(self):
  108. return self.xmrwallet_txview(op='txlist')
  109. def examples_bip_hd(self):
  110. if cfg.no_altcoin:
  111. return 'skip'
  112. return self.spawn('examples/bip_hd.py', cmd_dir='.')
  113. def coin_daemon_info(self):
  114. if cfg.no_altcoin:
  115. coins = ['btc']
  116. else:
  117. coins = ['btc', 'ltc', 'eth']
  118. start_test_daemons('ltc', 'eth')
  119. t = self.spawn('examples/coin-daemon-info.py', coins, cmd_dir='.')
  120. for coin in coins:
  121. t.expect(coin.upper() + r'\s+mainnet\s+Up', regex=True)
  122. if cfg.pexpect_spawn:
  123. t.send('q')
  124. if not cfg.no_altcoin:
  125. stop_test_daemons('ltc', 'eth')
  126. return t
  127. def term_echo(self):
  128. def test_echo():
  129. t.expect('echo> ', 'foo\n')
  130. t.expect('foo')
  131. def test_noecho():
  132. t.expect('noecho> ', 'foo\n')
  133. import pexpect
  134. try:
  135. t.expect('foo')
  136. except pexpect.TIMEOUT:
  137. imsg('[input not echoed - OK]')
  138. else:
  139. die('TestSuiteException', 'Terminal echoed in noecho mode!')
  140. t.send('x')
  141. if self.skip_for_win('no termios support') or self.skip_for_mac('termios.ECHO issues'):
  142. return 'skip'
  143. t = self.spawn('test/misc/term_ni.py', ['echo'], cmd_dir='.', pexpect_spawn=True, timeout=1)
  144. t.p.logfile = None
  145. t.p.logfile_read = sys.stdout if cfg.verbose or cfg.exact_output else None
  146. t.p.logfile_send = None
  147. test_noecho()
  148. test_echo()
  149. test_noecho()
  150. return t
  151. def term_cleanup(self):
  152. if self.skip_for_win('no termios support'):
  153. return 'skip'
  154. return self.spawn('test/misc/term_ni.py', ['cleanup'], cmd_dir='.', pexpect_spawn=True)
  155. class CmdTestOutput(CmdTestBase):
  156. 'screen output'
  157. networks = ('btc',)
  158. cmd_group = (
  159. ('output_gr', (1, 'Greek text', [])),
  160. ('output_ru', (1, 'Russian text', [])),
  161. ('output_zh', (1, 'Chinese text', [])),
  162. ('output_jp', (1, 'Japanese text', [])),
  163. ('oneshot_warning', (1, 'Oneshot warnings', [])),
  164. ('oneshot_warning_term', (1, 'Oneshot warnings (pexpect_spawn)', []))
  165. )
  166. color = True
  167. def screen_output(self, lang):
  168. return self.spawn('test/misc/utf8_output.py', [lang], cmd_dir='.')
  169. def output_gr(self):
  170. return self.screen_output('gr')
  171. def output_ru(self):
  172. return self.screen_output('ru')
  173. def output_zh(self):
  174. return self.screen_output('zh')
  175. def output_jp(self):
  176. return self.screen_output('jp')
  177. def oneshot_warning(self, pexpect_spawn=None):
  178. t = self.spawn('test/misc/oneshot_warning.py', cmd_dir='.', pexpect_spawn=pexpect_spawn)
  179. nl = '\r\n' if sys.platform == 'win32' or t.pexpect_spawn else '\n'
  180. for s in (
  181. f'pw{nl}wg1',
  182. 'foo is experimental',
  183. 'wg2', 'The bar command is dangerous',
  184. 'wg3', 'baz variant alpha',
  185. 'wg4', 'baz variant beta',
  186. 'w1', 'foo variant alpha',
  187. 'w2', 'foo variant beta',
  188. 'w3', 'bar is experimental',
  189. 'pw',
  190. "passphrase from file 'A'",
  191. "passphrase from file 'B'",
  192. f'wg1{nl}wg2{nl}wg3{nl}wg4{nl}w1{nl}w2{nl}w3',
  193. 'pw',
  194. "passphrase from file 'A'",
  195. "passphrase from file 'B'",
  196. f'wg1{nl}wg2{nl}wg3{nl}wg4{nl}w1{nl}w2{nl}w3',
  197. 'bottom',
  198. ):
  199. t.expect(s)
  200. return t
  201. def oneshot_warning_term(self):
  202. if self.skip_for_win('no pexpect_spawn'):
  203. return 'skip'
  204. return self.oneshot_warning(pexpect_spawn=True)
  205. class CmdTestRefTX(CmdTestMain, CmdTestBase):
  206. 'create a reference transaction file (administrative command)'
  207. segwit_opts_ok = False
  208. passthru_opts = ('daemon_data_dir', 'rpc_port', 'coin', 'testnet')
  209. tmpdir_nums = [31, 32, 33, 34]
  210. need_daemon = True
  211. cmd_group = (
  212. ('ref_tx_addrgen1', (31, 'address generation (legacy)', [[[], 1]])),
  213. ('ref_tx_addrgen2', (32, 'address generation (compressed)', [[[], 1]])),
  214. ('ref_tx_addrgen3', (33, 'address generation (segwit)', [[[], 1]])),
  215. ('ref_tx_addrgen4', (34, 'address generation (bech32)', [[[], 1]])),
  216. ('ref_tx_txcreate',
  217. (31, 'transaction creation',
  218. ([['addrs'], 31], [['addrs'], 32], [['addrs'], 33], [['addrs'], 34]))
  219. ),
  220. )
  221. def __init__(self, trunner, cfgs, spawn):
  222. if cfgs:
  223. for n in self.tmpdir_nums:
  224. cfgs[str(n)].update({
  225. 'addr_idx_list': '1-2',
  226. 'segwit': n in (33, 34),
  227. 'dep_generators': {'addrs':'ref_tx_addrgen'+str(n)[-1]}
  228. })
  229. CmdTestMain.__init__(self, trunner, cfgs, spawn)
  230. def ref_tx_addrgen(self, atype):
  231. if atype not in self.proto.mmtypes:
  232. return
  233. return self.spawn('mmgen-addrgen', ['--outdir='+self.tmpdir, '--type='+atype, dfl_words_file, '1-2'])
  234. def ref_tx_addrgen1(self):
  235. return self.ref_tx_addrgen(atype='L')
  236. def ref_tx_addrgen2(self):
  237. return self.ref_tx_addrgen(atype='C')
  238. def ref_tx_addrgen3(self):
  239. return self.ref_tx_addrgen(atype='S')
  240. def ref_tx_addrgen4(self):
  241. return self.ref_tx_addrgen(atype='B')
  242. def ref_tx_txcreate(self, f1, f2, f3, f4):
  243. sources = ['31', '32']
  244. if 'S' in self.proto.mmtypes:
  245. sources += ['33']
  246. if 'B' in self.proto.mmtypes:
  247. sources += ['34']
  248. return self.txcreate_common(
  249. addrs_per_wallet = 2,
  250. sources = sources,
  251. add_args = ['--locktime=1320969600'],
  252. do_label = True)