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/pendable_as_task.h"
16
17 #include "pw_async2/dispatcher.h"
18 #include "pw_unit_test/framework.h"
19
20 namespace {
21
22 using ::pw::async2::Context;
23 using ::pw::async2::Dispatcher;
24 using ::pw::async2::PendableAsTask;
25 using ::pw::async2::Pending;
26 using ::pw::async2::Poll;
27 using ::pw::async2::Ready;
28 using ::pw::async2::Waker;
29
30 struct StructWithPendMethod {
StructWithPendMethod__anonca40c9130111::StructWithPendMethod31 StructWithPendMethod(int& poll_count, bool& allow_completion, Waker& waker)
32 : poll_count_(poll_count),
33 allow_completion_(allow_completion),
34 waker_(waker) {}
35
Pend__anonca40c9130111::StructWithPendMethod36 Poll<> Pend(Context& cx) {
37 ++poll_count_;
38 if (allow_completion_) {
39 return Ready();
40 }
41 PW_ASYNC_STORE_WAKER(
42 cx, waker_, "StructWithPendMethod is waiting for waker_");
43 return Pending();
44 }
45
46 int& poll_count_;
47 bool& allow_completion_;
48 Waker& waker_;
49 };
50
TEST(PendableAsTask,PendDelegatesToPendable)51 TEST(PendableAsTask, PendDelegatesToPendable) {
52 Dispatcher dispatcher;
53
54 int poll_count = 0;
55 bool allow_completion = false;
56 Waker waker;
57 StructWithPendMethod pendable(poll_count, allow_completion, waker);
58 PendableAsTask task(std::move(pendable));
59
60 dispatcher.Post(task);
61
62 EXPECT_EQ(poll_count, 0);
63 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
64 EXPECT_EQ(poll_count, 1);
65
66 // Unwoken task is not polled.
67 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
68 EXPECT_EQ(poll_count, 1);
69
70 std::move(waker).Wake();
71 allow_completion = true;
72 EXPECT_EQ(dispatcher.RunUntilStalled(), Ready());
73 EXPECT_EQ(poll_count, 2);
74 }
75
TEST(PendableAsTask,PendDelegatesToPendablePtr)76 TEST(PendableAsTask, PendDelegatesToPendablePtr) {
77 Dispatcher dispatcher;
78
79 int poll_count = 0;
80 bool allow_completion = false;
81 Waker waker;
82 StructWithPendMethod pendable(poll_count, allow_completion, waker);
83 // Note the lack of `std::move` or a copy-- we pass a ptr.
84 PendableAsTask task(&pendable);
85
86 dispatcher.Post(task);
87
88 EXPECT_EQ(poll_count, 0);
89 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
90 EXPECT_EQ(poll_count, 1);
91
92 // Unwoken task is not polled.
93 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
94 EXPECT_EQ(poll_count, 1);
95
96 std::move(waker).Wake();
97 allow_completion = true;
98 EXPECT_EQ(dispatcher.RunUntilStalled(), Ready());
99 EXPECT_EQ(poll_count, 2);
100 }
101
102 } // namespace
103