The open source OpenXR runtime
1// Copyright 2021-2023, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Generic callback collection tests.
6 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
7 */
8
9#include "catch_amalgamated.hpp"
10
11#include <util/u_generic_callbacks.hpp>
12
13using xrt::auxiliary::util::GenericCallbacks;
14
15enum class MyEvent
16{
17 ACQUIRED = 1u << 0u,
18 LOST = 1u << 1u,
19};
20
21using mask_t = std::underlying_type_t<MyEvent>;
22
23static bool
24increment_userdata_int(MyEvent event, void *userdata)
25{
26 *static_cast<int *>(userdata) += 1;
27 return true;
28}
29
30
31using callback_t = bool (*)(MyEvent event, void *userdata);
32
33TEST_CASE("u_generic_callbacks")
34{
35 GenericCallbacks<callback_t, MyEvent> callbacks;
36 // Simplest possible invoker.
37 auto invoker = [](MyEvent event, callback_t callback, void *userdata) { return callback(event, userdata); };
38
39 SECTION("call when empty")
40 {
41 CHECK(0 == callbacks.invokeCallbacks(MyEvent::ACQUIRED, invoker));
42 CHECK(0 == callbacks.invokeCallbacks(MyEvent::LOST, invoker));
43 CHECK(0 == callbacks.removeCallback(&increment_userdata_int, (mask_t)MyEvent::LOST, nullptr));
44 }
45 SECTION("same function, different mask and userdata")
46 {
47 int numAcquired = 0;
48 int numLost = 0;
49 REQUIRE_NOTHROW(callbacks.addCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired));
50 REQUIRE_NOTHROW(callbacks.addCallback(increment_userdata_int, (mask_t)MyEvent::LOST, &numLost));
51 SECTION("contains")
52 {
53 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::LOST, &numLost));
54 CHECK_FALSE(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::LOST, &numAcquired));
55 }
56 SECTION("removal matching")
57 {
58 CHECK(0 ==
59 callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::LOST, &numAcquired));
60 CHECK(0 ==
61 callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numLost));
62 }
63 SECTION("duplicates, contains, and removal")
64 {
65 REQUIRE(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired));
66 REQUIRE_NOTHROW(
67 callbacks.addCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired));
68 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired));
69 // Now we have two ACQUIRED and one LOST callback.
70 SECTION("max_remove")
71 {
72 CHECK(0 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
73 &numAcquired, 0, 0));
74 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
75 &numAcquired));
76
77 CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
78 &numAcquired, 0, 1));
79 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
80 &numAcquired));
81
82 // LOST callback should still be there to remove
83 CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::LOST,
84 &numLost));
85 }
86 SECTION("large max_remove")
87 {
88 CHECK(2 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
89 &numAcquired, 0, 3));
90 CHECK_FALSE(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
91 &numAcquired));
92
93 // LOST callback should still be there to remove
94 CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::LOST,
95 &numLost));
96 }
97 SECTION("num_skip")
98 {
99 CHECK(0 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
100 &numAcquired, 3));
101 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
102 &numAcquired));
103
104 CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
105 &numAcquired, 1));
106 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
107 &numAcquired));
108
109 // LOST callback should still be there to remove
110 CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::LOST,
111 &numLost));
112 }
113 SECTION("invoke acquired")
114 {
115 CHECK(2 == callbacks.invokeCallbacks(MyEvent::ACQUIRED, invoker));
116 CHECK(2 == numAcquired);
117 CHECK(0 == numLost);
118 {
119 INFO("should have removed themselves");
120 CHECK_FALSE(callbacks.contains(increment_userdata_int,
121 (mask_t)MyEvent::ACQUIRED, &numAcquired));
122 }
123
124 {
125 INFO("LOST callbacks should still be there");
126 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::LOST,
127 &numLost));
128 CHECK(1 == callbacks.removeCallback(increment_userdata_int,
129 (mask_t)MyEvent::LOST, &numLost));
130 }
131 }
132 SECTION("invoke lost")
133 {
134 CHECK(1 == callbacks.invokeCallbacks(MyEvent::LOST, invoker));
135 CHECK(0 == numAcquired);
136 CHECK(1 == numLost);
137 {
138 INFO("should have removed themselves");
139 CHECK_FALSE(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::LOST,
140 &numLost));
141 }
142
143 {
144 INFO("ACQUIRED callbacks should still be there");
145 CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED,
146 &numAcquired));
147 CHECK(2 == callbacks.removeCallback(increment_userdata_int,
148 (mask_t)MyEvent::ACQUIRED, &numAcquired));
149 }
150 }
151 }
152 }
153}
154
155
156enum MyCEvent
157{
158 MY_C_EVENT_ACQUIRE = 1u << 0u,
159 MY_C_EVENT_LOST = 1u << 1u,
160};
161
162using c_callback_type = bool (*)(MyCEvent event, void *userdata);
163
164TEST_CASE("u_generic_callbacks-C")
165{
166 GenericCallbacks<c_callback_type, MyCEvent> callbacks;
167}