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