Browse Source

Coverage support for tests via Python trace module

MMGen 7 years ago
parent
commit
8fe92de627
6 changed files with 160 additions and 122 deletions
  1. 7 0
      mmgen/test.py
  2. 133 114
      scripts/test-release.sh
  3. 5 2
      test/mmgen_pexpect.py
  4. 5 2
      test/sha256test.py
  5. 1 0
      test/test.py
  6. 9 4
      test/tooltest.py

+ 7 - 0
mmgen/test.py

@@ -107,3 +107,10 @@ def cmp_or_die(s,t,skip_ok=False):
 			'ERROR: recoded data:\n%s\ndiffers from original data:\n%s\n' %
 			'ERROR: recoded data:\n%s\ndiffers from original data:\n%s\n' %
 				(repr(t),repr(s))))
 				(repr(t),repr(s))))
 		sys.exit(3)
 		sys.exit(3)
+
+def init_coverage():
+	coverdir = os.path.join('test','trace')
+	acc_file = os.path.join('test','trace.acc')
+	try: os.mkdir(coverdir,0755)
+	except: pass
+	return coverdir,acc_file

+ 133 - 114
scripts/test-release.sh

@@ -5,15 +5,27 @@
 export MMGEN_TEST_SUITE=1
 export MMGEN_TEST_SUITE=1
 export MMGEN_NO_LICENSE=1
 export MMGEN_NO_LICENSE=1
 export PYTHONPATH=.
 export PYTHONPATH=.
+test_py='test/test.py'
+objtest_py='test/objtest.py'
+tooltest_py='test/tooltest.py'
+gentest_py='test/gentest.py'
+scrambletest_py='test/scrambletest.py'
+mmgen_tool='cmds/mmgen-tool'
+mmgen_keygen='cmds/mmgen-keygen'
+python='python'
+rounds=100 rounds_low=20 rounds_spec=500 gen_rounds=10
+monero_addrs='3,99,2,22-24,101-104'
 
 
 dfl_tests='obj misc_ni alts monero misc btc btc_tn btc_rt bch bch_rt ltc ltc_tn ltc_rt tool gen'
 dfl_tests='obj misc_ni alts monero misc btc btc_tn btc_rt bch bch_rt ltc ltc_tn ltc_rt tool gen'
 PROGNAME=$(basename $0)
 PROGNAME=$(basename $0)
-while getopts hinPt OPT
+while getopts hCfinPt OPT
 do
 do
 	case "$OPT" in
 	case "$OPT" in
 	h)  printf "  %-16s Test MMGen release\n" "${PROGNAME}:"
 	h)  printf "  %-16s Test MMGen release\n" "${PROGNAME}:"
 		echo   "  USAGE:           $PROGNAME [options] [branch] [tests]"
 		echo   "  USAGE:           $PROGNAME [options] [branch] [tests]"
 		echo   "  OPTIONS: '-h'  Print this help message"
 		echo   "  OPTIONS: '-h'  Print this help message"
+		echo   "           '-C'  Run tests in coverage mode"
+		echo   "           '-f'  Speed up the tests by using fewer rounds"
 		echo   "           '-i'  Install only; don't run tests"
 		echo   "           '-i'  Install only; don't run tests"
 		echo   "           '-n'  Don't install; test in place"
 		echo   "           '-n'  Don't install; test in place"
 		echo   "           '-P'  Don't pause between tests"
 		echo   "           '-P'  Don't pause between tests"
@@ -38,6 +50,17 @@ do
 		echo   "     gen     - gentest (all supported coins)"
 		echo   "     gen     - gentest (all supported coins)"
 		echo   "  By default, all tests are run"
 		echo   "  By default, all tests are run"
 		exit ;;
 		exit ;;
+	C)  test_py='test/test.py --coverage'
+		tooltest_py='test/tooltest.py --coverage'
+		fcov='test/trace.acc' dcov='test/trace'
+		python="python -m trace --count --file=$fcov --coverdir=$dcov"
+		objtest_py="$python $objtest_py"
+		gentest_py="$python $gentest_py"
+		scrambletest_py="$python $scrambletest_py"
+		mmgen_tool="$python $mmgen_tool"
+		mmgen_keygen="$python $mmgen_keygen"
+		rounds=2 rounds_low=2 rounds_spec=2 gen_rounds=2 monero_addrs='3,23,105' ;;
+	f)  rounds=2 rounds_low=2 rounds_spec=2 gen_rounds=2 monero_addrs='3,23,105' ;;
 	i)  INSTALL_ONLY=1 ;;
 	i)  INSTALL_ONLY=1 ;;
 	n)  NO_INSTALL=1 ;;
 	n)  NO_INSTALL=1 ;;
 	P)  NO_PAUSE=1 ;;
 	P)  NO_PAUSE=1 ;;
