-
Notifications
You must be signed in to change notification settings - Fork 155
Move the exception handling logic from K to kevm-pyk #2816
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7b0f60a
15ffec5
6fb6120
72a46b7
6c762ad
e67d8e5
339f12a
46e7cc8
fc3acd1
a50b017
48aa1f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
| from dataclasses import dataclass | ||
| from functools import cached_property | ||
| from pathlib import Path | ||
| from subprocess import CalledProcessError | ||
| from typing import TYPE_CHECKING | ||
|
|
||
| from filelock import SoftFileLock | ||
|
|
@@ -602,8 +603,8 @@ def exec_run(options: RunOptions) -> None: | |
| if options.gst_name: | ||
| json_read = {options.gst_name: json_read[options.gst_name]} | ||
| kore_pattern_list = [ | ||
| (name, kore) | ||
| for (name, kore) in iterate_gst( | ||
| (name, kore, exception_metadata) | ||
| for (name, kore, exception_metadata) in iterate_gst( | ||
| json_read, options.mode, options.chainid, options.usegas, schedule=options.schedule | ||
| ) | ||
| ] | ||
|
|
@@ -617,21 +618,31 @@ def exec_run(options: RunOptions) -> None: | |
| kore_pgm_to_kore( | ||
| kore_pgm, SORT_ETHEREUM_SIMULATION, options.schedule, options.mode, options.chainid, options.usegas | ||
| ), | ||
| (False, False), | ||
| ), | ||
| ] | ||
|
|
||
| for name, kore_pattern in kore_pattern_list: | ||
| for name, kore_pattern, (exception_expected, _) in kore_pattern_list: | ||
| if name: | ||
| _LOGGER.info(f'Processing test - {name}') | ||
| kevm.run( | ||
| kore_pattern, | ||
| depth=options.depth, | ||
| term=True, | ||
| expand_macros=options.expand_macros, | ||
| output=options.output, | ||
| check=True, | ||
| debugger=options.debugger, | ||
| ) | ||
| if exception_expected: | ||
| _LOGGER.info(f'Test {name} is expected to fail.') | ||
| try: | ||
| kevm.run( | ||
| kore_pattern, | ||
| depth=options.depth, | ||
| term=True, | ||
| expand_macros=options.expand_macros, | ||
| output=options.output, | ||
| check=True, | ||
| debugger=options.debugger, | ||
| ) | ||
| except CalledProcessError: | ||
| if exception_expected: | ||
| _LOGGER.info(f'Test {name} failed as expected') | ||
| continue | ||
| else: | ||
| raise | ||
|
Comment on lines
+640
to
+645
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If an exception is expected, but no |
||
|
|
||
|
|
||
| def exec_kast(options: KastOptions) -> None: | ||
|
|
@@ -646,8 +657,8 @@ def exec_kast(options: KastOptions) -> None: | |
| if options.gst_name: | ||
| json_read = {options.gst_name: json_read[options.gst_name]} | ||
| kore_pattern_list = [ | ||
| (name, kore) | ||
| for (name, kore) in iterate_gst( | ||
| (name, kore, exception_metadata) | ||
| for (name, kore, exception_metadata) in iterate_gst( | ||
| json_read, options.mode, options.chainid, options.usegas, schedule=options.schedule | ||
| ) | ||
| ] | ||
|
Comment on lines
659
to
664
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same list comprehension as above can be applied here as well |
||
|
|
@@ -661,10 +672,11 @@ def exec_kast(options: KastOptions) -> None: | |
| kore_pgm_to_kore( | ||
| kore_pgm, SORT_ETHEREUM_SIMULATION, options.schedule, options.mode, options.chainid, options.usegas | ||
| ), | ||
| (False, False), | ||
| ), | ||
| ] | ||
|
|
||
| for name, kore_pattern in kore_pattern_list: | ||
| for name, kore_pattern, _ in kore_pattern_list: | ||
| if name: | ||
| _LOGGER.info(f'Processing test - {name}') | ||
| output_text = kore_print(kore_pattern, definition_dir=kevm.definition_dir, output=options.output) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,9 +7,9 @@ | |
| from typing import TYPE_CHECKING | ||
|
|
||
| import pytest | ||
| from pyk.kdist import kdist | ||
| from pyk.kdist._kdist import kdist | ||
| from pyk.kore.prelude import int_dv | ||
| from pyk.kore.syntax import App | ||
| from pyk.kore.syntax import App, SortApp, SymbolId | ||
| from pyk.kore.tools import PrintOutput, kore_print | ||
|
|
||
| from kevm_pyk.interpreter import interpret, iterate_gst | ||
|
|
@@ -27,8 +27,11 @@ | |
| REPO_ROOT: Final = Path(__file__).parents[3].resolve(strict=True) | ||
| GOLDEN: Final = (REPO_ROOT / 'tests/templates/output-success-llvm.json').read_text().rstrip() | ||
|
|
||
| DOT_STATUS_CODE: Final = App(SymbolId("Lbl'Stop'StatusCode'Unds'NETWORK'Unds'StatusCode")) | ||
| SORT_EXCEPTIONAL_STATUS_CODE: Final = SortApp('SortExceptionalStatusCode') | ||
|
|
||
| def _assert_exit_code_zero(pattern: Pattern) -> None: | ||
|
|
||
| def _assert_exit_code_zero(pattern: Pattern, exception_expected: bool = False) -> None: | ||
| assert type(pattern) is App | ||
| kevm_cell = pattern.args[0] | ||
| assert type(kevm_cell) is App | ||
|
|
@@ -38,23 +41,46 @@ def _assert_exit_code_zero(pattern: Pattern) -> None: | |
| exit_code = exit_code_cell.args[0] | ||
| if exit_code == int_dv(0): | ||
| return | ||
|
|
||
| elif exception_expected: | ||
| _assert_exit_code_exception(kevm_cell) | ||
| return | ||
|
Comment on lines
+44
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function name |
||
| pretty = kore_print(pattern, definition_dir=kdist.get('evm-semantics.llvm'), output=PrintOutput.PRETTY) | ||
| assert pretty == GOLDEN | ||
|
|
||
|
|
||
| def _skipped_tests(test_dir: Path, slow_tests_file: Path, failing_tests_file: Path) -> dict[Path, frozenset[str]]: | ||
| def _assert_exit_code_exception(kevm_cell: App) -> None: | ||
| """Assert that the status code in a kevm_cell has the ExceptionalStatusCode sort.""" | ||
| status_code = _fetch_status_code(kevm_cell) | ||
| # Some tests that are expected to fail might get stuck somewhere not related to the exception. | ||
| # This assert should catch any false negatives | ||
| assert status_code != DOT_STATUS_CODE | ||
| status_code_sort = status_code.sorts[0] | ||
| assert status_code_sort == SORT_EXCEPTIONAL_STATUS_CODE | ||
|
|
||
|
|
||
| def _fetch_status_code(kevm_cell: App) -> App: | ||
| """Return the value of the "<statusCode>" cell in a kevm_cell:App.""" | ||
| # <statusCode> is nested under <kevm><ethereum><evm> | ||
| ethereum_cell = kevm_cell.args[5] # type: ignore[attr-defined] | ||
| evm_cell = ethereum_cell.args[0] # type: ignore[attr-defined] | ||
| status_code_cell = evm_cell.args[1] # type: ignore[attr-defined] | ||
| status_code = status_code_cell.args[0] # type: ignore[attr-defined] | ||
|
Comment on lines
+64
to
+67
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These magic number indices look very susceptible to semantic changes to me. Can you replace them with a more reproducible mechanism like labels or something? |
||
| assert type(status_code) is App | ||
| return status_code | ||
|
|
||
|
|
||
| def _skipped_tests(test_dir: Path, slow_tests_file: Path, failing_tests_file: Path) -> dict[Path, list[str]]: | ||
| try: | ||
| slow_tests = read_csv_file(slow_tests_file) | ||
| except FileNotFoundError as e: | ||
| _LOGGER.warning(e) | ||
| slow_tests = () | ||
| failing_tests = read_csv_file(failing_tests_file) | ||
| skipped: dict[Path, set[str]] = {} | ||
| skipped: dict[Path, list[str]] = {} | ||
| for test_file, test in slow_tests + failing_tests: | ||
| test_file = test_dir / test_file | ||
| skipped.setdefault(test_file, set()).add(test) | ||
| return {k: frozenset(v) for k, v in skipped.items()} | ||
| skipped.setdefault(test_file, []).append(test) | ||
| return skipped | ||
|
|
||
|
|
||
| def read_csv_file(csv_file: Path) -> tuple[tuple[Path, str], ...]: | ||
|
|
@@ -70,35 +96,45 @@ def _test( | |
| usegas: bool, | ||
| save_failing: bool, | ||
| compute_chain_id: Callable[[str], int], | ||
| skipped_tests: dict[Path, frozenset[str]], | ||
| skipped_tests: dict[Path, list[str]], | ||
| test_dir: Path, | ||
| failing_tests_file: Path, | ||
| ) -> None: | ||
| skipped_gst_tests = skipped_tests.get(gst_file, frozenset()) | ||
| skipped_gst_tests = skipped_tests.get(gst_file, []) | ||
| if '*' in skipped_gst_tests: | ||
| pytest.skip() | ||
|
|
||
| gst_file_relative_path: Final[str] = str(gst_file.relative_to(test_dir)) | ||
|
|
||
| chain_id = compute_chain_id(gst_file_relative_path) | ||
|
|
||
| with gst_file.open() as f: | ||
| gst_data = json.load(f) | ||
|
|
||
| failing_tests: list[str] = [] | ||
|
|
||
| chain_id = compute_chain_id(gst_file_relative_path) | ||
|
|
||
| for test_name, init_kore in iterate_gst(gst_data, mode, chain_id, usegas, skipped_gst_tests): | ||
| for test_name, init_kore, (exception_expected, has_big_int) in iterate_gst( | ||
| gst_data, mode, chain_id, usegas, frozenset(skipped_gst_tests) | ||
| ): | ||
| _LOGGER.info(f'Running test: {gst_file} - {test_name}') | ||
| res = interpret(init_kore, check=False) | ||
|
|
||
| try: | ||
| _assert_exit_code_zero(res) | ||
| res = interpret(init_kore, check=False) | ||
| except RuntimeError: | ||
| if not has_big_int: | ||
| if not save_failing: | ||
| raise | ||
| failing_tests.append(test_name) | ||
| continue | ||
|
|
||
| try: | ||
| _assert_exit_code_zero(res, exception_expected) | ||
| except AssertionError: | ||
| if not save_failing: | ||
| raise | ||
| failing_tests.append(test_name) | ||
|
|
||
| if len(failing_tests) == 0: | ||
| if not failing_tests: | ||
| return | ||
|
|
||
| with failing_tests_file.open('a', newline='') as ff: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this instead be re-written as this?