File Coverage

t/dispatcher.cc
Criterion Covered Total %
statement 243 252 96.4
branch 410 1042 39.3
condition n/a
subroutine n/a
pod n/a
total 653 1294 50.4


line stmt bran cond sub pod time code
1             #include "test.h"
2             #include
3             #include
4              
5             using panda::CallbackDispatcher;
6             using test::Tracer;
7             using panda::function_details::tmp_abstract_function;
8             using panda::function_details::make_abstract_function;
9             using panda::iptr;
10              
11             using Dispatcher = CallbackDispatcher;
12             using Event = Dispatcher::Event;
13              
14             using panda::function;
15             using panda::string;
16              
17 19           TEST_CASE("empty callback dispatcher" , "[callbackdispatcher]") {
18 2 50         Dispatcher d;
19 1 50         d(1);
20 1 50         REQUIRE(true);
    50          
    50          
    50          
    0          
    0          
21 1           }
22              
23 19           TEST_CASE("dispatcher void()" , "[callbackdispatcher]") {
24 2 50         CallbackDispatcher d;
25 1           bool called = false;
26 3 50         CallbackDispatcher::SimpleCallback f = [&](){called = true;};
27 1 50         d.add(f);
28 1 50         d();
29 1 50         REQUIRE(called);
    50          
    50          
    50          
    0          
    0          
30              
31 1           }
32              
33 19           TEST_CASE("simplest callback dispatcher" , "[callbackdispatcher]") {
34 2 50         Dispatcher d;
35 2           function (Dispatcher::Event&, int)> cb = [](Event& e, int a) -> int {
36 1 50         return 1 + e.next(a).value_or(0);
37 3 50         };
38 1 50         d.add_event_listener(cb);
39 4 50         d.add_event_listener([](Event& e, int a) -> int {
40 1 50         return a + e.next(a).value_or(0);
41 2 50         });
42 1 50         REQUIRE(d(2).value_or(0) == 3);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
43 1           }
44              
45 19           TEST_CASE("remove callback dispatcher" , "[callbackdispatcher]") {
46 2 50         Dispatcher d;
47 5 50         d.add_event_listener([](Event& e, int a) -> int {
48 2 50         return 1 + e.next(a).value_or(0);
49 2 50         });
50 2           Dispatcher::Callback c = [](Event& e, int a) -> int {
51 1 50         return a + e.next(a).value_or(0);
52 3 50         };
53 1 50         d.add_event_listener(c);
54 1 50         REQUIRE(d(2).value_or(0) == 3);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
55 1 50         d.remove(c);
56 1 50         REQUIRE(d(2).value_or(0) == 1);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
57 1           }
58              
59 19           TEST_CASE("remove_all in process" , "[callbackdispatcher]") {
60 2 50         Dispatcher d;
61 3 50         d.add_event_listener([](Event&, int) -> int {
62 0           return 2;
63 2 50         });
64 3 50         d.add_event_listener([&](Event& e, int a) -> int {
65 1           d.remove_all();
66 1 50         return 1 + e.next(a).value_or(0);
67 1 50         });
68 1 50         REQUIRE(d(2).value_or(0) == 1);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
69 1           }
70              
71 19           TEST_CASE("callback dispatcher copy ellision" , "[callbackdispatcher]") {
72 2 50         Dispatcher d;
73 1           Tracer::refresh();
74             {
75 2 50         Dispatcher::Callback cb = Tracer(14);
76 1 50         d.add_event_listener(cb);
77 1 50         REQUIRE(d(2).value_or(0) == 16);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
78 1 50         d.remove(cb);
79 1 50         REQUIRE(d(2).value_or(0) == 0);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
80             }
81 1 50         REQUIRE(d(2).value_or(0) == 0);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
82              
83 1 50         REQUIRE(Tracer::ctor_calls == 1); // 1 for temporary object Tracer(10);
    50          
    50          
    50          
    50          
    0          
    0          
84 1 50         REQUIRE(Tracer::copy_calls == 0);
    50          
    50          
    50          
    50          
    0          
    0          
85 1 50         REQUIRE(Tracer::move_calls == 1); // 1 construction from tmp object function f = Tracer(10);
    50          
    50          
    50          
    50          
    0          
    0          
86 1 50         REQUIRE(Tracer::dtor_calls == 2);
    50          
    50          
    50          
    50          
    0          
    0          
87 1           }
88              
89 19           TEST_CASE("callback dispatcher without event" , "[callbackdispatcher]") {
90 2 50         Dispatcher d;
91 1           bool called = false;
92 1           Dispatcher::SimpleCallback s = [&](int) {
93 1           called = true;
94 2 50         };
95 1 50         d.add(s);
96 1 50         REQUIRE(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
97 1 50         REQUIRE(called);
    50          
    50          
    50          
    0          
    0          
98 1           }
99              
100 19           TEST_CASE("remove callback dispatcher without event" , "[callbackdispatcher]") {
101 2 50         Dispatcher d;
102 1           bool called = false;
103 1           Dispatcher::SimpleCallback s = [&](int) {
104 1           called = true;
105 2 50         };
106 1 50         d.add(s);
107 1 50         REQUIRE(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
108 1 50         REQUIRE(called);
    50          
    50          
    50          
    0          
    0          
109 1 50         d.remove(s);
110 1           called = false;
111 1 50         REQUIRE(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
112 1 50         REQUIRE(!called);
    50          
    50          
    50          
    0          
    0          
113 1           }
114              
115 19           TEST_CASE("remove callback dispatcher with compatible type" , "[callbackdispatcher]") {
116 2 50         Dispatcher d;
117 1           bool called = false;
118 1           function s = [&](int) {
119 1           called = true;
120 2 50         };
121 1 50         d.add(s);
    50          
122 1 50         REQUIRE(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
123 1 50         REQUIRE(called);
    50          
    50          
    50          
    0          
    0          
124 1 50         d.remove(s);
125 1           called = false;
126 1 50         REQUIRE(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
127 1 50         REQUIRE(!called);
    50          
    50          
    50          
    0          
    0          
128 1           }
129              
130 19           TEST_CASE("remove callback comparable functor" , "[callbackdispatcher]") {
131 2 50         Dispatcher d;
132             static bool called;
133             struct S {
134 2           void operator()(int) {
135 2           called = true;
136 2           }
137 2           bool operator ==(const S&) const {
138 2           return true;
139             }
140             };
141              
142             static_assert(panda::has_call_operator::value,
143             "S shuld be callable, it can be wrong implementation of panda::has_call_operator or a compiler error");
144              
145             S src;
146 1           called = false;
147 2 50         Dispatcher::SimpleCallback s = src;
148 1 50         d.add(s);
149 1 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
150 1 50         CHECK(called);
    50          
    50          
    50          
    0          
    0          
151 1 50         d.remove(s);
152 1           called = false;
153 1 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
154 1 50         CHECK(!called);
    50          
    50          
    50          
    0          
    0          
155              
156 1           called = false;
157 1 50         d.add(s);
158 1 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
159 1 50         CHECK(called);
    50          
    50          
    50          
    0          
    0          
160              
161 1 50         d.remove_object(S(src));
162 1           called = false;
163 1 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
164 1 50         CHECK(!called);
    50          
    50          
    50          
    0          
    0          
165 1           }
166              
167 20           TEST_CASE("remove callback comparable full functor" , "[callbackdispatcher]") {
168 4 50         Dispatcher d;
169             static bool called;
170             struct S {
171 2           int operator()(Dispatcher::Event& e, int a) {
172 2           called = true;
173 2           e.next(a);
174 2           return a + 10;
175             }
176 2           bool operator ==(const S&) const {
177 2           return true;
178             }
179             };
180              
181             static_assert(panda::has_call_operator::value,
182             "S shuld be callable, it can be wrong implementation of panda::has_call_operator or a compiler error");
183              
184             S src;
185 2           called = false;
186 4 50         Dispatcher::Callback s = src;
187 2 50         d.add_event_listener(s);
188              
189 2 50         CHECK(d(2).value_or(42) == 12);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
190 2 50         CHECK(called);
    50          
    50          
    50          
    0          
    0          
191 2           called = false;
192              
193 3 50         SECTION("standatd remove") {
    50          
    50          
    50          
    100          
194 1 50         d.remove(s);
195             }
196              
197 3 50         SECTION("fast remove") {
    50          
    50          
    50          
    100          
198 1 50         d.remove_object(S(src));
199             }
200              
201 2 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
202 2 50         CHECK(!called);
    50          
    50          
    50          
    0          
    0          
203 2           }
204              
205 19           TEST_CASE("remove simple callback self lambda" , "[callbackdispatcher]") {
206 2 50         Dispatcher d;
207             static bool called;
208 1           auto l = [&](panda::Ifunction& self, int) {
209 1           d.remove(self);
210 1           called = true;
211 2           };
212              
213 2 50         Dispatcher::SimpleCallback s = l;
214 1 50         d.add(s);
215 1 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
216 1 50         CHECK(called);
    50          
    50          
    50          
    0          
    0          
217 1           called = false;
218 1 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
219 1 50         CHECK(!called);
    50          
    50          
    50          
    0          
    0          
220 1           }
221              
222              
223 19           TEST_CASE("remove callback self lambda" , "[callbackdispatcher]") {
224             using panda::optional;
225 2 50         Dispatcher d;
226             static bool called;
227 1           auto l = [&](panda::Ifunction, Dispatcher::Event&, int>& self, Dispatcher::Event&, int a) {
228 1           d.remove(self);
229 1           called = true;
230 1           return a + 10;
231 1           };
232              
233 2 50         Dispatcher::Callback s = l;
234 1 50         d.add_event_listener(s);
235 1 50         CHECK(d(2).value_or(42) == 12);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
236 1 50         CHECK(called);
    50          
    50          
    50          
    0          
    0          
237 1           called = false;
238 1 50         CHECK(d(2).value_or(42) == 42);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
239 1 50         CHECK(!called);
    50          
    50          
    50          
    0          
    0          
240 1           }
241              
242 19           TEST_CASE("dispatcher to function conversion" , "[callbackdispatcher]") {
243 2 50         Dispatcher d;
244 5 50         d.add_event_listener([](Dispatcher::Event&, int a){return a*2;});
    50          
245 2 50         function(int)> f = d;
246 1 50         REQUIRE(f(10).value_or(0) == 20);
    50          
    50          
    50          
    50          
    50          
    0          
    0          
247              
248 1           }
249              
250 19           TEST_CASE("dispatcher 2 string calls" , "[callbackdispatcher]") {
251             using Dispatcher = CallbackDispatcher;
252 2 50         Dispatcher d;
253 5 50         d.add([](string s) {CHECK(s == "value");});
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
254 5 50         d.add([](string s) {CHECK(s == "value");});
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
255 1 50         d(string("value"));
256 2           string s = "value";
257 1 50         d(s);
258 1           }
259              
260 19           TEST_CASE("front order", "[callbackdispatcher]") {
261             using Dispatcher = CallbackDispatcher;
262 2 50         Dispatcher d;
263 2           std::vector res;
264 2 50         d.add([&]{ res.push_back(1); });
    50          
    50          
265 2 50         d.add([&]{ res.push_back(2); });
    50          
    50          
266 2 50         d.add_event_listener([&](Dispatcher::Event& e){ res.push_back(3); e.next(); });
    50          
    50          
267 1 50         d();
268 1 50         REQUIRE(res == std::vector({3,2,1}));
    50          
    50          
    50          
    50          
    50          
    0          
    0          
269 1           }
270              
271 19           TEST_CASE("back order", "[callbackdispatcher]") {
272             using Dispatcher = CallbackDispatcher;
273 2 50         Dispatcher d;
274 2           std::vector res;
275 2 50         d.add_event_listener([&](Dispatcher::Event& e){ res.push_back(1); e.next(); }, true);
    50          
    50          
276 2 50         d.add([&]{ res.push_back(2); }, true);
    50          
    50          
277 2 50         d.add_back([&]{ res.push_back(3); });
    50          
278 1 50         d();
279 1 50         REQUIRE(res == std::vector({1,2,3}));
    50          
    50          
    50          
    50          
    50          
    0          
    0          
280 1           }
281              
282 20           TEST_CASE("dispatcher const ref arg move" , "[callbackdispatcher]") {
283 2           Tracer::refresh();
284 4 50         CallbackDispatcher d;
285              
286 3 50         SECTION("many listenees") {
    50          
    50          
    50          
    100          
287 1           Tracer::refresh();
288 2 50         d.add([](auto&&...){});
    50          
289 2 50         d.add([](auto&&...){});
    50          
290 2 50         d.add([](auto&&...){});
    50          
291             }
292 2 50         SECTION("no listeners"){}
    50          
    50          
    50          
293              
294 2 50         d(Tracer());
295 2 50         CHECK(Tracer::ctor_total() == 1);
    50          
    50          
    50          
    50          
    0          
    0          
296 2           }
297              
298 19           TEST_CASE("dispatcher lambda self reference auto...", "[callbackdispatcher]") {
299 2 50         CallbackDispatcher d1;
300 2 50         CallbackDispatcher d2;
301              
302 0           auto l1 = [](auto...args) -> void { static_assert(sizeof...(args) == 1, "auto... resolved as without SELF"); };
303 0           auto l2 = [](auto&&...args) -> void { static_assert(sizeof...(args) == 1, "auto... resolved as without SELF"); };
304 0 0         auto l3 = [](auto&&...args) { REQUIRE(sizeof...(args) == 1); };
    0          
    0          
    0          
    0          
    0          
    0          
305              
306 1 50         d1.add(l1);
    50          
307 1 50         d1.add(l2);
    50          
308 1 50         d1.add(l3);
    50          
309 1 50         d2.add(l1);
    50          
310 1 50         d2.add(l2);
    50          
311 1 50         d2.add(l3);
    50          
312              
313 0           auto l1a = [](auto&, auto...args) -> int { static_assert(sizeof...(args) == 1, "auto... resolved as without SELF"); return 1; };
314 0           auto l2a = [](auto&&...args) -> int { static_assert(sizeof...(args) == 2, "auto... resolved as without SELF"); return 2; };
315 0 0         auto l3a = [](auto&&...args) { REQUIRE(sizeof...(args) == 2); return 3; };
    0          
    0          
    0          
    0          
    0          
    0          
316              
317 1 50         d2.add_event_listener(l1a);
    50          
318 1 50         d2.add_event_listener(l2a);
    50          
319 1 50         d2.add_event_listener(l3a);
    50          
320 1           }
321              
322 19           TEST_CASE("killing callback dispatcher" , "[callbackdispatcher]") {
323 1 50         Dispatcher* d = new Dispatcher;
    50          
324 1           function cb = [&](int) {
325 1 50         delete d;
326 2 50         };
327 1 50         d->add(cb);
328              
329 1           bool called = false;
330 0           function check = [&](int) {
331 0           called = true;
332 2 50         };
333 1 50         d->add(check, true);
334              
335 1 50         (*d)(10);
336 1 50         REQUIRE_FALSE(called);
    50          
    50          
    50          
    50          
    0          
    0          
337 73 50         }
    50          
338