onqtam | c9b4e1f | 2018-08-17 14:20:59 +0300 | [diff] [blame] | 1 | #include "doctest.h" |
| 2 | |
onqtam | 65cf692 | 2018-08-20 11:29:33 +0300 | [diff] [blame] | 3 | #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS |
| 4 | |
onqtam | c9b4e1f | 2018-08-17 14:20:59 +0300 | [diff] [blame] | 5 | DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN |
| 6 | #include <thread> |
onqtam | a2e77c7 | 2018-08-20 11:05:05 +0300 | [diff] [blame] | 7 | #include <mutex> |
| 8 | #include <exception> |
| 9 | #include <stdexcept> |
onqtam | c9b4e1f | 2018-08-17 14:20:59 +0300 | [diff] [blame] | 10 | DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END |
| 11 | |
onqtam | c9b4e1f | 2018-08-17 14:20:59 +0300 | [diff] [blame] | 12 | TEST_CASE("threads...") { |
onqtam | a2e77c7 | 2018-08-20 11:05:05 +0300 | [diff] [blame] | 13 | auto call_from_thread = [](int value) { |
| 14 | INFO("print me!"); |
| 15 | // one of these has to fail |
| 16 | CHECK(value == 1); |
| 17 | CHECK(value == 2); |
| 18 | }; |
| 19 | |
| 20 | int data_1 = 1; |
| 21 | int data_2 = 2; |
| 22 | CAPTURE(data_1); // will not be used for assertions in other threads |
| 23 | |
| 24 | // subcases have to be used only in the main thread (where the test runner is) |
| 25 | SUBCASE("test runner thread") { |
| 26 | call_from_thread(data_1); |
| 27 | } |
| 28 | |
| 29 | // normal threads which are assumed not to throw |
| 30 | SUBCASE("spawned threads") { |
| 31 | std::thread t1(call_from_thread, data_1); |
| 32 | std::thread t2(call_from_thread, data_2); |
| 33 | |
| 34 | t1.join(); |
| 35 | t2.join(); |
| 36 | } |
| 37 | |
| 38 | // exceptions from threads (that includes failing REQUIRE asserts) have to be handled explicitly |
| 39 | SUBCASE("spawned threads with exception propagation") { |
onqtam | 8f10044 | 2018-08-20 11:53:10 +0300 | [diff] [blame] | 40 | std::exception_ptr exception_ptr = nullptr; |
| 41 | std::mutex mutex; |
| 42 | |
| 43 | auto might_throw = [&]() { |
onqtam | a2e77c7 | 2018-08-20 11:05:05 +0300 | [diff] [blame] | 44 | try { |
| 45 | REQUIRE(1 == 1); |
| 46 | REQUIRE(1 == 2); // will fail and throw an exception |
| 47 | MESSAGE("not reached!"); |
| 48 | } catch(...) { |
onqtam | 8f10044 | 2018-08-20 11:53:10 +0300 | [diff] [blame] | 49 | // make sure there are no races when dealing with the exception ptr |
| 50 | std::lock_guard<std::mutex> lock(mutex); |
onqtam | a2e77c7 | 2018-08-20 11:05:05 +0300 | [diff] [blame] | 51 | |
onqtam | 8f10044 | 2018-08-20 11:53:10 +0300 | [diff] [blame] | 52 | // set the exception pointer in case of an exception - might overwrite |
onqtam | a2e77c7 | 2018-08-20 11:05:05 +0300 | [diff] [blame] | 53 | // another exception but here we care about propagating any exception - not all |
onqtam | 8f10044 | 2018-08-20 11:53:10 +0300 | [diff] [blame] | 54 | exception_ptr = std::current_exception(); |
onqtam | a2e77c7 | 2018-08-20 11:05:05 +0300 | [diff] [blame] | 55 | } |
| 56 | }; |
| 57 | std::thread t1(might_throw); |
| 58 | std::thread t2(might_throw); |
| 59 | |
| 60 | t1.join(); |
| 61 | t2.join(); |
| 62 | |
| 63 | // if any thread has thrown an exception - rethrow it |
onqtam | 8f10044 | 2018-08-20 11:53:10 +0300 | [diff] [blame] | 64 | if(exception_ptr) |
| 65 | std::rethrow_exception(exception_ptr); |
onqtam | a2e77c7 | 2018-08-20 11:05:05 +0300 | [diff] [blame] | 66 | } |
onqtam | c9b4e1f | 2018-08-17 14:20:59 +0300 | [diff] [blame] | 67 | } |
onqtam | 65cf692 | 2018-08-20 11:29:33 +0300 | [diff] [blame] | 68 | |
| 69 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS |