xref: /aosp_15_r20/external/pigweed/pw_async2/poll_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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