1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <lib/async-testutils/dispatcher_stub.h>
6 #include <lib/async/cpp/wait.h>
7 #include <unittest/unittest.h>
8 
9 namespace {
10 
11 const zx_handle_t dummy_handle = static_cast<zx_handle_t>(1);
12 const zx_signals_t dummy_trigger = ZX_USER_SIGNAL_0;
13 const zx_packet_signal_t dummy_signal{
14     .trigger = dummy_trigger,
15     .observed = ZX_USER_SIGNAL_0 | ZX_USER_SIGNAL_1,
16     .count = 0u,
17     .reserved0 = 0u,
18     .reserved1 = 0u};
19 
20 class MockDispatcher : public async::DispatcherStub {
21 public:
22     enum class Op {
23         NONE,
24         BEGIN_WAIT,
25         CANCEL_WAIT,
26     };
27 
BeginWait(async_wait_t * wait)28     zx_status_t BeginWait(async_wait_t* wait) override {
29         last_op = Op::BEGIN_WAIT;
30         last_wait = wait;
31         return next_status;
32     }
33 
CancelWait(async_wait_t * wait)34     zx_status_t CancelWait(async_wait_t* wait) override {
35         last_op = Op::CANCEL_WAIT;
36         last_wait = wait;
37         return next_status;
38     }
39 
40     Op last_op = Op::NONE;
41     async_wait_t* last_wait = nullptr;
42     zx_status_t next_status = ZX_OK;
43 };
44 
45 class Harness {
46 public:
Harness()47     Harness() { Reset(); }
48 
Reset()49     void Reset() {
50         handler_ran = false;
51         last_wait = nullptr;
52         last_status = ZX_ERR_INTERNAL;
53         last_signal = nullptr;
54     }
55 
Handler(async_dispatcher_t * dispatcher,async::WaitBase * wait,zx_status_t status,const zx_packet_signal_t * signal)56     void Handler(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
57                  const zx_packet_signal_t* signal) {
58         handler_ran = true;
59         last_wait = wait;
60         last_status = status;
61         last_signal = signal;
62     }
63 
64     virtual async::WaitBase& wait() = 0;
65 
66     bool handler_ran;
67     async::WaitBase* last_wait;
68     zx_status_t last_status;
69     const zx_packet_signal_t* last_signal;
70 };
71 
72 class LambdaHarness : public Harness {
73 public:
LambdaHarness(zx_handle_t object=ZX_HANDLE_INVALID,zx_signals_t trigger=ZX_SIGNAL_NONE)74     LambdaHarness(zx_handle_t object = ZX_HANDLE_INVALID,
75                   zx_signals_t trigger = ZX_SIGNAL_NONE)
76         : wait_{object, trigger,
77                 [this](async_dispatcher_t* dispatcher, async::Wait* wait, zx_status_t status,
78                        const zx_packet_signal_t* signal) {
79                     Handler(dispatcher, wait, status, signal);
80                 }} {}
81 
wait()82     async::WaitBase& wait() override { return wait_; }
83 
84 private:
85     async::Wait wait_;
86 };
87 
88 class MethodHarness : public Harness {
89 public:
MethodHarness(zx_handle_t object=ZX_HANDLE_INVALID,zx_signals_t trigger=ZX_SIGNAL_NONE)90     MethodHarness(zx_handle_t object = ZX_HANDLE_INVALID,
91                   zx_signals_t trigger = ZX_SIGNAL_NONE)
92         : wait_{this, object, trigger} {}
93 
wait()94     async::WaitBase& wait() override { return wait_; }
95 
96 private:
97     async::WaitMethod<Harness, &Harness::Handler> wait_;
98 };
99 
wait_set_handler_test()100 bool wait_set_handler_test() {
101     BEGIN_TEST;
102 
103     {
104         async::Wait wait;
105         EXPECT_FALSE(wait.has_handler());
106         EXPECT_FALSE(wait.is_pending());
107 
108         wait.set_handler([](async_dispatcher_t* dispatcher, async::Wait* wait, zx_status_t status,
109                             const zx_packet_signal_t* signal) {});
110         EXPECT_TRUE(wait.has_handler());
111     }
112 
113     {
114         async::Wait wait(ZX_HANDLE_INVALID, ZX_SIGNAL_NONE,
115                          [](async_dispatcher_t* dispatcher, async::Wait* wait, zx_status_t status,
116                             const zx_packet_signal_t* signal) {});
117         EXPECT_TRUE(wait.has_handler());
118         EXPECT_FALSE(wait.is_pending());
119     }
120 
121     END_TEST;
122 }
123 
124 template <typename Harness>
wait_properties_test()125 bool wait_properties_test() {
126     BEGIN_TEST;
127 
128     Harness harness;
129 
130     EXPECT_EQ(ZX_HANDLE_INVALID, harness.wait().object());
131     harness.wait().set_object(dummy_handle);
132     EXPECT_EQ(dummy_handle, harness.wait().object());
133 
134     EXPECT_EQ(ZX_SIGNAL_NONE, harness.wait().trigger());
135     harness.wait().set_trigger(dummy_trigger);
136     EXPECT_EQ(dummy_trigger, harness.wait().trigger());
137 
138     END_TEST;
139 }
140 
141 template <typename Harness>
wait_begin_test()142 bool wait_begin_test() {
143     BEGIN_TEST;
144 
145     MockDispatcher dispatcher;
146 
147     {
148         Harness harness(dummy_handle, dummy_trigger);
149         EXPECT_FALSE(harness.wait().is_pending());
150 
151         dispatcher.next_status = ZX_OK;
152         EXPECT_EQ(ZX_OK, harness.wait().Begin(&dispatcher));
153         EXPECT_TRUE(harness.wait().is_pending());
154         EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op);
155         EXPECT_EQ(dummy_handle, dispatcher.last_wait->object);
156         EXPECT_EQ(dummy_trigger, dispatcher.last_wait->trigger);
157         EXPECT_FALSE(harness.handler_ran);
158 
159         harness.Reset();
160         dispatcher.last_op = MockDispatcher::Op::NONE;
161         EXPECT_EQ(ZX_ERR_ALREADY_EXISTS, harness.wait().Begin(&dispatcher));
162         EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op);
163         EXPECT_FALSE(harness.handler_ran);
164     }
165     EXPECT_EQ(MockDispatcher::Op::CANCEL_WAIT, dispatcher.last_op);
166 
167     {
168         Harness harness(dummy_handle, dummy_trigger);
169         EXPECT_FALSE(harness.wait().is_pending());
170 
171         dispatcher.next_status = ZX_ERR_BAD_STATE;
172         EXPECT_EQ(ZX_ERR_BAD_STATE, harness.wait().Begin(&dispatcher));
173         EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op);
174         EXPECT_FALSE(harness.wait().is_pending());
175         EXPECT_FALSE(harness.handler_ran);
176     }
177     EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op);
178 
179     END_TEST;
180 }
181 
182 template <typename Harness>
wait_cancel_test()183 bool wait_cancel_test() {
184     BEGIN_TEST;
185 
186     MockDispatcher dispatcher;
187 
188     {
189         Harness harness(dummy_handle, dummy_trigger);
190         EXPECT_FALSE(harness.wait().is_pending());
191 
192         EXPECT_EQ(ZX_ERR_NOT_FOUND, harness.wait().Cancel());
193         EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op);
194         EXPECT_FALSE(harness.wait().is_pending());
195 
196         EXPECT_EQ(ZX_OK, harness.wait().Begin(&dispatcher));
197         EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op);
198         EXPECT_TRUE(harness.wait().is_pending());
199 
200         EXPECT_EQ(ZX_OK, harness.wait().Cancel());
201         EXPECT_EQ(MockDispatcher::Op::CANCEL_WAIT, dispatcher.last_op);
202         EXPECT_FALSE(harness.wait().is_pending());
203 
204         dispatcher.last_op = MockDispatcher::Op::NONE;
205         EXPECT_EQ(ZX_ERR_NOT_FOUND, harness.wait().Cancel());
206         EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op);
207         EXPECT_FALSE(harness.wait().is_pending());
208     }
209     EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op);
210 
211     END_TEST;
212 }
213 
214 template <typename Harness>
wait_run_handler_test()215 bool wait_run_handler_test() {
216     BEGIN_TEST;
217 
218     MockDispatcher dispatcher;
219 
220     {
221         Harness harness(dummy_handle, dummy_trigger);
222         EXPECT_FALSE(harness.wait().is_pending());
223 
224         EXPECT_EQ(ZX_OK, harness.wait().Begin(&dispatcher));
225         EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op);
226         EXPECT_TRUE(harness.wait().is_pending());
227 
228         harness.Reset();
229         dispatcher.last_wait->handler(&dispatcher, dispatcher.last_wait, ZX_OK, &dummy_signal);
230         EXPECT_TRUE(harness.handler_ran);
231         EXPECT_EQ(&harness.wait(), harness.last_wait);
232         EXPECT_EQ(ZX_OK, harness.last_status);
233         EXPECT_EQ(&dummy_signal, harness.last_signal);
234         EXPECT_FALSE(harness.wait().is_pending());
235 
236         dispatcher.last_op = MockDispatcher::Op::NONE;
237         EXPECT_EQ(ZX_ERR_NOT_FOUND, harness.wait().Cancel());
238         EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op);
239         EXPECT_FALSE(harness.wait().is_pending());
240     }
241     EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op);
242 
243     END_TEST;
244 }
245 
unsupported_begin_wait_test()246 bool unsupported_begin_wait_test() {
247     BEGIN_TEST;
248 
249     async::DispatcherStub dispatcher;
250     async_wait_t wait{};
251     EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, async_begin_wait(&dispatcher, &wait), "valid args");
252 
253     END_TEST;
254 }
255 
unsupported_cancel_wait_test()256 bool unsupported_cancel_wait_test() {
257     BEGIN_TEST;
258 
259     async::DispatcherStub dispatcher;
260     async_wait_t wait{};
261     EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, async_cancel_wait(&dispatcher, &wait), "valid args");
262 
263     END_TEST;
264 }
265 
266 } // namespace
267 
268 BEGIN_TEST_CASE(wait_tests)
269 RUN_TEST(wait_set_handler_test)
270 RUN_TEST((wait_properties_test<LambdaHarness>))
271 RUN_TEST((wait_properties_test<MethodHarness>))
272 RUN_TEST((wait_begin_test<LambdaHarness>))
273 RUN_TEST((wait_begin_test<MethodHarness>))
274 RUN_TEST((wait_cancel_test<LambdaHarness>))
275 RUN_TEST((wait_cancel_test<MethodHarness>))
276 RUN_TEST((wait_run_handler_test<LambdaHarness>))
277 RUN_TEST((wait_run_handler_test<MethodHarness>))
278 RUN_TEST(unsupported_begin_wait_test)
279 RUN_TEST(unsupported_cancel_wait_test)
280 END_TEST_CASE(wait_tests)
281