this repo has no description
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}