1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/lib/promise/seq.h"
16
17 #include <memory>
18 #include <string>
19 #include <vector>
20
21 #include "absl/strings/str_cat.h"
22 #include "gtest/gtest.h"
23
24 namespace grpc_core {
25
TEST(SeqTest,Immediate)26 TEST(SeqTest, Immediate) {
27 std::string execution_order;
28 Poll<int> result = Seq([&execution_order] {
29 absl::StrAppend(&execution_order, "1");
30 return 100;
31 })();
32 EXPECT_EQ(result, Poll<int>(100));
33 EXPECT_STREQ(execution_order.c_str(), "1");
34 }
35
TEST(SeqTest,OneThen)36 TEST(SeqTest, OneThen) {
37 std::string execution_order;
38 auto initial = [&execution_order,
39 test_destructor_invocation1 =
40 std::make_unique<int>(1)]() -> Poll<std::string> {
41 absl::StrAppend(&execution_order, "1");
42 return "Hello";
43 };
44 auto then = [&execution_order,
45 test_destructor_invocation2 =
46 std::make_unique<int>(2)](std::string initial_output) {
47 absl::StrAppend(&execution_order, "2");
48 return [test_destructor_invocation3 = std::make_unique<int>(3),
49 &execution_order, initial_output]() -> Poll<int> {
50 absl::StrAppend(&execution_order, "3");
51 return initial_output.length() + 4;
52 };
53 };
54 auto result = Seq(std::move(initial), std::move(then))();
55 EXPECT_TRUE(result.ready());
56 EXPECT_EQ(result.value(), 9);
57 EXPECT_STREQ(execution_order.c_str(), "123");
58 }
59
TEST(SeqTest,TestPending)60 TEST(SeqTest, TestPending) {
61 std::string execution_order;
62 bool return_pending = true;
63 auto initial = [&execution_order, &return_pending,
64 test_destructor_invocation1 =
65 std::make_unique<int>(1)]() -> Poll<int> {
66 absl::StrAppend(&execution_order, "1");
67 if (return_pending) return Pending{};
68 return 100;
69 };
70
71 auto then = [test_destructor_invocation2 = std::make_unique<int>(2),
72 &execution_order](int i) {
73 absl::StrAppend(&execution_order, "2");
74 return [i, test_destructor_invocation3 = std::make_unique<int>(3),
75 &execution_order]() -> Poll<int> {
76 absl::StrAppend(&execution_order, "3");
77 return i + 4;
78 };
79 };
80
81 auto seq_combinator = Seq(std::move(initial), std::move(then));
82 auto result = seq_combinator();
83 EXPECT_EQ(result, Poll<int>(Pending{}));
84 EXPECT_STREQ(execution_order.c_str(), "1");
85
86 execution_order.clear();
87 return_pending = false;
88 result = seq_combinator();
89 EXPECT_EQ(result, Poll<int>(104));
90 EXPECT_STREQ(execution_order.c_str(), "123");
91 }
92
TEST(SeqTest,ThreeTypedPendingThens)93 TEST(SeqTest, ThreeTypedPendingThens) {
94 std::string execution_order;
95 bool pending_a = true;
96 bool pending_b = true;
97 bool pending_c = true;
98 bool pending_d = true;
99
100 struct A {
101 int a_ = -1;
102 };
103 struct B {
104 int b_ = -1;
105 };
106 struct C {
107 int c_ = -1;
108 };
109 struct D {
110 int d_ = -1;
111 };
112
113 auto initial = [&execution_order, &pending_a]() -> Poll<A> {
114 absl::StrAppend(&execution_order, "0");
115 if (pending_a) {
116 absl::StrAppend(&execution_order, "P");
117 return Pending{};
118 }
119 absl::StrAppend(&execution_order, "a");
120 return A{100};
121 };
122
123 auto next1 = [&execution_order, &pending_b](A a) {
124 absl::StrAppend(&execution_order, "1");
125 return [&execution_order, &pending_b, a]() -> Poll<B> {
126 EXPECT_EQ(a.a_, 100);
127 if (pending_b) {
128 absl::StrAppend(&execution_order, "P");
129 return Pending{};
130 }
131 absl::StrAppend(&execution_order, "b");
132 return B{200};
133 };
134 };
135
136 auto next2 = [&execution_order, &pending_c](B b) {
137 absl::StrAppend(&execution_order, "2");
138 return [&execution_order, &pending_c, b]() -> Poll<C> {
139 EXPECT_EQ(b.b_, 200);
140 if (pending_c) {
141 absl::StrAppend(&execution_order, "P");
142 return Pending{};
143 }
144 absl::StrAppend(&execution_order, "c");
145 return C{300};
146 };
147 };
148
149 auto next3 = [&execution_order, &pending_d](C c) {
150 absl::StrAppend(&execution_order, "3");
151 return [&execution_order, &pending_d, c]() -> Poll<D> {
152 EXPECT_EQ(c.c_, 300);
153 if (pending_d) {
154 absl::StrAppend(&execution_order, "P");
155 return Pending{};
156 }
157 absl::StrAppend(&execution_order, "d");
158 return D{400};
159 };
160 };
161
162 auto seq_combinator = Seq(initial, next1, next2, next3);
163
164 auto retval = seq_combinator();
165 EXPECT_TRUE(retval.pending());
166 EXPECT_STREQ(execution_order.c_str(), "0P");
167
168 execution_order.clear();
169 pending_a = false;
170 retval = seq_combinator();
171 EXPECT_TRUE(retval.pending());
172 EXPECT_STREQ(execution_order.c_str(), "0a1P");
173
174 execution_order.clear();
175 pending_b = false;
176 retval = seq_combinator();
177 EXPECT_TRUE(retval.pending());
178 EXPECT_STREQ(execution_order.c_str(), "b2P");
179
180 execution_order.clear();
181 pending_c = false;
182 retval = seq_combinator();
183 EXPECT_TRUE(retval.pending());
184 EXPECT_STREQ(execution_order.c_str(), "c3P");
185
186 execution_order.clear();
187 pending_d = false;
188 retval = seq_combinator();
189 EXPECT_TRUE(retval.ready());
190 EXPECT_EQ(retval.value().d_, 400);
191 EXPECT_STREQ(execution_order.c_str(), "d");
192 }
193
194 // This does not compile, but is useful for testing error messages generated
195 // TEST(SeqTest, MisTypedThen) {
196 // struct A {};
197 // struct B {};
198 // auto initial = [] { return A{}; };
199 // auto next = [](B) { return []() { return B{}; }; };
200 // Seq(initial, next)().take();
201 //}
202 //
203
TEST(SeqTest,TwoThens)204 TEST(SeqTest, TwoThens) {
205 auto initial = [] { return std::string("a"); };
206 auto next1 = [](std::string i) { return [i]() { return i + "b"; }; };
207 auto next2 = [](std::string i) { return [i]() { return i + "c"; }; };
208 EXPECT_EQ(Seq(initial, next1, next2)(), Poll<std::string>("abc"));
209 }
210
TEST(SeqTest,ThreeThens)211 TEST(SeqTest, ThreeThens) {
212 EXPECT_EQ(
213 Seq([test_destructor_invocation1 =
214 std::make_unique<int>(1)] { return std::string("a"); },
215 [test_destructor_invocation2 =
216 std::make_unique<int>(2)](std::string i) {
217 return [i, y = std::make_unique<int>(2)]() { return i + "b"; };
218 },
219 [test_destructor_invocation3 =
220 std::make_unique<int>(1)](std::string i) {
221 return [i, y = std::make_unique<int>(3)]() { return i + "c"; };
222 },
223 [test_destructor_invocation4 =
224 std::make_unique<int>(1)](std::string i) {
225 return [i, y = std::make_unique<int>(4)]() { return i + "d"; };
226 })(),
227 Poll<std::string>("abcd"));
228 }
229
230 struct Big {
231 int x[256];
YesItIsUnusedgrpc_core::Big232 void YesItIsUnused() const {}
233 };
234
TEST(SeqTest,SaneSizes)235 TEST(SeqTest, SaneSizes) {
236 auto x = Big();
237 auto p1 = Seq(
238 [x] {
239 x.YesItIsUnused();
240 return 1;
241 },
242 [](int) {
243 auto y = Big();
244 return [y]() {
245 y.YesItIsUnused();
246 return 2;
247 };
248 });
249 LOG(INFO) << "sizeof(Big): " << sizeof(Big); // Was 1024
250 LOG(INFO) << "sizeof(p1): " << sizeof(p1); // Was 1048
251 EXPECT_GE(sizeof(p1), sizeof(Big));
252 EXPECT_LT(sizeof(p1), 1.05 * sizeof(Big)); // Watchout for size bloat!
253 }
254
TEST(SeqIterTest,Accumulate)255 TEST(SeqIterTest, Accumulate) {
256 std::vector<int> v{1, 2, 3, 4, 5};
257 EXPECT_EQ(SeqIter(v.begin(), v.end(), 0,
258 [](int cur, int next) {
259 return [cur, next]() { return cur + next; };
260 })(),
261 Poll<int>(15));
262 }
263
264 } // namespace grpc_core
265
main(int argc,char ** argv)266 int main(int argc, char** argv) {
267 ::testing::InitGoogleTest(&argc, argv);
268 return RUN_ALL_TESTS();
269 }
270