199 lines
5.2 KiB
Python
Executable file
199 lines
5.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import sys, os
|
|
pn = os.path.abspath(os.path.dirname(sys.argv[0]))
|
|
parpar = os.path.dirname(os.path.dirname(pn))
|
|
os.chdir(parpar)
|
|
sys.path[0] = os.curdir
|
|
|
|
from mmgen.cfg import Config, gc
|
|
from mmgen.color import yellow, blue, cyan, set_vt100
|
|
from mmgen.util import msg, ymsg, gmsg, fmt, fmt_list, die
|
|
|
|
commands = [
|
|
'start',
|
|
'get_terminal_size',
|
|
'color',
|
|
'license',
|
|
'line_input',
|
|
'urand',
|
|
'txview',
|
|
'get_char_one',
|
|
'get_char_one_raw',
|
|
]
|
|
|
|
match gc.platform:
|
|
case 'linux' | 'darwin':
|
|
commands.extend([
|
|
'get_char',
|
|
'get_char_immed_chars',
|
|
'get_char_raw',
|
|
])
|
|
case 'win32':
|
|
commands.extend([
|
|
'get_char_one_char_immed_chars',
|
|
])
|
|
|
|
opts_data = {
|
|
'text': {
|
|
'desc': 'Interactively test MMGen terminal functionality',
|
|
'usage': 'command',
|
|
'options': """
|
|
-h, --help Print this help message
|
|
""",
|
|
'notes': f"""
|
|
available commands for platform {gc.platform!r}:
|
|
{fmt_list(commands, fmt='col', indent=' ')}
|
|
"""
|
|
}
|
|
}
|
|
|
|
cfg = Config(opts_data=opts_data)
|
|
|
|
from mmgen.term import get_char_raw, get_terminal_size, get_term
|
|
from mmgen.ui import line_input, keypress_confirm, do_license_msg
|
|
import mmgen.term as term_mod
|
|
|
|
def cmsg(m):
|
|
msg('\n'+cyan(m))
|
|
|
|
def confirm(m):
|
|
if not keypress_confirm(cfg, m):
|
|
if keypress_confirm(cfg, 'Are you sure you want to exit test?'):
|
|
die(1, 'Exiting test at user request')
|
|
else:
|
|
msg('Continuing...')
|
|
|
|
def tt_start():
|
|
m = fmt("""
|
|
We will now test MMGen Wallet’s terminal capabilities.
|
|
This is a non-automated test and requires user interaction.
|
|
Continue?
|
|
""")
|
|
confirm(m.strip())
|
|
|
|
def tt_get_terminal_size():
|
|
cmsg('Testing get_terminal_size():')
|
|
msg('X' * get_terminal_size().width)
|
|
confirm('Do the X’s exactly fill the width of the screen?')
|
|
|
|
def tt_color():
|
|
cmsg('Testing color:')
|
|
confirm(blue('THIS TEXT') + ' should be blue. Is it?')
|
|
|
|
def tt_license():
|
|
cmsg('Testing do_license_msg() with pager')
|
|
ymsg('Press "w" to test the pager, then "c" to continue')
|
|
do_license_msg(cfg)
|
|
|
|
def tt_line_input():
|
|
set_vt100()
|
|
cmsg('Testing line_input():')
|
|
msg(fmt("""
|
|
At the Ready? prompt type and hold down "y".
|
|
Then Enter some text, followed by held-down ENTER.
|
|
The held-down "y" and ENTER keys should be blocked, not affecting the output
|
|
on screen or entered text.
|
|
"""))
|
|
get_char_raw('Ready? ', num_bytes=1)
|
|
reply = line_input(cfg, '\nEnter text: ')
|
|
confirm(f'Did you enter the text {reply!r}?')
|
|
|
|
def _tt_get_char(raw=False, one_char=False, immed_chars=''):
|
|
funcname = ('get_char', 'get_char_raw')[raw]
|
|
fs = fmt("""
|
|
Press some keys in quick succession.
|
|
{}{}
|
|
{}
|
|
When you’re finished, use Ctrl-C to exit.
|
|
""").strip()
|
|
m1 = (
|
|
'You should experience a delay with quickly repeated entry.',
|
|
'Your entry should be repeated back to you immediately.'
|
|
)[raw]
|
|
m2 = (
|
|
'',
|
|
f'\nThe characters {immed_chars!r} will be repeated immediately, the others with delay.'
|
|
)[bool(immed_chars)]
|
|
m3 = 'The F1-F12 keys will be ' + (
|
|
'blocked entirely.'
|
|
if one_char and not raw else
|
|
"echoed AS A SINGLE character '\\x1b'."
|
|
if one_char else
|
|
'echoed as a FULL CONTROL SEQUENCE.'
|
|
)
|
|
if gc.platform == 'win32':
|
|
if raw:
|
|
m3 = 'The Escape and F1-F12 keys will be returned as two-character strings.'
|
|
else:
|
|
m3 = 'The Escape and F1-F12 keys will be returned as single characters.'
|
|
kwargs = {}
|
|
if one_char:
|
|
kwargs.update({'num_bytes':1})
|
|
if immed_chars:
|
|
kwargs.update({'immed_chars':immed_chars})
|
|
|
|
cmsg('Testing {}({}):'.format(
|
|
funcname,
|
|
','.join(f'{a}={b!r}' for a, b in kwargs.items())
|
|
))
|
|
msg(fs.format(m1, yellow(m2), yellow(m3)))
|
|
|
|
try:
|
|
while True:
|
|
ret = getattr(term_mod, funcname)('Enter a letter: ', **kwargs)
|
|
msg(f'You typed {ret!r}')
|
|
except KeyboardInterrupt:
|
|
msg('\nDone')
|
|
|
|
def tt_urand():
|
|
cmsg('Testing _get_random_data_from_user():')
|
|
from mmgen.crypto import Crypto
|
|
ret = Crypto(cfg)._get_random_data_from_user(uchars=10, desc='data').decode()
|
|
msg(f'USER ENTROPY (user input + keystroke timings):\n\n{fmt(ret, " ")}')
|
|
times = ret.splitlines()[1:]
|
|
avg_prec = sum(len(t.split('.')[1]) for t in times) // len(times)
|
|
if avg_prec < gc.min_time_precision:
|
|
ymsg(f'WARNING: Avg. time precision of only {avg_prec} decimal points. User entropy quality is degraded!')
|
|
else:
|
|
msg(f'Average time precision: {avg_prec} decimal points - OK')
|
|
line_input(cfg, 'Press ENTER to continue: ')
|
|
|
|
def tt_txview():
|
|
cmsg('Testing tx.info.view_with_prompt() (try each viewing option)')
|
|
from mmgen.tx import UnsignedTX
|
|
fn = 'test/ref/0B8D5A[15.31789,14,tl=1320969600].rawtx'
|
|
tx = UnsignedTX(cfg=cfg, filename=fn, quiet_open=True)
|
|
while True:
|
|
tx.info.view_with_prompt('View data for transaction?', pause=False)
|
|
set_vt100()
|
|
if not keypress_confirm(cfg, 'Continue testing transaction view?', default_yes=True):
|
|
break
|
|
|
|
def tt_get_char_one():
|
|
_tt_get_char(one_char=True)
|
|
|
|
def tt_get_char_one_raw():
|
|
_tt_get_char(one_char=True, raw=True)
|
|
|
|
def tt_get_char():
|
|
_tt_get_char(one_char=False)
|
|
|
|
def tt_get_char_immed_chars():
|
|
_tt_get_char(one_char=False, immed_chars='asdf')
|
|
|
|
def tt_get_char_raw():
|
|
_tt_get_char(one_char=False, raw=True)
|
|
|
|
def tt_get_char_one_char_immed_chars():
|
|
_tt_get_char(one_char=True, immed_chars='asdf')
|
|
|
|
get_term().register_cleanup()
|
|
|
|
if cfg._args:
|
|
locals()['tt_'+cfg._args[0]]()
|
|
else:
|
|
for command in commands:
|
|
locals()['tt_'+command]()
|
|
|
|
gmsg('\nTest completed')
|