diff --git a/tests_main.cpp b/catch_main.cpp similarity index 83% rename from tests_main.cpp rename to catch_main.cpp index 637c53c..9500ab4 100644 --- a/tests_main.cpp +++ b/catch_main.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ diff --git a/invoke_tests.cpp b/invoke_tests.cpp new file mode 100644 index 0000000..14d0c5e --- /dev/null +++ b/invoke_tests.cpp @@ -0,0 +1,510 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/invoke.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018 Matvey Cherevko + ******************************************************************************/ + +#define CATCH_CONFIG_FAST_COMPILE +#include "catch.hpp" + +#include "invoke.hpp" +namespace inv = invoke_hpp; + +namespace +{ + void simple_static_function() { + } + + int simple_static_function_r() { + return 42; + } + + int simple_static_function_r_with_arg(int v) { + return v; + } + + const int& simple_static_function_r_with_ref_arg(const int& v) { + return v; + } + + class obj_t { + public: + int value = 42; + const int value_c = 42; + + void member() { + } + + int member_r() { + return 42; + } + + int member_r_with_arg(int v) { + return v; + } + + const int& member_r_with_ref_arg(const int& v) { + return v; + } + }; + + class obj2_t { + }; +} + +TEST_CASE("invoke"){ + SECTION("invoke_functions"){ + inv::invoke(simple_static_function); + REQUIRE(inv::invoke(simple_static_function_r) == 42); + REQUIRE(inv::invoke(simple_static_function_r_with_arg, 42) == 42); + { + int v = 42; + REQUIRE(&inv::invoke(simple_static_function_r_with_ref_arg, v) == &v); + } + } + SECTION("invoke_members"){ + obj_t o; + + inv::invoke(&obj_t::member, o); + inv::invoke(&obj_t::member, &o); + inv::invoke(&obj_t::member, std::ref(o)); + + REQUIRE(inv::invoke(&obj_t::member_r, o) == 42); + REQUIRE(inv::invoke(&obj_t::member_r, &o) == 42); + REQUIRE(inv::invoke(&obj_t::member_r, std::ref(o)) == 42); + + REQUIRE(inv::invoke(&obj_t::member_r_with_arg, o, 42) == 42); + REQUIRE(inv::invoke(&obj_t::member_r_with_arg, &o, 42) == 42); + REQUIRE(inv::invoke(&obj_t::member_r_with_arg, std::ref(o), 42) == 42); + + { + int v = 42; + REQUIRE(&inv::invoke(&obj_t::member_r_with_ref_arg, o, std::ref(v)) == &v); + REQUIRE(&inv::invoke(&obj_t::member_r_with_ref_arg, &o, std::ref(v)) == &v); + REQUIRE(&inv::invoke(&obj_t::member_r_with_ref_arg, std::ref(o), std::ref(v)) == &v); + } + } + SECTION("invoke_member_objects"){ + obj_t o; + + REQUIRE(inv::invoke(&obj_t::value, o) == 42); + REQUIRE(inv::invoke(&obj_t::value, &o) == 42); + REQUIRE(inv::invoke(&obj_t::value, std::ref(o)) == 42); + + REQUIRE(inv::invoke(&obj_t::value_c, o) == 42); + REQUIRE(inv::invoke(&obj_t::value_c, &o) == 42); + REQUIRE(inv::invoke(&obj_t::value_c, std::ref(o)) == 42); + } +} + +TEST_CASE("invoke_result"){ + SECTION("invoke_result_functions"){ + static_assert( + std::is_same< + void, + inv::invoke_result_t>::value, + "unit test fail"); + static_assert( + std::is_same< + int, + inv::invoke_result_t>::value, + "unit test fail"); + static_assert( + std::is_same< + int, + inv::invoke_result_t>::value, + "unit test fail"); + static_assert( + std::is_same< + const int&, + inv::invoke_result_t>::value, + "unit test fail"); + } + SECTION("invoke_result_members"){ + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>>::value, + "unit test fail"); + + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>>::value, + "unit test fail"); + + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same, int>>::value, + "unit test fail"); + + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same, const int&>>::value, + "unit test fail"); + } +} + +TEST_CASE("is_invocable"){ + SECTION("is_invocable_functions"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + } + SECTION("is_not_invocable_functions"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + } + SECTION("is_invocable_members"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable, int>::value, + "unit test fail"); + } + SECTION("is_not_invocable_members"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable*>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable, int>::value, + "unit test fail"); + } + SECTION("is_invocable_objects"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + } + SECTION("is_not_invocable_objects"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable>::value, + "unit test fail"); + } +} + +TEST_CASE("is_invocable_r"){ + SECTION("is_invocable_r_functions"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_functions"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + } + SECTION("is_invocable_r_members"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r, int>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r, int>::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_members"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + } + SECTION("is_invocable_r_objects"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_objects"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + } +} + +TEST_CASE("apply"){ + SECTION("apply_functions"){ + inv::apply(simple_static_function, std::make_tuple()); + REQUIRE(inv::apply(simple_static_function_r, std::make_tuple()) == 42); + REQUIRE(inv::apply(simple_static_function_r_with_arg, std::make_tuple(42)) == 42); + { + int v = 42; + REQUIRE(&inv::apply(simple_static_function_r_with_ref_arg, std::make_tuple(std::ref(v))) == &v); + } + } + SECTION("apply_members"){ + obj_t o; + + inv::apply(&obj_t::member, std::make_tuple(o)); + inv::apply(&obj_t::member, std::make_tuple(&o)); + inv::apply(&obj_t::member, std::make_tuple(std::ref(o))); + + REQUIRE(inv::apply(&obj_t::member_r, std::make_tuple(o)) == 42); + REQUIRE(inv::apply(&obj_t::member_r, std::make_tuple(&o)) == 42); + REQUIRE(inv::apply(&obj_t::member_r, std::make_tuple(std::ref(o))) == 42); + + REQUIRE(inv::apply(&obj_t::member_r_with_arg, std::make_tuple(o, 42)) == 42); + REQUIRE(inv::apply(&obj_t::member_r_with_arg, std::make_tuple(&o, 42)) == 42); + REQUIRE(inv::apply(&obj_t::member_r_with_arg, std::make_tuple(std::ref(o), 42)) == 42); + + { + int v = 42; + REQUIRE(&inv::apply(&obj_t::member_r_with_ref_arg, std::make_tuple(o, std::ref(v))) == &v); + REQUIRE(&inv::apply(&obj_t::member_r_with_ref_arg, std::make_tuple(&o, std::ref(v))) == &v); + REQUIRE(&inv::apply(&obj_t::member_r_with_ref_arg, std::make_tuple(std::ref(o), std::ref(v))) == &v); + } + } + SECTION("apply_member_objects"){ + obj_t o; + + REQUIRE(inv::apply(&obj_t::value, std::make_tuple(o)) == 42); + REQUIRE(inv::apply(&obj_t::value, std::make_tuple(&o)) == 42); + REQUIRE(inv::apply(&obj_t::value, std::make_tuple(std::ref(o))) == 42); + + REQUIRE(inv::apply(&obj_t::value_c, std::make_tuple(o)) == 42); + REQUIRE(inv::apply(&obj_t::value_c, std::make_tuple(&o)) == 42); + REQUIRE(inv::apply(&obj_t::value_c, std::make_tuple(std::ref(o))) == 42); + } +} diff --git a/jobber_tests.cpp b/jobber_tests.cpp new file mode 100644 index 0000000..a279bb9 --- /dev/null +++ b/jobber_tests.cpp @@ -0,0 +1,281 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/promise.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018 Matvey Cherevko + ******************************************************************************/ + +#define CATCH_CONFIG_FAST_COMPILE +#include "catch.hpp" + +#include +#include +#include + +#include "jobber.hpp" +namespace jb = jobber_hpp; + +TEST_CASE("jobber") { + { + jb::jobber j(1); + auto pv0 = j.async([](){ + throw std::exception(); + }); + REQUIRE_THROWS_AS(pv0.get(), std::exception); + } + { + auto pv0 = jb::promise(); + { + jb::jobber j{0}; + pv0 = j.async([](){ + return 42; + }); + } + REQUIRE_THROWS_AS(pv0.get(), jb::jobber_cancelled_exception); + } + { + int v5 = 5; + + jb::jobber j(1); + auto pv0 = j.async([](int v){ + REQUIRE(v == 5); + throw std::exception(); + }, v5); + REQUIRE_THROWS_AS(pv0.get(), std::exception); + + auto pv1 = j.async([](int& v){ + REQUIRE(v == 5); + return v != 5 + ? 0 + : throw std::exception(); + }, std::ref(v5)); + REQUIRE_THROWS_AS(pv1.get(), std::exception); + + auto pv3 = j.async([](int& v){ + v = 4; + return v; + }, std::ref(v5)); + REQUIRE(pv3.get() == v5); + REQUIRE(v5 == 4); + } + { + const float pi = 3.14159265358979323846264338327950288f; + jb::jobber j(1); + auto p0 = j.async([](float angle){ + return std::sin(angle); + }, pi); + auto p1 = j.async([](float angle){ + return std::cos(angle); + }, pi * 2); + REQUIRE(p0.get() == Approx(0.f).margin(0.01f)); + REQUIRE(p1.get() == Approx(1.f).margin(0.01f)); + } + { + jb::jobber j(1); + j.pause(); + jb::jobber_priority max_priority = jb::jobber_priority::highest; + j.async([](){ + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + }); + for ( std::size_t i = 0; i < 10; ++i ) { + jb::jobber_priority p = static_cast( + i % static_cast(jb::jobber_priority::highest)); + j.async(p, [&max_priority](jb::jobber_priority priority) { + REQUIRE(priority <= max_priority); + max_priority = priority; + }, p); + } + j.resume(); + j.wait_all(); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 10; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + j.resume(); + REQUIRE(counter < 10); + j.wait_all(); + REQUIRE(counter == 10); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 10; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + REQUIRE(counter < 10); + j.active_wait_all(); + REQUIRE(counter == 10); + } + { + jb::jobber j(1); + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); + + j.pause(); + j.async([]{}); + + REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 10; ++i ) { + j.async([&counter](){ + ++counter; + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + j.wait_all_for(std::chrono::milliseconds(10)); + j.wait_all_until(time_now() + std::chrono::milliseconds(10)); + REQUIRE(counter == 0); + + j.active_wait_all_for(std::chrono::milliseconds(10)); + j.active_wait_all_until(time_now() + std::chrono::milliseconds(10)); + REQUIRE(counter > 0); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 50; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + const auto b = time_now(); + + j.resume(); + j.wait_all_for(std::chrono::milliseconds(100)); + REQUIRE(time_now() - b > std::chrono::milliseconds(50)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + + j.wait_all_until(time_now() + std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 50; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + const auto b = time_now(); + + j.wait_all_for(std::chrono::milliseconds(15)); + REQUIRE(time_now() - b > std::chrono::milliseconds(10)); + REQUIRE(counter == 0); + + j.wait_all_until(time_now() + std::chrono::milliseconds(15)); + REQUIRE(time_now() - b > std::chrono::milliseconds(20)); + REQUIRE(counter == 0); + + j.active_wait_all_for(std::chrono::milliseconds(100)); + REQUIRE(time_now() - b > std::chrono::milliseconds(70)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + + j.active_wait_all_until(time_now() + std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 30; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + j.resume(); + REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(50))); + REQUIRE(counter > 0); + REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::seconds(5))); + REQUIRE(counter == 30); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 30; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(50))); + REQUIRE(counter > 0); + REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::seconds(5))); + REQUIRE(counter == 30); + } + { + jb::jobber j(2); + jb::jobber g(2); + + std::vector> jp(50); + for ( auto& jpi : jp ) { + jpi = j.async([&g](){ + std::vector> gp(50); + for ( std::size_t i = 0; i < gp.size(); ++i ) { + gp[i] = g.async([](float angle){ + return std::sin(angle); + }, static_cast(i)); + } + return std::accumulate(gp.begin(), gp.end(), 0.f, + [](float r, jb::promise& f){ + return r + f.get(); + }); + }); + } + float r0 = std::accumulate(jp.begin(), jp.end(), 0.f, + [](float r, jb::promise& f){ + return r + f.get(); + }); + float r1 = 0.f; + for ( std::size_t i = 0; i < 50; ++i ) { + r1 += std::sin(static_cast(i)); + } + REQUIRE(r0 == Approx(r1 * 50.f).margin(0.01f)); + } +} diff --git a/tests.cpp b/promise_tests.cpp similarity index 73% rename from tests.cpp rename to promise_tests.cpp index a3500de..e53714d 100644 --- a/tests.cpp +++ b/promise_tests.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ @@ -7,16 +7,12 @@ #define CATCH_CONFIG_FAST_COMPILE #include "catch.hpp" +#include #include #include -#include "jobber.hpp" #include "promise.hpp" -#include "scheduler.hpp" - -namespace jb = jobber_hpp; namespace pr = promise_hpp; -namespace sd = scheduler_hpp; namespace { @@ -982,368 +978,3 @@ TEST_CASE("get_and_wait") { } } } - -TEST_CASE("jobber") { - { - jb::jobber j(1); - auto pv0 = j.async([](){ - throw std::exception(); - }); - REQUIRE_THROWS_AS(pv0.get(), std::exception); - } - { - auto pv0 = pr::promise(); - { - jb::jobber j{0}; - pv0 = j.async([](){ - return 42; - }); - } - REQUIRE_THROWS_AS(pv0.get(), jb::jobber_cancelled_exception); - } - { - int v5 = 5; - - jb::jobber j(1); - auto pv0 = j.async([](int v){ - REQUIRE(v == 5); - throw std::exception(); - }, v5); - REQUIRE_THROWS_AS(pv0.get(), std::exception); - - auto pv1 = j.async([](int& v){ - REQUIRE(v == 5); - return v != 5 - ? 0 - : throw std::exception(); - }, std::ref(v5)); - REQUIRE_THROWS_AS(pv1.get(), std::exception); - - auto pv3 = j.async([](int& v){ - v = 4; - return v; - }, std::ref(v5)); - REQUIRE(pv3.get() == v5); - REQUIRE(v5 == 4); - } - { - const float pi = 3.14159265358979323846264338327950288f; - jb::jobber j(1); - auto p0 = j.async([](float angle){ - return std::sin(angle); - }, pi); - auto p1 = j.async([](float angle){ - return std::cos(angle); - }, pi * 2); - REQUIRE(p0.get() == Approx(0.f).margin(0.01f)); - REQUIRE(p1.get() == Approx(1.f).margin(0.01f)); - } - { - jb::jobber j(1); - j.pause(); - jb::jobber_priority max_priority = jb::jobber_priority::highest; - j.async([](){ - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - }); - for ( std::size_t i = 0; i < 10; ++i ) { - jb::jobber_priority p = static_cast( - i % static_cast(jb::jobber_priority::highest)); - j.async(p, [&max_priority](jb::jobber_priority priority) { - REQUIRE(priority <= max_priority); - max_priority = priority; - }, p); - } - j.resume(); - j.wait_all(); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 10; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - j.resume(); - REQUIRE(counter < 10); - j.wait_all(); - REQUIRE(counter == 10); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 10; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - REQUIRE(counter < 10); - j.active_wait_all(); - REQUIRE(counter == 10); - } - { - jb::jobber j(1); - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); - - j.pause(); - j.async([]{}); - - REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 10; ++i ) { - j.async([&counter](){ - ++counter; - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - j.wait_all_for(std::chrono::milliseconds(10)); - j.wait_all_until(time_now() + std::chrono::milliseconds(10)); - REQUIRE(counter == 0); - - j.active_wait_all_for(std::chrono::milliseconds(10)); - j.active_wait_all_until(time_now() + std::chrono::milliseconds(10)); - REQUIRE(counter > 0); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 50; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - const auto b = time_now(); - - j.resume(); - j.wait_all_for(std::chrono::milliseconds(100)); - REQUIRE(time_now() - b > std::chrono::milliseconds(50)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - - j.wait_all_until(time_now() + std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 50; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - const auto b = time_now(); - - j.wait_all_for(std::chrono::milliseconds(15)); - REQUIRE(time_now() - b > std::chrono::milliseconds(10)); - REQUIRE(counter == 0); - - j.wait_all_until(time_now() + std::chrono::milliseconds(15)); - REQUIRE(time_now() - b > std::chrono::milliseconds(20)); - REQUIRE(counter == 0); - - j.active_wait_all_for(std::chrono::milliseconds(100)); - REQUIRE(time_now() - b > std::chrono::milliseconds(70)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - - j.active_wait_all_until(time_now() + std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 30; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - j.resume(); - REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(50))); - REQUIRE(counter > 0); - REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::seconds(5))); - REQUIRE(counter == 30); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 30; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(50))); - REQUIRE(counter > 0); - REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::seconds(5))); - REQUIRE(counter == 30); - } - { - jb::jobber j(2); - jb::jobber g(2); - - std::vector> jp(50); - for ( auto& jpi : jp ) { - jpi = j.async([&g](){ - std::vector> gp(50); - for ( std::size_t i = 0; i < gp.size(); ++i ) { - gp[i] = g.async([](float angle){ - return std::sin(angle); - }, static_cast(i)); - } - return std::accumulate(gp.begin(), gp.end(), 0.f, - [](float r, pr::promise& f){ - return r + f.get(); - }); - }); - } - float r0 = std::accumulate(jp.begin(), jp.end(), 0.f, - [](float r, pr::promise& f){ - return r + f.get(); - }); - float r1 = 0.f; - for ( std::size_t i = 0; i < 50; ++i ) { - r1 += std::sin(static_cast(i)); - } - REQUIRE(r0 == Approx(r1 * 50.f).margin(0.01f)); - } -} - -TEST_CASE("scheduler") { - { - sd::scheduler s; - auto pv0 = s.schedule([](){ - throw std::exception(); - }); - s.process_all_tasks(); - REQUIRE_THROWS_AS(pv0.get(), std::exception); - } - { - auto pv0 = pr::promise(); - { - sd::scheduler s; - pv0 = s.schedule([](){ - return 42; - }); - } - REQUIRE_THROWS_AS(pv0.get(), sd::scheduler_cancelled_exception); - } - { - sd::scheduler s; - int counter = 0; - s.schedule([&counter](){ ++counter; }); - REQUIRE(counter == 0); - s.process_all_tasks(); - REQUIRE(counter == 1); - s.schedule([&counter](){ ++counter; }); - s.schedule([&counter](){ ++counter; }); - REQUIRE(counter == 1); - s.process_all_tasks(); - REQUIRE(counter == 3); - } - { - sd::scheduler s; - int counter = 0; - for ( std::size_t i = 0; i < 50; ++i ) { - s.schedule([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - s.process_tasks_for(std::chrono::milliseconds(-1)); - s.process_tasks_for(std::chrono::milliseconds(0)); - REQUIRE(counter == 0); - s.process_tasks_for(std::chrono::milliseconds(100)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - s.process_tasks_for(std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - sd::scheduler s; - int counter = 0; - for ( std::size_t i = 0; i < 50; ++i ) { - s.schedule([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - const auto b = time_now(); - - s.process_tasks_until(time_now() - std::chrono::milliseconds(1)); - s.process_tasks_until(time_now()); - REQUIRE(counter == 0); - s.process_tasks_until(time_now() + std::chrono::milliseconds(100)); - REQUIRE(time_now() - b > std::chrono::milliseconds(50)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - s.process_tasks_until(time_now() + std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - sd::scheduler s; - std::string accumulator; - s.schedule(sd::scheduler_priority::lowest, [](std::string& acc){ - acc.append("o"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::below_normal, [](std::string& acc){ - acc.append("l"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::highest, [](std::string& acc){ - acc.append("h"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::above_normal, [](std::string& acc){ - acc.append("e"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::normal, [](std::string& acc){ - acc.append("l"); - }, std::ref(accumulator)); - s.process_all_tasks(); - REQUIRE(accumulator == "hello"); - } -} diff --git a/scheduler_tests.cpp b/scheduler_tests.cpp new file mode 100644 index 0000000..f092eb9 --- /dev/null +++ b/scheduler_tests.cpp @@ -0,0 +1,114 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/promise.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018 Matvey Cherevko + ******************************************************************************/ + +#define CATCH_CONFIG_FAST_COMPILE +#include "catch.hpp" + +#include +#include +#include + +#include "scheduler.hpp" +namespace sd = scheduler_hpp; + +TEST_CASE("scheduler") { + { + sd::scheduler s; + auto pv0 = s.schedule([](){ + throw std::exception(); + }); + s.process_all_tasks(); + REQUIRE_THROWS_AS(pv0.get(), std::exception); + } + { + auto pv0 = sd::promise(); + { + sd::scheduler s; + pv0 = s.schedule([](){ + return 42; + }); + } + REQUIRE_THROWS_AS(pv0.get(), sd::scheduler_cancelled_exception); + } + { + sd::scheduler s; + int counter = 0; + s.schedule([&counter](){ ++counter; }); + REQUIRE(counter == 0); + s.process_all_tasks(); + REQUIRE(counter == 1); + s.schedule([&counter](){ ++counter; }); + s.schedule([&counter](){ ++counter; }); + REQUIRE(counter == 1); + s.process_all_tasks(); + REQUIRE(counter == 3); + } + { + sd::scheduler s; + int counter = 0; + for ( std::size_t i = 0; i < 50; ++i ) { + s.schedule([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + s.process_tasks_for(std::chrono::milliseconds(-1)); + s.process_tasks_for(std::chrono::milliseconds(0)); + REQUIRE(counter == 0); + s.process_tasks_for(std::chrono::milliseconds(100)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + s.process_tasks_for(std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + sd::scheduler s; + int counter = 0; + for ( std::size_t i = 0; i < 50; ++i ) { + s.schedule([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + const auto b = time_now(); + + s.process_tasks_until(time_now() - std::chrono::milliseconds(1)); + s.process_tasks_until(time_now()); + REQUIRE(counter == 0); + s.process_tasks_until(time_now() + std::chrono::milliseconds(100)); + REQUIRE(time_now() - b > std::chrono::milliseconds(50)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + s.process_tasks_until(time_now() + std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + sd::scheduler s; + std::string accumulator; + s.schedule(sd::scheduler_priority::lowest, [](std::string& acc){ + acc.append("o"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::below_normal, [](std::string& acc){ + acc.append("l"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::highest, [](std::string& acc){ + acc.append("h"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::above_normal, [](std::string& acc){ + acc.append("e"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::normal, [](std::string& acc){ + acc.append("l"); + }, std::ref(accumulator)); + s.process_all_tasks(); + REQUIRE(accumulator == "hello"); + } +}