mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-01-20 07:29:02 +00:00
implement new ssz generic tests
This commit is contained in:
parent
c628c8187b
commit
5b956b3d26
@ -1,46 +1,5 @@
|
||||
from uint_test_cases import (
|
||||
generate_random_uint_test_cases,
|
||||
generate_uint_wrong_length_test_cases,
|
||||
generate_uint_bounds_test_cases,
|
||||
generate_uint_out_of_bounds_test_cases
|
||||
)
|
||||
|
||||
from gen_base import gen_runner, gen_suite, gen_typing
|
||||
|
||||
def ssz_random_uint_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
|
||||
return ("uint_random", "uint", gen_suite.render_suite(
|
||||
title="UInt Random",
|
||||
summary="Random integers chosen uniformly over the allowed value range",
|
||||
forks_timeline= "mainnet",
|
||||
forks=["phase0"],
|
||||
config="mainnet",
|
||||
runner="ssz",
|
||||
handler="uint",
|
||||
test_cases=generate_random_uint_test_cases()))
|
||||
|
||||
|
||||
def ssz_wrong_uint_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
|
||||
return ("uint_wrong_length", "uint", gen_suite.render_suite(
|
||||
title="UInt Wrong Length",
|
||||
summary="Serialized integers that are too short or too long",
|
||||
forks_timeline= "mainnet",
|
||||
forks=["phase0"],
|
||||
config="mainnet",
|
||||
runner="ssz",
|
||||
handler="uint",
|
||||
test_cases=generate_uint_wrong_length_test_cases()))
|
||||
|
||||
|
||||
def ssz_uint_bounds_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
|
||||
return ("uint_bounds", "uint", gen_suite.render_suite(
|
||||
title="UInt Bounds",
|
||||
summary="Integers right at or beyond the bounds of the allowed value range",
|
||||
forks_timeline= "mainnet",
|
||||
forks=["phase0"],
|
||||
config="mainnet",
|
||||
runner="ssz",
|
||||
handler="uint",
|
||||
test_cases=generate_uint_bounds_test_cases() + generate_uint_out_of_bounds_test_cases()))
|
||||
from gen_base import gen_runner, gen_typing
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -1,93 +0,0 @@
|
||||
from collections.abc import (
|
||||
Mapping,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
from eth_utils import (
|
||||
encode_hex,
|
||||
to_dict,
|
||||
)
|
||||
|
||||
from ssz.sedes import (
|
||||
BaseSedes,
|
||||
Boolean,
|
||||
Bytes,
|
||||
BytesN,
|
||||
Container,
|
||||
List,
|
||||
UInt,
|
||||
)
|
||||
|
||||
|
||||
def render_value(value):
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
elif isinstance(value, int):
|
||||
return str(value)
|
||||
elif isinstance(value, bytes):
|
||||
return encode_hex(value)
|
||||
elif isinstance(value, Sequence):
|
||||
return tuple(render_value(element) for element in value)
|
||||
elif isinstance(value, Mapping):
|
||||
return render_dict_value(value)
|
||||
else:
|
||||
raise ValueError(f"Cannot render value {value}")
|
||||
|
||||
|
||||
@to_dict
|
||||
def render_dict_value(value):
|
||||
for key, value in value.items():
|
||||
yield key, render_value(value)
|
||||
|
||||
|
||||
def render_type_definition(sedes):
|
||||
if isinstance(sedes, Boolean):
|
||||
return "bool"
|
||||
|
||||
elif isinstance(sedes, UInt):
|
||||
return f"uint{sedes.length * 8}"
|
||||
|
||||
elif isinstance(sedes, BytesN):
|
||||
return f"bytes{sedes.length}"
|
||||
|
||||
elif isinstance(sedes, Bytes):
|
||||
return f"bytes"
|
||||
|
||||
elif isinstance(sedes, List):
|
||||
return [render_type_definition(sedes.element_sedes)]
|
||||
|
||||
elif isinstance(sedes, Container):
|
||||
return {
|
||||
field_name: render_type_definition(field_sedes)
|
||||
for field_name, field_sedes in sedes.fields
|
||||
}
|
||||
|
||||
elif isinstance(sedes, BaseSedes):
|
||||
raise Exception("Unreachable: All sedes types have been checked")
|
||||
|
||||
else:
|
||||
raise TypeError("Expected BaseSedes")
|
||||
|
||||
|
||||
@to_dict
|
||||
def render_test_case(*, sedes, valid, value=None, serial=None, description=None, tags=None):
|
||||
value_and_serial_given = value is not None and serial is not None
|
||||
if valid:
|
||||
if not value_and_serial_given:
|
||||
raise ValueError("For valid test cases, both value and ssz must be present")
|
||||
else:
|
||||
if value_and_serial_given:
|
||||
raise ValueError("For invalid test cases, one of either value or ssz must not be present")
|
||||
|
||||
if tags is None:
|
||||
tags = []
|
||||
|
||||
yield "type", render_type_definition(sedes)
|
||||
yield "valid", valid
|
||||
if value is not None:
|
||||
yield "value", render_value(value)
|
||||
if serial is not None:
|
||||
yield "ssz", encode_hex(serial)
|
||||
if description is not None:
|
||||
yield description
|
||||
yield "tags", tags
|
@ -1,4 +1,4 @@
|
||||
eth-utils==1.6.0
|
||||
../../test_libs/gen_helpers
|
||||
../../test_libs/config_helpers
|
||||
ssz==0.1.0a2
|
||||
../../test_libs/pyspec
|
||||
|
33
test_generators/ssz_generic/ssz_bitlist.py
Normal file
33
test_generators/ssz_generic/ssz_bitlist.py
Normal file
@ -0,0 +1,33 @@
|
||||
from .ssz_test_case import invalid_test_case, valid_test_case
|
||||
from eth2spec.utils.ssz.ssz_typing import Bitlist
|
||||
from eth2spec.utils.ssz.ssz_impl import serialize
|
||||
from random import Random
|
||||
from eth2spec.debug.random_value import RandomizationMode, get_random_ssz_object
|
||||
|
||||
|
||||
def bitlist_case_fn(rng: Random, mode: RandomizationMode, limit: int):
|
||||
return get_random_ssz_object(rng, Bitlist[limit],
|
||||
max_bytes_length=(limit // 8) + 1,
|
||||
max_list_length=limit,
|
||||
mode=mode, chaos=False)
|
||||
|
||||
|
||||
def valid_cases():
|
||||
rng = Random(1234)
|
||||
for size in [1, 2, 3, 4, 5, 8, 16, 31, 512, 513]:
|
||||
for variation in range(5):
|
||||
for mode in [RandomizationMode.mode_random, RandomizationMode.mode_zero, RandomizationMode.mode_max]:
|
||||
yield f'bitlist_{size}_{mode.to_name()}_{variation}', \
|
||||
valid_test_case(lambda: bitlist_case_fn(rng, mode, size))
|
||||
|
||||
|
||||
def invalid_cases():
|
||||
yield 'bitlist_no_delimiter_empty', invalid_test_case(lambda: b'')
|
||||
yield 'bitlist_no_delimiter_zero_byte', invalid_test_case(lambda: b'\x00')
|
||||
yield 'bitlist_no_delimiter_zeroes', invalid_test_case(lambda: b'\x00\x00\x00')
|
||||
rng = Random(1234)
|
||||
for (typ_limit, test_limit) in [(1, 2), (1, 8), (1, 9), (2, 3), (3, 4), (4, 5),
|
||||
(5, 6), (8, 9), (32, 64), (32, 33), (512, 513)]:
|
||||
yield f'bitlist_{typ_limit}_but_{test_limit}', \
|
||||
invalid_test_case(lambda: serialize(
|
||||
bitlist_case_fn(rng, RandomizationMode.mode_max_count, test_limit)))
|
30
test_generators/ssz_generic/ssz_bitvector.py
Normal file
30
test_generators/ssz_generic/ssz_bitvector.py
Normal file
@ -0,0 +1,30 @@
|
||||
from .ssz_test_case import invalid_test_case, valid_test_case
|
||||
from eth2spec.utils.ssz.ssz_typing import Bitvector
|
||||
from eth2spec.utils.ssz.ssz_impl import serialize
|
||||
from random import Random
|
||||
from eth2spec.debug.random_value import RandomizationMode, get_random_ssz_object
|
||||
|
||||
|
||||
def bitvector_case_fn(rng: Random, mode: RandomizationMode, size: int):
|
||||
return get_random_ssz_object(rng, Bitvector[size],
|
||||
max_bytes_length=(size + 7) // 8,
|
||||
max_list_length=size,
|
||||
mode=mode, chaos=False)
|
||||
|
||||
|
||||
def valid_cases():
|
||||
rng = Random(1234)
|
||||
for size in [1, 2, 3, 4, 5, 8, 16, 31, 512, 513]:
|
||||
for mode in [RandomizationMode.mode_random, RandomizationMode.mode_zero, RandomizationMode.mode_max]:
|
||||
yield f'bitvec_{size}_{mode.to_name()}', valid_test_case(lambda: bitvector_case_fn(rng, mode, size))
|
||||
|
||||
|
||||
def invalid_cases():
|
||||
# zero length bitvecors are illegal
|
||||
yield 'bitvec_0', lambda: b''
|
||||
rng = Random(1234)
|
||||
for (typ_size, test_size) in [(1, 2), (2, 3), (3, 4), (4, 5),
|
||||
(5, 6), (8, 9), (9, 8), (16, 8), (32, 33), (512, 513)]:
|
||||
for mode in [RandomizationMode.mode_random, RandomizationMode.mode_zero, RandomizationMode.mode_max]:
|
||||
yield f'bitvec_{typ_size}_{mode.to_name()}_{test_size}', \
|
||||
invalid_test_case(lambda: serialize(bitvector_case_fn(rng, mode, test_size)))
|
15
test_generators/ssz_generic/ssz_boolean.py
Normal file
15
test_generators/ssz_generic/ssz_boolean.py
Normal file
@ -0,0 +1,15 @@
|
||||
from .ssz_test_case import valid_test_case, invalid_test_case
|
||||
from eth2spec.utils.ssz.ssz_typing import boolean
|
||||
|
||||
|
||||
def valid_cases():
|
||||
yield "true", valid_test_case(lambda: boolean(True))
|
||||
yield "false", valid_test_case(lambda: boolean(False))
|
||||
|
||||
|
||||
def invalid_cases():
|
||||
yield "byte_2", invalid_test_case(lambda: b'\x02')
|
||||
yield "byte_rev_nibble", invalid_test_case(lambda: b'\x10')
|
||||
yield "byte_0x80", invalid_test_case(lambda: b'\x80')
|
||||
yield "byte_full", invalid_test_case(lambda: b'\xff')
|
||||
|
21
test_generators/ssz_generic/ssz_test_case.py
Normal file
21
test_generators/ssz_generic/ssz_test_case.py
Normal file
@ -0,0 +1,21 @@
|
||||
from eth2spec.utils.ssz.ssz_impl import serialize, hash_tree_root, signing_root
|
||||
from eth2spec.debug.encode import encode
|
||||
from eth2spec.utils.ssz.ssz_typing import SSZValue, Container
|
||||
from typing import Callable
|
||||
|
||||
|
||||
def valid_test_case(value_fn: Callable[[], SSZValue]):
|
||||
def case_fn():
|
||||
value = value_fn()
|
||||
yield "value", "data", encode(value)
|
||||
yield "serialized", "ssz", serialize(value)
|
||||
yield "root", "meta", '0x' + hash_tree_root(value).hex()
|
||||
if isinstance(value, Container):
|
||||
yield "signing_root", "meta", '0x' + signing_root(value).hex()
|
||||
return case_fn
|
||||
|
||||
|
||||
def invalid_test_case(bytez_fn: Callable[[], bytes]):
|
||||
def case_fn():
|
||||
yield "serialized", "ssz", bytez_fn()
|
||||
return case_fn
|
34
test_generators/ssz_generic/ssz_uints.py
Normal file
34
test_generators/ssz_generic/ssz_uints.py
Normal file
@ -0,0 +1,34 @@
|
||||
from .ssz_test_case import invalid_test_case, valid_test_case
|
||||
from eth2spec.utils.ssz.ssz_typing import BasicType, uint8, uint16, uint32, uint64, uint128, uint256
|
||||
from random import Random
|
||||
from eth2spec.debug.random_value import RandomizationMode, get_random_ssz_object
|
||||
|
||||
|
||||
def uint_case_fn(rng: Random, mode: RandomizationMode, typ: BasicType):
|
||||
return get_random_ssz_object(rng, typ,
|
||||
max_bytes_length=typ.byte_len,
|
||||
max_list_length=1,
|
||||
mode=mode, chaos=False)
|
||||
|
||||
|
||||
def valid_cases():
|
||||
rng = Random(1234)
|
||||
for uint_type in [uint8, uint16, uint32, uint64, uint128, uint256]:
|
||||
yield f'uint_{uint_type.byte_len * 8}_last_byte_empty', \
|
||||
valid_test_case(lambda: uint_type((2 ** ((uint_type.byte_len - 1) * 8)) - 1))
|
||||
for variation in range(5):
|
||||
for mode in [RandomizationMode.mode_random, RandomizationMode.mode_zero, RandomizationMode.mode_max]:
|
||||
yield f'uint_{uint_type.byte_len * 8}_{mode.to_name()}_{variation}', \
|
||||
valid_test_case(lambda: uint_case_fn(rng, mode, uint_type))
|
||||
|
||||
|
||||
def invalid_cases():
|
||||
for uint_type in [uint8, uint16, uint32, uint64, uint128, uint256]:
|
||||
yield f'uint_{uint_type.byte_len * 8}_one_too_high', \
|
||||
invalid_test_case(lambda: (2 ** (uint_type.byte_len * 8)).to_bytes(uint_type.byte_len + 1, 'little'))
|
||||
for uint_type in [uint8, uint16, uint32, uint64, uint128, uint256]:
|
||||
yield f'uint_{uint_type.byte_len * 8}_one_byte_longer', \
|
||||
invalid_test_case(lambda: (2 ** (uint_type.byte_len * 8) - 1).to_bytes(uint_type.byte_len + 1, 'little'))
|
||||
for uint_type in [uint8, uint16, uint32, uint64, uint128, uint256]:
|
||||
yield f'uint_{uint_type.byte_len * 8}_one_byte_shorter', \
|
||||
invalid_test_case(lambda: (2 ** ((uint_type.byte_len - 1) * 8) - 1).to_bytes(uint_type.byte_len - 1, 'little'))
|
Loading…
x
Reference in New Issue
Block a user