From 83ec2b96ce8bd7854fdc62d57a67425c2dca2f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 1 Sep 2026 16:12:25 +0200 Subject: [PATCH 1/2] tooling: Run one command per invocation A subcommand's own name among another's arguments parsed as a second command, and the dispatch tries run first, so a trailing "run" silently replaced the command asked for: "evmone t8n --state.fork Cancun run 6000" executed bytecode and exited 0. Claude-Session: https://claude.ai/code/session_016UHPAGwcwXMjqhTLpT31K7 --- test/integration/CMakeLists.txt | 28 ++++++++++++++++++++++++++++ tools/evmone/main.cpp | 1 + 2 files changed, 29 insertions(+) diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index fca940e0a5..4abbe17ece 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -21,6 +21,34 @@ if(TARGET evmone-cli) ${PREFIX}/run_bad_rev PROPERTIES PASS_REGULAR_EXPRESSION "unknown revision: NoSuchRev") + # A subcommand's own name among another's arguments is an argument. CLI11 would otherwise + # take it as a second command and run that one instead, exiting 0 with the wrong work done: + # the dispatch tries run first, so a trailing "run" hijacked every other subcommand. + add_test(NAME ${PREFIX}/one_command_per_invocation COMMAND evmone-cli + t8n --state.fork Cancun run 6000) + set_tests_properties( + ${PREFIX}/one_command_per_invocation PROPERTIES + PASS_REGULAR_EXPRESSION "arguments were not expected" + FAIL_REGULAR_EXPRESSION "Result: *success") + + add_test(NAME ${PREFIX}/one_command_per_invocation_reversed COMMAND evmone-cli + run 6000 t8n) + set_tests_properties( + ${PREFIX}/one_command_per_invocation_reversed PROPERTIES + PASS_REGULAR_EXPRESSION "argument was not expected: t8n" + FAIL_REGULAR_EXPRESSION "Result: *success") + + # A PASS_REGULAR_EXPRESSION makes CTest ignore the exit code, so run them again for that alone. + add_test(NAME ${PREFIX}/one_command_per_invocation_exit_code COMMAND evmone-cli + t8n --state.fork Cancun run 6000) + set_tests_properties( + ${PREFIX}/one_command_per_invocation_exit_code PROPERTIES WILL_FAIL TRUE) + + add_test(NAME ${PREFIX}/one_command_per_invocation_reversed_exit_code COMMAND evmone-cli + run 6000 t8n) + set_tests_properties( + ${PREFIX}/one_command_per_invocation_reversed_exit_code PROPERTIES WILL_FAIL TRUE) + add_test(NAME ${PREFIX}/version COMMAND evmone-cli --version) set_tests_properties( ${PREFIX}/version PROPERTIES PASS_REGULAR_EXPRESSION "evmone") diff --git a/tools/evmone/main.cpp b/tools/evmone/main.cpp index 82e4c1f154..e5e6c24ece 100644 --- a/tools/evmone/main.cpp +++ b/tools/evmone/main.cpp @@ -173,6 +173,7 @@ int main(int argc, const char* const* argv) noexcept VM vm{evmc_create_evmone()}; CLI::App app{"evmone EVM tool"}; + app.require_subcommand(0, 1); // Forbid multiple subcommands: run would hijack the rest. app.set_version_flag( "--version", [&vm] { return std::string{vm.name()} + " " + vm.version(); }); app.add_flag("--trace", trace, "Enable execution trace"); From a1ba4cc1433aadb214ff48e4a33f4226624e4146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 1 Sep 2026 22:50:10 +0200 Subject: [PATCH 2/2] test: Check a blockchain test stops at itself stops_at_one_test pinned that the test after the one which gave up still reports, but not that the one which gave up stopped: dropping the return after the block-validity failure kept it running and the ctest passed. Every failure repeats the test name, so a second one means it did not stop. Claude-Session: https://claude.ai/code/session_016UHPAGwcwXMjqhTLpT31K7 --- test/integration/blockchaintest/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/integration/blockchaintest/CMakeLists.txt b/test/integration/blockchaintest/CMakeLists.txt index 031ba8e0ae..06e6f0f7ce 100644 --- a/test/integration/blockchaintest/CMakeLists.txt +++ b/test/integration/blockchaintest/CMakeLists.txt @@ -73,6 +73,8 @@ set_tests_properties( ${PREFIX}/stops_at_one_test PROPERTIES PASS_REGULAR_EXPRESSION "a_stops_early:.*block validity.*b_still_runs:.*post state root" + # Every failure repeats the test name, so a second one means it did not stop. + FAIL_REGULAR_EXPRESSION "a_stops_early:.*a_stops_early:" ) # --collect-only lists what would run instead of running it, and --ignore drops a path from that