this repo has no description
at main 148 lines 4.2 kB view raw
1#include <cstddef> 2#include <exception> 3#include <exec/task.hpp> 4#include <gtest/gtest.h> 5#include <stdexcept> 6#include <stdexec/execution.hpp> 7#include <string_view> 8#include <task.hpp> 9 10template <typename T> using task = kev::task<T>; 11 12TEST(TaskTest, BasicTaskAwaiting) 13{ 14 auto task_lambda = []() -> task<int> { co_return 65; }(); 15 auto res = stdexec::sync_wait(std::move(task_lambda)); 16 auto [val] = *res; 17 EXPECT_EQ(val, 65); 18} 19 20TEST(TaskTest, NestedTaskAwaiting) 21{ 22 auto inner = []() -> task<int> { co_return 10; }; 23 auto outer = [&]() -> task<int> { 24 int value = co_await inner(); 25 co_return value + 5; 26 }; 27 auto res = stdexec::sync_wait(outer()); 28 auto [val] = *res; 29 EXPECT_EQ(val, 15); 30} 31 32TEST(TaskTest, VoidTaskAwaiting) 33{ 34 auto task_callable = []() -> task<void> { co_return; }(); 35 auto res = stdexec::sync_wait(std::move(task_callable)); 36 EXPECT_TRUE(res.has_value()); 37} 38 39TEST(TaskTest, MoveOnlyReturnValue) 40{ 41 auto task_callable = []() -> task<std::unique_ptr<int>> { co_return std::make_unique<int>(42); }(); 42 auto res = stdexec::sync_wait(std::move(task_callable)); 43 ASSERT_TRUE(res.has_value()); 44 auto [ptr] = std::move(*res); 45 ASSERT_TRUE(ptr); 46 EXPECT_EQ(*ptr, 42); 47} 48 49TEST(TaskTest, FormSenderChain) 50{ 51 auto task_callable = []() -> task<int> { co_return 20; }() | stdexec::then([](int value) { return value + 22; }); 52 auto res = stdexec::sync_wait(std::move(task_callable)); 53 ASSERT_TRUE(res.has_value()); 54 auto [val] = *res; 55 EXPECT_EQ(val, 42); 56} 57 58TEST(TaskTest, AwaitSenderInsideTask) 59{ 60 auto task_callable = []() -> task<int> { 61 int value = co_await (stdexec::just(7) | stdexec::then([](int v) { return v * 2; })); 62 co_return value + 1; 63 }(); 64 auto res = stdexec::sync_wait(std::move(task_callable)); 65 auto [val] = *res; 66 EXPECT_EQ(val, 15); 67} 68 69TEST(TaskTest, InnerTaskExceptionCanBeHandled) 70{ 71 auto inner = []() -> task<int> { 72 throw std::runtime_error("inner"); 73 co_return 0; 74 }; 75 auto outer = [&]() -> task<int> { 76 try 77 { 78 (void)co_await inner(); 79 } 80 catch (const std::runtime_error &) 81 { 82 co_return 99; 83 } 84 co_return 0; 85 }; 86 auto res = stdexec::sync_wait(outer()); 87 auto [val] = *res; 88 EXPECT_EQ(val, 99); 89} 90 91TEST(TaskTest, ErrorPropagatesToSyncWait) 92{ 93 EXPECT_THROW( 94 { 95 auto task_callable = []() -> task<int> { 96 throw std::runtime_error("boom"); 97 co_return 0; 98 }(); 99 (void)stdexec::sync_wait(std::move(task_callable)); 100 }, 101 std::runtime_error); 102} 103 104TEST(TaskTest, TestErrorHandling) 105{ 106 static constexpr std::string_view error_message = "Test error"; 107 auto task_callable = []() -> task<int> { 108 throw std::runtime_error(error_message.data()); 109 co_return 0; 110 }(); 111 auto task_t = std::move(task_callable) | stdexec::upon_error([](std::exception_ptr ep) -> int { 112 try 113 { 114 if (ep) 115 { 116 std::rethrow_exception(ep); 117 } 118 } 119 catch (const std::runtime_error &ex) 120 { 121 EXPECT_EQ(error_message, std::string_view(ex.what())); 122 return -1; // Return -1 on error 123 } 124 return 0; // Default return value 125 }); 126 auto res = stdexec::sync_wait(std::move(task_t)); 127 ASSERT_TRUE(res.has_value()); 128 auto [val] = *res; 129 EXPECT_EQ(val, -1); 130} 131 132TEST(TaskTest, CoAwaitTaskInLoopToVerifyNoStackOverflow) 133{ 134 static constexpr size_t iterations = 1000000; 135 auto task_callable = []() -> task<size_t> { 136 size_t sum = 0; 137 for (size_t i = 0; i < iterations; ++i) 138 { 139 auto task_callable = []() -> task<void> { co_return; }; 140 co_await task_callable(); 141 sum += 1; 142 } 143 co_return sum; 144 }(); 145 auto res = stdexec::sync_wait(std::move(task_callable)); 146 auto [val] = *res; 147 EXPECT_EQ(val, iterations); 148}