#include #include #include #include #include #include #include #include template using task = kev::task; TEST(TaskTest, BasicTaskAwaiting) { auto task_lambda = []() -> task { co_return 65; }(); auto res = stdexec::sync_wait(std::move(task_lambda)); auto [val] = *res; EXPECT_EQ(val, 65); } TEST(TaskTest, NestedTaskAwaiting) { auto inner = []() -> task { co_return 10; }; auto outer = [&]() -> task { int value = co_await inner(); co_return value + 5; }; auto res = stdexec::sync_wait(outer()); auto [val] = *res; EXPECT_EQ(val, 15); } TEST(TaskTest, VoidTaskAwaiting) { auto task_callable = []() -> task { co_return; }(); auto res = stdexec::sync_wait(std::move(task_callable)); EXPECT_TRUE(res.has_value()); } TEST(TaskTest, MoveOnlyReturnValue) { auto task_callable = []() -> task> { co_return std::make_unique(42); }(); auto res = stdexec::sync_wait(std::move(task_callable)); ASSERT_TRUE(res.has_value()); auto [ptr] = std::move(*res); ASSERT_TRUE(ptr); EXPECT_EQ(*ptr, 42); } TEST(TaskTest, FormSenderChain) { auto task_callable = []() -> task { co_return 20; }() | stdexec::then([](int value) { return value + 22; }); auto res = stdexec::sync_wait(std::move(task_callable)); ASSERT_TRUE(res.has_value()); auto [val] = *res; EXPECT_EQ(val, 42); } TEST(TaskTest, AwaitSenderInsideTask) { auto task_callable = []() -> task { int value = co_await (stdexec::just(7) | stdexec::then([](int v) { return v * 2; })); co_return value + 1; }(); auto res = stdexec::sync_wait(std::move(task_callable)); auto [val] = *res; EXPECT_EQ(val, 15); } TEST(TaskTest, InnerTaskExceptionCanBeHandled) { auto inner = []() -> task { throw std::runtime_error("inner"); co_return 0; }; auto outer = [&]() -> task { try { (void)co_await inner(); } catch (const std::runtime_error &) { co_return 99; } co_return 0; }; auto res = stdexec::sync_wait(outer()); auto [val] = *res; EXPECT_EQ(val, 99); } TEST(TaskTest, ErrorPropagatesToSyncWait) { EXPECT_THROW( { auto task_callable = []() -> task { throw std::runtime_error("boom"); co_return 0; }(); (void)stdexec::sync_wait(std::move(task_callable)); }, std::runtime_error); } TEST(TaskTest, TestErrorHandling) { static constexpr std::string_view error_message = "Test error"; auto task_callable = []() -> task { throw std::runtime_error(error_message.data()); co_return 0; }(); auto task_t = std::move(task_callable) | stdexec::upon_error([](std::exception_ptr ep) -> int { try { if (ep) { std::rethrow_exception(ep); } } catch (const std::runtime_error &ex) { EXPECT_EQ(error_message, std::string_view(ex.what())); return -1; // Return -1 on error } return 0; // Default return value }); auto res = stdexec::sync_wait(std::move(task_t)); ASSERT_TRUE(res.has_value()); auto [val] = *res; EXPECT_EQ(val, -1); } TEST(TaskTest, CoAwaitTaskInLoopToVerifyNoStackOverflow) { static constexpr size_t iterations = 1000000; auto task_callable = []() -> task { size_t sum = 0; for (size_t i = 0; i < iterations; ++i) { auto task_callable = []() -> task { co_return; }; co_await task_callable(); sum += 1; } co_return sum; }(); auto res = stdexec::sync_wait(std::move(task_callable)); auto [val] = *res; EXPECT_EQ(val, iterations); }