Browse Source

test suite: use `match` statement where practicable (21 files)

The MMGen Project 2 months ago
parent
commit
4573e170ed

+ 77 - 69
test/cmdtest_d/autosign.py

@@ -143,29 +143,30 @@ class CmdTestAutosignBase(CmdTestBase):
 					raise
 					raise
 
 
 	def _create_removable_device(self):
 	def _create_removable_device(self):
-		if sys.platform == 'linux':
-			self.txdev.create()
-			self.txdev.attach(silent=True)
-			args = [
-				'-E', 'root_owner={}:{}'.format(os.getuid(), os.getgid()),
-				'-L', self.asi.dev_label,
-				str(self.txdev.img_path)]
-			redir = DEVNULL
-			for cmd in ('/sbin/mkfs.ext2', 'mkfs.ext2'):
-				try:
-					run([cmd] + args, stdout=redir, stderr=redir, check=True)
-					break
-				except:
-					if cmd == 'mkfs.ext2':
-						raise
-			self.txdev.detach(silent=True)
-		elif sys.platform == 'darwin':
-			cmd = [
-				'hdiutil', 'create', '-size', '10M', '-fs', 'exFAT',
-				'-volname', self.asi.dev_label,
-				str(self.fs_image_path)]
-			redir = DEVNULL if self.tr.quiet else None
-			run(cmd, stdout=redir, check=True)
+		match sys.platform:
+			case 'linux':
+				self.txdev.create()
+				self.txdev.attach(silent=True)
+				args = [
+					'-E', 'root_owner={}:{}'.format(os.getuid(), os.getgid()),
+					'-L', self.asi.dev_label,
+					str(self.txdev.img_path)]
+				redir = DEVNULL
+				for cmd in ('/sbin/mkfs.ext2', 'mkfs.ext2'):
+					try:
+						run([cmd] + args, stdout=redir, stderr=redir, check=True)
+						break
+					except:
+						if cmd == 'mkfs.ext2':
+							raise
+				self.txdev.detach(silent=True)
+			case 'darwin':
+				cmd = [
+					'hdiutil', 'create', '-size', '10M', '-fs', 'exFAT',
+					'-volname', self.asi.dev_label,
+					str(self.fs_image_path)]
+				redir = DEVNULL if self.tr.quiet else None
+				run(cmd, stdout=redir, check=True)
 
 
 	def _macOS_mount_fs_image(self, loc):
 	def _macOS_mount_fs_image(self, loc):
 		time.sleep(0.2)
 		time.sleep(0.2)
@@ -261,32 +262,35 @@ class CmdTestAutosignBase(CmdTestBase):
 		if self.live:
 		if self.live:
 			return
 			return
 		loc = getattr(self, asi)
 		loc = getattr(self, asi)
-		if sys.platform == 'linux':
-			self._set_e2label(loc.dev_label)
-			self.txdev.attach()
-			for _ in range(20):
-				if loc.device_inserted:
-					break
-				time.sleep(0.1)
-			else:
-				die(2, f'device insert timeout exceeded {loc.dev_label}')
-		elif sys.platform == 'darwin':
-			self._macOS_mount_fs_image(loc)
+
+		match sys.platform:
+			case 'linux':
+				self._set_e2label(loc.dev_label)
+				self.txdev.attach()
+				for _ in range(20):
+					if loc.device_inserted:
+						break
+					time.sleep(0.1)
+				else:
+					die(2, f'device insert timeout exceeded {loc.dev_label}')
+			case 'darwin':
+				self._macOS_mount_fs_image(loc)
 
 
 	def remove_device(self, asi='asi'):
 	def remove_device(self, asi='asi'):
 		if self.live:
 		if self.live:
 			return
 			return
 		loc = getattr(self, asi)
 		loc = getattr(self, asi)
-		if sys.platform == 'linux':
-			self.txdev.detach()
-			for _ in range(20):
-				if not loc.device_inserted:
-					break
-				time.sleep(0.1)
-			else:
-				die(2, f'device remove timeout exceeded {loc.dev_label}')
-		elif sys.platform == 'darwin':
-			self._macOS_eject_disk(loc.dev_label)
+		match sys.platform:
+			case 'linux':
+				self.txdev.detach()
+				for _ in range(20):
+					if not loc.device_inserted:
+						break
+					time.sleep(0.1)
+				else:
+					die(2, f'device remove timeout exceeded {loc.dev_label}')
+			case 'darwin':
+				self._macOS_eject_disk(loc.dev_label)
 
 
 	def _mount_ops(self, loc, cmd, *args, **kwargs):
 	def _mount_ops(self, loc, cmd, *args, **kwargs):
 		return getattr(getattr(self, loc), cmd)(*args, silent=self.silent_mount, **kwargs)
 		return getattr(getattr(self, loc), cmd)(*args, silent=self.silent_mount, **kwargs)
@@ -837,18 +841,19 @@ class CmdTestAutosign(CmdTestAutosignBase):
 		# create or delete 2 bad tx files
 		# create or delete 2 bad tx files
 		self.spawn(msg_only=True)
 		self.spawn(msg_only=True)
 		fns = [joinpath(self.asi.tx_dir, f'bad{n}.rawtx') for n in (1, 2)]
 		fns = [joinpath(self.asi.tx_dir, f'bad{n}.rawtx') for n in (1, 2)]
-		if op == 'create':
-			for fn in fns:
-				with open(fn, 'w') as fp:
-					fp.write('bad tx data\n')
-			self.bad_tx_count = 2
-		elif op == 'remove':
-			for fn in fns:
-				try:
-					os.unlink(fn)
-				except:
-					pass
-			self.bad_tx_count = 0
+		match op:
+			case 'create':
+				for fn in fns:
+					with open(fn, 'w') as fp:
+						fp.write('bad tx data\n')
+				self.bad_tx_count = 2
+			case 'remove':
+				for fn in fns:
+					try:
+						os.unlink(fn)
+					except:
+						pass
+				self.bad_tx_count = 0
 		self.do_umount()
 		self.do_umount()
 		self.remove_device()
 		self.remove_device()
 		return 'ok'
 		return 'ok'
@@ -871,26 +876,29 @@ class CmdTestAutosign(CmdTestAutosignBase):
 		self.insert_device()
 		self.insert_device()
 		self.do_mount()
 		self.do_mount()
 		os.makedirs(destdir, exist_ok=True)
 		os.makedirs(destdir, exist_ok=True)
-		if op.endswith('_invalid'):
-			fn = os.path.join(destdir, 'DEADBE[BTC].rawmsg.json')
-			if op == 'create_invalid':
-				with open(fn, 'w') as fp:
-					fp.write('bad data\n')
-				self.bad_msg_count += 1
-			elif op == 'remove_invalid':
-				os.unlink(fn)
-				self.bad_msg_count -= 1
-		else:
-			for fn in self.ref_msgfiles:
-				if op == 'copy':
+
+		match op:
+			case 'create_invalid' | 'remove_invalid':
+				fn = os.path.join(destdir, 'DEADBE[BTC].rawmsg.json')
+				if op == 'create_invalid':
+					with open(fn, 'w') as fp:
+						fp.write('bad data\n')
+					self.bad_msg_count += 1
+				else:
+					os.unlink(fn)
+					self.bad_msg_count -= 1
+			case 'copy':
+				for fn in self.ref_msgfiles:
 					if os.path.basename(fn) == 'ED405C[BTC].rawmsg.json': # contains bad Seed ID
 					if os.path.basename(fn) == 'ED405C[BTC].rawmsg.json': # contains bad Seed ID
 						self.bad_msg_count += 1
 						self.bad_msg_count += 1
 					else:
 					else:
 						self.good_msg_count += 1
 						self.good_msg_count += 1
 					imsg(f'Copying: {fn} -> {destdir}')
 					imsg(f'Copying: {fn} -> {destdir}')
 					shutil.copy2(fn, destdir)
 					shutil.copy2(fn, destdir)
-				elif op == 'remove_signed':
+			case 'remove_signed':
+				for fn in self.ref_msgfiles:
 					os.unlink(os.path.join(destdir, os.path.basename(fn).replace('rawmsg', 'sigmsg')))
 					os.unlink(os.path.join(destdir, os.path.basename(fn).replace('rawmsg', 'sigmsg')))
+
 		self.do_umount()
 		self.do_umount()
 		self.remove_device()
 		self.remove_device()
 		return 'ok'
 		return 'ok'

+ 51 - 47
test/cmdtest_d/ethdev.py

@@ -95,35 +95,36 @@ amt2 = '888.111122223333444455'
 
 
 def set_vbals(daemon_id):
 def set_vbals(daemon_id):
 	global vbal1, vbal2, vbal3, vbal4, vbal5, vbal6, vbal7, vbal9
 	global vbal1, vbal2, vbal3, vbal4, vbal5, vbal6, vbal7, vbal9
-	if daemon_id == 'geth':
-		vbal1 = '1.2288334'
-		vbal2 = '99.996560752'
-		vbal3 = '1.2314176'
-		vbal4 = '127.0287834'
-		vbal5 = '999904.14775104212345678'
-		vbal6 = '999904.14880104212345678'
-		vbal7 = '999902.91891764212345678'
-		vbal9 = '1.2262504'
-	elif daemon_id == 'reth':
-		vbal1 = '1.2288334'
-		vbal2 = '99.996560752'
-		vbal3 = '1.23142525'
-		vbal3 = '1.2314176'
-		vbal4 = '127.0287834'
-		vbal5 = '999904.14775104212345678'
-		vbal6 = '999904.14880104212345678'
-		vbal7 = '999902.91891764212345678'
-		vbal9 = '1.2262504'
-	else:
-		vbal1 = '1.2288396'
-		vbal2 = '99.997088092'
-		vbal3 = '1.23142525'
-		vbal3 = '1.2314246'
-		vbal4 = '127.0287896'
-		vbal5 = '999904.14828458212345678'
-		vbal6 = '999904.14933458212345678'
-		vbal7 = '999902.91944498212345678'
-		vbal9 = '1.226261'
+	match daemon_id:
+		case 'geth':
+			vbal1 = '1.2288334'
+			vbal2 = '99.996560752'
+			vbal3 = '1.2314176'
+			vbal4 = '127.0287834'
+			vbal5 = '999904.14775104212345678'
+			vbal6 = '999904.14880104212345678'
+			vbal7 = '999902.91891764212345678'
+			vbal9 = '1.2262504'
+		case 'reth':
+			vbal1 = '1.2288334'
+			vbal2 = '99.996560752'
+			vbal3 = '1.23142525'
+			vbal3 = '1.2314176'
+			vbal4 = '127.0287834'
+			vbal5 = '999904.14775104212345678'
+			vbal6 = '999904.14880104212345678'
+			vbal7 = '999902.91891764212345678'
+			vbal9 = '1.2262504'
+		case _:
+			vbal1 = '1.2288396'
+			vbal2 = '99.997088092'
+			vbal3 = '1.23142525'
+			vbal3 = '1.2314246'
+			vbal4 = '127.0287896'
+			vbal5 = '999904.14828458212345678'
+			vbal6 = '999904.14933458212345678'
+			vbal7 = '999902.91944498212345678'
+			vbal9 = '1.226261'
 
 
 coin = cfg.coin
 coin = cfg.coin
 
 
@@ -275,16 +276,17 @@ class CmdTestEthdevMethods:
 		] + (['--wait'] if mmgen_cmd == 'txdo' else [])
 		] + (['--wait'] if mmgen_cmd == 'txdo' else [])
 
 
 		contract_addr = self._get_contract_address(dfl_devaddr)
 		contract_addr = self._get_contract_address(dfl_devaddr)
-		if key == 'Token':
-			self.write_to_tmpfile(f'token_addr{num}', contract_addr+'\n')
-		elif key == 'thorchain_router':
-			from mmgen.fileutil import write_data_to_file
-			write_data_to_file(
-				self.cfg,
-				thorchain_router_addr_file,
-				contract_addr + '\n',
-				ask_overwrite = False,
-				quiet = True)
+		match key:
+			case 'Token':
+				self.write_to_tmpfile(f'token_addr{num}', contract_addr+'\n')
+			case 'thorchain_router':
+				from mmgen.fileutil import write_data_to_file
+				write_data_to_file(
+					self.cfg,
+					thorchain_router_addr_file,
+					contract_addr + '\n',
+					ask_overwrite = False,
+					quiet = True)
 
 
 		if mmgen_cmd == 'txdo':
 		if mmgen_cmd == 'txdo':
 			args += ['-k', keyfile]
 			args += ['-k', keyfile]
@@ -395,10 +397,11 @@ class CmdTestEthdevMethods:
 
 
 		silence()
 		silence()
 		usr_addrs = list(map(gen_addr, usr_mmaddrs))
 		usr_addrs = list(map(gen_addr, usr_mmaddrs))
-		if op == 'show_bals':
-			await show_bals(await self.rpc)
-		elif op == 'fund_user':
-			await fund_user(await self.rpc)
+		match op:
+			case 'show_bals':
+				await show_bals(await self.rpc)
+			case 'fund_user':
+				await fund_user(await self.rpc)
 		end_silence()
 		end_silence()
 		return 'ok'
 		return 'ok'
 
 
@@ -907,10 +910,11 @@ class CmdTestEthdev(CmdTestEthdevMethods, CmdTestBase, CmdTestShared):
 		t = self.spawn(
 		t = self.spawn(
 			'mmgen-cli',
 			'mmgen-cli',
 			[f'--coin={self.proto.coin}', '--regtest=1', 'eth_getBalance', '0x'+dfl_devaddr, 'latest'])
 			[f'--coin={self.proto.coin}', '--regtest=1', 'eth_getBalance', '0x'+dfl_devaddr, 'latest'])
-		if self.daemon.id == 'geth':
-			t.expect('0x33b2e3c91ec0e9113986000')
-		elif self.daemon.id == 'reth':
-			t.expect('0xd3c21bab45fb313f0000')
+		match self.daemon.id:
+			case 'geth':
+				t.expect('0x33b2e3c91ec0e9113986000')
+			case 'reth':
+				t.expect('0xd3c21bab45fb313f0000')
 		return t
 		return t
 
 
 	async def _wallet_upgrade(self, src_fn, expect1, expect2=None):
 	async def _wallet_upgrade(self, src_fn, expect1, expect2=None):

+ 10 - 9
test/cmdtest_d/httpd/etherscan.py

@@ -22,15 +22,16 @@ class EtherscanServer(HTTPD):
 	content_type = 'text/html'
 	content_type = 'text/html'
 
 
 	def make_response_body(self, method, environ):
 	def make_response_body(self, method, environ):
-		if method == 'GET':
-			target = 'form'
-		elif method == 'POST':
-			target = 'result'
-			length = int(environ.get('CONTENT_LENGTH', '0'))
-			qs = environ['wsgi.input'].read(length).decode()
-			tx = [s for s in qs.split('&') if 'RawTx=' in s][0].split('=')[1]
-			keccak_256 = get_keccak()
-			txid = '0x' + keccak_256(bytes.fromhex(tx[2:])).hexdigest()
+		match method:
+			case 'GET':
+				target = 'form'
+			case 'POST':
+				target = 'result'
+				length = int(environ.get('CONTENT_LENGTH', '0'))
+				qs = environ['wsgi.input'].read(length).decode()
+				tx = [s for s in qs.split('&') if 'RawTx=' in s][0].split('=')[1]
+				keccak_256 = get_keccak()
+				txid = '0x' + keccak_256(bytes.fromhex(tx[2:])).hexdigest()
 
 
 		with open(f'test/ref/ethereum/etherscan-{target}.html') as fh:
 		with open(f'test/ref/ethereum/etherscan-{target}.html') as fh:
 			text = fh.read()
 			text = fh.read()

+ 15 - 14
test/cmdtest_d/include/input.py

@@ -47,20 +47,21 @@ def stealth_mnemonic_entry(t, mne, mn, entry_mode, pad_entry=False):
 			ret.append(w)
 			ret.append(w)
 		return ret
 		return ret
 
 
-	if entry_mode == 'fixed':
-		mn = ['bkr'] + mn[:5] + ['nfb'] + mn[5:]
-		ssl = mne.uniq_ss_len
-		def gen_mn():
-			for w in mn:
-				if len(w) >= ssl:
-					yield w[:ssl]
-				else:
-					yield w[0] + 'z\b' + '#' * (ssl-len(w)) + w[1:]
-		mn = list(gen_mn())
-	elif entry_mode in ('full', 'short'):
-		mn = ['fzr'] + mn[:5] + ['grd', 'grdbxm'] + mn[5:]
-		mn = pad_mnemonic(mn, mne.em.ss_len)
-		mn[10] = '@#$%*##' + mn[10]
+	match entry_mode:
+		case 'fixed':
+			mn = ['bkr'] + mn[:5] + ['nfb'] + mn[5:]
+			ssl = mne.uniq_ss_len
+			def gen_mn():
+				for w in mn:
+					if len(w) >= ssl:
+						yield w[:ssl]
+					else:
+						yield w[0] + 'z\b' + '#' * (ssl-len(w)) + w[1:]
+			mn = list(gen_mn())
+		case 'full' | 'short':
+			mn = ['fzr'] + mn[:5] + ['grd', 'grdbxm'] + mn[5:]
+			mn = pad_mnemonic(mn, mne.em.ss_len)
+			mn[10] = '@#$%*##' + mn[10]
 
 
 	wnum = 1
 	wnum = 1
 	p_ok, p_err = mne.word_prompt
 	p_ok, p_err = mne.word_prompt

+ 7 - 4
test/cmdtest_d/include/pexpect.py

@@ -88,10 +88,13 @@ class CmdTestPexpect:
 
 
 	def view_tx(self, view):
 	def view_tx(self, view):
 		self.expect(r'View.* transaction.*\? .*: ', view, regex=True)
 		self.expect(r'View.* transaction.*\? .*: ', view, regex=True)
-		if cfg.pexpect_spawn and view == 'v':
-			self.expect('END', 'q')
-		elif view not in 'vn\n':
-			self.expect('to continue: ', '\n')
+		match view:
+			case 'v' if cfg.pexpect_spawn:
+				self.expect('END', 'q')
+			case 'v' | 'n' | '\n':
+				pass
+			case _:
+				self.expect('to continue: ', '\n')
 
 
 	def do_comment(self, add_comment, has_label=False):
 	def do_comment(self, add_comment, has_label=False):
 		p = ('Add a comment to transaction', 'Edit transaction comment')[has_label]
 		p = ('Add a comment to transaction', 'Edit transaction comment')[has_label]

+ 20 - 18
test/cmdtest_d/include/runner.py

@@ -496,26 +496,28 @@ class CmdTestRunner:
 			print(r+('\n'+r).join(self.warnings))
 			print(r+('\n'+r).join(self.warnings))
 
 
 	def process_retval(self, cmd, ret):
 	def process_retval(self, cmd, ret):
-		if type(ret).__name__ == 'CmdTestPexpect':
-			ret.ok(exit_val=self.exit_val)
-			self.cmd_total += 1
-		elif ret == 'ok':
-			ok()
-			self.cmd_total += 1
-		elif ret in ('skip', 'skip_msg', 'silent'):
-			if ret == 'silent':
+		match ret:
+			case x if type(x).__name__ == 'CmdTestPexpect':
+				ret.ok(exit_val=self.exit_val)
 				self.cmd_total += 1
 				self.cmd_total += 1
-			elif ret == 'skip_msg':
+			case 'ok':
+				ok()
+				self.cmd_total += 1
+			case 'skip':
+				pass
+			case 'skip_msg':
 				ok('SKIP')
 				ok('SKIP')
-		elif ret == 'error':
-			die(2, red(f'\nTest {self.tg.test_name!r} failed'))
-		elif isinstance(ret, tuple) and ret[0] == 'skip_warn':
-			wmsg = 'Test {!r} was skipped:\n  {}'.format(cmd, '\n  '.join(ret[1].split('\n')))
-			self.skipped_warnings.append(wmsg)
-			if self.logging:
-				self.log_fd.write(f'WARNING: {wmsg}\n')
-		else:
-			die(2, f'{cmd!r} returned {ret}')
+			case 'silent':
+				self.cmd_total += 1
+			case 'error':
+				die(2, red(f'\nTest {self.tg.test_name!r} failed'))
+			case (x, _) if x == 'skip_warn':
+				wmsg = 'Test {!r} was skipped:\n  {}'.format(cmd, '\n  '.join(ret[1].split('\n')))
+				self.skipped_warnings.append(wmsg)
+				if self.logging:
+					self.log_fd.write(f'WARNING: {wmsg}\n')
+			case _:
+				die(2, f'{cmd!r} returned {ret}')
 
 
 	def warn(self, text):
 	def warn(self, text):
 		ymsg(text)
 		ymsg(text)

+ 16 - 16
test/cmdtest_d/main.py

@@ -823,22 +823,22 @@ class CmdTestMain(CmdTestBase, CmdTestShared):
 
 
 		ocls = get_wallet_cls(fmt_code=out_fmt)
 		ocls = get_wallet_cls(fmt_code=out_fmt)
 
 
-		if ocls.enc and ocls.type != 'brain':
-			t.passphrase_new('new '+ocls.desc, self.wpasswd)
-			t.usr_rand(self.usr_rand_chars)
-
-		if ocls.type.startswith('incog'):
-			m = 'Encrypting random data from your operating system with ephemeral key'
-			t.expect(m)
-			t.expect(m)
-			incog_id = t.expect_getend('New Incog Wallet ID: ')
-			t.expect(m)
-
-		if ocls.type == 'incog_hidden':
-			self.write_to_tmpfile(incog_id_fn, incog_id)
-			t.hincog_create(hincog_bytes)
-		elif ocls.type == 'mmgen':
-			t.label()
+		if ocls.enc:
+			if ocls.type != 'brain':
+				t.passphrase_new('new '+ocls.desc, self.wpasswd)
+				t.usr_rand(self.usr_rand_chars)
+			match ocls.type:
+				case 'incog' | 'incog_hex' | 'incog_hidden':
+					m = 'Encrypting random data from your operating system with ephemeral key'
+					t.expect(m)
+					t.expect(m)
+					incog_id = t.expect_getend('New Incog Wallet ID: ')
+					t.expect(m)
+					if ocls.type == 'incog_hidden':
+						self.write_to_tmpfile(incog_id_fn, incog_id)
+						t.hincog_create(hincog_bytes)
+				case 'mmgen':
+					t.label()
 
 
 		return t.written_to_file(capfirst(ocls.desc)), t
 		return t.written_to_file(capfirst(ocls.desc)), t
 
 

+ 9 - 8
test/cmdtest_d/misc.py

@@ -111,14 +111,15 @@ class CmdTestMisc(CmdTestBase):
 		files = get_file_with_ext('test/ref/monero', 'tx', no_dot=True, delete=False, return_list=True)
 		files = get_file_with_ext('test/ref/monero', 'tx', no_dot=True, delete=False, return_list=True)
 		t = self.spawn('mmgen-xmrwallet', [op] + files)
 		t = self.spawn('mmgen-xmrwallet', [op] + files)
 		res = t.read(strip_color=True)
 		res = t.read(strip_color=True)
-		if op == 'txview':
-			for s in (
-				'Amount:    0.74 XMR',
-				'Dest:      56VQ9M6k',
-			):
-				assert s in res, f'{s} not in {res}'
-		elif op == 'txlist':
-			assert re.search('3EBD06-.*D94583-.*8BFA29-', res, re.DOTALL)
+		match op:
+			case 'txview':
+				for s in (
+					'Amount:    0.74 XMR',
+					'Dest:      56VQ9M6k',
+				):
+					assert s in res, f'{s} not in {res}'
+			case 'txlist':
+				assert re.search('3EBD06-.*D94583-.*8BFA29-', res, re.DOTALL)
 		return t
 		return t
 
 
 	def xmrwallet_txlist(self):
 	def xmrwallet_txlist(self):

