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,15 +50,48 @@ 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- """Remove non-repricing tests when --fixed-opcode-count is specified."""
82+ """Remove non-repricing tests when ` --fixed-opcode-count` is specified."""
4883 fixed_opcode_count = config .getoption ("fixed_opcode_count" )
49- if not fixed_opcode_count :
50- # If --fixed-opcode-count is not specified, don't filter anything
84+
85+ # Only filter if --fixed-opcode-count flag was provided (with or without value)
86+ if fixed_opcode_count is None :
5187 return
5288
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]
94+
5395 filtered = []
5496 for item in items :
5597 if not item .get_closest_marker ("benchmark" ):
@@ -79,10 +121,10 @@ def pytest_collection_modifyitems(
79121def pytest_generate_tests (metafunc : pytest .Metafunc ) -> None :
80122 """Generate tests for the gas benchmark values and fixed opcode counts."""
81123 gas_benchmark_values = metafunc .config .getoption ("gas_benchmark_value" )
82- fixed_opcode_counts = metafunc .config .getoption ("fixed_opcode_count" )
124+ fixed_opcode_counts_cli = metafunc .config .getoption ("fixed_opcode_count" )
83125
84126 # Ensure mutual exclusivity
85- if gas_benchmark_values and fixed_opcode_counts :
127+ if gas_benchmark_values and fixed_opcode_counts_cli :
86128 raise pytest .UsageError (
87129 "--gas-benchmark-values and --fixed-opcode-count are mutually exclusive. "
88130 "Use only one at a time."
@@ -110,16 +152,32 @@ def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
110152 metafunc .definition .get_closest_marker ("repricing" ) is not None
111153 )
112154 if has_repricing :
113- if fixed_opcode_counts :
114- opcode_counts = [
115- int (x .strip ()) for x in fixed_opcode_counts .split ("," )
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 ("," )
116161 ]
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 :
117175 opcode_count_parameters = [
118176 pytest .param (
119177 opcode_count ,
120178 id = f"opcount_{ opcode_count } K" ,
121179 )
122- for opcode_count in opcode_counts
180+ for opcode_count in opcode_counts_to_use
123181 ]
124182 metafunc .parametrize (
125183 "fixed_opcode_count" ,
@@ -134,8 +192,9 @@ def gas_benchmark_value(request: pytest.FixtureRequest) -> int:
134192 if hasattr (request , "param" ):
135193 return request .param
136194
137- # If --fixed-opcode-count is specified, use high gas limit to avoid gas constraints
138- 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 :
139198 return HIGH_GAS_LIMIT
140199
141200 return EnvironmentDefaults .gas_limit
0 commit comments