ct_help.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2025 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet
  9. # https://gitlab.com/mmgen/mmgen-wallet
  10. """
  11. test.cmdtest_d.ct_help: helpscreen test group for the cmdtest.py test suite
  12. """
  13. import sys, os, time
  14. from mmgen.util import ymsg
  15. from mmgen.cfg import gc
  16. from ..include.common import cfg
  17. from .ct_base import CmdTestBase
  18. class CmdTestHelp(CmdTestBase):
  19. 'help, info and usage screens'
  20. networks = ('btc', 'ltc', 'bch', 'eth', 'xmr', 'doge')
  21. passthru_opts = ('daemon_data_dir', 'rpc_port', 'coin', 'testnet')
  22. cmd_group = (
  23. ('usage1', (1, 'usage message (via --usage)', [])),
  24. ('usage2', (1, 'usage message (via --usage, with --coin)', [])),
  25. ('usage3', (1, 'usage message (via bad invocation)', [])),
  26. ('usage4', (1, 'usage message (via bad invocation, with --coin)', [])),
  27. ('version', (1, 'version message', [])),
  28. ('license', (1, 'license message', [])),
  29. ('helpscreens', (1, 'help screens', [])),
  30. ('longhelpscreens', (1, 'help screens (--longhelp)', [])),
  31. ('show_hash_presets', (1, 'info screen (--show-hash-presets)', [])),
  32. ('tool_help', (1, '‘mmgen-tool’ usage screen', [])),
  33. ('tool_cmd_usage', (1, '‘mmgen-tool’ usage screen', [])),
  34. ('test_help', (1, '‘cmdtest.py’ help screens', [])),
  35. ('tooltest_help', (1, '‘tooltest.py’ help screens', [])),
  36. )
  37. def usage1(self):
  38. return self._usage('walletgen', ['--usage'], True, False, 0)
  39. def usage2(self):
  40. return self._usage('tool' if self.coin == 'xmr' else 'txcreate', ['--usage'], True, True, 0)
  41. def usage3(self):
  42. return self._usage('walletgen', ['foo'], True, False, 1)
  43. def usage4(self):
  44. return self._usage('tool' if self.coin == 'xmr' else 'txcreate', [], True, True, 1)
  45. def _usage(self, cmd_arg, args, no_passthru_opts, add_coin_opt, exit_val):
  46. if cmd := (None if self._gen_skiplist(cmd_arg) else cmd_arg):
  47. t = self.spawn(
  48. f'mmgen-{cmd}',
  49. ([f'--coin={self.coin}'] if add_coin_opt else []) + args,
  50. exit_val = exit_val,
  51. no_passthru_opts = no_passthru_opts)
  52. t.expect(f'USAGE: mmgen-{cmd}')
  53. return t
  54. return 'skip'
  55. def version(self):
  56. t = self.spawn('mmgen-tool', ['--version'], exit_val=0)
  57. t.expect('MMGEN-TOOL version')
  58. return t
  59. def license(self):
  60. t = self.spawn(
  61. 'mmgen-walletconv',
  62. ['--stdout', '--in-fmt=hex', '--out-fmt=hex'],
  63. env = {'MMGEN_NO_LICENSE':''},
  64. no_passthru_opts = True)
  65. t.expect('to continue: ', 'w')
  66. t.expect('TERMS AND CONDITIONS') # start of GPL text
  67. if cfg.pexpect_spawn:
  68. t.send('G')
  69. t.expect('return for a fee.') # end of GPL text
  70. if cfg.pexpect_spawn:
  71. t.send('q')
  72. t.expect('to continue: ', 'c')
  73. t.expect('data: ', 'beadcafe'*4 + '\n')
  74. t.expect('to confirm: ', 'YES\n')
  75. return t
  76. def spawn_chk_expect(self, *args, **kwargs):
  77. expect = kwargs.pop('expect')
  78. t = self.spawn(*args, **kwargs)
  79. t.expect(expect)
  80. if t.pexpect_spawn:
  81. time.sleep(0.4)
  82. t.send('q')
  83. t.read()
  84. t.ok()
  85. t.skip_ok = True
  86. return t
  87. def _gen_skiplist(self, scripts):
  88. def gen(scripts):
  89. if isinstance(scripts, str):
  90. scripts = [scripts]
  91. for script in scripts:
  92. d = gc.cmd_caps_data[script]
  93. if sys.platform == 'win32' and 'w' not in d.platforms:
  94. yield script
  95. elif not (d.use_coin_opt or self.proto.coin.lower() == 'btc'):
  96. yield script
  97. else:
  98. for cap in d.caps:
  99. if cap not in self.proto.mmcaps:
  100. yield script
  101. break
  102. return set(gen(scripts))
  103. def helpscreens(self, arg='--help', scripts=(), expect='USAGE:.*OPTIONS:', pager=True):
  104. scripts = list(scripts or gc.cmd_caps_data)
  105. cmdlist = sorted(set(scripts) - self._gen_skiplist(scripts))
  106. for cmdname in cmdlist:
  107. cmd_caps = gc.cmd_caps_data[cmdname]
  108. assert cmd_caps, cmdname
  109. t = self.spawn(
  110. f'mmgen-{cmdname}',
  111. [arg],
  112. extra_desc = f'(mmgen-{cmdname})',
  113. no_passthru_opts = not cmd_caps.use_coin_opt)
  114. t.expect(expect, regex=True)
  115. if pager and t.pexpect_spawn:
  116. time.sleep(0.2)
  117. t.send('q')
  118. t.read()
  119. t.ok()
  120. t.skip_ok = True
  121. return 'silent'
  122. def longhelpscreens(self):
  123. return self.helpscreens(arg='--longhelp', expect='USAGE:.*GLOBAL OPTIONS:')
  124. def show_hash_presets(self):
  125. return self.helpscreens(
  126. arg = '--show-hash-presets',
  127. scripts = (
  128. 'walletgen', 'walletconv', 'walletchk', 'passchg', 'subwalletgen',
  129. 'addrgen', 'keygen', 'passgen',
  130. 'txdo', 'swaptxdo', 'txsign', 'txbump'),
  131. expect = 'Available parameters.*Preset',
  132. pager = False)
  133. def tool_help(self):
  134. if os.getenv('PYTHONOPTIMIZE') == '2':
  135. ymsg('Skipping tool help with PYTHONOPTIMIZE=2 (no docstrings)')
  136. return 'skip'
  137. for arg in (
  138. 'help',
  139. 'usage',
  140. ):
  141. t = self.spawn_chk_expect(
  142. 'mmgen-tool',
  143. [arg],
  144. extra_desc = f'(mmgen-tool {arg})',
  145. expect = 'GENERAL USAGE')
  146. return t
  147. def tool_cmd_usage(self):
  148. if os.getenv('PYTHONOPTIMIZE') == '2':
  149. ymsg('Skipping tool cmd usage with PYTHONOPTIMIZE=2 (no docstrings)')
  150. return 'skip'
  151. from mmgen.main_tool import mods
  152. for cmdlist in mods.values():
  153. for cmd in cmdlist:
  154. t = self.spawn_chk('mmgen-tool', ['help', cmd], extra_desc=f'({cmd})')
  155. return t
  156. def test_help(self):
  157. for arg, expect in (
  158. ('--help', 'USAGE'),
  159. ('--list-cmds', 'AVAILABLE COMMANDS'),
  160. ('--list-cmd-groups', 'AVAILABLE COMMAND GROUPS')
  161. ):
  162. t = self.spawn_chk_expect(
  163. 'cmdtest.py',
  164. [arg],
  165. cmd_dir = 'test',
  166. extra_desc = f'(cmdtest.py {arg})',
  167. expect = expect)
  168. return t
  169. def tooltest_help(self):
  170. for arg, expect in (
  171. ('--list-cmds', 'Available commands'),
  172. ('--testing-status', 'Testing status')
  173. ):
  174. t = self.spawn_chk_expect(
  175. 'tooltest.py',
  176. [arg],
  177. cmd_dir = 'test',
  178. extra_desc = f'(tooltest.py {arg})',
  179. expect = expect)
  180. return t