@@ -98,199 +121,197 @@ do_test() {
 i_obj='Data object'
 i_obj='Data object'
 s_obj='Testing data objects'
 s_obj='Testing data objects'
 t_obj=(
 t_obj=(
-	'test/objtest.py --coin=btc -S'
-	'test/objtest.py --coin=btc --testnet=1 -S'
-	'test/objtest.py --coin=ltc -S'
-	'test/objtest.py --coin=ltc --testnet=1 -S')
+	"$objtest_py --coin=btc -S"
+	"$objtest_py --coin=btc --testnet=1 -S"
+	"$objtest_py --coin=ltc -S"
+	"$objtest_py --coin=ltc --testnet=1 -S")
 f_obj='Data object test complete'
 f_obj='Data object test complete'
 
 
+i_misc_ni='Miscellaneous operations (non-interactive)'
+s_misc_ni='Testing miscellaneous operations (non-interactive)'
+t_misc_ni=(
+	"$python test/sha256test.py $rounds_spec")
+f_misc_ni='Miscellaneous non-interactive tests complete'
+
 i_alts='Gen-only altcoin'
 i_alts='Gen-only altcoin'
 s_alts='The following tests will test generation operations for all supported altcoins'
 s_alts='The following tests will test generation operations for all supported altcoins'
-ROUNDS=100
-ROUNDS_LOW=20
-ROUNDS_SPEC=500
 if [ "$MINGW" ]; then
 if [ "$MINGW" ]; then
 	t_alts=(
 	t_alts=(
-	'test/scrambletest.py'
-	'test/test.py -n altcoin_ref'
-	"test/gentest.py --coin=btc 2 $ROUNDS"
-	"test/gentest.py --coin=btc --type=compressed 2 $ROUNDS"
-	"test/gentest.py --coin=btc --type=segwit 2 $ROUNDS"
-	"test/gentest.py --coin=ltc 2 $ROUNDS"
-	"test/gentest.py --coin=ltc --type=compressed 2 $ROUNDS"
-	"test/gentest.py --coin=ltc --type=segwit 2 $ROUNDS"
-	"test/gentest.py --coin=zec 2 $ROUNDS"
-	"test/gentest.py --coin=etc 2 $ROUNDS"
-	"test/gentest.py --coin=eth 2 $ROUNDS")
+	"$scrambletest_py"
+	"$test_py -n altcoin_ref"
+	"$gentest_py --coin=btc 2 $rounds"
+	"$gentest_py --coin=btc --type=compressed 2 $rounds"
+	"$gentest_py --coin=btc --type=segwit 2 $rounds"
+	"$gentest_py --coin=ltc 2 $rounds"
+	"$gentest_py --coin=ltc --type=compressed 2 $rounds"
+	"$gentest_py --coin=ltc --type=segwit 2 $rounds"
+	"$gentest_py --coin=zec 2 $rounds"
+	"$gentest_py --coin=etc 2 $rounds"
+	"$gentest_py --coin=eth 2 $rounds")
 else
 else
 	t_alts=(
 	t_alts=(
-	'test/scrambletest.py'
-	'test/test.py -n altcoin_ref'
-	"test/gentest.py --coin=btc 2 $ROUNDS"
-	"test/gentest.py --coin=btc --type=compressed 2 $ROUNDS"
-	"test/gentest.py --coin=btc --type=segwit 2 $ROUNDS"
-	"test/gentest.py --coin=ltc 2 $ROUNDS"
-	"test/gentest.py --coin=ltc --type=compressed 2 $ROUNDS"
-	"test/gentest.py --coin=ltc --type=segwit 2 $ROUNDS"
-	"test/gentest.py --coin=zec 2 $ROUNDS"
-	"test/gentest.py --coin=zec --type=zcash_z 2 $ROUNDS_SPEC"
-	"test/gentest.py --coin=etc 2 $ROUNDS"
-	"test/gentest.py --coin=eth 2 $ROUNDS"
-
-	"test/gentest.py --coin=btc 2:ext $ROUNDS"
-	"test/gentest.py --coin=btc --type=compressed 2:ext $ROUNDS"
-	"test/gentest.py --coin=btc --type=segwit 2:ext $ROUNDS"
-	"test/gentest.py --coin=ltc 2:ext $ROUNDS"
-	"test/gentest.py --coin=ltc --type=compressed 2:ext $ROUNDS"
-#	"test/gentest.py --coin=ltc --type=segwit 2:ext $ROUNDS" # pycoin generates old-style LTC Segwit addrs
-	"test/gentest.py --coin=etc 2:ext $ROUNDS"
-	"test/gentest.py --coin=eth 2:ext $ROUNDS"
-	"test/gentest.py --coin=zec 2:ext $ROUNDS"
-	"test/gentest.py --coin=zec --type=zcash_z 2:ext $ROUNDS_SPEC"
-
-	"test/gentest.py --all 2:pycoin $ROUNDS_LOW"
-	"test/gentest.py --all 2:pyethereum $ROUNDS_LOW"
-	"test/gentest.py --all 2:keyconv $ROUNDS_LOW"
-	"test/gentest.py --all 2:zcash_mini $ROUNDS_LOW")
+	"$scrambletest_py"
+	"$test_py -n altcoin_ref"
+	"$gentest_py --coin=btc 2 $rounds"
+	"$gentest_py --coin=btc --type=compressed 2 $rounds"
+	"$gentest_py --coin=btc --type=segwit 2 $rounds"
+	"$gentest_py --coin=ltc 2 $rounds"
+	"$gentest_py --coin=ltc --type=compressed 2 $rounds"
+	"$gentest_py --coin=ltc --type=segwit 2 $rounds"
+	"$gentest_py --coin=zec 2 $rounds"
+	"$gentest_py --coin=zec --type=zcash_z 2 $rounds_spec"
+	"$gentest_py --coin=etc 2 $rounds"
+	"$gentest_py --coin=eth 2 $rounds"
+
+	"$gentest_py --coin=btc 2:ext $rounds"
+	"$gentest_py --coin=btc --type=compressed 2:ext $rounds"
+	"$gentest_py --coin=btc --type=segwit 2:ext $rounds"
+	"$gentest_py --coin=ltc 2:ext $rounds"
+	"$gentest_py --coin=ltc --type=compressed 2:ext $rounds"
+#	"$gentest_py --coin=ltc --type=segwit 2:ext $rounds" # pycoin generates old-style LTC Segwit addrs
+	"$gentest_py --coin=etc 2:ext $rounds"
+	"$gentest_py --coin=eth 2:ext $rounds"
+	"$gentest_py --coin=zec 2:ext $rounds"
+	"$gentest_py --coin=zec --type=zcash_z 2:ext $rounds_spec"
+
+	"$gentest_py --all 2:pycoin $rounds_low"
+	"$gentest_py --all 2:pyethereum $rounds_low"
+	"$gentest_py --all 2:keyconv $rounds_low"
+	"$gentest_py --all 2:zcash_mini $rounds_low")
 fi
 fi
 f_alts='Gen-only altcoin tests completed'
 f_alts='Gen-only altcoin tests completed'
 
 
+TMPDIR='/tmp/mmgen-test-release-'$(cat /dev/urandom | base32 - | head -n1 | cut -b 1-16)
+mkdir -p $TMPDIR
+
 i_monero='Monero'
 i_monero='Monero'
 s_monero='Testing generation and wallet creation operations for Monero'
 s_monero='Testing generation and wallet creation operations for Monero'
 s_monero='The monerod (mainnet) daemon must be running for the following tests'
 s_monero='The monerod (mainnet) daemon must be running for the following tests'
-ROUNDS=1000
 t_monero=(
 t_monero=(
-'python cmds/mmgen-keygen --accept-defaults --outdir $TMPDIR --coin=xmr test/ref/98831F3A.mmwords 3,99,2,22-24,101-104'
-'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallets $TMPDIR/988*XMR*akeys addrs=23'
-'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallets $TMPDIR/988*XMR*akeys addrs=103-200'
+"$mmgen_keygen --accept-defaults --outdir $TMPDIR --coin=xmr test/ref/98831F3A.mmwords $monero_addrs"
+"$mmgen_tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallets $TMPDIR/988*XMR*akeys addrs=23"
+"$mmgen_tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallets $TMPDIR/988*XMR*akeys addrs=103-200"
 'rm $TMPDIR/*-MoneroWallet*'
 'rm $TMPDIR/*-MoneroWallet*'
-'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallets $TMPDIR/988*XMR*akeys'
-'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR syncmonerowallets $TMPDIR/988*XMR*akeys addrs=3'
-'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR syncmonerowallets $TMPDIR/988*XMR*akeys addrs=23-29'
-'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR syncmonerowallets $TMPDIR/988*XMR*akeys'
+"$mmgen_tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallets $TMPDIR/988*XMR*akeys"
+"$mmgen_tool -q --accept-defaults --outdir $TMPDIR syncmonerowallets $TMPDIR/988*XMR*akeys addrs=3"
+"$mmgen_tool -q --accept-defaults --outdir $TMPDIR syncmonerowallets $TMPDIR/988*XMR*akeys addrs=23-29"
+"$mmgen_tool -q --accept-defaults --outdir $TMPDIR syncmonerowallets $TMPDIR/988*XMR*akeys"
 )
 )
 [ "$MINGW" ] && t_monero=("$t_monero")
 [ "$MINGW" ] && t_monero=("$t_monero")
 f_monero='Monero tests completed'
 f_monero='Monero tests completed'
 
 
-i_misc_ni='Miscellaneous operations (non-interactive)'
-s_misc_ni='Testing miscellaneous operations (non-interactive)'
-t_misc_ni=(
-	'test/sha256test.py')
-f_misc_ni='Miscellaneous non-interactive tests complete'
-
 i_misc='Miscellaneous operations (interactive)' # includes autosign!
 i_misc='Miscellaneous operations (interactive)' # includes autosign!
 s_misc='The bitcoin, bitcoin-abc and litecoin (mainnet) daemons must be running for the following tests'
 s_misc='The bitcoin, bitcoin-abc and litecoin (mainnet) daemons must be running for the following tests'
 t_misc=(
 t_misc=(
-	'test/test.py -On misc')
+	"$test_py -On misc")
 f_misc='Miscellaneous interactive tests test complete'
 f_misc='Miscellaneous interactive tests 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/test.py -On'
-	'test/test.py -On --segwit dfl_wallet main ref ref_other'
-	'test/test.py -On --segwit-random dfl_wallet main'
-	'test/tooltest.py rpc'
-	"scripts/compute-file-chksum.py $REFDIR/*testnet.rawtx >/dev/null 2>&1")
+	"$test_py -On"
+	"$test_py -On --segwit dfl_wallet main ref ref_other"
+	"$test_py -On --segwit-random dfl_wallet main"
+	"$tooltest_py rpc"
+	"$python scripts/compute-file-chksum.py $REFDIR/*testnet.rawtx >/dev/null 2>&1")
 f_btc='You may stop the bitcoin (mainnet) daemon if you wish'
 f_btc='You may stop the bitcoin (mainnet) daemon if you wish'
 
 
 i_btc_tn='Bitcoin testnet'
 i_btc_tn='Bitcoin testnet'
 s_btc_tn='The bitcoin testnet daemon must both be running for the following tests'
 s_btc_tn='The bitcoin testnet daemon must both be running for the following tests'
 t_btc_tn=(
 t_btc_tn=(
-	'test/test.py -On --testnet=1'
-	'test/test.py -On --testnet=1 --segwit dfl_wallet main ref ref_other'
-	'test/test.py -On --testnet=1 --segwit-random dfl_wallet main'
-	'test/tooltest.py --testnet=1 rpc')
+	"$test_py -On --testnet=1"
+	"$test_py -On --testnet=1 --segwit dfl_wallet main ref ref_other"
+	"$test_py -On --testnet=1 --segwit-random dfl_wallet main"
+	"$tooltest_py --testnet=1 rpc")
 f_btc_tn='You may stop the bitcoin testnet daemon if you wish'
 f_btc_tn='You may stop the bitcoin testnet daemon if you wish'
 
 
 i_btc_rt='Bitcoin regtest'
 i_btc_rt='Bitcoin regtest'
 s_btc_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
 s_btc_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
 t_btc_rt=(
 t_btc_rt=(
-	'test/test.py -On regtest'
-#	'test/test.py -On regtest_split' # no official B2X support, so skip
+	"$test_py -On regtest"
+#	"$test_py -On regtest_split" # no official B2X support, so skip
 	)
 	)
 f_btc_rt='Regtest (Bob and Alice) mode tests for BTC completed'
 f_btc_rt='Regtest (Bob and Alice) mode tests for BTC completed'
 
 
 i_bch='Bitcoin cash (BCH)'
 i_bch='Bitcoin cash (BCH)'
 s_bch='The bitcoin cash daemon (Bitcoin ABC) must both be running for the following tests'
 s_bch='The bitcoin cash daemon (Bitcoin ABC) must both be running for the following tests'
