Last active
April 6, 2026 08:46
-
-
Save spchamp/ebf376b90bda529e5b8cb02e16b0ad65 to your computer and use it in GitHub Desktop.
macros for async tests with catch2, boost cobalt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // header for include in test.cpp files | |
| // | |
| // [public domain] | |
| // | |
| // usage: | |
| // | |
| // - include this source file in test_async.cpp, ... | |
| // | |
| // - in test_async.cpp, ... define any one or more sections like as follows: | |
| // | |
| // ASYNC_TEST_CASE("name...") { /* coroutine... */ } | |
| // | |
| // ... along with any non-async TEST_CASE or other Catch2 test macros | |
| // | |
| // The ASYNC_TEST_CASE macro should serve as mostly a drop-in replacement | |
| // for Catch2 TEST_CASE, with the added feature of the test body representing | |
| // a coroutine. The coroutine will be run within a cobalt::task<void> via | |
| // cobalt::spawn, using Boost Cobalt. | |
| // | |
| // - use TEST_MAIN() at the end of the source file, thus ensuring Cobalt's | |
| // co_main will be used when running the file's catch2 tests | |
| // | |
| // - Link swith Boost::cobalt, Catch2::Catch2, ... | |
| // | |
| // - Known limitation: No support for test tags in this ASYNC_TEST_CASE | |
| // | |
| // - Known limitation: When the actual test code is included within | |
| // each cobalt::task<void> section, the output from catch2 at the | |
| // command line may not accurately represent the number of test | |
| // assertions in each async test1 | |
| // | |
| // cmake e.g: | |
| // | |
| // find_package(Catch2 3.0.0 REQUIRED) | |
| // include(Catch) | |
| // | |
| // find_package(Boost REQUIRED COMPONENTS system) | |
| // find_package(Boost REQUIRED CONFIG COMPONENTS asio cobalt preprocessor) | |
| // | |
| // add_executable(test_async test_async.cpp) | |
| // taget_link_libraries(test_async PRIVATE | |
| // Boost::system Boost::asio Boost::cobalt | |
| // Boost::preprocessor Catch2::Catch2 | |
| // ) | |
| // target_include_directories(test_async PRIVATE | |
| // ${ANY_VAR}/any_directory_containing_this_file/) | |
| // catch_discover_tests(test_async) | |
| #pragma once | |
| #include <boost/asio/io_context.hpp> | |
| #include <boost/asio/use_future.hpp> | |
| #include <boost/cobalt/main.hpp> | |
| #include <boost/cobalt/task.hpp> | |
| #include <boost/cobalt/this_thread.hpp> | |
| #include <boost/cobalt/spawn.hpp> | |
| #include <boost/preprocessor/cat.hpp> | |
| #include <catch2/catch_session.hpp> | |
| #include <catch2/catch_test_macros.hpp> | |
| // NOLINTBEGIN(misc-unused-alias-decls) | |
| namespace asio = boost::asio; | |
| namespace cobalt = boost::cobalt; | |
| namespace sys = boost::system; | |
| // NOLINTEND(misc-unused-alias-decls) | |
| #ifndef ASYNC_TEST_CASE | |
| # define ASYNC_TEST_CASE(_name, ...) \ | |
| cobalt::task<void> BOOST_PP_CAT(test_task_, __LINE__)(); \ | |
| TEST_CASE(_name) { \ | |
| asio::io_context ctx{BOOST_ASIO_CONCURRENCY_HINT_1}; \ | |
| auto exec = ctx.get_executor(); \ | |
| cobalt::this_thread::set_executor(exec); \ | |
| \ | |
| auto ftr = cobalt::spawn(ctx, BOOST_PP_CAT(test_task_, __LINE__)(), \ | |
| asio::use_future); \ | |
| ctx.run(); \ | |
| ftr.wait(); \ | |
| } \ | |
| cobalt::task<void> BOOST_PP_CAT(test_task_, __LINE__)() | |
| #endif | |
| #ifndef TEST_MAIN | |
| # define TEST_MAIN(...) \ | |
| cobalt::main co_main(int argc, char* argv[]) { \ | |
| __VA_ARGS__ \ | |
| co_return Catch::Session{}.run(argc, argv); \ | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment