Skip to content

Commit f00f893

Browse files
tcoratgerclaude
andauthored
test: extend SSZ round-trip properties to every type family (leanEthereum#866)
The first property pass covered unsigned integers and bitfields only. The remaining families are just as property-testable. Booleans, fixed byte vectors, bounded byte lists, element lists, element vectors, and mixed fixed-and-variable containers now all round-trip random values in their mirrored test files. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent bf49884 commit f00f893

4 files changed

Lines changed: 58 additions & 0 deletions

File tree

tests/lean_spec/spec/ssz/test_boolean.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Any, Callable
66

77
import pytest
8+
from hypothesis import given, strategies as st
89
from pydantic import BaseModel, ValidationError
910

1011
from lean_spec.spec.ssz.boolean import Boolean
@@ -323,3 +324,10 @@ def test_deserialize_premature_stream_end(self) -> None:
323324
stream = io.BytesIO(b"") # Empty stream
324325
with pytest.raises(SSZSerializationError, match=r"^Boolean: expected 1 byte, got 0$"):
325326
Boolean.deserialize(stream, scope=1)
327+
328+
329+
@given(boolean_value=st.booleans())
330+
def test_encode_decode_round_trip_random_values(boolean_value: bool) -> None:
331+
"""Either truth value survives an encode and decode round trip unchanged."""
332+
instance = Boolean(boolean_value)
333+
assert Boolean.decode_bytes(instance.encode_bytes()) == instance

tests/lean_spec/spec/ssz/test_byte_arrays.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Any
88

99
import pytest
10+
from hypothesis import given, strategies as st
1011
from pydantic import BaseModel
1112

1213
from lean_spec.spec.ssz.byte_arrays import (
@@ -505,3 +506,17 @@ def test_json_dumpable_via_hex() -> None:
505506
"payload": ByteList5(data=b"\x00\x01\x02").hex(),
506507
}
507508
assert json.loads(json.dumps(hex_encoded_fields)) == hex_encoded_fields
509+
510+
511+
@given(raw_bytes=st.binary(min_size=32, max_size=32))
512+
def test_byte_vector_round_trip_random_bytes(raw_bytes: bytes) -> None:
513+
"""Any fixed-length byte pattern survives an encode and decode round trip."""
514+
instance = Bytes32(raw_bytes)
515+
assert Bytes32.decode_bytes(instance.encode_bytes()) == instance
516+
517+
518+
@given(raw_bytes=st.binary(max_size=16))
519+
def test_byte_list_round_trip_random_bytes(raw_bytes: bytes) -> None:
520+
"""Any byte pattern up to the limit, including empty, round-trips unchanged."""
521+
instance = ByteList16(data=raw_bytes)
522+
assert ByteList16.decode_bytes(instance.encode_bytes()) == instance

tests/lean_spec/spec/ssz/test_collections.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import Any, cast
55

66
import pytest
7+
from hypothesis import given, strategies as st
78
from pydantic import BaseModel, ValidationError
89

910
from lean_spec.spec.crypto.koalabear import Fp
@@ -965,3 +966,17 @@ def test_container_elements_pass_through_to_pydantic(self) -> None:
965966
)
966967

967968
assert instance.model_dump(mode="json") == {"data": [{"a": 1, "b": 2}, {"a": 3, "b": 4}]}
969+
970+
971+
@given(values=st.lists(st.integers(min_value=0, max_value=2**16 - 1), max_size=4))
972+
def test_list_round_trip_random_values(values: list[int]) -> None:
973+
"""Any element sequence up to the limit, including empty, round-trips unchanged."""
974+
instance = Uint16List4(data=[Uint16(value) for value in values])
975+
assert Uint16List4.decode_bytes(instance.encode_bytes()) == instance
976+
977+
978+
@given(values=st.lists(st.integers(min_value=0, max_value=255), min_size=4, max_size=4))
979+
def test_vector_round_trip_random_values(values: list[int]) -> None:
980+
"""Any fixed-length element sequence round-trips unchanged."""
981+
instance = Uint8Vector4(data=[Uint8(value) for value in values])
982+
assert Uint8Vector4.decode_bytes(instance.encode_bytes()) == instance

tests/lean_spec/spec/ssz/test_container.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io
44

55
import pytest
6+
from hypothesis import given, strategies as st
67
from pydantic import ValidationError
78

89
from lean_spec.spec.ssz.collections import SSZList
@@ -430,3 +431,22 @@ def test_nested_container_field_accepts_hex_string(self) -> None:
430431
}
431432
)
432433
assert outer == OuterFixedNested(z=Uint64(7), inner=InnerFixed(x=Uint64(1), y=Uint64(2)))
434+
435+
436+
@given(
437+
a=st.integers(min_value=0, max_value=2**64 - 1),
438+
b=st.lists(st.integers(min_value=0, max_value=2**16 - 1), max_size=4),
439+
c=st.integers(min_value=0, max_value=2**32 - 1),
440+
d=st.lists(st.integers(min_value=0, max_value=2**16 - 1), max_size=4),
441+
)
442+
def test_mixed_container_round_trip_random_values(
443+
a: int, b: list[int], c: int, d: list[int]
444+
) -> None:
445+
"""Any mix of fixed and variable field values round-trips unchanged."""
446+
instance = Mixed(
447+
a=Uint64(a),
448+
b=Uint16List4(data=[Uint16(value) for value in b]),
449+
c=Uint32(c),
450+
d=Uint16List4(data=[Uint16(value) for value in d]),
451+
)
452+
assert Mixed.decode_bytes(instance.encode_bytes()) == instance

0 commit comments

Comments
 (0)