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