+ 8 - 8
test/cmdtest_d/xmrwallet.py

@@ -674,14 +674,14 @@ class CmdTestXMRWallet(CmdTestBase):
 				ignore_battery       = True,  # ignore battery state (on laptop)
 				ignore_battery       = True,  # ignore battery state (on laptop)
 				miner_address        = addr,  # account address to mine to
 				miner_address        = addr,  # account address to mine to
 				threads_count        = 1)    # number of mining threads to run
 				threads_count        = 1)    # number of mining threads to run
-			status = self.get_status(ret)
-			if status == 'OK':
-				return True
-			elif status == 'BUSY':
-				await asyncio.sleep(5)
-				omsg('Daemon busy.  Attempting to start mining...')
-			else:
-				die(2, f'Monerod returned status {status}')
+			match self.get_status(ret):
+				case 'OK':
+					return True
+				case 'BUSY':
+					await asyncio.sleep(5)
+					omsg('Daemon busy.  Attempting to start mining...')
+				case status:
+					die(2, f'Monerod returned status {status}')
 		die(2, 'Max retries exceeded')
 		die(2, 'Max retries exceeded')
 
 
 	async def stop_mining(self):
 	async def stop_mining(self):

+ 9 - 8
test/daemontest_d/msg.py

@@ -15,20 +15,21 @@ from ..include.common import cfg, silence, end_silence, restart_test_daemons, st
 
 
 def get_obj(coin, network, msghash_type):
 def get_obj(coin, network, msghash_type):
 
 
-	if coin == 'bch':
-		addrlists = 'DEADBEEF:C:1-20 98831F3A:C:8,2 A091ABAA:L:111 A091ABAA:C:1'
-	elif coin == 'eth':
-		addrlists = 'DEADBEEF:E:1-20 98831F3A:E:8,2 A091ABAA:E:111'
-	else:
-		# A091ABAA = 98831F3A:5S
-		addrlists = 'DEADBEEF:C:1-20 98831F3A:B:8,2 A091ABAA:S:10-11 A091ABAA:111 A091ABAA:C:1'
+	def get_addrlists():
+		match coin:
+			case 'bch':
+				return 'DEADBEEF:C:1-20 98831F3A:C:8,2 A091ABAA:L:111 A091ABAA:C:1'
+			case 'eth':
+				return 'DEADBEEF:E:1-20 98831F3A:E:8,2 A091ABAA:E:111'
+			case _:
+				return 'DEADBEEF:C:1-20 98831F3A:B:8,2 A091ABAA:S:10-11 A091ABAA:111 A091ABAA:C:1'
 
 
 	return NewMsg(
 	return NewMsg(
 		cfg       = cfg,
 		cfg       = cfg,
 		coin      = coin,
 		coin      = coin,
 		network   = network,
 		network   = network,
 		message   = '08/Jun/2021 Bitcoin Law Enacted by El Salvador Legislative Assembly',
 		message   = '08/Jun/2021 Bitcoin Law Enacted by El Salvador Legislative Assembly',
-		addrlists = addrlists,
+		addrlists = get_addrlists(),
 		msghash_type = msghash_type)
 		msghash_type = msghash_type)
 
 
 def print_total(n):
 def print_total(n):

+ 47 - 58
test/gentest.py

@@ -490,57 +490,44 @@ def get_protos(proto, addr_type, toolname):
 
 
 def parse_args():
 def parse_args():
 
 
-	if len(cfg._args) != 2:
-		cfg._usage()
-
-	arg1, arg2 = cfg._args
-	gen1, gen2, rounds = (0, 0, 0)
-	tool, all_backends, dumpfile = (None, None, None)
-
-	if is_int(arg1) and is_int(arg2):
-		test = 'speed'
-		gen1 = arg1
-		rounds = arg2
-	elif is_int(arg1) and os.access(arg2, os.R_OK):
-		test = 'dump'
-		gen1 = arg1
-		dumpfile = arg2
-	else:
-		test = 'ab'
-		rounds = arg2
-
-		if not is_int(arg2):
-			die(1, 'Second argument must be dump filename or integer rounds specification')
-
-		try:
-			a, b = arg1.split(':')
-		except:
-			die(1, 'First argument must be a generator backend number or two colon-separated arguments')
-
-		if is_int(a):
-			gen1 = a
-		else:
-			if a == 'all':
-				all_backends = True
-			else:
-				die(1, "First part of first argument must be a generator backend number or 'all'")
-
-		if is_int(b):
-			if cfg.all_coins:
-				die(1, '--all-coins must be used with external tool only')
-			gen2 = b
-		else:
-			tool = b
-			ext_progs = list(cinfo.external_tests[cfg._proto.network]) + ['ext']
-			if b not in ext_progs:
-				die(1, f'Second part of first argument must be a generator backend number or one of {ext_progs}')
+	all_backends, gen2, tool = (False, None, None)
+
+	match cfg._args:
+		case (gen1, rounds) if is_int(gen1) and is_int(rounds):
+			test, dumpfile = ('speed', None)
+		case (gen1, dumpfile) if is_int(gen1) and os.access(dumpfile, os.R_OK):
+			test, rounds = ('dump', None)
+		case (ab, rounds) if (ab := ab.split(':')) and is_int(rounds):
+			test, dumpfile = ('ab', None)
+
+			match ab[0]:
+				case x if is_int(x):
+					gen1 = x
+				case 'all':
+					all_backends = True
+					gen1 = None
+				case _:
+					die(1, "First part of first argument must be a generator backend number or 'all'")
+
+			match ab[1]:
+				case x if is_int(x):
+					if cfg.all_coins:
+						die(1, '--all-coins must be used with external tool only')
+					gen2 = x
+				case x:
+					tool = x
+					ext_progs = list(cinfo.external_tests[cfg._proto.network]) + ['ext']
+					if tool not in ext_progs:
+						die(1, f'Second part of first argument must be a generator backend number or one of {ext_progs}')
+		case _:
+			cfg._usage()
 
 
 	return namedtuple('parsed_args',
 	return namedtuple('parsed_args',
 			['test', 'gen1', 'gen2', 'rounds', 'tool', 'all_backends', 'dumpfile'])(
 			['test', 'gen1', 'gen2', 'rounds', 'tool', 'all_backends', 'dumpfile'])(
 		test,
 		test,
-		int(gen1) or None,
-		int(gen2) or None,
-		int(rounds) or None,
+		None if gen1 is None else int(gen1),
+		None if gen2 is None else int(gen2),
+		None if rounds is None else int(rounds),
 		tool,
 		tool,
 		all_backends,
 		all_backends,
 		dumpfile)
 		dumpfile)
