11"""The module contains the pytest hooks for the gas benchmark values."""
22
3+ import importlib .util
4+ import sys
5+ from pathlib import Path
6+
37import pytest
48
59from execution_testing .test_types import Environment , EnvironmentDefaults
@@ -26,7 +30,12 @@ def pytest_addoption(parser: pytest.Parser) -> None:
2630 dest = "fixed_opcode_count" ,
2731 type = str ,
2832 default = None ,
29- help = "Specify fixed opcode counts (in thousands) for benchmark tests as a comma-separated list." ,
33+ nargs = "?" ,
34+ const = "" ,
35+ help = (
36+ "Specify fixed opcode counts (in thousands) for benchmark tests as a comma-separated list. "
37+ "If provided without a value, uses defaults from tests/benchmark/configs/fixed_opcode_counts.py."
38+ ),
3039 )
3140
3241
@@ -41,20 +50,47 @@ def pytest_configure(config: pytest.Config) -> None:
4150 config .op_mode = OpMode .BENCHMARKING # type: ignore[attr-defined]
4251
4352
53+ def _load_opcode_counts_config (config : pytest .Config ) -> dict [str , list [int ]] | None :
54+ """
55+ Load the opcode counts configuration from `tests/benchmark/configs/fixed_opcode_counts.py`.
56+
57+ Returns dictionary mapping scenario IDs to opcode counts, or None if config not found.
58+ """
59+ config_path = Path (config .rootpath ) / "tests" / "benchmark" / "configs" / "fixed_opcode_counts.py"
60+
61+ if not config_path .exists ():
62+ return None
63+
64+ # Load the module dynamically
65+ spec = importlib .util .spec_from_file_location ("fixed_opcode_counts" , config_path )
66+ if spec is None or spec .loader is None :
67+ return None
68+
69+ module = importlib .util .module_from_spec (spec )
70+ sys .modules ["fixed_opcode_counts" ] = module
71+ spec .loader .exec_module (module )
72+
73+ return {
74+ "scenario_counts" : getattr (module , "SCENARIO_OPCODE_COUNTS" , {}),
75+ "default_counts" : getattr (module , "DEFAULT_OPCODE_COUNTS" , [100 , 500 , 1000 ]),
76+ }
77+
78+
4479def pytest_collection_modifyitems (
4580 config : pytest .Config , items : list [pytest .Item ]
4681) -> None :
47- """Filter tests based on repricing marker"""
48- gas_benchmark_value = config .getoption ("gas_benchmark_value" )
82+ """Remove non-repricing tests when `--fixed-opcode-count` is specified."""
4983 fixed_opcode_count = config .getoption ("fixed_opcode_count" )
5084
51- if not gas_benchmark_value and not fixed_opcode_count :
85+ # Only filter if --fixed-opcode-count flag was provided (with or without value)
86+ if fixed_opcode_count is None :
5287 return
5388
54- # Check if -m repricing marker filter was specified
55- markexpr = config .getoption ("markexpr" , "" )
56- if "repricing" not in markexpr :
57- return
89+ # Load config data if flag provided without value (empty string)
90+ if fixed_opcode_count == "" :
91+ config_data = _load_opcode_counts_config (config )
92+ if config_data :
93+ config ._opcode_counts_config = config_data # type: ignore[attr-defined]
5894
5995 filtered = []
6096 for item in items :
@@ -85,10 +121,10 @@ def pytest_collection_modifyitems(
85121def pytest_generate_tests (metafunc : pytest .Metafunc ) -> None :
86122 """Generate tests for the gas benchmark values and fixed opcode counts."""
87123 gas_benchmark_values = metafunc .config .getoption ("gas_benchmark_value" )
88- fixed_opcode_counts = metafunc .config .getoption ("fixed_opcode_count" )
124+ fixed_opcode_counts_cli = metafunc .config .getoption ("fixed_opcode_count" )
89125
90126 # Ensure mutual exclusivity
91- if gas_benchmark_values and fixed_opcode_counts :
127+ if gas_benchmark_values and fixed_opcode_counts_cli :
92128 raise pytest .UsageError (
93129 "--gas-benchmark-values and --fixed-opcode-count are mutually exclusive. "
94130 "Use only one at a time."
@@ -111,22 +147,43 @@ def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
111147 )
112148
113149 if "fixed_opcode_count" in metafunc .fixturenames :
114- if fixed_opcode_counts :
115- opcode_counts = [
116- int (x .strip ()) for x in fixed_opcode_counts .split ("," )
117- ]
118- opcode_count_parameters = [
119- pytest .param (
120- opcode_count ,
121- id = f"opcount_{ opcode_count } K" ,
150+ # Only parametrize if test has repricing marker
151+ has_repricing = (
152+ metafunc .definition .get_closest_marker ("repricing" ) is not None
153+ )
154+ if has_repricing :
155+ opcode_counts_to_use = None
156+
157+ if fixed_opcode_counts_cli and fixed_opcode_counts_cli != "" :
158+ # CLI flag with value takes precedence
159+ opcode_counts_to_use = [
160+ int (x .strip ()) for x in fixed_opcode_counts_cli .split ("," )
161+ ]
162+ elif fixed_opcode_counts_cli == "" :
163+ # Flag provided without value - load from config file
164+ config_data = getattr (
165+ metafunc .config , "_opcode_counts_config" , None
166+ )
167+ if config_data :
168+ default_counts = config_data .get (
169+ "default_counts" , [100 ] # Default to 100k for all.
170+ )
171+ opcode_counts_to_use = default_counts
172+
173+ # Parametrize if we have counts to use
174+ if opcode_counts_to_use :
175+ opcode_count_parameters = [
176+ pytest .param (
177+ opcode_count ,
178+ id = f"opcount_{ opcode_count } K" ,
179+ )
180+ for opcode_count in opcode_counts_to_use
181+ ]
182+ metafunc .parametrize (
183+ "fixed_opcode_count" ,
184+ opcode_count_parameters ,
185+ scope = "function" ,
122186 )
123- for opcode_count in opcode_counts
124- ]
125- metafunc .parametrize (
126- "fixed_opcode_count" ,
127- opcode_count_parameters ,
128- scope = "function" ,
129- )
130187
131188
132189@pytest .fixture (scope = "function" )
@@ -135,8 +192,9 @@ def gas_benchmark_value(request: pytest.FixtureRequest) -> int:
135192 if hasattr (request , "param" ):
136193 return request .param
137194
138- # If --fixed-opcode-count is specified, use high gas limit to avoid gas constraints
139- if request .config .getoption ("fixed_opcode_count" ):
195+ # Only use high gas limit if --fixed-opcode-count flag was provided
196+ fixed_opcode_count = request .config .getoption ("fixed_opcode_count" )
197+ if fixed_opcode_count is not None :
140198 return HIGH_GAS_LIMIT
141199
142200 return EnvironmentDefaults .gas_limit
0 commit comments