#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include
#include
// --------------------------------------------------------
// Testcase: static_task
// --------------------------------------------------------
void static_task(unsigned W) {
tf::Taskflow taskflow;
tf::Executor executor(W);
std::atomic counter(0);
auto A = taskflow.emplace([&](){ counter.fetch_add(1, std::memory_order_relaxed); });
auto B = taskflow.emplace([&](){ counter.fetch_add(1, std::memory_order_relaxed); });
auto C = taskflow.emplace([&](){ counter.fetch_add(1, std::memory_order_relaxed); });
auto D = taskflow.emplace([&](){ counter.fetch_add(1, std::memory_order_relaxed); });
auto E = taskflow.emplace([&](){ counter.fetch_add(1, std::memory_order_relaxed); });
auto F = taskflow.emplace([&](){ counter.fetch_add(1, std::memory_order_relaxed); });
A.precede(B);
B.precede(C);
C.precede(D);
D.precede(E);
E.precede(F);
REQUIRE_NOTHROW(executor.run(taskflow).get());
REQUIRE(counter == 6);
counter = 0;
C.work([](){ throw std::runtime_error("x"); });
REQUIRE_THROWS_WITH_AS(executor.run(taskflow).get(), "x", std::runtime_error);
REQUIRE(counter == 2);
try {
counter = 0;
executor.run(taskflow).get();
REQUIRE(false);
}
catch(std::runtime_error& e) {
REQUIRE(counter == 2);
REQUIRE(std::strcmp(e.what(), "x") == 0);
}
}
TEST_CASE("Exception.StaticTask.1thread" * doctest::timeout(300)) {
static_task(1);
}
TEST_CASE("Exception.StaticTask.2threads" * doctest::timeout(300)) {
static_task(2);
}
TEST_CASE("Exception.StaticTask.3threads" * doctest::timeout(300)) {
static_task(3);
}
TEST_CASE("Exception.StaticTask.4threads" * doctest::timeout(300)) {
static_task(4);
}
// --------------------------------------------------------
// Testcase: condition_task
// --------------------------------------------------------
void condition_task(unsigned W) {
tf::Taskflow taskflow;
tf::Executor executor(W);
std::atomic counter(0);
auto A = taskflow.emplace([&](){
counter.fetch_add(1, std::memory_order_relaxed);
return 0;
});
auto B = taskflow.emplace([&](){
counter.fetch_add(1, std::memory_order_relaxed);
return 0;
});
auto C = taskflow.emplace([&](){
counter.fetch_add(1, std::memory_order_relaxed);
return 0;
});
auto D = taskflow.emplace([&](){
counter.fetch_add(1, std::memory_order_relaxed);
return 0;
});
auto E = taskflow.emplace([&](){
counter.fetch_add(1, std::memory_order_relaxed);
return 0;
});
auto F = taskflow.emplace([&](){
counter.fetch_add(1, std::memory_order_relaxed);
return 0;
});
A.precede(B);
B.precede(C);
C.precede(D);
D.precede(E);
E.precede(F);
REQUIRE_NOTHROW(executor.run(taskflow).get());
REQUIRE(counter == 6);
counter = 0;
C.work([](){ throw std::runtime_error("x"); });
REQUIRE_THROWS_WITH_AS(executor.run(taskflow).get(), "x", std::runtime_error);
REQUIRE(counter == 2);
try {
counter = 0;
executor.run(taskflow).get();
REQUIRE(false);
}
catch(std::runtime_error& e) {
REQUIRE(counter == 2);
REQUIRE(std::strcmp(e.what(), "x") == 0);
}
}
TEST_CASE("Exception.ConditionTask.1thread" * doctest::timeout(300)) {
condition_task(1);
}
TEST_CASE("Exception.ConditionTask.2threads" * doctest::timeout(300)) {
condition_task(2);
}
TEST_CASE("Exception.ConditionTask.3threads" * doctest::timeout(300)) {
condition_task(3);
}
TEST_CASE("Exception.ConditionTask.4threads" * doctest::timeout(300)) {
condition_task(4);
}
// --------------------------------------------------------
// Testcase: multicondition_task
// --------------------------------------------------------
void multicondition_task(unsigned W) {
tf::Taskflow taskflow;
tf::Executor executor(W);
std::atomic counter(0);
auto A = taskflow.emplace([&](){
tf::SmallVector ret = {0};
counter.fetch_add(1, std::memory_order_relaxed);
return ret;
});
auto B = taskflow.emplace([&](){
tf::SmallVector ret = {0};
counter.fetch_add(1, std::memory_order_relaxed);
return ret;
});
auto C = taskflow.emplace([&](){
tf::SmallVector ret = {0};
counter.fetch_add(1, std::memory_order_relaxed);
return ret;
});
auto D = taskflow.emplace([&](){
tf::SmallVector ret = {0};
counter.fetch_add(1, std::memory_order_relaxed);
return ret;
});
auto E = taskflow.emplace([&](){
tf::SmallVector ret = {0};
counter.fetch_add(1, std::memory_order_relaxed);
return ret;
});
auto F = taskflow.emplace([&](){
tf::SmallVector ret = {0};
counter.fetch_add(1, std::memory_order_relaxed);
return ret;
});
A.precede(B);
B.precede(C);
C.precede(D);
D.precede(E);
E.precede(F);
REQUIRE_NOTHROW(executor.run(taskflow).get());
REQUIRE(counter == 6);
counter = 0;
C.work([](){ throw std::runtime_error("x"); });
REQUIRE_THROWS_WITH_AS(executor.run(taskflow).get(), "x", std::runtime_error);
REQUIRE(counter == 2);
try {
counter = 0;
executor.run(taskflow).get();
REQUIRE(false);
}
catch(std::runtime_error& e) {
REQUIRE(counter == 2);
REQUIRE(std::strcmp(e.what(), "x") == 0);
}
}
TEST_CASE("Exception.MultiConditionTask.1thread" * doctest::timeout(300)) {
multicondition_task(1);
}
TEST_CASE("Exception.MultiConditionTask.2threads" * doctest::timeout(300)) {
multicondition_task(2);
}
TEST_CASE("Exception.MultiConditionTask.3threads" * doctest::timeout(300)) {
multicondition_task(3);
}
TEST_CASE("Exception.MultiConditionTask.4threads" * doctest::timeout(300)) {
multicondition_task(4);
}
// ----------------------------------------------------------------------------
// Subflow Task
// ----------------------------------------------------------------------------
void subflow_task(unsigned W) {
tf::Taskflow taskflow;
tf::Executor executor(W);
// subflow work throws
for(int i=0; i