@@ -551,17 +538,19 @@ def main():
 
 
 	addr_type = MMGenAddrType(proto=proto, id_str=cfg.type or proto.dfl_mmtype)
 	addr_type = MMGenAddrType(proto=proto, id_str=cfg.type or proto.dfl_mmtype)
 
 
-	if scfg.test == 'ab':
-		protos = get_protos(proto, addr_type, scfg.tool) if cfg.all_coins else [proto]
-		for p in protos:
-			ab_test(p, scfg)
-	else:
-		kg = KeyGenerator(cfg, proto, addr_type.pubkey_type, backend=scfg.gen1)
-		ag = AddrGenerator(cfg, proto, addr_type)
-		if scfg.test == 'speed':
-			speed_test(proto, kg, ag, scfg.rounds)
-		elif scfg.test == 'dump':
-			dump_test(proto, kg, ag, scfg.dumpfile)
+	match scfg.test:
+		case 'ab':
+			protos = get_protos(proto, addr_type, scfg.tool) if cfg.all_coins else [proto]
+			for p in protos:
+				ab_test(p, scfg)
+		case 'speed' | 'dump':
+			kg = KeyGenerator(cfg, proto, addr_type.pubkey_type, backend=scfg.gen1)
+			ag = AddrGenerator(cfg, proto, addr_type)
+			match scfg.test:
+				case 'speed':
+					speed_test(proto, kg, ag, scfg.rounds)
+				case 'dump':
+					dump_test(proto, kg, ag, scfg.dumpfile)
 
 
 	if saved_results:
 	if saved_results:
 		import json
 		import json

+ 12 - 10
test/include/common.py

@@ -387,21 +387,23 @@ def create_addrpairs(proto, mmtype, num):
 			for m in range(num)]
 			for m in range(num)]
 
 
 def VirtBlockDevice(img_path, size):
 def VirtBlockDevice(img_path, size):
-	if sys.platform == 'linux':
-		return VirtBlockDeviceLinux(img_path, size)
-	elif sys.platform == 'darwin':
-		return VirtBlockDeviceMacOS(img_path, size)
+	match sys.platform:
+		case 'linux':
+			return VirtBlockDeviceLinux(img_path, size)
+		case 'darwin':
+			return VirtBlockDeviceMacOS(img_path, size)
 
 
 class VirtBlockDeviceBase:
 class VirtBlockDeviceBase:
 
 
 	@property
 	@property
 	def dev(self):
 	def dev(self):
-		res = self._get_associations()
-		if len(res) < 1:
-			die(2, f'No device associated with {self.img_path}')
-		elif len(res) > 1:
-			die(2, f'More than one device associated with {self.img_path}')
-		return res[0]
+		match self._get_associations():
+			case [x]:
+				return x
+			case []:
+				die(2, f'No device associated with {self.img_path}')
+			case _:
+				die(2, f'More than one device associated with {self.img_path}')
 
 
 	def try_detach(self):
 	def try_detach(self):
 		try:
 		try:

+ 7 - 7
test/misc/cfg_main.py

@@ -35,16 +35,16 @@ msg(f'Usr cfg file:    {os.path.relpath(cf_usr.fn)}')
 msg(f'Sys cfg file:    {os.path.relpath(cf_sys.fn)}')
 msg(f'Sys cfg file:    {os.path.relpath(cf_sys.fn)}')
 msg(f'Sample cfg file: {os.path.relpath(cf_sample.fn)}')
 msg(f'Sample cfg file: {os.path.relpath(cf_sample.fn)}')
 
 
-if op:
-	if op == 'print_cfg':
+match op:
+	case 'print_cfg':
 		for name in args:
 		for name in args:
 			msg('{} {}'.format(name+':', getattr(cfg, name)))
 			msg('{} {}'.format(name+':', getattr(cfg, name)))
-	elif op == 'parse_test':
+	case 'parse_test':
 		ps = cf_sample.get_lines()
 		ps = cf_sample.get_lines()
 		msg(f'parsed chunks: {len(ps)}')
 		msg(f'parsed chunks: {len(ps)}')
 		pu = cf_usr.get_lines()
 		pu = cf_usr.get_lines()
 		msg('usr cfg: {}'.format(' '.join(f'{i.name}={i.value}' for i in pu)))
 		msg('usr cfg: {}'.format(' '.join(f'{i.name}={i.value}' for i in pu)))
-	elif op == 'coin_specific_vars':
+	case 'coin_specific_vars':
 		for varname in args:
 		for varname in args:
 			msg('{}.{}.{}: {}'.format(
 			msg('{}.{}.{}: {}'.format(
 				cfg._proto.coin.lower(),
 				cfg._proto.coin.lower(),
@@ -52,11 +52,11 @@ if op:
 				varname,
 				varname,
 				getattr(cfg._proto, varname)
 				getattr(cfg._proto, varname)
 			))
 			))
-	elif op == 'autoset_opts':
+	case 'autoset_opts':
 		assert cfg.rpc_backend == 'aiohttp', "cfg.rpc_backend != 'aiohttp'"
 		assert cfg.rpc_backend == 'aiohttp', "cfg.rpc_backend != 'aiohttp'"
-	elif op == 'autoset_opts_cmdline':
+	case 'autoset_opts_cmdline':
 		assert cfg.rpc_backend == 'curl', "cfg.rpc_backend != 'curl'"
 		assert cfg.rpc_backend == 'curl', "cfg.rpc_backend != 'curl'"
