From c8c20b6faeadec60606dbd6d296d82f832524c0e Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Tue, 31 May 2016 17:30:13 -0700 Subject: [PATCH 1/4] add hypothesis property based testing --- .gitignore | 1 + .travis.yml | 4 ++ dev_requirements.txt | 1 + ethereum/tests/abi_type_strategies.py | 92 +++++++++++++++++++++++++++ ethereum/tests/test_abi.py | 26 +++++++- 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 ethereum/tests/abi_type_strategies.py diff --git a/.gitignore b/.gitignore index 827274029..4a5b7ac18 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ pyethereum/todo.txt pyethereum/monkeypatch.py .eggs .cache +.hypothesis diff --git a/.travis.yml b/.travis.yml index 83ced25b8..8eb2bcfca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,10 @@ env: - TOX_ENV=py27 global: secure: cKbIgpTJ1yjKLBxpCEiT6IH7NShDWZUE+BvnrAfc+ujCsR6LyLJcKxFQmKnWryJCqg7fp82Ep2bF2oDKzanAROar2xDY1SFGbai42seYMaFCw53YPGJ6u3VNCcfT0rN9BWgE7el/m4fjcD6CRsZYKArNNJbMX8csRt3uXXCFLso= +cache: + directories: + - $HOME/.cache/pip + - .hypothesis install: - pip install -Ur requirements.txt - pip install -Ur dev_requirements.txt diff --git a/dev_requirements.txt b/dev_requirements.txt index 8bd463833..054e4e75b 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -3,4 +3,5 @@ coveralls pytest>=2.9.0 pytest-catchlog==1.2.2 pytest-timeout==1.0.0 +hypothesis>=3.4.0 https://github.com/ethereum/serpent/tarball/develop diff --git a/ethereum/tests/abi_type_strategies.py b/ethereum/tests/abi_type_strategies.py new file mode 100644 index 000000000..37c124867 --- /dev/null +++ b/ethereum/tests/abi_type_strategies.py @@ -0,0 +1,92 @@ +import itertools + +import hypothesis.strategies as st + + +strat_int256 = st.integers(min_value=-1 * 2**255, max_value=2**255 - 1) +strat_uint256 = st.integers(min_value=0, max_value=2**256 - 1) + +MAX_LIST_SIZE = 3 +MIN_LIST_SIZE = 0 + + +def listify(value): + return [value] + + +uint_raw_strats = [ + ('uint' + str(sub), st.integers(min_value=0, max_value=2**sub - 1)) + for sub in range(8, 257, 8) +] +uint_strats = [ + st.tuples(st.just(key), strat) for key, strat in uint_raw_strats +] + + +int_raw_strats = [ + ('int' + str(sub), st.integers(min_value=-1 * 2**(sub - 1), max_value=2**(sub - 1) - 1)) + for sub in range(8, 257, 8) +] +int_strats = [ + st.tuples(st.just(key), strat) for key, strat in int_raw_strats +] + + +bytes_raw_strats = [ + ('bytes' + str(sub), st.binary(min_size=sub, max_size=sub)) + for sub in range(1, 33) +] +bytes_strats = [ + st.tuples(st.just(key), strat) for key, strat in bytes_raw_strats +] + + +address_raw_strat = st.binary(min_size=20, max_size=20).map(lambda v: v.encode('hex')) +address_strat = st.tuples( + st.just('address'), + address_raw_strat, +) + + +all_basic_raw_strats = list(itertools.chain( + int_raw_strats, uint_raw_strats, bytes_raw_strats, [('address', address_raw_strat)], +)) +all_basic_strats = list(itertools.chain( + int_strats, uint_strats, bytes_strats, [address_strat], +)) + + +unsized_list_raw_strats = [ + (type_str + "[]", st.lists(type_strat, min_size=0, max_size=MAX_LIST_SIZE)) + for type_str, type_strat in all_basic_raw_strats +] +unsized_list_strats = [ + st.tuples(st.just(type_str), type_strat) + for type_str, type_strat in unsized_list_raw_strats +] + + +sized_list_strats = [ + st.tuples( + st.shared( + st.integers(min_value=MIN_LIST_SIZE, max_value=MAX_LIST_SIZE), + key="n", + ).map(lambda n: type_str + "[{0}]".format(n)), + st.shared( + st.integers(min_value=MIN_LIST_SIZE, max_value=MAX_LIST_SIZE), + key="n", + ).flatmap(lambda n: st.lists(type_strat, min_size=n, max_size=n)) + ) for type_str, type_strat in all_basic_raw_strats +] + + +def zip_types_and_values(types_and_values): + types, values = zip(*types_and_values) + return list(types), list(values) + + +all_abi_strats = st.lists( + st.one_of(itertools.chain(unsized_list_strats, sized_list_strats, all_basic_strats)), + min_size=1, + max_size=10, +).map(zip_types_and_values) diff --git a/ethereum/tests/test_abi.py b/ethereum/tests/test_abi.py index 03fd3933a..d9e7f3483 100644 --- a/ethereum/tests/test_abi.py +++ b/ethereum/tests/test_abi.py @@ -1,13 +1,37 @@ -import os +import itertools import pytest +from hypothesis import given +import hypothesis.strategies as st import ethereum.testutils as testutils from ethereum.slogging import get_logger import ethereum.abi as abi from ethereum.utils import zpad +from .abi_type_strategies import all_abi_strats + + logger = get_logger() +#@given(st.one_of(address_strat, *itertools.chain( +# uint_strats, +# int_strats, +# bytes_strats, +# unsized_list_strats, +# sized_list_strats, +#))) +@given(all_abi_strats) +def test_reversability(types_and_values): + """ + Tests round trip encoding and decoding for basic types and lists of basic + types. + """ + types, value = types_and_values + encoded_value = abi.encode_abi(types, value) + decoded_value = abi.decode_abi(types, encoded_value) + assert value == decoded_value + + def test_abi_encode_var_sized_array(): abi.encode_abi(['address[]'], [[b'\x00' * 20] * 3]) From f328acb7a89dc2fc2fe05fb1a7ab9b2cce95cf9f Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Mon, 13 Jun 2016 12:36:03 -0600 Subject: [PATCH 2/4] increase max list size --- ethereum/tests/abi_type_strategies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/tests/abi_type_strategies.py b/ethereum/tests/abi_type_strategies.py index 37c124867..79d35b85d 100644 --- a/ethereum/tests/abi_type_strategies.py +++ b/ethereum/tests/abi_type_strategies.py @@ -6,7 +6,7 @@ strat_int256 = st.integers(min_value=-1 * 2**255, max_value=2**255 - 1) strat_uint256 = st.integers(min_value=0, max_value=2**256 - 1) -MAX_LIST_SIZE = 3 +MAX_LIST_SIZE = 8 MIN_LIST_SIZE = 0 From ef1018cc73a52413f9438a83ae6d359a99c56a1b Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Mon, 13 Jun 2016 14:43:41 -0600 Subject: [PATCH 3/4] remove listify function --- ethereum/tests/abi_type_strategies.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ethereum/tests/abi_type_strategies.py b/ethereum/tests/abi_type_strategies.py index 79d35b85d..86819709a 100644 --- a/ethereum/tests/abi_type_strategies.py +++ b/ethereum/tests/abi_type_strategies.py @@ -10,10 +10,6 @@ MIN_LIST_SIZE = 0 -def listify(value): - return [value] - - uint_raw_strats = [ ('uint' + str(sub), st.integers(min_value=0, max_value=2**sub - 1)) for sub in range(8, 257, 8) From 4d4c8d0dd5200d8e7638d4c395c1966660943b61 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Mon, 13 Jun 2016 14:44:29 -0600 Subject: [PATCH 4/4] cleanup test file --- ethereum/tests/test_abi.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ethereum/tests/test_abi.py b/ethereum/tests/test_abi.py index d9e7f3483..bf6dde62e 100644 --- a/ethereum/tests/test_abi.py +++ b/ethereum/tests/test_abi.py @@ -1,7 +1,5 @@ -import itertools import pytest from hypothesis import given -import hypothesis.strategies as st import ethereum.testutils as testutils from ethereum.slogging import get_logger import ethereum.abi as abi @@ -13,13 +11,6 @@ logger = get_logger() -#@given(st.one_of(address_strat, *itertools.chain( -# uint_strats, -# int_strats, -# bytes_strats, -# unsized_list_strats, -# sized_list_strats, -#))) @given(all_abi_strats) def test_reversability(types_and_values): """