Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ pip-delete-this-directory.txt
/doc/autoapi

tests/execution-spec-generated-tests
tests/fixtures
/tests/**/fixtures/
tests/t8n_testdata

fixtures/
/fixtures/

# Trace output (generated by --traces flag)
/traces/
Expand Down
2 changes: 1 addition & 1 deletion packages/testing/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ exclude = ["*tests*"]
"execution_testing.test_types" = ["kzg_trusted_setup.txt"]

[tool.ruff]
line-length = 79
extend = "../../pyproject.toml"

[tool.codespell]
skip = ".venv,__pycache__,.git,build,dist,*.pyc,*.lock"
Expand Down
10 changes: 4 additions & 6 deletions packages/testing/src/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,11 @@ def default_t8n(
DEFAULT_TRANSITION_TOOL_FOR_UNIT_TESTS.__name__
)
if instance is None:
raise Exception(
f"Failed to instantiate {DEFAULT_TRANSITION_TOOL_FOR_UNIT_TESTS.__name__}"
)
tool_name = DEFAULT_TRANSITION_TOOL_FOR_UNIT_TESTS.__name__
raise Exception(f"Failed to instantiate {tool_name}")
if isinstance(instance, Exception):
raise Exception(
f"Failed to instantiate {DEFAULT_TRANSITION_TOOL_FOR_UNIT_TESTS.__name__}"
) from instance
tool_name = DEFAULT_TRANSITION_TOOL_FOR_UNIT_TESTS.__name__
raise Exception(f"Failed to instantiate {tool_name}") from instance
return instance


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ def __str__(self) -> str:
label_str = ""
if self.address.label is not None:
label_str = f" ({self.address.label})"
hint_str = f" ({self.hint})" if self.hint else ""
return (
f"incorrect value in address {self.address}{label_str} for "
+ f"key {Hash(self.key)}{f' ({self.hint})' if self.hint else ''}:"
+ f"key {Hash(self.key)}{hint_str}:"
+ f" want {HexNumber(self.want)} (dec:{int(self.want)}),"
+ f" got {HexNumber(self.got)} (dec:{int(self.got)})"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ def to_fixed_size_bytes(
if right_padding:
return input_bytes.ljust(size, b"\x00")
raise Exception(
f"input is too small for fixed size bytes: {len(input_bytes)} < {size}\n"
f"input is too small for fixed size bytes: "
f"{len(input_bytes)} < {size}\n"
"Use `left_padding=True` or `right_padding=True` to allow padding."
)
return input_bytes
Expand Down
6 changes: 3 additions & 3 deletions packages/testing/src/execution_testing/base_types/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ def __repr_args__(self) -> Any:

# Convert field values based on their type. This ensures consistency
# between JSON and Python object representations. Should a custom
# `__repr__` be needed for a specific type, it can be added in the match
# statement below. Otherwise, the default string representation is
# used.
# `__repr__` be needed for a specific type, it can be added in the
# match statement below. Otherwise, the default string representation
# is used.
repr_attrs: List[Tuple[str, Any]] = []
for a, v in attrs:
match v:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ def _get_latest_spec(self) -> Dict | None:

if response.status_code != 200:
warnings.warn(
f"Unable to get latest version, status code: {response.status_code} - "
f"Unable to get latest version, "
f"status code: {response.status_code} - "
f"text: {response.text}",
stacklevel=2,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ def to_list(self, signing: bool = False) -> List[Any]:
if signing:
if not self.signable:
raise Exception(
f'Object "{self.__class__.__name__}" does not support signing'
f'Object "{self.__class__.__name__}" '
"does not support signing"
)
field_list = self.get_rlp_signing_fields()
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ def test_json_deserialization(
"""Test that to_json returns the expected JSON for the given object."""
if not can_be_deserialized:
pytest.skip(
reason="The model instance in this case can not be deserialized"
reason="The model instance in this case can not be "
"deserialized"
)
model_type = type(model_instance)
assert model_type(**json) == model_instance
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def unwrap_annotation(hint: Any) -> Any:

Returns:
The unwrapped base type

"""
type_args = get_args(hint)
if not type_args:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ class DataPortionVariables(
If the opcode contains variables in its data portion, for
each variable `n` of the opcode that accesses the nth stack
item, test `n` being:
"""
""" # noqa: D400,D415

class Top(ChecklistItem):
"""`n` is the top stack item."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ def test_checklist_template_consistency() -> None:

if missing_in_checklist:
errors.append(
f"IDs found in markdown template but missing in EIPChecklist class "
f"({len(missing_in_checklist)} items):\n"
f"IDs found in markdown template but missing in EIPChecklist "
f"class ({len(missing_in_checklist)} items):\n"
+ "\n".join(f" - `{id_}`" for id_ in sorted(missing_in_checklist))
)

Expand Down
28 changes: 24 additions & 4 deletions packages/testing/src/execution_testing/cli/benchmark_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
if not self._has_benchmark_test_param(node):
return

# Filter for code generator usage (required for fixed-opcode-count mode)
# Filter for code generator usage (required for fixed-opcode-count
# mode)
if not self._uses_code_generator(node):
return

Expand Down Expand Up @@ -149,19 +150,37 @@ def _extract_opcode_name(self, node: ast.expr) -> str | None:
Supported patterns (opcode must be first element):

Case 1 - Direct opcode reference:

```python
@pytest.mark.parametrize("opcode", [Op.ADD, Op.MUL])
```
Result: ["ADD", "MUL"]

Case 2a - pytest.param with direct opcode:
@pytest.mark.parametrize("opcode", [pytest.param(Op.ADD, id="add")])

```python
@pytest.mark.parametrize(
"opcode", [pytest.param(Op.ADD, id="add")]
)
```
Result: ["ADD"]

Case 2b - pytest.param with tuple (opcode first):
@pytest.mark.parametrize("opcode,arg", [pytest.param((Op.ADD, 123))])

```python
@pytest.mark.parametrize(
"opcode,arg", [pytest.param((Op.ADD, 123))]
)
```
Result: ["ADD"]

Case 3 - Plain tuple (opcode first):
@pytest.mark.parametrize("opcode,arg", [(Op.ADD, 123), (Op.MUL, 456)])

```python
@pytest.mark.parametrize(
"opcode,arg", [(Op.ADD, 123), (Op.MUL, 456)]
)
```
Result: ["ADD", "MUL"]
"""
# Case 1: Direct opcode - Op.ADD
Expand Down Expand Up @@ -200,6 +219,7 @@ def scan_benchmark_tests(
Tuple of (config, pattern_sources) where:
- config: mapping of pattern -> opcode counts
- pattern_sources: mapping of pattern -> source file path

"""
config: dict[str, list[int]] = {}
pattern_sources: dict[str, Path] = {}
Expand Down
8 changes: 6 additions & 2 deletions packages/testing/src/execution_testing/cli/check_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ def check_json(json_file_path: Path) -> None:
raise HashMismatchExceptionError(
original_hash,
new_hash,
message=f"Fixture hash attributes do not match for {fixture_name}",
message=(
f"Fixture hash attributes do not match for {fixture_name}"
),
)
if "hash" in fixture.info and fixture.info["hash"] != original_hash:
info_hash = fixture.info["hash"]
Expand Down Expand Up @@ -125,7 +127,9 @@ def get_input_files() -> Generator[Path, None, None]:

with Progress(
TextColumn(
f"[bold cyan]{{task.fields[filename]:<{filename_display_width}}}[/]",
"[bold cyan]"
f"{{task.fields[filename]:<{filename_display_width}}}"
"[/]",
justify="left",
),
BarColumn(
Expand Down
11 changes: 7 additions & 4 deletions packages/testing/src/execution_testing/cli/diff_opcode_counts.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,11 @@ def compare_opcode_counts(
"--remove-from-fixture-names",
"-r",
multiple=True,
help="String to be removed from the fixture name, in case the fixture names have changed, "
"in order to make the comparison easier. "
"Can be specified multiple times.",
help=(
"String to be removed from the fixture name, in case the fixture "
"names have changed, in order to make the comparison easier. "
"Can be specified multiple times."
),
)
def main(
base: Path,
Expand Down Expand Up @@ -205,7 +207,8 @@ def main(
)
elif show_common:
print(
f"\n{common_with_same_counts} fixtures have identical opcode counts"
f"\n{common_with_same_counts} fixtures have identical opcode "
"counts"
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ def info() -> None:

version = AppConfig().version

git_commit = get_current_commit_hash_or_tag(shorten_hash=True)
info_text = f"""
{title} {click.style(f"v{version}", fg="blue", bold=True)}
{"─" * 50}

Git commit: {click.style(get_current_commit_hash_or_tag(shorten_hash=True), fg="yellow")}
Git commit: {click.style(git_commit, fg="yellow")}
Python: {click.style(platform.python_version(), fg="blue")}
uv: {click.style(get_uv_version(), fg="magenta")}
OS: {click.style(f"{platform.system()} {platform.release()}", fg="cyan")}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,12 @@ def test() -> None:
if fork in [dev_fork.name() for dev_fork in get_development_forks()]:
fork_option = f" --until={fork}"

docs_url = DocsConfig().DOCS_URL__WRITING_TESTS
click.echo(
click.style(
f"\n 📝 Get started with tests: {DocsConfig().DOCS_URL__WRITING_TESTS}"
f"\n ⛽ To fill this test, run: `uv run fill {module_path}{fork_option}`",
f"\n 📝 Get started with tests: {docs_url}"
f"\n ⛽ To fill this test, run: "
f"`uv run fill {module_path}{fork_option}`",
fg="cyan",
)
)
33 changes: 22 additions & 11 deletions packages/testing/src/execution_testing/cli/eest/quotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,33 @@
make_something_great = [
"🎨 Simplicity is the ultimate sophistication. - Leonardo D.",
"🖌️ Simplicity is an acquired taste. - Katharine G.",
"💡 To create a memorable design you need to start with a thought that’s worth remembering."
" - Thomas M.",
(
"💡 To create a memorable design you need to start with a thought "
"that's worth remembering. - Thomas M."
),
"🚀 Well begun is half done. - Aristotle",
"🖌️ Designers are crazy and yet sane enough to know where to draw the line. - Benjamin W.",
(
"🖌️ Designers are crazy and yet sane enough to know where to draw "
"the line. - Benjamin W."
),
"🌟 Creativity is piercing the mundane to find the marvelous. - Bill M.",
"🔍 Mistakes are the portals of discovery. - James J.",
"🧠 It's extremely difficult to be simultaneously concerned with the end-user experience of"
" whatever it is that you're building and the architecture of the program that delivers that"
" experience. - James H.",
(
"🧠 It's extremely difficult to be simultaneously concerned with the "
"end-user experience of whatever it is that you're building and the "
"architecture of the program that delivers that experience. - James H."
),
"🧠 Good design is a lot like clear thinking made visual. - Edward T.",
"🚀 Innovation leads one to see the new in the old and distinguishes the ingenious from the"
" ingenuous. - Paul R.",
(
"🚀 Innovation leads one to see the new in the old and distinguishes "
"the ingenious from the ingenuous. - Paul R."
),
"🔮 The best way to predict the future is to invent it. - Alan K.",
"🌟 Perfection is achieved, not when there is nothing more to add, but when there is nothing"
" left to take away. - Antoine d.",
"📏 You can’t improve what you don’t measure. - Tom D.",
(
"🌟 Perfection is achieved, not when there is nothing more to add, "
"but when there is nothing left to take away. - Antoine d."
),
"📏 You can't improve what you don't measure. - Tom D.",
]


Expand Down
4 changes: 2 additions & 2 deletions packages/testing/src/execution_testing/cli/evm_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ def process_evm_bytes(evm_bytes: bytes) -> List[OpcodeWithOperands]: # noqa: D1
return opcodes


def format_opcodes(
def format_opcodes( # noqa: D103
opcodes: List[OpcodeWithOperands], assembly: bool = False
) -> str: # noqa: D103
) -> str:
if assembly:
opcodes_with_empty_lines: List[OpcodeWithOperands] = []
for i, op_with_operands in enumerate(opcodes):
Expand Down
18 changes: 11 additions & 7 deletions packages/testing/src/execution_testing/cli/extract_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
)

from execution_testing.base_types import Alloc
from execution_testing.cli.pytest_commands.plugins.consume.simulators.helpers.ruleset import (
from execution_testing.cli.pytest_commands.plugins.consume.simulators.helpers.ruleset import ( # noqa: E501
ruleset,
)
from execution_testing.fixtures import (
Expand Down Expand Up @@ -130,6 +130,8 @@ def extract_client_files(


class GenesisState(BaseModel):
"""Model representing genesis state for configuration extraction."""

header: FixtureHeader
alloc: Alloc
chain_id: int = Field(exclude=True)
Expand All @@ -139,6 +141,7 @@ class GenesisState(BaseModel):
def serialize_model(
self, handler: SerializerFunctionWrapHandler
) -> dict[str, object]:
"""Serialize the genesis state model to a dictionary."""
serialized = handler(self)
output = serialized["header"]
output["alloc"] = {
Expand Down Expand Up @@ -189,17 +192,16 @@ def from_fixture(cls, fixture_path: Path) -> Self:
)

def get_client_environment(self) -> dict:
"""
Get the environment variables for starting a client with the given fixture.
"""
"""Get the env vars to start a client with a fixture."""
if self.fork not in ruleset:
raise ValueError(f"Fork '{self.fork}' not found in hive ruleset")

return {
"HIVE_CHAIN_ID": str(self.chain_id),
"HIVE_FORK_DAO_VOTE": "1",
"HIVE_NODETYPE": "full",
"HIVE_CHECK_LIVE_PORT": "8545", # Using RPC port for liveness check
# Using RPC port for liveness check
"HIVE_CHECK_LIVE_PORT": "8545",
**{k: f"{v:d}" for k, v in ruleset[self.fork].items()},
}

Expand Down Expand Up @@ -324,14 +326,16 @@ def extract_config(

if len(new_containers) != 1:
click.echo(
f"Expected exactly 1 new container, found {len(new_containers)}",
f"Expected exactly 1 new container, found "
f"{len(new_containers)}",
err=True,
)
sys.exit(1)

container_id = new_containers.pop()
click.echo(
f"Client started successfully (Container ID: {container_id})"
f"Client started successfully "
f"(Container ID: {container_id})"
)

# Optionally list files in container
Expand Down
Loading
Loading