diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 97a034ded78..b5a12f7277d 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -64,7 +64,6 @@ add_executable(test_bitcoin miniminer_tests.cpp miniscript_tests.cpp minisketch_tests.cpp - mock_process.cpp multisig_tests.cpp bip328_tests.cpp net_peer_connection_tests.cpp @@ -192,8 +191,6 @@ function(add_boost_test source_file) list(TRANSFORM test_suite_macro REPLACE "(BOOST_FIXTURE_TEST_SUITE|BOOST_AUTO_TEST_SUITE)\\(" "" ) - # The mock_process test suite does not contain unit tests. - list(REMOVE_ITEM test_suite_macro "mock_process") foreach(test_suite_name IN LISTS test_suite_macro) add_test(NAME ${test_suite_name} COMMAND test_bitcoin --run_test=${test_suite_name} --catch_system_error=no --log_level=test_suite -- -printtoconsole=1 diff --git a/src/test/mock_process.cpp b/src/test/mock_process.cpp deleted file mode 100644 index c9100c9fe0d..00000000000 --- a/src/test/mock_process.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2025-present The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or https://opensource.org/license/mit/. - -#include - -#include -#include - -BOOST_AUTO_TEST_SUITE(mock_process, *boost::unit_test::disabled()) - -BOOST_AUTO_TEST_CASE(valid_json, *boost::unit_test::disabled()) -{ - std::cout << R"({"success": true})" << std::endl; -} - -BOOST_AUTO_TEST_CASE(nonzeroexit_nooutput, *boost::unit_test::disabled()) -{ - BOOST_FAIL("Test unconditionally fails."); -} - -BOOST_AUTO_TEST_CASE(nonzeroexit_stderroutput, *boost::unit_test::disabled()) -{ - std::cerr << "err\n"; - BOOST_FAIL("Test unconditionally fails."); -} - -BOOST_AUTO_TEST_CASE(invalid_json, *boost::unit_test::disabled()) -{ - std::cout << "{\n"; -} - -BOOST_AUTO_TEST_CASE(pass_stdin_to_stdout, *boost::unit_test::disabled()) -{ - std::string s; - std::getline(std::cin, s); - std::cout << s << std::endl; -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index 408666d6708..1b1d6bc75e0 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -11,33 +11,65 @@ #include #include +#include +#include +#include + #ifdef ENABLE_EXTERNAL_SIGNER #include #endif // ENABLE_EXTERNAL_SIGNER -#include #include #include +namespace { +// When set in the environment, test_bitcoin acts as a mock subprocess for the +// run_command test below instead of running unit tests. +constexpr const char* MOCK_PROCESS_ENV = "BITCOIN_TEST_MOCK_PROCESS"; + +const bool g_maybe_run_mock_dispatcher_before_main{[]() { + const char* name = std::getenv(MOCK_PROCESS_ENV); + if (!name) return false; + const std::string_view n{name}; + if (n == "valid_json") { + std::cout << R"({"success": true})" << std::endl; + std::_Exit(EXIT_SUCCESS); + } + if (n == "nonzeroexit_nooutput") { + std::_Exit(EXIT_FAILURE); + } + if (n == "nonzeroexit_stderroutput") { + std::cerr << "err" << std::endl; + std::_Exit(EXIT_FAILURE); + } + if (n == "invalid_json") { + std::cout << "{" << std::endl; + std::_Exit(EXIT_SUCCESS); + } + if (n == "pass_stdin_to_stdout") { + std::string s; + std::getline(std::cin, s); + std::cout << s << std::endl; + std::_Exit(EXIT_SUCCESS); + } + std::cerr << "Unknown mock process: " << n << std::endl; + std::_Exit(EXIT_FAILURE); +}()}; +} // namespace + BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup) #ifdef ENABLE_EXTERNAL_SIGNER -static std::vector mock_executable(std::string name) +static std::vector mock_executable(const std::string& name) { - // Invoke the mock_process/* test case with all unsolicited output suppressed. - return { - boost::unit_test::framework::master_test_suite().argv[0], - // Disable false-positive memory leak dumps to stderr - // in debug builds when using the Windows UCRT. - "--detect_memory_leaks=0", - // Disable logging to stdout. - "--log_level=nothing", - // Disable the test report to stderr. - "--report_level=no", - "--run_test=mock_process/" + name, - }; +#if defined(WIN32) + _putenv_s(MOCK_PROCESS_ENV, name.c_str()); +#else + setenv(MOCK_PROCESS_ENV, name.c_str(), /*overwrite=*/1); +#endif + return {boost::unit_test::framework::master_test_suite().argv[0]}; } BOOST_AUTO_TEST_CASE(run_command) @@ -67,7 +99,7 @@ BOOST_AUTO_TEST_CASE(run_command) const std::vector command = mock_executable("nonzeroexit_nooutput"); BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) { const std::string what{e.what()}; - BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned %d: \n", util::Join(command, " "), boost::exit_test_failure)) != std::string::npos); + BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned %d: \n", util::Join(command, " "), EXIT_FAILURE)) != std::string::npos); return true; }); } @@ -77,7 +109,7 @@ BOOST_AUTO_TEST_CASE(run_command) const std::string expected{"err"}; BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) { const std::string what(e.what()); - BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned %s: %s", util::Join(command, " "), boost::exit_test_failure, "err")) != std::string::npos); + BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned %s: %s", util::Join(command, " "), EXIT_FAILURE, "err")) != std::string::npos); BOOST_CHECK(what.find(expected) != std::string::npos); return true; }); diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py index 18f47240f9d..2e8417ea734 100755 --- a/test/lint/lint-includes.py +++ b/test/lint/lint-includes.py @@ -21,7 +21,6 @@ EXCLUDED_DIRS = ["contrib/devtools/bitcoin-tidy/", ] + SHARED_EXCLUDED_SUBTREES EXPECTED_BOOST_INCLUDES = [ - "boost/cstdlib.hpp", "boost/multi_index/detail/hash_index_iterator.hpp", "boost/multi_index/hashed_index.hpp", "boost/multi_index/identity.hpp",