-t_bch=('test/test.py -On --coin=bch dfl_wallet main ref ref_other')
+t_bch=("$test_py -On --coin=bch dfl_wallet main ref ref_other")
 f_bch='You may stop the Bitcoin ABC daemon if you wish'
 f_bch='You may stop the Bitcoin ABC daemon if you wish'
 
 
 i_bch_rt='Bitcoin cash (BCH) regtest'
 i_bch_rt='Bitcoin cash (BCH) regtest'
 s_bch_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
 s_bch_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
-t_bch_rt=('test/test.py --coin=bch -On regtest')
+t_bch_rt=("$test_py --coin=bch -On regtest")
 f_bch_rt='Regtest (Bob and Alice) mode tests for BCH completed'
 f_bch_rt='Regtest (Bob and Alice) mode tests for BCH completed'
 
 
 i_b2x='Bitcoin 2X (B2X)'
 i_b2x='Bitcoin 2X (B2X)'
 s_b2x='The bitcoin 2X daemon (BTC1) must both be running for the following tests'
 s_b2x='The bitcoin 2X daemon (BTC1) must both be running for the following tests'
-t_b2x=('test/test.py -On --coin=b2x dfl_wallet main ref ref_other')
+t_b2x=("$test_py -On --coin=b2x dfl_wallet main ref ref_other")
 f_b2x='You may stop the Bitcoin 2X daemon if you wish'
 f_b2x='You may stop the Bitcoin 2X daemon if you wish'
 
 
 i_b2x_rt='Bitcoin 2X (B2X) regtest'
 i_b2x_rt='Bitcoin 2X (B2X) regtest'
 s_b2x_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
 s_b2x_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
-t_b2x_rt=('test/test.py --coin=b2x -On regtest')
+t_b2x_rt=("$test_py --coin=b2x -On regtest")
 f_b2x_rt='Regtest (Bob and Alice) mode tests for B2X completed'
 f_b2x_rt='Regtest (Bob and Alice) mode tests for B2X completed'
 
 
 i_ltc='Litecoin'
 i_ltc='Litecoin'
 s_ltc='The litecoin daemon must both be running for the following tests'
 s_ltc='The litecoin daemon must both be running for the following tests'
 t_ltc=(
 t_ltc=(
-	'test/test.py --coin=ltc -On dfl_wallet main'
-	'test/test.py --coin=ltc --segwit -On dfl_wallet main'
-	'test/test.py --coin=ltc --segwit-random -On dfl_wallet main'
-	'test/tooltest.py --coin=ltc rpc'
+	"$test_py --coin=ltc -On dfl_wallet main"
+	"$test_py --coin=ltc --segwit -On dfl_wallet main"
+	"$test_py --coin=ltc --segwit-random -On dfl_wallet main"
+	"$tooltest_py --coin=ltc rpc"
 )
 )
 f_ltc='You may stop the litecoin daemon if you wish'
 f_ltc='You may stop the litecoin daemon if you wish'
 
 
 i_ltc_tn='Litecoin testnet'
 i_ltc_tn='Litecoin testnet'
 s_ltc_tn='The litecoin testnet daemon must both be running for the following tests'
 s_ltc_tn='The litecoin testnet daemon must both be running for the following tests'
 t_ltc_tn=(
 t_ltc_tn=(
-	'test/test.py --coin=ltc -On --testnet=1'
-	'test/test.py --coin=ltc -On --testnet=1 --segwit dfl_wallet main ref ref_other'
-	'test/test.py --coin=ltc -On --testnet=1 --segwit-random dfl_wallet main'
-	'test/tooltest.py --coin=ltc --testnet=1 rpc')
+	"$test_py --coin=ltc -On --testnet=1"
+	"$test_py --coin=ltc -On --testnet=1 --segwit dfl_wallet main ref ref_other"
+	"$test_py --coin=ltc -On --testnet=1 --segwit-random dfl_wallet main"
+	"$tooltest_py --coin=ltc --testnet=1 rpc")
 f_ltc_tn='You may stop the litecoin testnet daemon if you wish'
 f_ltc_tn='You may stop the litecoin testnet daemon if you wish'
 
 
 i_ltc_rt='Litecoin regtest'
 i_ltc_rt='Litecoin regtest'
 s_ltc_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
 s_ltc_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
