1 // Copyright 2018 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/trap.h>
7 #include <unittest/unittest.h>
8
9 namespace {
10
11 const zx_handle_t dummy_guest = static_cast<zx_handle_t>(1);
12 const zx_vaddr_t dummy_addr = 0x1000;
13 const size_t dummy_length = 0x1000;
14 const zx_packet_guest_bell_t dummy_bell{
15 .addr = dummy_addr,
16 .reserved0 = 0u,
17 .reserved1 = 0u,
18 .reserved2 = 0u,
19 };
20
21 class MockDispatcher : public async::DispatcherStub {
22 public:
SetGuestBellTrap(async_guest_bell_trap_t * trap,const zx::guest & guest,zx_vaddr_t addr,size_t length)23 zx_status_t SetGuestBellTrap(async_guest_bell_trap_t* trap,
24 const zx::guest& guest,
25 zx_vaddr_t addr, size_t length) override {
26 last_trap = trap;
27 last_guest = guest.get();
28 last_addr = addr;
29 last_length = length;
30 return ZX_OK;
31 }
32
33 async_guest_bell_trap_t* last_trap = nullptr;
34 zx_handle_t last_guest = ZX_HANDLE_INVALID;
35 zx_vaddr_t last_addr = 0u;
36 size_t last_length = 0u;
37 };
38
39 class Harness {
40 public:
Handler(async_dispatcher_t * dispatcher,async::GuestBellTrapBase * trap,zx_status_t status,const zx_packet_guest_bell_t * bell)41 void Handler(async_dispatcher_t* dispatcher,
42 async::GuestBellTrapBase* trap,
43 zx_status_t status,
44 const zx_packet_guest_bell_t* bell) {
45 handler_ran = true;
46 last_trap = trap;
47 last_status = status;
48 last_bell = bell;
49 }
50
51 virtual async::GuestBellTrapBase& trap() = 0;
52
53 bool handler_ran = false;
54 async::GuestBellTrapBase* last_trap = nullptr;
55 zx_status_t last_status = ZX_ERR_INTERNAL;
56 const zx_packet_guest_bell_t* last_bell = nullptr;
57 };
58
59 class LambdaHarness : public Harness {
60 public:
trap()61 async::GuestBellTrapBase& trap() override { return trap_; }
62
63 private:
64 async::GuestBellTrap trap_{[this](async_dispatcher_t* dispatcher, async::GuestBellTrap* trap,
__anonb279cbaa0202() 65 zx_status_t status, const zx_packet_guest_bell_t* bell) {
66 Handler(dispatcher, trap, status, bell);
67 }};
68 };
69
70 class MethodHarness : public Harness {
71 public:
trap()72 async::GuestBellTrapBase& trap() override { return trap_; }
73
74 private:
75 async::GuestBellTrapMethod<Harness, &Harness::Handler> trap_{this};
76 };
77
guest_bell_trap_set_handler_test()78 bool guest_bell_trap_set_handler_test() {
79 BEGIN_TEST;
80
81 {
82 async::GuestBellTrap trap;
83 EXPECT_FALSE(trap.has_handler());
84
85 trap.set_handler([](async_dispatcher_t* dispatcher, async::GuestBellTrap* trap,
86 zx_status_t status, const zx_packet_guest_bell_t* bell) {});
87 EXPECT_TRUE(trap.has_handler());
88 }
89
90 {
91 async::GuestBellTrap trap([](async_dispatcher_t* dispatcher, async::GuestBellTrap* trap,
92 zx_status_t status, const zx_packet_guest_bell_t* bell) {});
93 EXPECT_TRUE(trap.has_handler());
94 }
95
96 END_TEST;
97 }
98
99 template <typename Harness>
guest_bell_trap_test()100 bool guest_bell_trap_test() {
101 BEGIN_TEST;
102
103 MockDispatcher dispatcher;
104 Harness harness;
105
106 EXPECT_EQ(ZX_OK, harness.trap().SetTrap(
107 &dispatcher, *zx::unowned_guest(dummy_guest), dummy_addr, dummy_length));
108 EXPECT_EQ(dummy_guest, dispatcher.last_guest);
109 EXPECT_EQ(dummy_addr, dispatcher.last_addr);
110 EXPECT_EQ(dummy_length, dispatcher.last_length);
111
112 dispatcher.last_trap->handler(&dispatcher, dispatcher.last_trap, ZX_OK, &dummy_bell);
113 EXPECT_TRUE(harness.handler_ran);
114 EXPECT_EQ(&harness.trap(), harness.last_trap);
115 EXPECT_EQ(ZX_OK, harness.last_status);
116 EXPECT_EQ(&dummy_bell, harness.last_bell);
117
118 END_TEST;
119 }
120
121 } // namespace
122
123 BEGIN_TEST_CASE(trap_tests)
124 RUN_TEST(guest_bell_trap_set_handler_test)
125 RUN_TEST((guest_bell_trap_test<LambdaHarness>))
126 RUN_TEST((guest_bell_trap_test<MethodHarness>))
127 END_TEST_CASE(trap_tests)
128