xref: /aosp_15_r20/external/pigweed/pw_async2/once_sender_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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/once_sender.h"
16 
17 #include "pw_async2/dispatcher.h"
18 #include "pw_containers/vector.h"
19 #include "pw_unit_test/framework.h"
20 
21 namespace {
22 
23 using ::pw::async2::Context;
24 using ::pw::async2::Dispatcher;
25 using ::pw::async2::OnceReceiver;
26 using ::pw::async2::OnceRefReceiver;
27 using ::pw::async2::OnceRefSender;
28 using ::pw::async2::OnceSender;
29 using ::pw::async2::Pending;
30 using ::pw::async2::Poll;
31 using ::pw::async2::Ready;
32 using ::pw::async2::Task;
33 
34 class MoveOnlyValue {
35  public:
MoveOnlyValue(int value)36   MoveOnlyValue(int value) : value_(value) {}
37   MoveOnlyValue(const MoveOnlyValue&) = delete;
38   MoveOnlyValue& operator=(const MoveOnlyValue&) = delete;
39   MoveOnlyValue(MoveOnlyValue&&) = default;
40   MoveOnlyValue& operator=(MoveOnlyValue&&) = default;
41 
value()42   int& value() { return value_; }
43 
44  private:
45   int value_;
46 };
47 
48 class ValueTask : public Task {
49  public:
ValueTask(bool use_make_constructor=true)50   ValueTask(bool use_make_constructor = true)
51       : use_make_constructor_(use_make_constructor) {}
DoPend(Context & cx)52   Poll<> DoPend(Context& cx) override {
53     if (!receiver_) {
54       if (use_make_constructor_) {
55         auto [send, recv] =
56             pw::async2::MakeOnceSenderAndReceiver<MoveOnlyValue>();
57         sender_.emplace(std::move(send));
58         receiver_.emplace(std::move(recv));
59       } else {
60         receiver_.emplace();
61         sender_.emplace();
62         pw::async2::InitializeOnceSenderAndReceiver<MoveOnlyValue>(
63             sender_.value(), receiver_.value());
64       }
65     }
66     Poll<pw::Result<MoveOnlyValue>> poll = receiver_.value().Pend(cx);
67     if (poll.IsReady()) {
68       ready_value_.emplace(std::move(poll.value()));
69       return Ready();
70     }
71     return Pending();
72   }
ready_value()73   std::optional<pw::Result<MoveOnlyValue>>& ready_value() {
74     return ready_value_;
75   }
sender()76   std::optional<OnceSender<MoveOnlyValue>>& sender() { return sender_; }
77 
DestroySender()78   void DestroySender() { sender_.reset(); }
DestroyReceiver()79   void DestroyReceiver() { receiver_.reset(); }
80 
81  private:
82   bool use_make_constructor_;
83   std::optional<pw::Result<MoveOnlyValue>> ready_value_;
84   std::optional<OnceReceiver<MoveOnlyValue>> receiver_;
85   std::optional<OnceSender<MoveOnlyValue>> sender_;
86 };
87 
TEST(OnceSender,OnceSenderEmplace)88 TEST(OnceSender, OnceSenderEmplace) {
89   Dispatcher dispatcher;
90   ValueTask task;
91   dispatcher.Post(task);
92   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
93 
94   task.sender()->emplace(5);
95   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
96 
97   ASSERT_TRUE(task.ready_value().has_value());
98   ASSERT_TRUE(task.ready_value().value().ok());
99   EXPECT_EQ(task.ready_value().value()->value(), 5);
100 }
101 
TEST(OnceSender,OnceSenderEmplaceUseInitializeConstructor)102 TEST(OnceSender, OnceSenderEmplaceUseInitializeConstructor) {
103   Dispatcher dispatcher;
104   ValueTask task(/*use_make_constructor=*/false);
105   dispatcher.Post(task);
106   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
107 
108   task.sender()->emplace(5);
109   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
110 
111   ASSERT_TRUE(task.ready_value().has_value());
112   ASSERT_TRUE(task.ready_value().value().ok());
113   EXPECT_EQ(task.ready_value().value()->value(), 5);
114 }
115 
TEST(OnceSender,OnceSenderMoveAssign)116 TEST(OnceSender, OnceSenderMoveAssign) {
117   Dispatcher dispatcher;
118   ValueTask task;
119   dispatcher.Post(task);
120   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
121 
122   MoveOnlyValue value(7);
123   *task.sender() = std::move(value);
124   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
125 
126   ASSERT_TRUE(task.ready_value().has_value());
127   ASSERT_TRUE(task.ready_value().value().ok());
128   EXPECT_EQ(task.ready_value().value()->value(), 7);
129 }
130 
TEST(OnceSender,DestroyingOnceSenderCausesReceiverPendToReturnCancelled)131 TEST(OnceSender, DestroyingOnceSenderCausesReceiverPendToReturnCancelled) {
132   Dispatcher dispatcher;
133   ValueTask task;
134   dispatcher.Post(task);
135   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
136 
137   task.DestroySender();
138   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
139   task.DestroyReceiver();
140 
141   ASSERT_TRUE(task.ready_value().has_value());
142   ASSERT_FALSE(task.ready_value().value().ok());
143   ASSERT_TRUE(task.ready_value().value().status().IsCancelled());
144 }
145 
TEST(OnceSender,DestroyingOnceReceiverCausesSenderMethodsToBeNoOps)146 TEST(OnceSender, DestroyingOnceReceiverCausesSenderMethodsToBeNoOps) {
147   Dispatcher dispatcher;
148   ValueTask task;
149   dispatcher.Post(task);
150   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
151 
152   task.DestroyReceiver();
153   task.sender()->emplace(6);
154   task.DestroySender();
155   task.Deregister();
156 }
157 
158 class VectorTask : public Task {
159  public:
VectorTask(bool use_make_constructor=true)160   VectorTask(bool use_make_constructor = true)
161       : use_make_constructor_(use_make_constructor) {}
162 
DoPend(Context & cx)163   Poll<> DoPend(Context& cx) override {
164     if (!receiver_) {
165       if (use_make_constructor_) {
166         auto [send, recv] =
167             pw::async2::MakeOnceRefSenderAndReceiver<pw::Vector<int>>(value_);
168         sender_.emplace(std::move(send));
169         receiver_.emplace(std::move(recv));
170       } else {
171         sender_.emplace();
172         receiver_.emplace();
173         pw::async2::InitializeOnceRefSenderAndReceiver<pw::Vector<int>>(
174             sender_.value(), receiver_.value(), value_);
175       }
176     }
177     Poll<pw::Status> poll = receiver_->Pend(cx);
178     if (poll.IsReady()) {
179       ready_value_.emplace(poll.value());
180       return Ready();
181     }
182     return Pending();
183   }
184 
value() const185   const pw::Vector<int>& value() const { return value_; }
ready_value() const186   const std::optional<pw::Status>& ready_value() const { return ready_value_; }
sender()187   std::optional<OnceRefSender<pw::Vector<int>>>& sender() { return sender_; }
188 
DestroySender()189   void DestroySender() { sender_.reset(); }
DestroyReceiver()190   void DestroyReceiver() { receiver_.reset(); }
191 
192  private:
193   bool use_make_constructor_;
194   pw::Vector<int, 3> value_;
195   std::optional<pw::Status> ready_value_;
196   std::optional<OnceRefReceiver<pw::Vector<int>>> receiver_;
197   std::optional<OnceRefSender<pw::Vector<int>>> sender_;
198 };
199 
TEST(OnceSender,OnceRefSenderSetConstRef)200 TEST(OnceSender, OnceRefSenderSetConstRef) {
201   Dispatcher dispatcher;
202   VectorTask task;
203   dispatcher.Post(task);
204   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
205 
206   pw::Vector<int, 2> other = {0, 1};
207   task.sender()->Set(other);
208   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
209   EXPECT_EQ(task.value()[0], 0);
210   EXPECT_EQ(task.value()[1], 1);
211 }
212 
TEST(OnceSender,OnceRefSenderSetConstRefUseInitializeConstructor)213 TEST(OnceSender, OnceRefSenderSetConstRefUseInitializeConstructor) {
214   Dispatcher dispatcher;
215   VectorTask task(/*use_make_constructor=*/false);
216   dispatcher.Post(task);
217   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
218 
219   pw::Vector<int, 2> other = {0, 1};
220   task.sender()->Set(other);
221   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
222   EXPECT_EQ(task.value()[0], 0);
223   EXPECT_EQ(task.value()[1], 1);
224 }
225 
TEST(OnceSender,OnceRefSenderModify)226 TEST(OnceSender, OnceRefSenderModify) {
227   Dispatcher dispatcher;
228   VectorTask task;
229   dispatcher.Post(task);
230   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
231 
232   task.sender()->ModifyUnsafe([](pw::Vector<int>& vec) { vec.push_back(0); });
233   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
234 
235   task.sender()->ModifyUnsafe([](pw::Vector<int>& vec) { vec.push_back(1); });
236   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
237 
238   task.sender()->Commit();
239   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
240   EXPECT_EQ(task.value()[0], 0);
241   EXPECT_EQ(task.value()[1], 1);
242 }
243 
TEST(OnceSender,DestroyingOnceRefSenderCausesReceiverPendToReturnCancelled)244 TEST(OnceSender, DestroyingOnceRefSenderCausesReceiverPendToReturnCancelled) {
245   Dispatcher dispatcher;
246   VectorTask task;
247   dispatcher.Post(task);
248   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
249 
250   task.DestroySender();
251   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
252   task.DestroyReceiver();
253 
254   ASSERT_TRUE(task.ready_value().has_value());
255   ASSERT_TRUE(task.ready_value().value().IsCancelled());
256 }
257 
258 class MoveOnlyRefTask : public Task {
259  public:
DoPend(Context & cx)260   Poll<> DoPend(Context& cx) override {
261     if (!receiver_) {
262       auto [send, recv] =
263           pw::async2::MakeOnceRefSenderAndReceiver<MoveOnlyValue>(value_);
264       sender_.emplace(std::move(send));
265       receiver_.emplace(std::move(recv));
266     }
267     Poll<pw::Status> poll = receiver_->Pend(cx);
268     if (poll.IsReady()) {
269       ready_value_.emplace(poll.value());
270       return Ready();
271     }
272     return Pending();
273   }
274 
value()275   MoveOnlyValue& value() { return value_; }
ready_value()276   std::optional<pw::Status>& ready_value() { return ready_value_; }
sender()277   std::optional<OnceRefSender<MoveOnlyValue>>& sender() { return sender_; }
278 
279  private:
280   MoveOnlyValue value_{0};
281   std::optional<pw::Status> ready_value_;
282   std::optional<OnceRefReceiver<MoveOnlyValue>> receiver_;
283   std::optional<OnceRefSender<MoveOnlyValue>> sender_;
284 };
285 
TEST(OnceSender,OnceRefSenderSetRValue)286 TEST(OnceSender, OnceRefSenderSetRValue) {
287   Dispatcher dispatcher;
288   MoveOnlyRefTask task;
289   dispatcher.Post(task);
290   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
291 
292   MoveOnlyValue value2(2);
293   task.sender()->Set(std::move(value2));
294   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
295   ASSERT_TRUE(task.ready_value().has_value());
296   ASSERT_TRUE(task.ready_value()->ok());
297   EXPECT_EQ(task.value().value(), 2);
298 }
299 
300 class AlreadyCompletedReceiverTask : public Task {
301  public:
AlreadyCompletedReceiverTask(OnceReceiver<MoveOnlyValue> receiver)302   AlreadyCompletedReceiverTask(OnceReceiver<MoveOnlyValue> receiver)
303       : receiver_(std::move(receiver)) {}
304 
DoPend(Context & cx)305   Poll<> DoPend(Context& cx) override {
306     Poll<pw::Result<MoveOnlyValue>> poll = receiver_.Pend(cx);
307     if (poll.IsReady()) {
308       ready_value_.emplace(std::move(poll.value()));
309       return Ready();
310     }
311     return Pending();
312   }
313 
ready_value()314   std::optional<pw::Result<MoveOnlyValue>>& ready_value() {
315     return ready_value_;
316   }
317 
318  private:
319   std::optional<pw::Result<MoveOnlyValue>> ready_value_;
320   OnceReceiver<MoveOnlyValue> receiver_;
321 };
322 
TEST(OnceSender,OnceReceiverAlreadyCompleted)323 TEST(OnceSender, OnceReceiverAlreadyCompleted) {
324   Dispatcher dispatcher;
325   OnceReceiver<MoveOnlyValue> receiver(2);
326   AlreadyCompletedReceiverTask task(std::move(receiver));
327   dispatcher.Post(task);
328   EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
329   ASSERT_TRUE(task.ready_value().has_value());
330   ASSERT_TRUE(task.ready_value()->ok());
331   EXPECT_EQ(task.ready_value()->value().value(), 2);
332 }
333 
334 }  // namespace
335