-t_ltc_rt=('test/test.py --coin=ltc -On regtest')
+t_ltc_rt=("$test_py --coin=ltc -On regtest")
 f_ltc_rt='Regtest (Bob and Alice) mode tests for LTC completed'
 f_ltc_rt='Regtest (Bob and Alice) mode tests for LTC completed'
 
 
 i_tool='Tooltest'
 i_tool='Tooltest'
-s_tool='The following tests will run test/tooltest.py for all supported coins'
+s_tool="The following tests will run '$tooltest_py' for all supported coins"
 t_tool=(
 t_tool=(
-	'test/tooltest.py --coin=btc util'
-	'test/tooltest.py --coin=btc cryptocoin'
-	'test/tooltest.py --coin=btc mnemonic'
-	'test/tooltest.py --coin=ltc cryptocoin'
-	'test/tooltest.py --coin=eth cryptocoin'
-	'test/tooltest.py --coin=etc cryptocoin'
-	'test/tooltest.py --coin=dash cryptocoin'
-	'test/tooltest.py --coin=doge cryptocoin'
-	'test/tooltest.py --coin=emc cryptocoin'
-	'test/tooltest.py --coin=zec cryptocoin')
+	"$tooltest_py --coin=btc util"
+	"$tooltest_py --coin=btc cryptocoin"
+	"$tooltest_py --coin=btc mnemonic"
+	"$tooltest_py --coin=ltc cryptocoin"
+	"$tooltest_py --coin=eth cryptocoin"
+	"$tooltest_py --coin=etc cryptocoin"
+	"$tooltest_py --coin=dash cryptocoin"
+	"$tooltest_py --coin=doge cryptocoin"
+	"$tooltest_py --coin=emc cryptocoin"
+	"$tooltest_py --coin=zec cryptocoin")
 
 
 [ "$MINGW" ] || {
 [ "$MINGW" ] || {
 	t_tool_len=${#t_tool[*]}
 	t_tool_len=${#t_tool[*]}
-	t_tool[$t_tool_len]='test/tooltest.py --coin=zec --type=zcash_z cryptocoin'
+	t_tool[$t_tool_len]="$tooltest_py --coin=zec --type=zcash_z cryptocoin"
 }
 }
 f_tool='tooltest tests completed'
 f_tool='tooltest tests completed'
 
 
 i_gen='Gentest'
 i_gen='Gentest'
-s_gen='The following tests will run test/gentest.py on mainnet and testnet for all supported coins'
+s_gen="The following tests will run '$gentest_py' on mainnet and testnet for all supported coins"
 t_gen=(
 t_gen=(
-	"test/gentest.py -q 2 $REFDIR/btcwallet.dump"
-	'test/gentest.py -q 1:2 10'
-	'test/gentest.py -q --type=segwit 1:2 10'
-	"test/gentest.py -q --testnet=1 2 $REFDIR/btcwallet-testnet.dump"
-	'test/gentest.py -q --testnet=1 1:2 10'
-	'test/gentest.py -q --testnet=1 --type=segwit 1:2 10'
-	"test/gentest.py -q --coin=ltc 2 $REFDIR/litecoin/ltcwallet.dump"
-	'test/gentest.py -q --coin=ltc 1:2 10'
-	'test/gentest.py -q --coin=ltc --type=segwit 1:2 10'
-	"test/gentest.py -q --coin=ltc --testnet=1 2 $REFDIR/litecoin/ltcwallet-testnet.dump"
-	'test/gentest.py -q --coin=ltc --testnet=1 1:2 10'
-	'test/gentest.py -q --coin=ltc --testnet=1 --type=segwit 1:2 10'
-	)
+	"$gentest_py -q 2 $REFDIR/btcwallet.dump"
+	"$gentest_py -q 1:2 $gen_rounds"
+	"$gentest_py -q --type=segwit 1:2 $gen_rounds"
+	"$gentest_py -q --testnet=1 2 $REFDIR/btcwallet-testnet.dump"
+	"$gentest_py -q --testnet=1 1:2 $gen_rounds"
+	"$gentest_py -q --testnet=1 --type=segwit 1:2 $gen_rounds"
+	"$gentest_py -q --coin=ltc 2 $REFDIR/litecoin/ltcwallet.dump"
+	"$gentest_py -q --coin=ltc 1:2 $gen_rounds"
+	"$gentest_py -q --coin=ltc --type=segwit 1:2 $gen_rounds"
+	"$gentest_py -q --coin=ltc --testnet=1 2 $REFDIR/litecoin/ltcwallet-testnet.dump"
+	"$gentest_py -q --coin=ltc --testnet=1 1:2 $gen_rounds"
+	"$gentest_py -q --coin=ltc --testnet=1 --type=segwit 1:2 $gen_rounds")
 f_gen='gentest tests completed'
 f_gen='gentest tests completed'
 
 
 [ -d .git -a -z "$NO_INSTALL"  -a -z "$TESTING" ] && {
 [ -d .git -a -z "$NO_INSTALL"  -a -z "$TESTING" ] && {
@@ -328,8 +349,6 @@ tests=$dfl_tests
 
 
 check_args
 check_args
 
 
-TMPDIR='/tmp/mmgen-test-release-'$(cat /dev/urandom | base32 - | head -n1 | cut -b 1-16)
-mkdir -p $TMPDIR
 run_tests "$tests"
 run_tests "$tests"
 rm -rf /tmp/mmgen-test-release-*
 rm -rf /tmp/mmgen-test-release-*
 
 

+ 5 - 2
test/mmgen_pexpect.py

@@ -21,7 +21,7 @@ test/mmgen_pexpect.py: pexpect implementation for MMGen test suites
 """
 """
 
 
 from mmgen.common import *
 from mmgen.common import *
-from mmgen.test import getrandstr,ok
+from mmgen.test import getrandstr,ok,init_coverage
 
 
 try:
 try:
 	import pexpect
 	import pexpect
@@ -111,6 +111,9 @@ class MMGenPexpect(object):
 			args = [(a,"'{}'".format(a))[' ' in a] for a in args]
 			args = [(a,"'{}'".format(a))[' ' in a] for a in args]
 
 
 		cmd_str = '{} {}'.format(cmd,' '.join(args)).replace('\\','/')
 		cmd_str = '{} {}'.format(cmd,' '.join(args)).replace('\\','/')
+		if opt.coverage:
+			fs = 'python -m trace --count --coverdir={} --file={} {c}'
+			cmd_str = fs.format(*init_coverage(),c=cmd_str)
 
 
 		if opt.log:
 		if opt.log:
 			log_fd.write(cmd_str+'\n')
 			log_fd.write(cmd_str+'\n')
@@ -148,7 +151,7 @@ class MMGenPexpect(object):
 	def ok(self,exit_val=0):
 	def ok(self,exit_val=0):
 		ret = self.p.wait()
 		ret = self.p.wait()
 #		Msg('expect: {} got: {}'.format(exit_val,ret))
 #		Msg('expect: {} got: {}'.format(exit_val,ret))
-		if ret != exit_val:
+		if ret != exit_val and not opt.coverage:
 			die(1,red('test.py: spawned program exited with value {}'.format(ret)))
 			die(1,red('test.py: spawned program exited with value {}'.format(ret)))
 		if opt.profile: return
 		if opt.profile: return
 		if opt.verbose or opt.exact_output:
 		if opt.verbose or opt.exact_output:

+ 5 - 2
test/sha256test.py

@@ -1,8 +1,11 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 
 
+
 import sys,os,hashlib
 import sys,os,hashlib
 from mmgen.sha256 import Sha256
 from mmgen.sha256 import Sha256
 
 
+random_rounds = int(sys.argv[1]) if len(sys.argv) == 2 else 500
+
 def msg(s): sys.stderr.write(s)
 def msg(s): sys.stderr.write(s)
 def green(s): return '\033[32;1m' + s + '\033[0m'
 def green(s): return '\033[32;1m' + s + '\033[0m'
 
 
@@ -34,7 +37,7 @@ def test_ref():
 
 
 def test_random(rounds):
 def test_random(rounds):
 	for i in range(rounds):
 	for i in range(rounds):
-		if not (i+1) % 10:
+		if i+1 in (1,rounds) or not (i+1) % 10:
 			msg('\rTesting random input data:    {:4}/{} '.format(i+1,rounds))
 			msg('\rTesting random input data:    {:4}/{} '.format(i+1,rounds))
 		dlen = int(os.urandom(4).encode('hex'),16) >> 18
 		dlen = int(os.urandom(4).encode('hex'),16) >> 18
 		compare_hashes(dlen,os.urandom(dlen))
 		compare_hashes(dlen,os.urandom(dlen))
@@ -43,4 +46,4 @@ def test_random(rounds):
 msg(green('Testing MMGen implementation of Sha256()\n'))
 msg(green('Testing MMGen implementation of Sha256()\n'))
 test_K()
 test_K()
 test_ref()
 test_ref()
-test_random(500)
+test_random(random_rounds)

+ 1 - 0
test/test.py

@@ -113,6 +113,7 @@ opts_data = lambda: {
 --, --longhelp      Print help message for long options (common options)
 --, --longhelp      Print help message for long options (common options)
 -b, --buf-keypress  Use buffered keypresses as with real human input
 -b, --buf-keypress  Use buffered keypresses as with real human input
 -c, --print-cmdline Print the command line of each spawned command
 -c, --print-cmdline Print the command line of each spawned command
+-C, --coverage      Produce code coverage info using trace module
 -d, --debug-scripts Turn on debugging output in executed scripts
 -d, --debug-scripts Turn on debugging output in executed scripts
 -x, --debug-pexpect Produce debugging output for pexpect calls
 -x, --debug-pexpect Produce debugging output for pexpect calls
 -D, --direct-exec   Bypass pexpect and execute a command directly (for
 -D, --direct-exec   Bypass pexpect and execute a command directly (for

+ 9 - 4
test/tooltest.py

@@ -20,7 +20,7 @@
 test/tooltest.py:  Tests for the 'mmgen-tool' utility
 test/tooltest.py:  Tests for the 'mmgen-tool' utility
 """
 """
 
 
-import sys,os,subprocess
+import sys,os,subprocess,binascii
 repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),os.pardir)))
 repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),os.pardir)))
 os.chdir(repo_root)
 os.chdir(repo_root)
 sys.path.__setitem__(0,repo_root)
 sys.path.__setitem__(0,repo_root)
