Skip to content

Commit

Permalink
fix(plugins/forks): fix forks when there are multiple dev forks
Browse files Browse the repository at this point in the history
  • Loading branch information
marioevz committed May 30, 2024
1 parent 37410da commit a6df183
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 67 deletions.
133 changes: 67 additions & 66 deletions src/pytest_plugins/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import sys
import textwrap
from dataclasses import dataclass, field
from typing import Any, Dict, List
from typing import Any, List

import pytest
from pytest import Metafunc
Expand Down Expand Up @@ -149,14 +149,23 @@ def add_values(self, metafunc: Metafunc, fork_parametrizer: ForkParametrizer) ->
]


def get_last_descendant(fork_names: List[str], fork_map: Dict[str, Fork], fork_name: str) -> str:
def get_fork_range(forks: List[Fork], forks_from: Fork, forks_until: Fork) -> List[Fork]:
"""
Get the fork range from forks_from to forks_until.
"""
return [
next_fork for next_fork in forks if next_fork <= forks_until and next_fork >= forks_from
]


def get_last_descendant(forks: List[Fork], fork: Fork) -> Fork:
"""
Get the last descendant of a class in the inheritance hierarchy.
"""
for next_fork in reversed(fork_names):
if fork_map[next_fork] >= fork_map[fork_name]:
for next_fork in reversed(forks):
if next_fork >= fork:
return next_fork
return fork_name
return fork


@pytest.hookimpl(tryfirst=True)
Expand Down Expand Up @@ -186,19 +195,8 @@ def pytest_configure(config):
for d in fork_covariant_descriptors:
config.addinivalue_line("markers", f"{d.marker_name}: {d.description}")

def get_fork_option(config, option_name):
"""Post-process get option to allow for external fork conditions."""
option = config.getoption(option_name)
return "Paris" if option == "Merge" else option

single_fork = get_fork_option(config, "single_fork")
forks_from = get_fork_option(config, "forks_from")
forks_until = get_fork_option(config, "forks_until")
show_fork_help = config.getoption("show_fork_help")

config.all_forks = [fork for fork in get_forks() if not fork.ignore()]
config.fork_map = {fork.name(): fork for fork in config.all_forks}
config.fork_names = list(config.fork_map.keys())
config.forks = [fork for fork in get_forks() if not fork.ignore()]
config.fork_names = [fork.name() for fork in config.forks]

available_forks_help = textwrap.dedent(
f"""\
Expand All @@ -212,6 +210,31 @@ def get_fork_option(config, option_name):
{", ".join([fork.name() for fork in get_transition_forks()])}
"""
)

def get_fork_option(config, option_name: str, parameter_name: str) -> Fork | None:
"""Post-process get option to allow for external fork conditions."""
option = config.getoption(option_name)
if not option:
return None
if option == "Merge":
option = "Paris"
for fork in get_forks():
if option == fork.name():
return fork
print(
f"Error: Unsupported fork provided to {parameter_name}:",
option,
"\n",
file=sys.stderr,
)
print(available_forks_help, file=sys.stderr)
pytest.exit("Invalid command-line options.", returncode=pytest.ExitCode.USAGE_ERROR)

single_fork = get_fork_option(config, "single_fork", "--fork")
forks_from = get_fork_option(config, "forks_from", "--from")
forks_until = get_fork_option(config, "forks_until", "--until")
show_fork_help = config.getoption("show_fork_help")

