Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
176 lines (130 sloc) 6.55 KB
# Author: Florian Tramer
import glob
import unittest
from ethereum import utils
from os.path import basename
from utils.pyethereum_test_utils import PyEthereumTestCase, bytes_to_int, int_to_bytes
try:
from examples.ERC20.test.test_config import PATH_TO_CONTRACTS
except:
PATH_TO_CONTRACTS = ""
#from ethereum.slogging import configure_logging
#config_string = ':trace'
#configure_logging(config_string=config_string)
log_sigs = {
'Transfer': bytes_to_int(utils.sha3("Transfer(address,address,uint256)")),
'Approval': bytes_to_int(utils.sha3("Approval(address,address,uint256)"))
}
class TestERC20Flo(PyEthereumTestCase):
def test_all(self):
self.assertEqual(self.c.totalSupply(), 0, "Token not initially empty")
orig_balance0 = self.s.head_state.get_balance(self.t.a0)
orig_balance1 = self.s.head_state.get_balance(self.t.a1)
self.c.deposit(sender=self.t.k0, value=1000)
self.check_logs([log_sigs['Transfer'], 0, bytes_to_int(self.t.a0)],
int_to_bytes(1000))
new_balance0 = self.s.head_state.get_balance(self.t.a0)
self.assertEqual(self.c.totalSupply(), 1000, "Deposit not working")
self.assertEqual(self.c.balanceOf(self.t.a0), 1000,
"Deposit not working")
self.assertEqual(new_balance0, orig_balance0 - 1000,
"Deposit did not use funds")
self.assertEqual(self.c.balanceOf(self.t.a1), 0,
"Account balance not empty initially")
# If this fails, transfer worked although funds were insufficient
self.assert_tx_failed(lambda: self.c.transfer(self.t.a1, 2000, sender=self.t.k0))
self.assertTrue(self.c.transfer(self.t.a1, 500, sender=self.t.k0),
"Transfer not working")
self.check_logs([log_sigs['Transfer'], bytes_to_int(self.t.a0),
bytes_to_int(self.t.a1)], int_to_bytes(500))
self.assertEqual(self.c.totalSupply(), 1000, "Transfer changed balance")
self.assertEqual(self.c.balanceOf(self.t.a0), 500,
"Transfer did not remove funds")
self.assertEqual(self.c.balanceOf(self.t.a1), 500,
"Transfer did not add funds")
self.assertTrue(self.c.approve(self.t.a0, 200, sender=self.t.k1),
"Approval did not work")
self.check_logs([log_sigs['Approval'], bytes_to_int(self.t.a1),
bytes_to_int(self.t.a0)], int_to_bytes(200))
# If this fails, Transfered larger value than approved
self.assert_tx_failed(lambda: self.c.transferFrom(
self.t.a1, self.t.a0, 201, sender=self.t.k0))
self.assertTrue(self.c.transferFrom(
self.t.a1, self.t.a0, 100, sender=self.t.k0),
"Transfer not approved")
self.check_logs([log_sigs['Transfer'], bytes_to_int(self.t.a1),
bytes_to_int(self.t.a0)], int_to_bytes(100))
self.assertEqual( self.c.totalSupply(), 1000,
"TransferFrom changed balance")
self.assertEqual( self.c.balanceOf(self.t.a0), 600,
"TransferFrom did not add funds")
self.assertEqual( self.c.balanceOf(self.t.a1), 400,
"TransferFrom did not remove funds")
# Check TransferFrom did not reduce allowance
self.assert_tx_failed(lambda: self.c.transferFrom(
self.t.a1, self.t.a0, 101, sender=self.t.k0))
# If failed, withdraw more than balance allowed
self.assert_tx_failed(lambda: self.c.withdraw(601, sender=self.t.k0))
self.assertTrue(self.c.withdraw(500, sender=self.t.k0),
"Withdraw did not work")
self.check_logs([log_sigs['Transfer'], bytes_to_int(self.t.a0), 0],
int_to_bytes(500))
self.assertEqual(self.c.balanceOf(self.t.a0), 100,
"Withdraw did not reduce funds")
new_balance0 = self.s.head_state.get_balance(self.t.a0)
self.assertEqual(new_balance0, orig_balance0 - 500,
"Withdraw did not send funds")
self.assertEqual(self.c.totalSupply(), 500,
"Withdraw did not change balance correctly")
self.assertTrue(self.c.withdraw(100, sender=self.t.k0),
"Withdraw did not work")
self.assertTrue(self.c.withdraw(400, sender=self.t.k1),
"Withdraw did not work")
self.assertEqual(self.c.totalSupply(), 0,
"Token not empty after withdraw")
new_balance0 = self.s.head_state.get_balance(self.t.a0)
new_balance1 = self.s.head_state.get_balance(self.t.a1)
self.assertEqual(new_balance0, orig_balance0 - 400,
"Withdraw did not send funds")
self.assertEqual(new_balance1, orig_balance1 + 400,
"Withdraw did not send funds")
@classmethod
def listenForEvents(cls):
cls.hydra_events = []
cls.s.head_state.log_listeners.append(
lambda x: cls.hydra_events.append(cls.c.translator.listen(x)))
class TestSingleERC20(TestERC20Flo):
in_file = None
@classmethod
def setUpClass(cls):
super(TestSingleERC20, cls).setUpClass()
print("Testing {}".format(cls.in_file))
gas_used_before = cls.s.head_state.gas_used
cls.c = cls.deploy_contract_from_file(cls, cls.in_file)
gas_used_after = cls.s.head_state.gas_used
print("Deploying contract at {} used {} gas".format(
utils.encode_hex(cls.c.address),
gas_used_after - gas_used_before))
cls.listenForEvents()
cls.initial_state = cls.s.snapshot()
def setUp(self):
super().setUp()
test_suites = []
for f in glob.glob(PATH_TO_CONTRACTS + "nonvyper/*") + glob.glob(PATH_TO_CONTRACTS + "ERC20.v.py"):
# ugly hack: copy the class instance to set a different file path
# replace extension with underscore so that unittest parses it correctly
cls_name = basename(f.replace('.', '_'))
suite = type(cls_name, (TestSingleERC20,), {})
globals()[cls_name] = suite
suite.in_file = f
test_suites.append(suite)
def load_tests(loader, tests, pattern):
full_suite = unittest.TestSuite()
for suite in test_suites:
tests = loader.loadTestsFromTestCase(suite)
full_suite.addTests(tests)
return full_suite
if __name__ == '__main__':
# run with `python3 -m path.to.this.test`
# or `python3 -m path.to.this.test [ERC20 class name]`
unittest.main(verbosity=2)