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
9namespace {
10
11const zx_handle_t dummy_handle = static_cast<zx_handle_t>(1);
12const zx_signals_t dummy_trigger = ZX_USER_SIGNAL_0;
13const 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
20class MockDispatcher : public async::DispatcherStub {
21public:
22    enum class Op {
23        NONE,
24        BEGIN_WAIT,
25        CANCEL_WAIT,
26    };
27
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
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
45class Harness {
46public:
47    Harness() { Reset(); }
48
49    void Reset() {
50        handler_ran = false;
51        last_wait = nullptr;
52        last_status = ZX_ERR_INTERNAL;
53        last_signal = nullptr;
54    }
55
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
72class LambdaHarness : public Harness {
73public:
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
82    async::WaitBase& wait() override { return wait_; }
83
84private:
85    async::Wait wait_;
86};
87
88class MethodHarness : public Harness {
89public:
90    MethodHarness(zx_handle_t object = ZX_HANDLE_INVALID,
91                  zx_signals_t trigger = ZX_SIGNAL_NONE)
92        : wait_{this, object, trigger} {}
93
94    async::WaitBase& wait() override { return wait_; }
95
96private:
97    async::WaitMethod<Harness, &Harness::Handler> wait_;
98};
99
100bool 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
124template <typename Harness>
125bool 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
141template <typename Harness>
142bool 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
182template <typename Harness>
183bool 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
214template <typename Harness>
215bool 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
246bool 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
256bool 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
268BEGIN_TEST_CASE(wait_tests)
269RUN_TEST(wait_set_handler_test)
270RUN_TEST((wait_properties_test<LambdaHarness>))
271RUN_TEST((wait_properties_test<MethodHarness>))
272RUN_TEST((wait_begin_test<LambdaHarness>))
273RUN_TEST((wait_begin_test<MethodHarness>))
274RUN_TEST((wait_cancel_test<LambdaHarness>))
275RUN_TEST((wait_cancel_test<MethodHarness>))
276RUN_TEST((wait_run_handler_test<LambdaHarness>))
277RUN_TEST((wait_run_handler_test<MethodHarness>))
278RUN_TEST(unsupported_begin_wait_test)
279RUN_TEST(unsupported_cancel_wait_test)
280END_TEST_CASE(wait_tests)
281