1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_async2/poll.h"
16
17 #include <type_traits>
18
19 #include "gtest/gtest.h"
20 #include "pw_async2/try.h"
21 #include "pw_result/result.h"
22
23 namespace pw::async2 {
24 namespace {
25
26 class MoveOnly {
27 public:
28 MoveOnly() = delete;
MoveOnly(int value)29 MoveOnly(int value) : value_(value) {}
30 MoveOnly(const MoveOnly&) = delete;
31 MoveOnly& operator=(const MoveOnly&) = delete;
32 MoveOnly(MoveOnly&&) = default;
33 MoveOnly& operator=(MoveOnly&&) = default;
value() const34 int value() const { return value_; }
35
36 private:
37 int value_;
38 };
39
40 struct Immovable {
41 public:
42 Immovable() = delete;
Immovablepw::async2::__anon57899f4a0111::Immovable43 Immovable(MoveOnly&& value) : value_(std::move(value)) {}
44 Immovable(const Immovable&) = delete;
45 Immovable& operator=(const Immovable&) = delete;
46 Immovable(Immovable&&) = delete;
47 Immovable& operator=(Immovable&&) = delete;
valuepw::async2::__anon57899f4a0111::Immovable48 int value() const { return value_.value(); }
49
50 private:
51 MoveOnly value_;
52 };
53
TEST(Poll,ConstructsReadyInPlace)54 TEST(Poll, ConstructsReadyInPlace) {
55 Poll<Immovable> mr(std::in_place, MoveOnly(5));
56 EXPECT_TRUE(mr.IsReady());
57 EXPECT_EQ(mr->value(), 5);
58 }
59
TEST(Poll,ConstructsReadyFromValueType)60 TEST(Poll, ConstructsReadyFromValueType) {
61 Poll<MoveOnly> mr = MoveOnly(5);
62 EXPECT_TRUE(mr.IsReady());
63 EXPECT_EQ(mr->value(), 5);
64 }
65
TEST(Poll,ConstructsFromValueConvertibleToValueType)66 TEST(Poll, ConstructsFromValueConvertibleToValueType) {
67 Poll<Immovable> mr(MoveOnly(5));
68 EXPECT_TRUE(mr.IsReady());
69 EXPECT_EQ(mr->value(), 5);
70 }
71
TEST(Poll,ConstructsFromPollWithValueConvertibleToValueType)72 TEST(Poll, ConstructsFromPollWithValueConvertibleToValueType) {
73 Poll<MoveOnly> move_poll(MoveOnly(5));
74 Poll<Immovable> no_move_poll(std::move(move_poll));
75 EXPECT_TRUE(no_move_poll.IsReady());
76 EXPECT_EQ(no_move_poll->value(), 5);
77 }
78
TEST(Poll,ConstructsPendingFromPendingType)79 TEST(Poll, ConstructsPendingFromPendingType) {
80 Poll<MoveOnly> mr(Pending());
81 EXPECT_FALSE(mr.IsReady());
82 }
83
TEST(Poll,ConstructorInfersValueType)84 TEST(Poll, ConstructorInfersValueType) {
85 auto res = Poll("hello");
86 static_assert(std::is_same_v<decltype(res), Poll<const char*>>);
87 EXPECT_TRUE(res.IsReady());
88 EXPECT_STREQ(res.value(), "hello");
89 }
90
TEST(Poll,ReadinessOnReadyValueReturnsReadyWithoutValue)91 TEST(Poll, ReadinessOnReadyValueReturnsReadyWithoutValue) {
92 Poll<int> v = Ready(5);
93 Poll<> readiness = v.Readiness();
94 EXPECT_TRUE(readiness.IsReady());
95 }
96
TEST(Poll,ReadinessOnPendingValueReturnsPendingWithoutValue)97 TEST(Poll, ReadinessOnPendingValueReturnsPendingWithoutValue) {
98 Poll<int> v = Pending();
99 Poll<> readiness = v.Readiness();
100 EXPECT_TRUE(readiness.IsPending());
101 }
102
TEST(Poll,ReadyToString)103 TEST(Poll, ReadyToString) {
104 char buffer[128] = {};
105 Poll<> v = Ready();
106 EXPECT_EQ(5u, ToString(v, buffer).size());
107 EXPECT_STREQ("Ready", buffer);
108 }
109
TEST(Poll,ReadyValueToString)110 TEST(Poll, ReadyValueToString) {
111 char buffer[128] = {};
112 Poll<uint16_t> v = 5;
113 EXPECT_EQ(8u, ToString(v, buffer).size());
114 EXPECT_STREQ("Ready(5)", buffer);
115 }
116
TEST(Poll,PendingToString)117 TEST(Poll, PendingToString) {
118 char buffer[128] = {};
119 Poll<uint16_t> v = Pending();
120 EXPECT_EQ(7u, ToString(v, buffer).size());
121 EXPECT_STREQ("Pending", buffer);
122 }
123
TEST(PendingFunction,ReturnsValueConvertibleToPendingPoll)124 TEST(PendingFunction, ReturnsValueConvertibleToPendingPoll) {
125 Poll<MoveOnly> mr = Pending();
126 EXPECT_FALSE(mr.IsReady());
127 }
128
TEST(ReadyFunction,CalledWithNoArgumentsReturnsPollWithReadyType)129 TEST(ReadyFunction, CalledWithNoArgumentsReturnsPollWithReadyType) {
130 Poll<> mr = Ready();
131 EXPECT_TRUE(mr.IsReady());
132 [[maybe_unused]] ReadyType& ready_value = mr.value();
133 }
134
TEST(ReadyFunction,ConstructsReadyInPlace)135 TEST(ReadyFunction, ConstructsReadyInPlace) {
136 Poll<Immovable> mr = Ready<Immovable>(std::in_place, MoveOnly(5));
137 EXPECT_TRUE(mr.IsReady());
138 EXPECT_EQ(mr->value(), 5);
139 }
140
TEST(ReadyFunction,ConstructsReadyFromValueType)141 TEST(ReadyFunction, ConstructsReadyFromValueType) {
142 Poll<MoveOnly> mr = Ready(MoveOnly(5));
143 EXPECT_TRUE(mr.IsReady());
144 EXPECT_EQ(mr->value(), 5);
145 }
146
EndToEndTest(int input)147 Poll<Result<int>> EndToEndTest(int input) {
148 if (input == 0) {
149 // Check that returning plain ``Status`` works.
150 return Status::PermissionDenied();
151 }
152 if (input == 1) {
153 // Check that returning ``Pending`` works.
154 return Pending();
155 }
156 if (input == 2) {
157 // Check that returning ``Result<int>`` works.
158 Result<int> v = 2;
159 return v;
160 }
161 if (input == 3) {
162 // Check that returning plain ``int`` works.
163 return 3;
164 }
165 if (input == 4) {
166 // Check that returning ``Poll<int>`` works.
167 return Ready(4);
168 }
169 if (input == 5) {
170 // Check that returning ``Poll<Status>`` works.
171 return Ready(Status::DataLoss());
172 }
173 return Status::Unknown();
174 }
175
TEST(EndToEndTest,ReturnsStatus)176 TEST(EndToEndTest, ReturnsStatus) {
177 Poll<Result<int>> result = EndToEndTest(0);
178 ASSERT_TRUE(result.IsReady());
179 EXPECT_EQ(result->status(), Status::PermissionDenied());
180 }
181
TEST(EndToEndTest,ReturnsPending)182 TEST(EndToEndTest, ReturnsPending) {
183 Poll<Result<int>> result = EndToEndTest(1);
184 EXPECT_FALSE(result.IsReady());
185 }
186
TEST(EndToEndTest,ReturnsValue)187 TEST(EndToEndTest, ReturnsValue) {
188 Poll<Result<int>> result = EndToEndTest(3);
189 ASSERT_TRUE(result.IsReady());
190 ASSERT_TRUE(result->ok());
191 EXPECT_EQ(**result, 3);
192 }
193
TEST(EndToEndTest,ReturnsReady)194 TEST(EndToEndTest, ReturnsReady) {
195 Poll<Result<int>> result = EndToEndTest(4);
196 ASSERT_TRUE(result.IsReady());
197 ASSERT_TRUE(result->ok());
198 EXPECT_EQ(**result, 4);
199 }
200
TEST(EndToEndTest,ReturnsPollStatus)201 TEST(EndToEndTest, ReturnsPollStatus) {
202 Poll<Result<int>> result = EndToEndTest(5);
203 ASSERT_TRUE(result.IsReady());
204 EXPECT_EQ(result->status(), Status::DataLoss());
205 }
206
207 enum TryReadyAction {
208 kDoPend,
209 kDoReady,
210 };
211
TestTryReady(TryReadyAction action)212 Poll<Status> TestTryReady(TryReadyAction action) {
213 Poll<Status> pending(Pending());
214 Poll<Status> ready(Ready(OkStatus()));
215 PW_TRY_READY(action == kDoPend ? pending : ready);
216 return ready;
217 }
218
TEST(TryReady,PollPending)219 TEST(TryReady, PollPending) {
220 ASSERT_TRUE(TestTryReady(kDoPend).IsPending());
221 ASSERT_TRUE(TestTryReady(kDoReady).IsReady());
222 }
223
TestTryReadyAssignSimple(TryReadyAction action)224 Poll<Status> TestTryReadyAssignSimple(TryReadyAction action) {
225 Poll<Status> pending(Pending());
226 Poll<Status> ready(Ready(OkStatus()));
227 PW_TRY_READY_ASSIGN(auto poll, action == kDoPend ? pending : ready);
228 return poll;
229 }
230
TEST(TryReadyAssign,PollPending)231 TEST(TryReadyAssign, PollPending) {
232 ASSERT_TRUE(TestTryReadyAssignSimple(kDoPend).IsPending());
233 ASSERT_TRUE(TestTryReadyAssignSimple(kDoReady).IsReady());
234 }
235
MakeImmovable(TryReadyAction action)236 Poll<Immovable> MakeImmovable(TryReadyAction action) {
237 return action == kDoReady ? Poll<Immovable>(5) : Pending();
238 }
239
TryReadyAssignImmovable(TryReadyAction action)240 Poll<int> TryReadyAssignImmovable(TryReadyAction action) {
241 PW_TRY_READY_ASSIGN(auto&& x, MakeImmovable(action));
242 return x.value();
243 }
244
TEST(TryReadyAssign,ImmovableIsReady)245 TEST(TryReadyAssign, ImmovableIsReady) {
246 auto poll = TryReadyAssignImmovable(kDoReady);
247 ASSERT_TRUE(poll.IsReady());
248 ASSERT_EQ(poll.value(), 5);
249 }
250
TEST(TryReadyAssign,ImmovableIsPending)251 TEST(TryReadyAssign, ImmovableIsPending) {
252 auto poll = TryReadyAssignImmovable(kDoPend);
253 ASSERT_TRUE(poll.IsPending());
254 }
255
TryReadyAssignMoveOnly(TryReadyAction action)256 Poll<int> TryReadyAssignMoveOnly(TryReadyAction action) {
257 PW_TRY_READY_ASSIGN(auto&& x,
258 action == kDoReady ? Ready(MoveOnly(5)) : Pending());
259 return x.value();
260 }
261
TEST(TryReadyAssign,MoveOnlyIsReady)262 TEST(TryReadyAssign, MoveOnlyIsReady) {
263 auto poll = TryReadyAssignMoveOnly(kDoReady);
264 ASSERT_TRUE(poll.IsReady());
265 ASSERT_EQ(poll.value(), 5);
266 }
267
TEST(TryReadyAssign,MoveOnlyIsPending)268 TEST(TryReadyAssign, MoveOnlyIsPending) {
269 auto poll = TryReadyAssignMoveOnly(kDoPend);
270 ASSERT_TRUE(poll.IsPending());
271 }
272
273 } // namespace
274 } // namespace pw::async2
275