// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include namespace { const zx_handle_t dummy_handle = static_cast(1); const zx_signals_t dummy_trigger = ZX_USER_SIGNAL_0; const zx_packet_signal_t dummy_signal{ .trigger = dummy_trigger, .observed = ZX_USER_SIGNAL_0 | ZX_USER_SIGNAL_1, .count = 0u, .reserved0 = 0u, .reserved1 = 0u}; class MockDispatcher : public async::DispatcherStub { public: enum class Op { NONE, BEGIN_WAIT, CANCEL_WAIT, }; zx_status_t BeginWait(async_wait_t* wait) override { last_op = Op::BEGIN_WAIT; last_wait = wait; return next_status; } zx_status_t CancelWait(async_wait_t* wait) override { last_op = Op::CANCEL_WAIT; last_wait = wait; return next_status; } Op last_op = Op::NONE; async_wait_t* last_wait = nullptr; zx_status_t next_status = ZX_OK; }; class Harness { public: Harness() { Reset(); } void Reset() { handler_ran = false; last_wait = nullptr; last_status = ZX_ERR_INTERNAL; last_signal = nullptr; } void Handler(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, const zx_packet_signal_t* signal) { handler_ran = true; last_wait = wait; last_status = status; last_signal = signal; } virtual async::WaitBase& wait() = 0; bool handler_ran; async::WaitBase* last_wait; zx_status_t last_status; const zx_packet_signal_t* last_signal; }; class LambdaHarness : public Harness { public: LambdaHarness(zx_handle_t object = ZX_HANDLE_INVALID, zx_signals_t trigger = ZX_SIGNAL_NONE) : wait_{object, trigger, [this](async_dispatcher_t* dispatcher, async::Wait* wait, zx_status_t status, const zx_packet_signal_t* signal) { Handler(dispatcher, wait, status, signal); }} {} async::WaitBase& wait() override { return wait_; } private: async::Wait wait_; }; class MethodHarness : public Harness { public: MethodHarness(zx_handle_t object = ZX_HANDLE_INVALID, zx_signals_t trigger = ZX_SIGNAL_NONE) : wait_{this, object, trigger} {} async::WaitBase& wait() override { return wait_; } private: async::WaitMethod wait_; }; bool wait_set_handler_test() { BEGIN_TEST; { async::Wait wait; EXPECT_FALSE(wait.has_handler()); EXPECT_FALSE(wait.is_pending()); wait.set_handler([](async_dispatcher_t* dispatcher, async::Wait* wait, zx_status_t status, const zx_packet_signal_t* signal) {}); EXPECT_TRUE(wait.has_handler()); } { async::Wait wait(ZX_HANDLE_INVALID, ZX_SIGNAL_NONE, [](async_dispatcher_t* dispatcher, async::Wait* wait, zx_status_t status, const zx_packet_signal_t* signal) {}); EXPECT_TRUE(wait.has_handler()); EXPECT_FALSE(wait.is_pending()); } END_TEST; } template bool wait_properties_test() { BEGIN_TEST; Harness harness; EXPECT_EQ(ZX_HANDLE_INVALID, harness.wait().object()); harness.wait().set_object(dummy_handle); EXPECT_EQ(dummy_handle, harness.wait().object()); EXPECT_EQ(ZX_SIGNAL_NONE, harness.wait().trigger()); harness.wait().set_trigger(dummy_trigger); EXPECT_EQ(dummy_trigger, harness.wait().trigger()); END_TEST; } template bool wait_begin_test() { BEGIN_TEST; MockDispatcher dispatcher; { Harness harness(dummy_handle, dummy_trigger); EXPECT_FALSE(harness.wait().is_pending()); dispatcher.next_status = ZX_OK; EXPECT_EQ(ZX_OK, harness.wait().Begin(&dispatcher)); EXPECT_TRUE(harness.wait().is_pending()); EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op); EXPECT_EQ(dummy_handle, dispatcher.last_wait->object); EXPECT_EQ(dummy_trigger, dispatcher.last_wait->trigger); EXPECT_FALSE(harness.handler_ran); harness.Reset(); dispatcher.last_op = MockDispatcher::Op::NONE; EXPECT_EQ(ZX_ERR_ALREADY_EXISTS, harness.wait().Begin(&dispatcher)); EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op); EXPECT_FALSE(harness.handler_ran); } EXPECT_EQ(MockDispatcher::Op::CANCEL_WAIT, dispatcher.last_op); { Harness harness(dummy_handle, dummy_trigger); EXPECT_FALSE(harness.wait().is_pending()); dispatcher.next_status = ZX_ERR_BAD_STATE; EXPECT_EQ(ZX_ERR_BAD_STATE, harness.wait().Begin(&dispatcher)); EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op); EXPECT_FALSE(harness.wait().is_pending()); EXPECT_FALSE(harness.handler_ran); } EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op); END_TEST; } template bool wait_cancel_test() { BEGIN_TEST; MockDispatcher dispatcher; { Harness harness(dummy_handle, dummy_trigger); EXPECT_FALSE(harness.wait().is_pending()); EXPECT_EQ(ZX_ERR_NOT_FOUND, harness.wait().Cancel()); EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op); EXPECT_FALSE(harness.wait().is_pending()); EXPECT_EQ(ZX_OK, harness.wait().Begin(&dispatcher)); EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op); EXPECT_TRUE(harness.wait().is_pending()); EXPECT_EQ(ZX_OK, harness.wait().Cancel()); EXPECT_EQ(MockDispatcher::Op::CANCEL_WAIT, dispatcher.last_op); EXPECT_FALSE(harness.wait().is_pending()); dispatcher.last_op = MockDispatcher::Op::NONE; EXPECT_EQ(ZX_ERR_NOT_FOUND, harness.wait().Cancel()); EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op); EXPECT_FALSE(harness.wait().is_pending()); } EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op); END_TEST; } template bool wait_run_handler_test() { BEGIN_TEST; MockDispatcher dispatcher; { Harness harness(dummy_handle, dummy_trigger); EXPECT_FALSE(harness.wait().is_pending()); EXPECT_EQ(ZX_OK, harness.wait().Begin(&dispatcher)); EXPECT_EQ(MockDispatcher::Op::BEGIN_WAIT, dispatcher.last_op); EXPECT_TRUE(harness.wait().is_pending()); harness.Reset(); dispatcher.last_wait->handler(&dispatcher, dispatcher.last_wait, ZX_OK, &dummy_signal); EXPECT_TRUE(harness.handler_ran); EXPECT_EQ(&harness.wait(), harness.last_wait); EXPECT_EQ(ZX_OK, harness.last_status); EXPECT_EQ(&dummy_signal, harness.last_signal); EXPECT_FALSE(harness.wait().is_pending()); dispatcher.last_op = MockDispatcher::Op::NONE; EXPECT_EQ(ZX_ERR_NOT_FOUND, harness.wait().Cancel()); EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op); EXPECT_FALSE(harness.wait().is_pending()); } EXPECT_EQ(MockDispatcher::Op::NONE, dispatcher.last_op); END_TEST; } bool unsupported_begin_wait_test() { BEGIN_TEST; async::DispatcherStub dispatcher; async_wait_t wait{}; EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, async_begin_wait(&dispatcher, &wait), "valid args"); END_TEST; } bool unsupported_cancel_wait_test() { BEGIN_TEST; async::DispatcherStub dispatcher; async_wait_t wait{}; EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, async_cancel_wait(&dispatcher, &wait), "valid args"); END_TEST; } } // namespace BEGIN_TEST_CASE(wait_tests) RUN_TEST(wait_set_handler_test) RUN_TEST((wait_properties_test)) RUN_TEST((wait_properties_test)) RUN_TEST((wait_begin_test)) RUN_TEST((wait_begin_test)) RUN_TEST((wait_cancel_test)) RUN_TEST((wait_cancel_test)) RUN_TEST((wait_run_handler_test)) RUN_TEST((wait_run_handler_test)) RUN_TEST(unsupported_begin_wait_test) RUN_TEST(unsupported_cancel_wait_test) END_TEST_CASE(wait_tests)