mmgen-wallet/test/modtest_d/obj.py

206 lines
6.6 KiB
Python
Executable file

#!/usr/bin/env python3
"""
test.modtest_d.obj: data object unit tests for the MMGen suite
"""
from decimal import Decimal, getcontext
from ..include.common import vmsg, cfg, parity_dev_amt
from mmgen.protocol import init_proto
def test_equal(res, chk):
vmsg(f' checking {res}')
if type(res) is type:
assert res is chk, f'{res} != {chk}'
else:
assert res == chk, f'{res} != {chk}'
def coinamt_test(cls, aa, bb, ut):
def do(desc, res, chk):
vmsg(f'{desc:10} = {res:<{cls.max_prec+10}} [{type(res).__name__}]')
if chk is not None:
assert res == chk, f'{res} != {chk}'
assert type(res) is cls, f'{type(res).__name__} != {cls.__name__}'
vmsg(f'\nTesting {cls.__name__} arithmetic operations...')
A, B = (Decimal(aa), Decimal(bb))
a, b = (cls(aa), cls(bb))
do('A', A, None)
do('B', B, None)
do('a', a, A)
do('b', b, B)
do('b + a', b + a, B + A)
do('sum([b,a])', sum([b, a]), B + A)
do('b - a', b - a, B - A)
do('b * a', b * a, B * A)
do('b * A', b * A, B * A)
do('B * a', B * a, B * A)
do('b / a', b / a, cls(B / A, from_decimal=True))
do('b / A', b / A, cls(B / A, from_decimal=True))
do('a / b', a / b, cls(A / B, from_decimal=True))
do('a * a / a', a * a / a, A * A / A)
do('a * b / a', a * b / a, A * B / A)
do('a * b / b', a * b / b, A * B / B)
vmsg(f'\nChecking {cls.__name__} error handling...')
bad_data = (
('negation', 'NotImplementedError', 'not implemented', lambda: -a),
('modulus', 'NotImplementedError', 'not implemented', lambda: b % a),
('floor division', 'NotImplementedError', 'not implemented', lambda: b // a),
('negative result', 'ObjectInitError', 'cannot be negative', lambda: a - b),
('operand type', 'TypeError', 'incorrect type', lambda: a + B),
('operand type', 'TypeError', 'incorrect type', lambda: b - A),
)
if cls.max_amt is not None:
bad_data += (
('result', 'ObjectInitError', 'too large', lambda: b + b),
('result', 'ObjectInitError', 'too large', lambda: b * b),
)
ut.process_bad_data(bad_data)
vmsg('OK')
class unit_tests:
altcoin_deps = ('coinamt_alt', 'coinamt_alt2')
def coinamt(self, name, ut, desc='BTCAmt class'):
from mmgen.amt import BTCAmt
for cls, aa, bb in (
(BTCAmt, '1.2345', '11234567.897'),
):
coinamt_test(cls, aa, bb, ut)
return True
def coinamt_alt(self, name, ut, desc='LTCAmt, XMRAmt and ETHAmt classes'):
from mmgen.amt import LTCAmt, XMRAmt, ETHAmt
for cls, aa, bb in (
(LTCAmt, '1.2345', '44938271.588'),
(XMRAmt, '1.2345', '11234567.98765432'),
(ETHAmt, '1.2345', '11234567.98765432123456'),
):
coinamt_test(cls, aa, bb, ut)
return True
def coinamt2(self, name, ut, desc='CoinAmt class'):
from decimal import Decimal
proto = init_proto(cfg, 'btc', network='testnet', need_amt=True)
test_equal(getcontext().prec, proto.decimal_prec)
coin_amt = proto.coin_amt
test_equal(coin_amt.__name__, 'BTCAmt')
a = coin_amt('1.234')
a2 = coin_amt('2.468')
# addition with integer zero:
b = a + 0 # __add__
b = 0 + a # __radd__
test_equal(sum([a, a]), a2) # __radd__ (sum() starts with integer 0)
# __add__
b = coin_amt('333.2456')
test_equal(a + b, coin_amt('334.4796'))
# __sub__
test_equal(a - coin_amt('1'), coin_amt('0.234'))
test_equal(coin_amt('2') - a, coin_amt('0.766'))
# __mul__
b = a * 2
test_equal(type(b), coin_amt)
test_equal(b, a2)
# __rmul__
b = 2 * a
test_equal(type(b), coin_amt)
test_equal(b, a2)
# __truediv__
b = a / 2
test_equal(type(b), coin_amt)
test_equal(b, coin_amt('0.617'))
# __rtruediv__
b = 2 / a
test_equal(type(b), coin_amt)
test_equal(b, coin_amt('1.62074554'))
def bad1(): b = a + 1
def bad2(): b = a - 1
def bad3(): a + Decimal(1)
def bad4(): b = a + 0.0
def bad5(): b = a - 0.0
def bad1r(): b = 1 + a
def bad2r(): b = 3 - a
def bad3r(): Decimal(1) + a
def bad4r(): b = 0.0 + a
def bad5r(): b = 0.0 - a
def bad10(): b = coin_amt('1') - a
def bad11(): b = a * -2
def bad12(): b = a / -2
def bad13(): b = a - coin_amt('2')
def bad14(): b = -2 * a
def bad15(): b = -2 / a
def bad16(): b = coin_amt(a)
vmsg('Testing error handling:')
ut.process_bad_data(
(
('addition with int', 'TypeError', 'incorrect type', bad1),
('subtraction with int', 'TypeError', 'incorrect type', bad2),
('addition with Decimal', 'TypeError', 'incorrect type', bad3),
('addition with float', 'TypeError', 'incorrect type', bad4),
('subtraction with float', 'TypeError', 'incorrect type', bad5),
('addition with int', 'TypeError', 'incorrect type', bad1r),
('subtraction with int', 'TypeError', 'incorrect type', bad2r),
('addition with Decimal', 'TypeError', 'incorrect type', bad3r),
('addition with float', 'TypeError', 'incorrect type', bad4r),
('subtraction with float', 'TypeError', 'incorrect type', bad5r),
('negative result', 'ObjectInitError', 'cannot be negative', bad10),
('negative result', 'ObjectInitError', 'cannot be negative', bad11),
('negative result', 'ObjectInitError', 'cannot be negative', bad12),
('negative result', 'ObjectInitError', 'cannot be negative', bad13),
('negative result', 'ObjectInitError', 'cannot be negative', bad14),
('negative result', 'ObjectInitError', 'cannot be negative', bad15),
('double initialization', 'TypeError', 'is instance', bad16),
),
pfx = '')
return True
def coinamt_alt2(self, name, ut, desc='CoinAmt class (altcoins)'):
proto = init_proto(cfg, 'etc', network='regtest', need_amt=True)
test_equal(getcontext().prec, proto.decimal_prec)
coin_amt = proto.coin_amt
dev_amt = coin_amt(parity_dev_amt, from_unit='wei')
dev_amt_s = '1606938044258990275541962092341162602522202.993782792835301376'
dev_amt_a1 = '1606938044258990275541962092341162602522203.993782792835301377'
dev_amt_s1 = '1606938044258990275541962092341162602522201.993782792835301375'
dev_amt_d2 = '803469022129495137770981046170581301261101.496891396417650688'
dev_amt_d10 = '160693804425899027554196209234116260252220.299378279283530138'
test_equal(str(dev_amt), dev_amt_s)
addend = coin_amt('1.000000000000000001')
test_equal(dev_amt + addend, coin_amt(dev_amt_a1))
test_equal(dev_amt - addend, coin_amt(dev_amt_s1))
test_equal(dev_amt / coin_amt('2'), coin_amt(dev_amt_d2))
test_equal(dev_amt / coin_amt('10'), coin_amt(dev_amt_d10))
test_equal(2 / coin_amt('0.3456'), coin_amt('5.787037037037037037'))
test_equal(2.345 * coin_amt('2.3456'), coin_amt('5.500432000000000458'))
return True