Skip to content

Commit

Permalink
fix(fw): Fix Blocks generator, add assertion on ModelGenerator
Browse files Browse the repository at this point in the history
  • Loading branch information
marioevz committed Apr 4, 2024
1 parent cfb4407 commit a41a283
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 27 deletions.
7 changes: 7 additions & 0 deletions src/ethereum_test_tools/common/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,13 @@ def __init__(self, *, limit: int | Iterable[int] | Iterator[int] = -1, **kwargs:
else:
value = kwargs.pop(field_with_suffix)
assert value is not None, f"value for {field_with_suffix} cannot be None"
assert not isinstance(
value, ModelGenerator
), f"""
Iter value for {field_with_suffix} in {self.__class__.__name__} cannot
be a ModelGenerator ({value.__class__.__name__}).
Use the normal field name without the suffix ({field}) instead.
"""
if isinstance(value, Iterator):
self.iterators[field] = value
elif isinstance(value, Iterable):
Expand Down
23 changes: 23 additions & 0 deletions src/ethereum_test_tools/spec/blockchain/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
Hash,
HeaderNonce,
HexNumber,
ModelGenerator,
Number,
ZeroPaddedHexNumber,
)
Expand Down Expand Up @@ -337,6 +338,28 @@ def set_environment(self, env: Environment) -> Environment:
return env.copy(**new_env_values)


class Blocks(ModelGenerator, model=Block):
"""
Block generator.
This class is used to generate blocks for a blockchain test case.
Takes the same arguments as `Block`, but if an iterable is provided for a
field, it will generate a block for each element in the iterable.
If none of the values are iterables, an exception will be raised because none of the provided
values will be bounded, unless the `limit` argument is provided, which will limit the number
of blocks generated.
Fields that are already supposed to be iterables, such as `txs` and
`withdrawals`, can be parametrized as `txs_iter` and
`withdrawals_iter` respectively and an iterable of iterables can be provided to be
used in each generated block.
"""

pass


class FixtureExecutionPayload(CamelModel):
"""
Representation of an Ethereum execution payload within a test Fixture.
Expand Down
41 changes: 14 additions & 27 deletions src/ethereum_test_tools/tests/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,7 @@
import pytest

from ..common import Address, Transaction, Transactions, Withdrawal, Withdrawals
from ..common.base_types import ModelGenerator
from ..spec.blockchain.types import Block


# Blocks is currently broken, single test involving Blocks is expected to fail
class Blocks(ModelGenerator, model=Block):
"""
Block generator.
This class is used to generate blocks for a blockchain test case.
Takes the same arguments as `Block`, but if an iterable is provided for a
field, it will generate a block for each element in the iterable.
If none of the values are iterables, an exception will be raised because none of the provided
values will be bounded, unless the `limit` argument is provided, which will limit the number
of blocks generated.
Fields that are already supposed to be iterables, such as `txs` and
`withdrawals`, can be parametrized as `txs_iter` and
`withdrawals_iter` respectively and an iterable of iterables can be provided to be
used in each generated block.
"""

pass
from ..spec.blockchain.types import Block, Blocks


@pytest.mark.parametrize(
Expand Down Expand Up @@ -560,7 +536,12 @@ class Blocks(ModelGenerator, model=Block):
),
pytest.param(
Blocks(
txs_iter=Transactions(
# One quirk of the ModelGenerator is that, when used as a field value to other
# ModelGenerators, it has to be added to the normal field instead of
# the `_iter` field.
# Reason being is that the iterator is generated again on every iteration,
# so the generator is embedded into a `cycle` function.
txs=Transactions(
to=(Address(i * 0x100) for i in count(1)),
limit=[3, 2],
),
Expand All @@ -575,26 +556,29 @@ class Blocks(ModelGenerator, model=Block):
to=Address(0x100),
),
Transaction(
nonce=1,
to=Address(0x200),
),
Transaction(
nonce=2,
to=Address(0x300),
),
],
),
Block(
txs=[
Transaction(
nonce=3,
to=Address(0x400),
),
Transaction(
nonce=4,
to=Address(0x500),
),
],
),
]
],
marks=pytest.mark.xfail(reason="Blocks generator is broken"),
id="blocks-1",
),
],
Expand All @@ -604,6 +588,9 @@ def test_generators(
chunks: int,
expected_lists: List[List[Transaction | Withdrawal | Block]],
):
"""
Test generating models using the provided model generators.
"""
chunked_elements: List[List[Transaction | Withdrawal | Block]] = []
for _ in range(chunks):
chunked_elements.append(list(generator))
Expand Down

0 comments on commit a41a283

Please sign in to comment.