term.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #!/usr/bin/env python3
  2. import sys,os
  3. pn = os.path.abspath(os.path.dirname(sys.argv[0]))
  4. parpar = os.path.dirname(os.path.dirname(pn))
  5. os.chdir(parpar)
  6. sys.path[0] = os.curdir
  7. from mmgen.common import *
  8. opts_data = {
  9. 'text': {
  10. 'desc': 'Interactively test MMGen terminal functionality',
  11. 'usage':'',
  12. 'options': """
  13. -h, --help Print this help message
  14. """,
  15. 'notes': """
  16. """
  17. }
  18. }
  19. cmd_args = opts.init(opts_data)
  20. from mmgen.term import get_char,get_char_raw,get_terminal_size
  21. import mmgen.term as term_mod
  22. def cmsg(m):
  23. msg('\n'+cyan(m))
  24. def confirm(m):
  25. if not keypress_confirm(m):
  26. if keypress_confirm('Are you sure you want to exit test?'):
  27. die(1,'Exiting test at user request')
  28. else:
  29. msg('Continuing...')
  30. def tt_start():
  31. m = fmt("""
  32. We will now test MMGen’s terminal capabilities.
  33. This is a non-automated test and requires user interaction.
  34. Continue?
  35. """)
  36. confirm(m.strip())
  37. def tt_get_terminal_size():
  38. cmsg('Testing get_terminal_size():')
  39. msg('X' * get_terminal_size().width)
  40. confirm('Do the X’s exactly fill the width of the screen?')
  41. def tt_color():
  42. cmsg('Testing color:')
  43. confirm(blue('THIS TEXT') + ' should be blue. Is it?')
  44. def tt_license():
  45. cmsg('Testing do_license_msg() with pager')
  46. ymsg('Press "w" to test the pager, then "c" to continue')
  47. do_license_msg()
  48. def tt_line_input():
  49. cmsg('Testing line_input():')
  50. msg(fmt("""
  51. At the Ready? prompt type and hold down "y".
  52. Then Enter some text, followed by held-down ENTER.
  53. The held-down "y" and ENTER keys should be blocked, not affecting the output
  54. on screen or entered text.
  55. """))
  56. get_char_raw('Ready? ',num_chars=1)
  57. reply = line_input('\nEnter text: ')
  58. confirm(f'Did you enter the text {reply!r}?')
  59. def tt_get_char(raw=False,one_char=False,sleep=0,immed_chars=''):
  60. funcname = ('get_char','get_char_raw')[raw]
  61. fs = fmt("""
  62. Press some keys in quick succession.
  63. {}{}{}
  64. {}
  65. When you’re finished, use Ctrl-C to exit.
  66. """).strip()
  67. m1 = (
  68. 'You should experience a delay with quickly repeated entry.',
  69. 'Your entry should be repeated back to you immediately.'
  70. )[raw]
  71. m2 = (
  72. '',
  73. f'\nA delay of {sleep} seconds will added before each prompt'
  74. )[bool(sleep)]
  75. m3 = (
  76. '',
  77. f'\nThe characters {immed_chars!r} will be repeated immediately, the others with delay.'
  78. )[bool(immed_chars)]
  79. m4 = 'The F1-F12 keys will be ' + (
  80. 'blocked entirely.'
  81. if one_char and not raw else
  82. "echoed AS A SINGLE character '\\x1b'."
  83. if one_char else
  84. 'echoed as a FULL CONTROL SEQUENCE.'
  85. )
  86. if g.platform == 'win':
  87. m4 = 'The Escape and F1-F12 keys will be returned as single characters.'
  88. kwargs = {}
  89. if one_char:
  90. kwargs.update({'num_chars':1})
  91. if sleep:
  92. kwargs.update({'sleep':sleep})
  93. if immed_chars:
  94. kwargs.update({'immed_chars':immed_chars})
  95. cmsg('Testing {}({}):'.format(
  96. funcname,
  97. ','.join(f'{a}={b!r}' for a,b in kwargs.items())
  98. ))
  99. msg(fs.format( m1, yellow(m2), yellow(m3), yellow(m4) ))
  100. try:
  101. while True:
  102. ret = getattr( term_mod, funcname )('Enter a letter: ',**kwargs)
  103. msg(f'You typed {ret!r}')
  104. except KeyboardInterrupt:
  105. msg('\nDone')
  106. def tt_urand():
  107. cmsg('Testing _get_random_data_from_user():')
  108. from mmgen.crypto import _get_random_data_from_user
  109. ret = _get_random_data_from_user(10,desc='data').decode()
  110. msg(f'USER ENTROPY (user input + keystroke timings):\n\n{fmt(ret," ")}')
  111. times = ret.splitlines()[1:]
  112. avg_prec = sum(len(t.split('.')[1]) for t in times) // len(times)
  113. if avg_prec < g.min_time_precision:
  114. ymsg(f'WARNING: Avg. time precision of only {avg_prec} decimal points. User entropy quality is degraded!')
  115. else:
  116. msg(f'Average time precision: {avg_prec} decimal points - OK')
  117. line_input('Press ENTER to continue: ')
  118. def tt_txview():
  119. cmsg('Testing tx.info.view_with_prompt() (try each viewing option)')
  120. from mmgen.tx import UnsignedTX
  121. fn = 'test/ref/0B8D5A[15.31789,14,tl=1320969600].rawtx'
  122. tx = UnsignedTX(filename=fn,quiet_open=True)
  123. while True:
  124. tx.info.view_with_prompt('View data for transaction?',pause=False)
  125. set_vt100()
  126. if not keypress_confirm('Continue testing transaction view?',default_yes=True):
  127. break
  128. if g.platform == 'linux':
  129. import termios,atexit
  130. fd = sys.stdin.fileno()
  131. old = termios.tcgetattr(fd)
  132. atexit.register(lambda: termios.tcsetattr(fd,termios.TCSADRAIN,old))
  133. tt_start()
  134. tt_get_terminal_size()
  135. tt_color()
  136. tt_license()
  137. set_vt100()
  138. tt_line_input()
  139. tt_urand()
  140. tt_txview()
  141. tt_get_char(one_char=True)
  142. tt_get_char(one_char=True,sleep=1)
  143. tt_get_char(one_char=True,raw=True)
  144. if g.platform == 'linux':
  145. tt_get_char(one_char=False)
  146. tt_get_char(one_char=False,immed_chars='asdf')
  147. tt_get_char(one_char=False,raw=True)
  148. else:
  149. tt_get_char(one_char=True,immed_chars='asdf')
  150. gmsg('\nTest completed')