From 9a1ea3430933dd3a08ab043e60452341bc9e6e2d Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Thu, 20 Oct 2022 18:14:15 +0000 Subject: [PATCH] initialize developer tools via `builtins`; add test --- mmgen/data/version | 2 +- mmgen/devinit.py | 68 ++++++ mmgen/devtools.py | 314 +++++++++++++++------------- mmgen/globalvars.py | 2 - mmgen/objmethods.py | 8 +- mmgen/proto/btc/regtest.py | 1 + mmgen/protocol.py | 2 +- mmgen/rpc.py | 2 +- scripts/exec_wrapper.py | 3 + test/objtest.py | 3 + test/objtest_py_d/ot_btc_mainnet.py | 2 + test/objtest_py_d/ot_eth_mainnet.py | 2 + test/objtest_py_d/ot_ltc_mainnet.py | 2 + test/test_py_d/ts_ethdev.py | 3 +- test/unit_tests.py | 4 + test/unit_tests_d/ut_devtools.py | 87 ++++++++ test/unit_tests_d/ut_obj.py | 2 + 17 files changed, 351 insertions(+), 156 deletions(-) create mode 100755 mmgen/devinit.py create mode 100755 test/unit_tests_d/ut_devtools.py diff --git a/mmgen/data/version b/mmgen/data/version index 3492253d..f005e997 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -13.3.dev6 +13.3.dev7 diff --git a/mmgen/devinit.py b/mmgen/devinit.py new file mode 100755 index 00000000..dbe2d796 --- /dev/null +++ b/mmgen/devinit.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# Licensed under the GNU General Public License, Version 3: +# https://www.gnu.org/licenses +# Public project repositories: +# https://github.com/mmgen/mmgen +# https://gitlab.com/mmgen/mmgen + +""" +devinit.py: Developer tools init/launch code for the MMGen suite +""" + +devtools_funcs = { + 'pfmt': lambda *args,**kwargs: devtools_call('pfmt',*args,**kwargs), + 'pmsg': lambda *args,**kwargs: devtools_call('pmsg',*args,**kwargs), + 'pdie': lambda *args,**kwargs: devtools_call('pdie',*args,**kwargs), + 'pexit': lambda *args,**kwargs: devtools_call('pexit',*args,**kwargs), + 'Pmsg': lambda *args,**kwargs: devtools_call('Pmsg',*args,**kwargs), + 'Pdie': lambda *args,**kwargs: devtools_call('Pdie',*args,**kwargs), + 'Pexit': lambda *args,**kwargs: devtools_call('Pexit',*args,**kwargs), + 'print_stack_trace': lambda *args,**kwargs: devtools_call('print_stack_trace',*args,**kwargs), + 'get_diff': lambda *args,**kwargs: devtools_call('get_diff',*args,**kwargs), + 'print_diff': lambda *args,**kwargs: devtools_call('print_diff',*args,**kwargs), + 'get_ndiff': lambda *args,**kwargs: devtools_call('get_ndiff',*args,**kwargs), + 'print_ndiff': lambda *args,**kwargs: devtools_call('print_ndiff',*args,**kwargs), +} + +def devtools_call(funcname,*args,**kwargs): + import mmgen.devtools + return getattr(mmgen.devtools,funcname)(*args,**kwargs) + +def MMGenObject_call(methodname,*args,**kwargs): + from .devtools import MMGenObjectMethods + return getattr(MMGenObjectMethods,methodname)(*args,**kwargs) + +class MMGenObject: + + pmsg = lambda *args,**kwargs: MMGenObject_call('pmsg',*args,**kwargs) + pdie = lambda *args,**kwargs: MMGenObject_call('pdie',*args,**kwargs) + pexit = lambda *args,**kwargs: MMGenObject_call('pexit',*args,**kwargs) + pfmt = lambda *args,**kwargs: MMGenObject_call('pfmt',*args,**kwargs) + + # Check that all immutables have been initialized. Expensive, so do only when testing. + def immutable_attr_init_check(self): + + cls = type(self) + + for attrname in self.valid_attrs: + + for o in (cls,cls.__bases__[0]): # assume there's only one base class + if attrname in o.__dict__: + attr = o.__dict__[attrname] + break + else: + from .util import die + die(4,f'unable to find descriptor {cls.__name__}.{attrname}') + + if type(attr).__name__ == 'ImmutableAttr' and attrname not in self.__dict__: + from .util import die + die(4,f'attribute {attrname!r} of {cls.__name__} has not been initialized in constructor!') + +def init_dev(): + import builtins + setattr(builtins,'MMGenObject',MMGenObject) + for funcname,func in devtools_funcs.items(): + setattr(builtins,funcname,func) diff --git a/mmgen/devtools.py b/mmgen/devtools.py index ba1c1e86..d2f8571d 100755 --- a/mmgen/devtools.py +++ b/mmgen/devtools.py @@ -1,162 +1,180 @@ #!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# Licensed under the GNU General Public License, Version 3: +# https://www.gnu.org/licenses +# Public project repositories: +# https://github.com/mmgen/mmgen +# https://gitlab.com/mmgen/mmgen -class MMGenObject(object): - 'placeholder - overridden when testing' - def immutable_attr_init_check(self): pass +""" +devtools.py: Developer tools for the MMGen suite +""" -import os -if os.getenv('MMGEN_DEBUG') or os.getenv('MMGEN_TEST_SUITE') or os.getenv('MMGEN_EXEC_WRAPPER'): +import sys - import sys,re,traceback,json,pprint - from decimal import Decimal - from difflib import unified_diff,ndiff +def pfmt(*args): + import pprint + return ( + pprint.PrettyPrinter(indent=4).pformat( + args if len(args) > 1 else '' if not args else args[0] ) + + '\n' ) - def pmsg(*args,out=sys.stderr): - d = args if len(args) > 1 else '' if not args else args[0] - out.write(pprint.PrettyPrinter(indent=4).pformat(d) + '\n') - def pdie(*args,exit_val=1,out=sys.stderr): - pmsg(*args,out=out) +def pmsg(*args): + sys.stderr.write(pfmt(*args)) + +def pdie(*args,exit_val=1): + pmsg(*args) + sys.exit(exit_val) + +def pexit(*args): + pdie(*args,exit_val=0) + +def Pmsg(*args): + sys.stdout.write(pfmt(*args)) + +def Pdie(*args,exit_val=1): + Pmsg(*args) + sys.exit(exit_val) + +def Pexit(*args): + Pdie(*args,exit_val=0) + +def print_stack_trace(message=None,fh_list=[],nl='\n',sep='\n ',trim=4): + import os + if not fh_list: + fh_list.append(open(f'devtools.trace.{os.getpid()}','w')) + nl = '' + res = get_stack_trace(message,nl,sep,trim) + sys.stderr.write(res) + fh_list[0].write(res) + +def get_stack_trace(message=None,nl='\n',sep='\n ',trim=3): + + import os,re,traceback + + tb = [t for t in traceback.extract_stack() if t.filename[:1] != '<'] + fs = '{}:{}: in {}:\n {}' + out = [ + fs.format( + re.sub(r'^\./','',os.path.relpath(t.filename)), + t.lineno, + (t.name+'()' if t.name[-1] != '>' else t.name), + t.line or '(none)') + for t in (tb[:-trim] if trim else tb) ] + + return f'{nl}STACK TRACE {message or "[unnamed]"}:{sep}{sep.join(out)}\n' + +def print_diff(*args,**kwargs): + sys.stderr.write(get_diff(*args,**kwargs)) + +def get_diff(a,b,a_fn='',b_fn='',from_json=True): + + if from_json: + import json + a = json.dumps(json.loads(a),indent=4) + b = json.dumps(json.loads(b),indent=4) + + from difflib import unified_diff + # chunk headers have trailing newlines, hence the rstrip() + return ' DIFF:\n {}\n'.format( + '\n '.join(a.rstrip('\n') for a in unified_diff( + a.split('\n'), + b.split('\n'), + a_fn, + b_fn ))) + +def print_ndiff(*args,**kwargs): + sys.stderr.write(get_ndiff(*args,**kwargs)) + +def get_ndiff(a,b): + from difflib import ndiff + return list(ndiff( + a.split('\n'), + b.split('\n') )) + +class MMGenObjectMethods: # mixin class for MMGenObject + + # Pretty-print an MMGenObject instance, recursing into sub-objects - WIP + def pmsg(self): + sys.stdout.write('\n'+self.pfmt()) + + def pdie(self,exit_val=1): + self.pmsg() sys.exit(exit_val) - def pexit(*args,out=sys.stderr): - pdie(*args,exit_val=0,out=out) - def Pmsg(*args): - pmsg(*args,out=sys.stdout) - def Pdie(*args): - pdie(*args,out=sys.stdout) - def Pexit(*args): - pexit(*args,out=sys.stdout) + def pexit(self): + self.pdie(exit_val=0) - def print_stack_trace(message=None,fh=[],nl='\n',sep='\n '): - - if not fh: - fh.append(open(f'devtools.trace.{os.getpid()}','w')) - nl = '' - - tb = [t for t in traceback.extract_stack() if t.filename[:1] != '<'][:-1] - fs = '{}:{}: in {}:\n {}' - out = [ - fs.format( - re.sub(r'^\./','',os.path.relpath(t.filename)), - t.lineno, - (t.name+'()' if t.name[-1] != '>' else t.name), - t.line or '(none)') - for t in tb ] - - text = f'{nl}STACK TRACE {message or "[unnamed]"}:{sep}{sep.join(out)}\n' - sys.stderr.write(text) - fh[0].write(text) - - class MMGenObject(object): - - # Pretty-print any object subclassed from MMGenObject, recursing into sub-objects - WIP - def pmsg(self,*args): - print(args[0] if len(args) == 1 else args if args else self.pfmt()) - - def pdie(self,*args): - self.pmsg(*args) - sys.exit(1) - - def pexit(self,*args): - self.pmsg(*args) - sys.exit(0) - - def pfmt(self,lvl=0,id_list=[]): - scalars = (str,int,float,Decimal) - def do_list(out,e,lvl=0,is_dict=False): - out.append('\n') - for i in e: - el = i if not is_dict else e[i] - if is_dict: - out.append('{s}{:<{l}}'.format(i,s=' '*(4*lvl+8),l=10,l2=8*(lvl+1)+8)) - if hasattr(el,'pfmt'): - out.append('{:>{l}}{}'.format( - '', - el.pfmt( lvl=lvl+1, id_list=id_list+[id(self)] ), - l = (lvl+1)*8 )) - elif isinstance(el,scalars): - if isList(e): - out.append( '{:>{l}}{!r:16}\n'.format( '', el, l=lvl*8 )) - else: - out.append(f' {el!r}') - elif isList(el) or isDict(el): - indent = 1 if is_dict else lvl*8+4 - out.append('{:>{l}}{:16}'.format( '', f'<{type(el).__name__}>', l=indent )) - if isList(el) and isinstance(el[0],scalars): - out.append('\n') - do_list(out,el,lvl=lvl+1,is_dict=isDict(el)) - else: - out.append('{:>{l}}{:16} {!r}\n'.format( '', f'<{type(el).__name__}>', el, l=(lvl*8)+8 )) - out.append('\n') - - if not e: - out.append(f'{e!r}\n') - - def isDict(obj): - return isinstance(obj,dict) - def isList(obj): - return isinstance(obj,list) - def isScalar(obj): - return isinstance(obj,scalars) - - out = [f'<{type(self).__name__}>{" "+repr(self) if isScalar(self) else ""}\n'] - - if id(self) in id_list: - return out[-1].rstrip() + ' [RECURSION]\n' - if isList(self) or isDict(self): - do_list(out,self,lvl=lvl,is_dict=isDict(self)) - - for k in self.__dict__: - e = getattr(self,k) - if isList(e) or isDict(e): - out.append('{:>{l}}{:<10} {:16}'.format( '', k, f'<{type(e).__name__}>', l=(lvl*8)+4 )) - do_list(out,e,lvl=lvl,is_dict=isDict(e)) - elif hasattr(e,'pfmt') and type(e) != type: - out.append('{:>{l}}{:10} {}'.format( + def pfmt(self,lvl=0,id_list=[]): + from decimal import Decimal + scalars = (str,int,float,Decimal) + def do_list(out,e,lvl=0,is_dict=False): + out.append('\n') + for i in e: + el = i if not is_dict else e[i] + if is_dict: +# out.append('{s}{:<{l}}'.format(i,s=' '*(4*lvl+8),l=10,l2=8*(lvl+1)+8)) + out.append('{s1}{i}{s2}'.format( + i = i, + s1 = ' ' * (4*lvl+8), + s2 = ' ' * 10 )) + if hasattr(el,'pfmt'): + out.append('{:>{l}}{}'.format( '', - k, - e.pfmt( lvl=lvl+1, id_list=id_list+[id(self)] ), - l = (lvl*8)+4 )) + el.pfmt( lvl=lvl+1, id_list=id_list+[id(self)] ), + l = (lvl+1)*8 )) + elif isinstance(el,scalars): + if isList(e): + out.append( '{:>{l}}{!r:16}\n'.format( '', el, l=lvl*8 )) + else: + out.append(f' {el!r}') + elif isList(el) or isDict(el): + indent = 1 if is_dict else lvl*8+4 + out.append('{:>{l}}{:16}'.format( '', f'<{type(el).__name__}>', l=indent )) + if isList(el) and isinstance(el[0],scalars): + out.append('\n') + do_list(out,el,lvl=lvl+1,is_dict=isDict(el)) else: - out.append('{:>{l}}{:<10} {:16} {}\n'.format( - '', - k, - f'<{type(e).__name__}>', - repr(e), - l=(lvl*8)+4 )) + out.append('{:>{l}}{:16} {!r}\n'.format( '', f'<{type(el).__name__}>', el, l=(lvl*8)+8 )) + out.append('\n') - import re - return re.sub('\n+','\n',''.join(out)) + if not e: + out.append(f'{e!r}\n') - # Check that all immutables have been initialized. Expensive, so do only when testing. - def immutable_attr_init_check(self): - from .globalvars import g - if g.test_suite: - from .util import die - cls = type(self) - for attrname in sorted({a for a in self.valid_attrs if a[0] != '_'}): - for o in (cls,cls.__bases__[0]): # assume there's only one base class - if attrname in o.__dict__: - attr = o.__dict__[attrname] - break - else: - die(4,f'unable to find descriptor {cls.__name__}.{attrname}') - if type(attr).__name__ == 'ImmutableAttr': - if attrname not in self.__dict__: - die(4, - f'attribute {attrname!r} of {cls.__name__} has not been initialized in constructor!') + def isDict(obj): + return isinstance(obj,dict) + def isList(obj): + return isinstance(obj,list) + def isScalar(obj): + return isinstance(obj,scalars) - def print_diff(a,b,from_file='',to_file='',from_json=True): - if from_json: - a = json.dumps(json.loads(a),indent=4).split('\n') if a else [] - b = json.dumps(json.loads(b),indent=4).split('\n') if b else [] - else: - a = a.split('\n') - b = b.split('\n') - sys.stderr.write(' DIFF:\n {}\n'.format( - '\n '.join(unified_diff(a,b,from_file,to_file)) )) + out = [f'<{type(self).__name__}>{" "+repr(self) if isScalar(self) else ""}\n'] - def get_ndiff(a,b): - a = a.split('\n') - b = b.split('\n') - return list(ndiff(a,b)) + if id(self) in id_list: + return out[-1].rstrip() + ' [RECURSION]\n' + if isList(self) or isDict(self): + do_list(out,self,lvl=lvl,is_dict=isDict(self)) + + for k in self.__dict__: + e = getattr(self,k) + if isList(e) or isDict(e): + out.append('{:>{l}}{:<10} {:16}'.format( '', k, f'<{type(e).__name__}>', l=(lvl*8)+4 )) + do_list(out,e,lvl=lvl,is_dict=isDict(e)) + elif hasattr(e,'pfmt') and type(e) != type: + out.append('{:>{l}}{:10} {}'.format( + '', + k, + e.pfmt( lvl=lvl+1, id_list=id_list+[id(self)] ), + l = (lvl*8)+4 )) + else: + out.append('{:>{l}}{:<10} {:16} {}\n'.format( + '', + k, + f'<{type(e).__name__}>', + repr(e), + l=(lvl*8)+4 )) + + import re + return re.sub('\n+','\n',''.join(out)) diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index ed4968b5..ab1b4738 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -22,8 +22,6 @@ globalvars.py: Constants and configuration options for the MMGen suite import sys,os from collections import namedtuple -from .devtools import * - from .base_obj import Lockable def die(exit_val,s=''): diff --git a/mmgen/objmethods.py b/mmgen/objmethods.py index a5ef4f0f..9e21218d 100755 --- a/mmgen/objmethods.py +++ b/mmgen/objmethods.py @@ -22,9 +22,15 @@ objmethods.py: Mixin classes for MMGen data objects import unicodedata from .globalvars import g -from .devtools import * import mmgen.color as color_mod +if 'MMGenObject' in __builtins__: # added to builtins by devinit.init_dev() + MMGenObject = __builtins__['MMGenObject'] +else: + class MMGenObject: + 'placeholder - overridden when testing' + def immutable_attr_init_check(self): pass + def truncate_str(s,width): # width = screen width wide_count = 0 for i in range(len(s)): diff --git a/mmgen/proto/btc/regtest.py b/mmgen/proto/btc/regtest.py index 2ac16030..87c8e6fc 100755 --- a/mmgen/proto/btc/regtest.py +++ b/mmgen/proto/btc/regtest.py @@ -25,6 +25,7 @@ from subprocess import run,PIPE from ...common import * from ...protocol import init_proto from ...rpc import rpc_init,json_encoder +from ...objmethods import MMGenObject def create_data_dir(data_dir): try: os.stat(os.path.join(data_dir,'regtest')) diff --git a/mmgen/protocol.py b/mmgen/protocol.py index f6376f2e..494843fe 100755 --- a/mmgen/protocol.py +++ b/mmgen/protocol.py @@ -22,8 +22,8 @@ protocol.py: Coin protocol base classes and initializer from collections import namedtuple -from .devtools import * from .globalvars import g +from .objmethods import MMGenObject decoded_wif = namedtuple('decoded_wif',['sec','pubkey_type','compressed']) decoded_addr = namedtuple('decoded_addr',['bytes','ver_bytes','fmt']) diff --git a/mmgen/rpc.py b/mmgen/rpc.py index eb1f26b3..bf855c53 100755 --- a/mmgen/rpc.py +++ b/mmgen/rpc.py @@ -26,7 +26,7 @@ from collections import namedtuple from .common import * from .base_obj import AsyncInit -from .objmethods import Hilite,InitErrors +from .objmethods import Hilite,InitErrors,MMGenObject auth_data = namedtuple('rpc_auth_data',['user','passwd']) diff --git a/scripts/exec_wrapper.py b/scripts/exec_wrapper.py index 57f94b74..bbb06290 100755 --- a/scripts/exec_wrapper.py +++ b/scripts/exec_wrapper.py @@ -111,6 +111,9 @@ exec_wrapper_init() # sets sys.path[0], runs overlay_setup() exec_wrapper_tstart = time.time() exec_wrapper_tracemalloc_setup() +from mmgen.devinit import init_dev # import mmgen mods only after overlay setup! +init_dev() + try: sys.argv.pop(0) exec_wrapper_execed_file = sys.argv[0] diff --git a/test/objtest.py b/test/objtest.py index d4fab417..039f3926 100755 --- a/test/objtest.py +++ b/test/objtest.py @@ -26,6 +26,9 @@ from include.tests_header import repo_root from test.overlay import overlay_setup sys.path.insert(0,overlay_setup(repo_root)) +from mmgen.devinit import init_dev +init_dev() + os.environ['MMGEN_TEST_SUITE'] = '1' # Import these _after_ local path's been added to sys.path diff --git a/test/objtest_py_d/ot_btc_mainnet.py b/test/objtest_py_d/ot_btc_mainnet.py index 789cb689..18fd07ac 100755 --- a/test/objtest_py_d/ot_btc_mainnet.py +++ b/test/objtest_py_d/ot_btc_mainnet.py @@ -7,6 +7,8 @@ test.objtest_py_d.ot_btc_mainnet: BTC mainnet test vectors for MMGen data objects """ +from decimal import Decimal + from mmgen.obj import * from mmgen.addrlist import AddrIdxList from mmgen.seedsplit import * diff --git a/test/objtest_py_d/ot_eth_mainnet.py b/test/objtest_py_d/ot_eth_mainnet.py index e083f69c..76e19f69 100755 --- a/test/objtest_py_d/ot_eth_mainnet.py +++ b/test/objtest_py_d/ot_eth_mainnet.py @@ -7,6 +7,8 @@ test.objtest_py_d.ot_eth_mainnet: ETH mainnet test vectors for MMGen data objects """ +from decimal import Decimal + from mmgen.obj import * from .ot_common import * diff --git a/test/objtest_py_d/ot_ltc_mainnet.py b/test/objtest_py_d/ot_ltc_mainnet.py index 1fefb87f..08ccdb58 100755 --- a/test/objtest_py_d/ot_ltc_mainnet.py +++ b/test/objtest_py_d/ot_ltc_mainnet.py @@ -7,6 +7,8 @@ test.objtest_py_d.ot_ltc_mainnet: LTC mainnet test vectors for MMGen data objects """ +from decimal import Decimal + from mmgen.obj import * from .ot_common import * diff --git a/test/test_py_d/ts_ethdev.py b/test/test_py_d/ts_ethdev.py index 6ddf9933..6f41ce2c 100755 --- a/test/test_py_d/ts_ethdev.py +++ b/test/test_py_d/ts_ethdev.py @@ -20,7 +20,7 @@ ts_ethdev.py: Ethdev tests for the test.py test suite """ -import sys,os,re,shutil,asyncio +import sys,os,re,shutil,asyncio,json from decimal import Decimal from collections import namedtuple from subprocess import run,PIPE,DEVNULL @@ -504,7 +504,6 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared): if cp.returncode: die(1,cp.stderr.decode()) - import json d.stop(quiet=True) d.remove_datadir() diff --git a/test/unit_tests.py b/test/unit_tests.py index 626a1eb4..257acd3b 100755 --- a/test/unit_tests.py +++ b/test/unit_tests.py @@ -24,6 +24,10 @@ import sys,os,time,importlib,platform from include.tests_header import repo_root from include.common import end_msg + +from mmgen.devinit import init_dev +init_dev() + from mmgen.common import * opts_data = { diff --git a/test/unit_tests_d/ut_devtools.py b/test/unit_tests_d/ut_devtools.py new file mode 100755 index 00000000..ab537b0e --- /dev/null +++ b/test/unit_tests_d/ut_devtools.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +""" +test.unit_tests_d.ut_devtools: devtools unit tests for the MMGen suite +""" + +import os,json +from mmgen.devtools import * +from . import unit_tests_base + +textA = """ +def main(): + a = 1 + b = 2 + c = 3 +""".lstrip() + +textB = """ +def main(): + a = 1 + b = 0 + c = 3 +""".lstrip() + +jsonA = open('test/ref/ethereum/tracking-wallet-v1.json').read() +dataB = json.loads(jsonA) +dataB['coin'] = 'ETC' +jsonB = json.dumps(dataB) + +text_data = ( + (textA, textB, 'a/main.py', 'b/main.py', False, 'text: one line difference'), + ('', textB, 'a/main.py', 'b/main.py', False, 'text: first file empty'), + (textA, textA, 'a/main.py', 'b/main.py', False, 'text: identical files'), + ('', '', 'a/empty.txt', 'b/empty.txt', False, 'text: empty files'), +) + +json_data = ( + (jsonA, jsonB, 'a/data.json', 'b/data.json', True, 'json: one difference'), + ('{}', jsonB, 'a/data.json', 'b/data.json', True, 'json: first file empty'), + (jsonA, jsonA, 'a/data.json', 'b/data.json', True, 'json: identical files'), + ('{}', '{}', 'a/data.json', 'b/data.json', True, 'json: empty files'), +) + +def print_hdr(hdr): + print('{a} {b} {c}'.format( + a = '-' * ((78 - len(hdr))//2), + b = hdr, + c = '-' * ((78 - len(hdr))//2 + (len(hdr) % 2)) )) + +# TODO: add data checks +class unit_tests(unit_tests_base): + + def _pre_subtest(self,name,subname,ut): + self._silence() + + def _post_subtest(self,name,subname,ut): + print('-' * 80 + '\n') + self._end_silence() + + def diff(self,name,ut): + for data in text_data + json_data: + print_hdr(data[-1]) + print_diff(*data[:-1]) + return True + + def ndiff(self,name,ut): + for data in text_data: + print_hdr(data[-1]) + print('\n'.join(get_ndiff(*data[:2]))) + return True + + def stack_trace(self,name,ut): + print_hdr('stack trace') + print_stack_trace('Test',fh_list=[open(os.devnull,'w')],trim=0) + return True + + def obj_pmsg(self,name,ut): + from mmgen.protocol import init_proto + from mmgen.seed import Seed + from mmgen.addrlist import AddrList + print_hdr('MMGenObject.pmsg()') + AddrList( + proto = init_proto('btc'), + seed = Seed(seed_bin=bytes.fromhex('bead'*16)), + addr_idxs = '1', + mmtype = 'B', + skip_chksum = True ).pmsg() + return True diff --git a/test/unit_tests_d/ut_obj.py b/test/unit_tests_d/ut_obj.py index aba76a56..d436c952 100755 --- a/test/unit_tests_d/ut_obj.py +++ b/test/unit_tests_d/ut_obj.py @@ -3,6 +3,8 @@ test.unit_tests_d.ut_obj: data object unit tests for the MMGen suite """ +from decimal import Decimal + from mmgen.common import * class unit_tests: