xref: /aosp_15_r20/external/pigweed/pw_async2/join_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/join.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::Join;
25 using ::pw::async2::Pending;
26 using ::pw::async2::Poll;
27 using ::pw::async2::Waker;
28 
29 // Windows GCC emits a bogs uninitialized error for the
30 // move constructor below.
31 PW_MODIFY_DIAGNOSTICS_PUSH();
32 PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wmaybe-uninitialized");
33 struct SomeMoveOnlyValue {
SomeMoveOnlyValue__anon0eae9da30111::SomeMoveOnlyValue34   explicit SomeMoveOnlyValue(int result) : result_(result), move_count_(0) {}
35   SomeMoveOnlyValue(const SomeMoveOnlyValue&) = delete;
36   SomeMoveOnlyValue& operator=(const SomeMoveOnlyValue&) = delete;
SomeMoveOnlyValue__anon0eae9da30111::SomeMoveOnlyValue37   SomeMoveOnlyValue(SomeMoveOnlyValue&& other)
38       : result_(other.result_), move_count_(other.move_count_ + 1) {
39     other.result_ = -1;
40   }
operator =__anon0eae9da30111::SomeMoveOnlyValue41   SomeMoveOnlyValue& operator=(SomeMoveOnlyValue&& other) {
42     result_ = other.result_;
43     other.result_ = -1;
44     move_count_ = other.move_count_ + 1;
45     return *this;
46   }
47   ~SomeMoveOnlyValue() = default;
48   int result_;
49   int move_count_;
50 };
51 PW_MODIFY_DIAGNOSTICS_POP();
52 
53 struct PendableController {
PendableController__anon0eae9da30111::PendableController54   PendableController() : poll_count_(0), allow_completion_(false), waker_() {}
55   PendableController(PendableController&) = delete;
56   PendableController(PendableController&&) = delete;
57   PendableController& operator=(const PendableController&) = delete;
58   PendableController& operator=(PendableController&&) = delete;
59   ~PendableController() = default;
60 
61   int poll_count_;
62   bool allow_completion_;
63   Waker waker_;
64 };
65 
66 struct StructWithPendMethod {
StructWithPendMethod__anon0eae9da30111::StructWithPendMethod67   StructWithPendMethod(int result, PendableController& controller)
68       : result_(result), controller_(&controller) {}
69 
70   StructWithPendMethod(const StructWithPendMethod&) = delete;
71   StructWithPendMethod& operator=(const StructWithPendMethod&) = delete;
72   StructWithPendMethod(StructWithPendMethod&&) = default;
73   StructWithPendMethod& operator=(StructWithPendMethod&&) = default;
74   ~StructWithPendMethod() = default;
75 
Pend__anon0eae9da30111::StructWithPendMethod76   Poll<SomeMoveOnlyValue> Pend(Context& cx) {
77     ++controller_->poll_count_;
78     if (controller_->allow_completion_) {
79       return Poll<SomeMoveOnlyValue>(result_);
80     }
81     PW_ASYNC_STORE_WAKER(
82         cx,
83         controller_->waker_,
84         "StructWithPendMethod is waiting for PendableController's waker");
85     return Pending();
86   }
87 
88   int result_;
89   PendableController* controller_;
90 };
91 
TEST(Join,PendDelegatesToPendables)92 TEST(Join, PendDelegatesToPendables) {
93   Dispatcher dispatcher;
94 
95   PendableController controller_1;
96   PendableController controller_2;
97   StructWithPendMethod pendable_1(1, controller_1);
98   StructWithPendMethod pendable_2(2, controller_2);
99   Join join(std::move(pendable_1), std::move(pendable_2));
100 
101   EXPECT_EQ(dispatcher.RunPendableUntilStalled(join), Pending());
102   controller_2.allow_completion_ = true;
103   std::move(controller_2.waker_).Wake();
104   EXPECT_EQ(dispatcher.RunPendableUntilStalled(join), Pending());
105   controller_1.allow_completion_ = true;
106   std::move(controller_1.waker_).Wake();
107   auto&& result = dispatcher.RunPendableUntilStalled(join);
108   ASSERT_TRUE(result.IsReady());
109   auto&& [v1, v2] = std::move(*result);
110   EXPECT_EQ(v1.result_, 1);
111   EXPECT_EQ(v2.result_, 2);
112   EXPECT_EQ(v1.move_count_, 1);
113   EXPECT_EQ(v2.move_count_, 1);
114 }
115 
TEST(Join,BindsDirectly)116 TEST(Join, BindsDirectly) {
117   Dispatcher dispatcher;
118   PendableController controller_1;
119   controller_1.allow_completion_ = true;
120   PendableController controller_2;
121   controller_2.allow_completion_ = true;
122   StructWithPendMethod pendable_1(1, controller_1);
123   StructWithPendMethod pendable_2(2, controller_2);
124   Join join(std::move(pendable_1), std::move(pendable_2));
125 
126   auto&& [v1, v2] = dispatcher.RunPendableToCompletion(join);
127   EXPECT_EQ(v1.result_, 1);
128   EXPECT_EQ(v2.result_, 2);
129   EXPECT_EQ(v1.move_count_, 1);
130   EXPECT_EQ(v2.move_count_, 1);
131 }
132 
133 }  // namespace
134