@@ -28,12 +28,14 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
 
 
 # Import this _after_ local path's been added to sys.path
 # Import this _after_ local path's been added to sys.path
 from mmgen.common import *
 from mmgen.common import *
+from mmgen.test import *
 
 
 opts_data = lambda: {
 opts_data = lambda: {
 	'desc': "Test suite for the 'mmgen-tool' utility",
 	'desc': "Test suite for the 'mmgen-tool' utility",
 	'usage':'[options] [command]',
 	'usage':'[options] [command]',
 	'options': """
 	'options': """
 -h, --help          Print this help message
 -h, --help          Print this help message
+-C, --coverage      Produce code coverage info using trace module
 --, --longhelp      Print help message for long options (common options)
 --, --longhelp      Print help message for long options (common options)
 -l, --list-cmds     List and describe the tests and commands in this test suite
 -l, --list-cmds     List and describe the tests and commands in this test suite
 -L, --list-names    List the names of all tested 'mmgen-tool' commands
 -L, --list-names    List the names of all tested 'mmgen-tool' commands
@@ -158,7 +160,12 @@ if not opt.system:
 	os.environ['PYTHONPATH'] = repo_root
 	os.environ['PYTHONPATH'] = repo_root
 	mmgen_cmd = os.path.relpath(os.path.join(repo_root,'cmds',mmgen_cmd))
 	mmgen_cmd = os.path.relpath(os.path.join(repo_root,'cmds',mmgen_cmd))
 
 
-spawn_cmd = ([],['python'])[g.platform == 'win'] + [mmgen_cmd]
+spawn_cmd = [mmgen_cmd]
+if opt.coverage:
+	d,f = init_coverage()
+	spawn_cmd = ['python','-m','trace','--count','--coverdir='+d,'--file='+f] + spawn_cmd
+elif g.platform == 'win':
+	spawn_cmd = ['python'] + spawn_cmd
 
 
 add_spawn_args = ['--data-dir='+cfg['tmpdir']] + ['--{}{}'.format(
 add_spawn_args = ['--data-dir='+cfg['tmpdir']] + ['--{}{}'.format(
 		k.replace('_','-'),'='+getattr(opt,k) if getattr(opt,k) != True else '')
 		k.replace('_','-'),'='+getattr(opt,k) if getattr(opt,k) != True else '')
@@ -186,8 +193,6 @@ if opt.list_names:
 	msg('\n{}\n{}'.format(yellow('Untested commands:'),'\n'.join(uc)))
 	msg('\n{}\n{}'.format(yellow('Untested commands:'),'\n'.join(uc)))
 	die()
 	die()
 
 
-import binascii
-from mmgen.test import *
 from mmgen.tx import is_wif,is_coin_addr
 from mmgen.tx import is_wif,is_coin_addr
 
 
 msg_w = 35
 msg_w = 35