dev_forks_help = textwrap.dedent(
"To run tests for a fork under active development, it must be "
"specified explicitly via --forks-until=FORK.\n"
Expand All @@ -223,11 +246,6 @@ def get_fork_option(config, option_name):
print(dev_forks_help)
pytest.exit("After displaying help.", returncode=0)

if single_fork and single_fork not in config.fork_map.keys():
print("Error: Unsupported fork provided to --fork:", single_fork, "\n", file=sys.stderr)
print(available_forks_help, file=sys.stderr)
pytest.exit("Invalid command-line options.", returncode=pytest.ExitCode.USAGE_ERROR)

if single_fork and (forks_from or forks_until):
print(
"Error: --fork cannot be used in combination with --from or --until", file=sys.stderr
Expand All @@ -239,27 +257,16 @@ def get_fork_option(config, option_name):
forks_until = single_fork
else:
if not forks_from:
forks_from = config.fork_names[0]
forks_from = config.forks[0]
if not forks_until:
forks_until = get_deployed_forks()[-1].name()
forks_until = get_last_descendant(get_deployed_forks(), forks_from)

if forks_from not in config.fork_map.keys():
print(f"Error: Unsupported fork provided to --from: {forks_from}\n", file=sys.stderr)
print(available_forks_help, file=sys.stderr)
pytest.exit("Invalid command-line options.", returncode=pytest.ExitCode.USAGE_ERROR)

if forks_until not in config.fork_map.keys():
print(f"Error: Unsupported fork provided to --until: {forks_until}\n", file=sys.stderr)
print(available_forks_help, file=sys.stderr)
pytest.exit("Invalid command-line options.", returncode=pytest.ExitCode.USAGE_ERROR)

config.fork_range = config.fork_names[
config.fork_names.index(forks_from) : config.fork_names.index(forks_until) + 1
]
config.fork_range = get_fork_range(config.forks, forks_from, forks_until)

if not config.fork_range:
print(
f"Error: --from {forks_from} --until {forks_until} creates an empty fork range.",
f"Error: --from {forks_from.name()} --until {forks_until.name()} "
"creates an empty fork range.",
file=sys.stderr,
)
pytest.exit(
Expand All @@ -275,7 +282,7 @@ def get_fork_option(config, option_name):
evm_bin = config.getoption("evm_bin")
t8n = TransitionTool.from_binary_path(binary_path=evm_bin)
config.unsupported_forks = [
fork for fork in config.fork_range if not t8n.is_fork_supported(config.fork_map[fork])
fork for fork in config.fork_range if not t8n.is_fork_supported(fork)
]


Expand All @@ -286,7 +293,11 @@ def pytest_report_header(config, start_path):
warning = "\033[93m"
reset = "\033[39;49m"
header = [
(bold + f"Executing tests for: {', '.join(config.fork_range)} " + reset),
(
bold
+ f"Executing tests for: {', '.join([f.name() for f in config.fork_range])} "
+ reset
),
]
if config.getoption("forks_until") is None:
header += [
Expand All @@ -311,7 +322,7 @@ def get_validity_marker_args(
metafunc: Metafunc,
validity_marker_name: str,
test_name: str,
) -> str | None:
) -> Fork | None:
"""Check and return the arguments specified to validity markers.
Check that the validity markers:
Expand Down Expand Up @@ -347,14 +358,16 @@ def get_validity_marker_args(
f"'{test_name}': Too many arguments specified to '{validity_marker_name}' marker. "
)
fork_name = validity_markers[0].args[0]
if fork_name not in metafunc.config.fork_names: # type: ignore
pytest.fail(
f"'{test_name}' specifies an invalid fork '{fork_name}' to the "
f"'{validity_marker_name}'. "
f"List of valid forks: {', '.join(metafunc.config.fork_names)}" # type: ignore
)

return fork_name
for fork in metafunc.config.forks: # type: ignore
if fork.name() == fork_name:
return fork

pytest.fail(
f"'{test_name}' specifies an invalid fork '{fork_name}' to the "
f"'{validity_marker_name}'. "
f"List of valid forks: {', '.join(metafunc.config.fork_names)}" # type: ignore
)


def pytest_generate_tests(metafunc):
Expand Down Expand Up @@ -383,26 +396,16 @@ def pytest_generate_tests(metafunc):

if valid_at_transition_to:
if valid_at_transition_to in metafunc.config.fork_range:
to_fork = metafunc.config.fork_map[valid_at_transition_to]
intersection_range = transition_fork_to(to_fork)
intersection_range = transition_fork_to(valid_at_transition_to)

else:
if not valid_from:
valid_from = metafunc.config.fork_names[0]
valid_from = metafunc.config.forks[0]

if not valid_until:
valid_until = get_last_descendant(
metafunc.config.fork_names, metafunc.config.fork_map, valid_from
)
valid_until = get_last_descendant(metafunc.config.fork_range, valid_from)

test_fork_range = set(
metafunc.config.fork_names[
metafunc.config.fork_names.index(valid_from) : metafunc.config.fork_names.index(
valid_until
)
+ 1
]
)
test_fork_range = get_fork_range(metafunc.config.forks, valid_from, valid_until)

if not test_fork_range:
pytest.fail(
Expand All @@ -413,10 +416,8 @@ def pytest_generate_tests(metafunc):
f"@pytest.mark.valid_until ({valid_until})."
)

intersection_range = list(set(metafunc.config.fork_range) & test_fork_range)

intersection_range = list(set(metafunc.config.fork_range) & set(test_fork_range))
intersection_range.sort(key=metafunc.config.fork_range.index)
intersection_range = [metafunc.config.fork_map[fork] for fork in intersection_range]

if "fork" in metafunc.fixturenames:
if not intersection_range:
Expand Down
7 changes: 6 additions & 1 deletion src/pytest_plugins/test_filler/test_filler.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,12 @@ class so that upon instantiation within the test case, it provides the
pytest.fail(
f"{request.node.name}: Expected one argument in 'compile_yul_with' marker."
)
solc_target_fork = request.config.fork_map[marker.args[0]]
for fork in request.config.forks:
if fork.name() == marker.args[0]:
solc_target_fork = fork
break
else:
pytest.fail(f"{request.node.name}: Fork {marker.args[0]} not found in forks list.")
assert solc_target_fork in get_forks_with_solc_support(request.config.solc_version)
else:
solc_target_fork = get_closest_fork_with_solc_support(fork, request.config.solc_version)
Expand Down

0 comments on commit a6df183

Please sign in to comment.