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