-	elif op == 'mnemonic_entry_modes':
+	case 'mnemonic_entry_modes':
 		from mmgen.mn_entry import mn_entry
 		from mmgen.mn_entry import mn_entry
 		msg('mnemonic_entry_modes: {}\nmmgen: {}\nbip39: {}'.format(
 		msg('mnemonic_entry_modes: {}\nmmgen: {}\nbip39: {}'.format(
 			cfg.mnemonic_entry_modes,
 			cfg.mnemonic_entry_modes,

+ 22 - 25
test/misc/input_func.py

@@ -18,28 +18,25 @@ opts_data = {
 
 
 cfg = Config(opts_data=opts_data)
 cfg = Config(opts_data=opts_data)
 
 
-cmd_args = cfg._args
-
-cmd = cmd_args[0]
-
-if cmd == 'passphrase':
-	from mmgen.ui import get_words_from_user
-	pw = get_words_from_user(
-		cfg,
-		('Enter passphrase: ', 'Enter passphrase (echoed): ')[bool(cfg.echo_passphrase)] )
-	msg('Entered: {}'.format(' '.join(pw)))
-elif cmd 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  term: {get_char.__self__.__name__}')
-	msg(f'  cfg.hold_protect_disable: {cfg.hold_protect_disable}')
-	if cmd == 'line_input':
-		func_args.update({'cfg':cfg})
-	msg('  Calling {name}({args})'.format(
-		name = cmd,
-		args = ', '.join(f'{k}={v!r}' for k, v in func_args.items())
-		))
-	ret = locals()[cmd](**func_args)
-	msg(f'  ==> {ret!r}')
+match cfg._args:
+	case ['passphrase']:
+		from mmgen.ui import get_words_from_user
+		pw = get_words_from_user(
+			cfg,
+			('Enter passphrase: ', 'Enter passphrase (echoed): ')[bool(cfg.echo_passphrase)] )
+		msg('Entered: {}'.format(' '.join(pw)))
+	case 'get_char' | 'line_input' as cmd, args:
+		from mmgen.term import get_char
+		from mmgen.ui import line_input
+		from ast import literal_eval
+		func_args = literal_eval(args)
+		msg(f'\n  term: {get_char.__self__.__name__}')
+		msg(f'  cfg.hold_protect_disable: {cfg.hold_protect_disable}')
+		if cmd == 'line_input':
+			func_args.update({'cfg':cfg})
+		msg('  Calling {name}({args})'.format(
+			name = cmd,
+			args = ', '.join(f'{k}={v!r}' for k, v in func_args.items())
+			))
+		ret = locals()[cmd](**func_args)
+		msg(f'  ==> {ret!r}')

+ 12 - 10
test/misc/term.py

@@ -21,16 +21,18 @@ commands = [
 	'get_char_one',
 	'get_char_one',
 	'get_char_one_raw',
 	'get_char_one_raw',
 ]
 ]
-if sys.platform in ('linux', 'darwin'):
-	commands.extend([
-		'get_char',
-		'get_char_immed_chars',
-		'get_char_raw',
-	])
-elif sys.platform == 'win32':
-	commands.extend([
-		'get_char_one_char_immed_chars',
-	])
+
+match sys.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 = {
 opts_data = {
 	'text': {
 	'text': {

+ 24 - 26
test/misc/term_ni.py

@@ -12,29 +12,27 @@ from mmgen.term import init_term, get_term
 init_term(cfg)
 init_term(cfg)
 term = get_term()
 term = get_term()
 
 
-if sys.argv[1] == 'echo':
-
-	from mmgen.ui import line_input
-	from mmgen.term import get_char_raw
-
-	def test_noecho():
-		term.init(noecho=True)
-		ret = line_input(cfg, 'noecho> ')
-		msg(f'==> [{ret.upper()}]')
-		get_char_raw()
-
-	def test_echo():
-		term.set('echo')
-		ret = line_input(cfg, 'echo> ')
-		msg(f'==> [{ret.upper()}]')
-
-	test_noecho()
-	test_echo()
-	test_noecho()
-
-elif sys.argv[1] == 'cleanup':
-
-	term.register_cleanup()
-
-	import tty
-	tty.setcbreak(term.stdin_fd)
+match sys.argv[1]:
+	case 'echo':
+		from mmgen.ui import line_input
+		from mmgen.term import get_char_raw
+
+		def test_noecho():
+			term.init(noecho=True)
+			ret = line_input(cfg, 'noecho> ')
+			msg(f'==> [{ret.upper()}]')
+			get_char_raw()
+
+		def test_echo():
+			term.set('echo')
+			ret = line_input(cfg, 'echo> ')
+			msg(f'==> [{ret.upper()}]')
+
+		test_noecho()
+		test_echo()
+		test_noecho()
+
+	case 'cleanup':
+		term.register_cleanup()
+		import tty
+		tty.setcbreak(term.stdin_fd)

+ 7 - 6
test/modtest_d/mn_entry.py

@@ -68,10 +68,11 @@ class unit_tests:
 				for vec in self.vectors[wl_id]['idx_minimal']:
 				for vec in self.vectors[wl_id]['idx_minimal']:
 					chk = vec[1]
 					chk = vec[1]
 					b = m.idx(vec[0], 'minimal')
 					b = m.idx(vec[0], 'minimal')
-					if chk is False:
-						assert b is None, (b, None)
-					elif chk is None:
-						assert type(b) is tuple, (type(b), tuple)
-					elif type(chk) is int:
-						assert b == chk, (b, chk)
+					match chk:
+						case False:
+							assert b is None, (b, None)
+						case None:
+							assert type(b) is tuple, (type(b), tuple)
+						case int(x):
+							assert b == x, (b, x)
 		return True
 		return True

+ 11 - 10
test/modtest_d/rune.py

@@ -143,16 +143,17 @@ def test_tx(src, cfg, vec):
 
 
 	assert src in ('parse', 'build', 'swapbuild')
 	assert src in ('parse', 'build', 'swapbuild')
 
 
-	if src == 'parse':
-		tx_in = open(os.path.join('test/ref/thorchain', vec.fn), 'br').read()
-		tx = RuneTx.loads(tx_in)
-		if not parms.from_addr:
-			ymsg(f'Warning: missing test vector data for {vec.fn}')
-		assert bytes(tx) == tx_in
-	elif src == 'build':
-		tx = build_tx(cfg, proto, parms, null_fee=vec.null_fee)
-	elif src == 'swapbuild':
-		tx = build_swap_tx(cfg, proto, parms)
+	match src:
+		case 'parse':
+			tx_in = open(os.path.join('test/ref/thorchain', vec.fn), 'br').read()
+			tx = RuneTx.loads(tx_in)
+			if not parms.from_addr:
+				ymsg(f'Warning: missing test vector data for {vec.fn}')
+			assert bytes(tx) == tx_in
+		case 'build':
+			tx = build_tx(cfg, proto, parms, null_fee=vec.null_fee)
+		case 'swapbuild':
+			tx = build_swap_tx(cfg, proto, parms)
 
 
 	vmsg(pp_fmt(tx))
 	vmsg(pp_fmt(tx))
 
 

+ 13 - 12
test/objattrtest.py

@@ -90,19 +90,20 @@ def test_attr_perm(obj, attrname, perm_name, perm_value, dobj, attrval_type):
 	pstem = pname.rstrip('e')
 	pstem = pname.rstrip('e')
 
 
 	try:
 	try:
-		if perm_name == 'read_ok': # non-existent perm
-			getattr(obj, attrname)
-		elif perm_name == 'reassign_ok':
-			try:
-				so = sample_objs[attrval_type.__name__]
-			except Exception as e:
-				raise SampleObjError(f'unable to find sample object of type {attrval_type.__name__!r}') from e
-			# ListItemAttr allows setting an attribute if its value is None
-			if type(dobj) is ListItemAttr and getattr(obj, attrname) is None:
+		match perm_name:
+			case 'read_ok': # non-existent perm
+				getattr(obj, attrname)
+			case 'reassign_ok':
+				try:
+					so = sample_objs[attrval_type.__name__]
+				except Exception as e:
+					raise SampleObjError(f'unable to find sample object of type {attrval_type.__name__!r}') from e
+				# ListItemAttr allows setting an attribute if its value is None
+				if type(dobj) is ListItemAttr and getattr(obj, attrname) is None:
+					setattr(obj, attrname, so)
 				setattr(obj, attrname, so)
 				setattr(obj, attrname, so)
-			setattr(obj, attrname, so)
-		elif perm_name == 'delete_ok':
-			delattr(obj, attrname)
+			case 'delete_ok':
+				delattr(obj, attrname)
 	except SampleObjError as e:
 	except SampleObjError as e:
 		die(4, f'Test script error ({e})')
 		die(4, f'Test script error ({e})')
 	except Exception as e:
 	except Exception as e:

+ 12 - 13
test/tooltest.py

@@ -514,26 +514,25 @@ def do_cmds(cmd_group):
 		getattr(tc, cmd)(*cmdline)
 		getattr(tc, cmd)(*cmdline)
 
 
 def main():
 def main():
-	if cfg._args:
-		if len(cfg._args) != 1:
+	match cfg._args:
+		case []:
+			cleandir(tcfg['tmpdir'], do_msg=True)
+			for cmd in cmd_data:
+				msg('Running tests for {}:'.format(cmd_data[cmd]['desc']))
+				do_cmds(cmd)
+				if cmd is not list(cmd_data.keys())[-1]:
+					msg('')
+		case [_, _]:
 			die(1, 'Only one command may be specified')
 			die(1, 'Only one command may be specified')
-		cmd = cfg._args[0]
-		if cmd in cmd_data:
+		case [cmd] if cmd in cmd_data:
 			cleandir(tcfg['tmpdir'], do_msg=True)
 			cleandir(tcfg['tmpdir'], do_msg=True)
 			msg('Running tests for {}:'.format(cmd_data[cmd]['desc']))
 			msg('Running tests for {}:'.format(cmd_data[cmd]['desc']))
 			do_cmds(cmd)
 			do_cmds(cmd)
-		elif cmd == 'clean':
+		case ['clean']:
 			cleandir(tcfg['tmpdir'], do_msg=True)
 			cleandir(tcfg['tmpdir'], do_msg=True)
 			sys.exit(0)
 			sys.exit(0)
-		else:
+		case _:
 			die(1, f'{cmd!r}: unrecognized command')
 			die(1, f'{cmd!r}: unrecognized command')
-	else:
-		cleandir(tcfg['tmpdir'], do_msg=True)
-		for cmd in cmd_data:
-			msg('Running tests for {}:'.format(cmd_data[cmd]['desc']))
-			do_cmds(cmd)
-			if cmd is not list(cmd_data.keys())[-1]:
-				msg('')
 	end_msg(int(time.time()) - start_time)
 	end_msg(int(time.time()) - start_time)
 
 
 from mmgen.main import launch
 from mmgen.main import launch

+ 8 - 8
test/tooltest2.py

@@ -167,14 +167,14 @@ def check_output(out, chk):
 		assert chk(outd), f'{chk.__name__}({outd}) failed!'
 		assert chk(outd), f'{chk.__name__}({outd}) failed!'
 	elif isinstance(chk, dict):
 	elif isinstance(chk, dict):
 		for k, v in chk.items():
 		for k, v in chk.items():
-			if k == 'boolfunc':
-				assert v(outd), f'{v.__name__}({outd}) failed!'
-			elif k == 'value':
-				assert outd == v, err_fs.format(outd, v)
-			else:
-				outval = getattr(__builtins__, k)(out)
-				if outval != v:
-					die(1, f'{k}({out}) returned {outval}, not {v}!')
+			match k:
+				case 'boolfunc':
+					assert v(outd), f'{v.__name__}({outd}) failed!'
+				case 'value':
+					assert outd == v, err_fs.format(outd, v)
+				case _:
+					if (outval := getattr(__builtins__, k)(out)) != v:
+						die(1, f'{k}({out}) returned {outval}, not {v}!')
 	elif chk is not None:
 	elif chk is not None:
 		assert out == chk, err_fs.format(out, chk)
 		assert out == chk, err_fs.format(out, chk)