Browse Source

test.py: add password_entry, mnemonic_entry tests

MMGen 5 years ago
parent
commit
7ed00d98e5
7 changed files with 71 additions and 6 deletions
  1. 1 0
      MANIFEST.in
  2. 8 4
      mmgen/seed.py
  3. 1 1
      mmgen/term.py
  4. 12 0
      test/misc/password_entry.py
  5. 1 1
      test/test-release.sh
  6. 2 0
      test/test.py
  7. 46 0
      test/test_py_d/ts_misc.py

+ 1 - 0
MANIFEST.in

@@ -11,6 +11,7 @@ include test/ref/ethereum_classic/*
 include test/ref/dash/*
 include test/ref/dash/*
 include test/ref/zcash/*
 include test/ref/zcash/*
 include test/ref/monero/*
 include test/ref/monero/*
+include test/misc/*.py
 
 
 include mmgen/altcoins/eth/rlp/LICENSE
 include mmgen/altcoins/eth/rlp/LICENSE
 include mmgen/altcoins/eth/pyethereum/LICENSE
 include mmgen/altcoins/eth/pyethereum/LICENSE

+ 8 - 4
mmgen/seed.py

@@ -541,13 +541,17 @@ class Mnemonic (SeedSourceUnenc):
 		longest_word = max(len(w) for w in wl)
 		longest_word = max(len(w) for w in wl)
 		from string import ascii_lowercase
 		from string import ascii_lowercase
 
 
-		m  = 'Enter your {}-word mnemonic, hitting ENTER or SPACE after each word.\n'
+		m  = 'Enter your {ml}-word mnemonic, hitting ENTER or SPACE after each word.\n'
 		m += "Optionally, you may use pad characters.  Anything you type that's not a\n"
 		m += "Optionally, you may use pad characters.  Anything you type that's not a\n"
-		m += 'lowercase letter will be treated as a “pad character”, i.e. it will simply\n'
+		m += 'lowercase letter will be treated as a {lq}pad character{rq}, i.e. it will simply\n'
 		m += 'be discarded.  Pad characters may be typed before, after, or in the middle\n'
 		m += 'be discarded.  Pad characters may be typed before, after, or in the middle\n'
-		m += "of words.  For each word, once you've typed {} characters total (including\n"
+		m += "of words.  For each word, once you've typed {lw} characters total (including\n"
 		m += 'pad characters) a pad character will enter the word.'
 		m += 'pad characters) a pad character will enter the word.'
-		msg(m.format(mn_len,longest_word))
+
+		# pexpect chokes on these utf8 chars under MSYS2
+		lq,rq = (('“','”'),('"','"'))[g.test_suite and g.platform=='win']
+
+		msg(m.format(ml=mn_len,lw=longest_word,lq=lq,rq=rq))
 
 
 		def get_word():
 		def get_word():
 			s,pad = '',0
 			s,pad = '',0

+ 1 - 1
mmgen/term.py

@@ -137,7 +137,7 @@ def _get_keypress_mswin_raw(prompt='',immed_chars='',prehold_protect=None,num_ch
 	msg_r(prompt)
 	msg_r(prompt)
 	sys.stderr.flush()
 	sys.stderr.flush()
 	ch = msvcrt.getch()
 	ch = msvcrt.getch()
-	if ch == 3: raise KeyboardInterrupt
+	if ch == b'\x03': raise KeyboardInterrupt
 	return ch
 	return ch
 
 
 def _get_keypress_mswin_stub(prompt='',immed_chars='',prehold_protect=None,num_chars=None):
 def _get_keypress_mswin_stub(prompt='',immed_chars='',prehold_protect=None,num_chars=None):

+ 12 - 0
test/misc/password_entry.py

@@ -0,0 +1,12 @@
+#!/usr/bin/env python3
+
+from mmgen.util import msg
+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)]
+
+pw = get_words_from_user(p)
+msg('Entered: {}'.format(' '.join(pw)))
+#msg(ascii(pw))

+ 1 - 1
test/test-release.sh

@@ -323,7 +323,7 @@ f_autosign_live='Autosign Live test complete'
 i_btc='Bitcoin mainnet'
 i_btc='Bitcoin mainnet'
 s_btc='The bitcoin (mainnet) daemon must both be running for the following tests'
 s_btc='The bitcoin (mainnet) daemon must both be running for the following tests'
 t_btc="
 t_btc="
-	$test_py --exclude regtest
+	$test_py --exclude regtest,autosign_minimal
 	$test_py --segwit
 	$test_py --segwit
 	$test_py --segwit-random
 	$test_py --segwit-random
 	$test_py --bech32
 	$test_py --bech32

+ 2 - 0
test/test.py

@@ -446,6 +446,7 @@ class CmdGroupMgr(object):
 		'ref':              ('TestSuiteRef',{}),
 		'ref':              ('TestSuiteRef',{}),
 		'ref_altcoin':      ('TestSuiteRefAltcoin',{}),
 		'ref_altcoin':      ('TestSuiteRefAltcoin',{}),
 		'tool':             ('TestSuiteTool',{'modname':'misc','full_data':True}),
 		'tool':             ('TestSuiteTool',{'modname':'misc','full_data':True}),
+		'input':            ('TestSuiteInput',{'modname':'misc','full_data':True}),
 		'regtest':          ('TestSuiteRegtest',{}),
 		'regtest':          ('TestSuiteRegtest',{}),
 #		'chainsplit':       ('TestSuiteChainsplit',{}),
 #		'chainsplit':       ('TestSuiteChainsplit',{}),
 		'ethdev':           ('TestSuiteEthdev',{}),
 		'ethdev':           ('TestSuiteEthdev',{}),
@@ -462,6 +463,7 @@ class CmdGroupMgr(object):
 					'ref3',
 					'ref3',
 					'ref_altcoin',
 					'ref_altcoin',
 					'tool',
 					'tool',
+					'input',
 					'autosign_minimal',
 					'autosign_minimal',
 					'regtest',
 					'regtest',
 					'ethdev')
 					'ethdev')

+ 46 - 0
test/test_py_d/ts_misc.py

@@ -77,6 +77,52 @@ class TestSuiteHelp(TestSuiteBase):
 		self._run_cmd('test.py',['-L'],cmd_dir='test',extra_desc='(cmd group list)')
 		self._run_cmd('test.py',['-L'],cmd_dir='test',extra_desc='(cmd group list)')
 		return self._run_cmd('test.py',['-l'],cmd_dir='test',extra_desc='(cmd list)')
 		return self._run_cmd('test.py',['-l'],cmd_dir='test',extra_desc='(cmd list)')
 
 
+class TestSuiteInput(TestSuiteBase):
+	'user input tests'
+	networks = ('btc',)
+	tmpdir_nums = []
+	cmd_group = (
+		('password_entry_noecho', (1,"utf8 password entry", [])),
+		('password_entry_echo',   (1,"utf8 password entry (echoed)", [])),
+		('mnemonic_entry',        (1,"stealth mnemonic entry", [])),
+	)
+
+	def password_entry(self,prompt,cmd_args):
+		t = self.spawn('test/misc/password_entry.py',cmd_args,cmd_dir='.')
+		pw = 'abc-α'
+		t.expect(prompt,pw)
+		ret = t.expect_getend('Entered: ')
+		assert ret == pw,'Password mismatch! {} != {}'.format(ret,pw)
+		return t
+
+	def password_entry_noecho(self):
+		if self.skip_for_win():
+			msg('Perform this test by hand on MSWin (it will fail with utf8 password):')
+			msg('  test/misc/password_entry.py')
+			return 'skip' # getpass() can't handle utf8, and pexpect double-escapes utf8, so skip
+		return self.password_entry('Enter passphrase: ',[])
+
+	def password_entry_echo(self):
+		if self.skip_for_win():
+			msg('Perform this test by hand on MSWin with utf8 password:')
+			msg('  test/misc/password_entry.py --echo-passphrase')
+			return 'skip' # pexpect double-escapes utf8, so skip
+		return self.password_entry('Enter passphrase (echoed): ',['--echo-passphrase'])
+
+	def mnemonic_entry(self):
+		mn = read_from_file(dfl_words_file).strip().split()[:12]
+		mn = ['foo'] + mn[:5] + ['realiz','realized'] + mn[5:]
+		t = self.spawn('mmgen-walletconv',['-S','-i','words','-o','words'])
+		t.expect('words: ','1')
+		t.expect('(Y/n): ','y')
+		stealth_mnemonic_entry(t,mn)
+		sid_chk = '5F9BC42F'
+		sid = t.expect_getend('Valid mnemonic data for Seed ID ')[:8]
+		assert sid == sid_chk,'Seed ID mismatch! {} != {}'.format(sid,sid_chk)
+		t.expect('to confirm: ','YES\n')
+		t.read()
+		return t
+
 class TestSuiteTool(TestSuiteMain,TestSuiteBase):
 class TestSuiteTool(TestSuiteMain,TestSuiteBase):
 	"tests for interactive 'mmgen-tool' commands"
 	"tests for interactive 'mmgen-tool' commands"
 	networks = ('btc',)
 	networks = ('btc',)