From 2b74f417499115f0d3a525f75b0e188ff1e7eff5 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 29 Oct 2022 20:10:24 +0000 Subject: [PATCH] test.py input: add `char` and `line` subgroups Testing: $ test/test.py --demo input.char $ test/test.py --demo input.line --- mmgen/data/version | 2 +- test/misc/input_func.py | 28 ++++++++ test/misc/password_entry.py | 17 ----- test/test_py_d/ts_input.py | 127 +++++++++++++++++++++++++++++++++++- 4 files changed, 155 insertions(+), 19 deletions(-) create mode 100755 test/misc/input_func.py delete mode 100755 test/misc/password_entry.py diff --git a/mmgen/data/version b/mmgen/data/version index 5f8c275d..ad266b1c 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -13.3.dev13 +13.3.dev14 diff --git a/test/misc/input_func.py b/test/misc/input_func.py new file mode 100755 index 00000000..4db17979 --- /dev/null +++ b/test/misc/input_func.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# this script is used both for interactive and automated testing + +import sys,os +os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(sys.argv[0]))))) +sys.path[0] = os.curdir + +from mmgen.common import * + +cmd_args = opts.init({'text': { 'desc': '', 'usage':'', 'options':'-e, --echo-passphrase foo' }}) + +if cmd_args[0] == 'passphrase': + from mmgen.ui import get_words_from_user + pw = get_words_from_user( + ('Enter passphrase: ','Enter passphrase (echoed): ')[bool(opt.echo_passphrase)] ) + msg('Entered: {}'.format(' '.join(pw))) +elif cmd_args[0] in ('get_char','line_input'): + from mmgen.term import get_char + from mmgen.ui import line_input + from ast import literal_eval + func_args = literal_eval(cmd_args[1]) + Msg(f'\n g.hold_protect_disable: {g.hold_protect_disable}') + Msg(' {name}( {args} )'.format( + name = cmd_args[0], + args = ', '.join(f'{k}={v!r}' for k,v in func_args.items()) + )) + ret = locals()[cmd_args[0]](**func_args) + Msg(' ==> {!r}'.format(ret)) diff --git a/test/misc/password_entry.py b/test/misc/password_entry.py deleted file mode 100755 index d3656783..00000000 --- a/test/misc/password_entry.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/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.common import * - -cmd_args = opts.init({'text': { 'desc': '', 'usage':'', 'options':'-e, --echo-passphrase foo' }}) - -p = ('Enter passphrase: ','Enter passphrase (echoed): ')[bool(opt.echo_passphrase)] - -from mmgen.ui import get_words_from_user -pw = get_words_from_user(p) -msg('Entered: {}'.format(' '.join(pw))) diff --git a/test/test_py_d/ts_input.py b/test/test_py_d/ts_input.py index fc9825b5..226c4a2d 100755 --- a/test/test_py_d/ts_input.py +++ b/test/test_py_d/ts_input.py @@ -10,6 +10,8 @@ ts_input.py: user input tests for the MMGen test.py test suite """ +import time + from ..include.common import * from .ts_base import * from .input import * @@ -21,6 +23,8 @@ class TestSuiteInput(TestSuiteBase): tmpdir_nums = [1] color = True cmd_group_in = ( + ('subgroup.char', []), + ('subgroup.line', []), ('subgroup.password', []), ('subgroup.misc', []), ('subgroup.wallet', []), @@ -28,10 +32,34 @@ class TestSuiteInput(TestSuiteBase): ('subgroup.dieroll', []), ) cmd_subgroups = { + 'char': ( + 'get_char() function', + ('get_char1', 'get_char()'), + ('get_char2', 'get_char() [multiple characters]'), + ('get_char3', 'get_char() [no prompt]'), + ('get_char4', 'get_char() [utf8]'), + ('get_char_term1', 'get_char() [term, utf8]'), + ('get_char_term2', 'get_char() [term, multiple characters]'), + ('get_char_term3', 'get_char() [term, prehold_protect=False]'), + ('get_char_term4', 'get_char() [term, immed_chars="xyz"]'), + ), + 'line': ( + 'line_input() function', + ('line_input', 'line_input()'), + ('line_input_term1', 'line_input() [term]'), + ('line_input_term2', 'line_input() [term, no hold protect]'), + ('line_input_insert', 'line_input() [inserted text]'), + ('line_input_insert_term1', 'line_input() [inserted text, term]'), + ('line_input_insert_term2', 'line_input() [inserted text, term, no hold protect]'), + ('line_input_edit_term', 'line_input() [inserted + edited text, term, utf8]'), + ('line_input_erase_term', 'line_input() [inserted + erased text, term]'), + ), 'password': ( 'password entry via line_input()', ('password_entry_noecho', 'utf8 password entry'), + ('password_entry_noecho_term', 'utf8 password entry [term]'), ('password_entry_echo', 'utf8 password entry (echoed)'), + ('password_entry_echo_term', 'utf8 password entry (echoed) [term]'), ), 'misc': ( 'miscellaneous user-level UI functions', @@ -190,8 +218,95 @@ class TestSuiteInput(TestSuiteBase): return t + def _input_func(self,func_name,arg_dfls,func_args,text,expect,term): + func_args = {k:v for k,v in zip(arg_dfls.keys(),func_args)} + t = self.spawn( + 'test/misc/input_func.py', + [func_name,repr(func_args)], + cmd_dir='.', + pexpect_spawn=term ) + imsg('Parameters:') + imsg(' terminal: {}'.format(term)) + imsg(' sending: {!r}'.format(text)) + imsg(' expecting: {!r}'.format(expect)) + imsg('\nFunction args:') + for k,v in func_args.items(): + imsg(' {:14} {!r}'.format(k+':',v)) + imsg_r('\nScript output: ') + prompt_add = (func_args['insert_txt'] if term else '') if func_name == 'line_input' else '' + t.expect( func_args['prompt'] + prompt_add, text ) + ret = t.expect_getend(' ==> ') + assert ret == repr(expect), f'Text mismatch! {ret} != {repr(expect)}' + return t + + def _get_char(self,func_args,text,expect,term): + arg_dfls = { + 'prompt': '', + 'immed_chars': '', + 'prehold_protect': True, + 'num_bytes': 5, + } + return self._input_func('get_char',arg_dfls,func_args,text,expect,term) + + def _line_input(self,func_args,text,expect,term): + arg_dfls = { + 'prompt': '', # positional + 'echo': True, + 'insert_txt': '', + 'hold_protect': True, + } + return self._input_func('line_input',arg_dfls,func_args,text+'\n',expect,term) + + def get_char1(self): + return self._get_char(['prompt> ','',True,5],'x','x',False) + + def get_char2(self): + return self._get_char(['prompt> ','',True,5],'xxxxx','xxxxx',False) + + def get_char3(self): + return self._get_char(['','',True,5],'x','x',False) + + def get_char4(self): + return self._get_char(['prompt> ','',True,2],'α','α',False) # UTF-8, must get 2 bytes + + def get_char_term1(self): + return self._get_char(['prompt> ','',True,2],'β','β',True) # UTF-8, must get 2 bytes + + def get_char_term2(self): + return self._get_char(['prompt> ','',True,5],'xxxxx','xxxxx',True) + + def get_char_term3(self): + return self._get_char(['','',False,5],'x','x',True) + + def get_char_term4(self): + return self._get_char(['prompt> ','xyz',False,5],'x','x',True) + + def line_input(self): + return self._line_input(['prompt> ',True,'',True],'foo','foo',False) + + def line_input_term1(self): + return self._line_input(['prompt> ',True,'',True],'foo','foo',True) + + def line_input_term2(self): + return self._line_input(['prompt> ',True,'',False],'foo','foo',True) + + def line_input_insert(self): + return self._line_input(['prompt> ',True,'inserted text',True],'foo','foo',False) + + def line_input_insert_term1(self): + return self._line_input(['prompt> ',True,'foo',True],'bar','foobar',True) + + def line_input_insert_term2(self): + return self._line_input(['prompt> ',True,'foo',False],'bar','foobar',True) + + def line_input_edit_term(self): + return self._line_input(['prompt> ',True,'φυφυ',True],'\b\bβαρ','φυβαρ',True) + + def line_input_erase_term(self): + return self._line_input(['prompt> ',True,'foobarbaz',True],Ctrl_U+'foobar','foobar',True) + def _password_entry(self,prompt,opts=[],term=False): - t = self.spawn( 'test/misc/password_entry.py', opts, cmd_dir='.', pexpect_spawn=term ) + t = self.spawn( 'test/misc/input_func.py', opts + ['passphrase'], cmd_dir='.', pexpect_spawn=term ) imsg('Terminal: {}'.format(term)) pw = 'abc-α' t.expect(prompt,pw+'\n') @@ -211,9 +326,19 @@ class TestSuiteInput(TestSuiteBase): def password_entry_noecho(self,term=False): return self._password_entry('Enter passphrase: ',term=term) + def password_entry_noecho_term(self): + if self.skip_for_win(): + return ('skip_warn','\n' + fmt(self.winskip_msg.format(''),strip_char='\t')) + return self.password_entry_noecho(term=True) + def password_entry_echo(self,term=False): return self._password_entry('Enter passphrase (echoed): ',['--echo-passphrase'],term=term) + def password_entry_echo_term(self): + if self.skip_for_win(): + return ('skip_warn','\n' + fmt(self.winskip_msg.format(' --echo-passphrase'),strip_char='\t')) + return self.password_entry_echo(term=True) + def _mn2hex(self,fmt,entry_mode='full',mn=None,pad_entry=False,enter_for_dfl=False): mn = mn or sample_mn[fmt]['mn'].split() t = self.spawn('mmgen-tool',['mn2hex_interactive','fmt='+fmt,'mn_len=12','print_mn=1'])