1 | /* |
2 | * Copyright © 2013 Marek Chalupa |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining |
5 | * a copy of this software and associated documentation files (the |
6 | * "Software"), to deal in the Software without restriction, including |
7 | * without limitation the rights to use, copy, modify, merge, publish, |
8 | * distribute, sublicense, and/or sell copies of the Software, and to |
9 | * permit persons to whom the Software is furnished to do so, subject to |
10 | * the following conditions: |
11 | * |
12 | * The above copyright notice and this permission notice (including the |
13 | * next paragraph) shall be included in all copies or substantial |
14 | * portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
20 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
21 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | * SOFTWARE. |
24 | */ |
25 | |
26 | #include <assert.h> |
27 | |
28 | #include "test-runner.h" |
29 | #include "wayland-server-private.h" |
30 | |
31 | static void |
32 | signal_notify(struct wl_listener *listener, void *data) |
33 | { |
34 | /* only increase counter*/ |
35 | ++(*((int *) data)); |
36 | } |
37 | |
38 | TEST(signal_init) |
39 | { |
40 | struct wl_priv_signal signal; |
41 | |
42 | wl_priv_signal_init(signal: &signal); |
43 | |
44 | /* Test if listeners' list is initialized */ |
45 | assert(&signal.listener_list == signal.listener_list.next |
46 | && "Maybe wl_priv_signal implementation changed?" ); |
47 | assert(signal.listener_list.next == signal.listener_list.prev |
48 | && "Maybe wl_priv_signal implementation changed?" ); |
49 | } |
50 | |
51 | TEST(signal_add_get) |
52 | { |
53 | struct wl_priv_signal signal; |
54 | |
55 | /* we just need different values of notify */ |
56 | struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1}; |
57 | struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2}; |
58 | struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3}; |
59 | /* one real, why not */ |
60 | struct wl_listener l4 = {.notify = signal_notify}; |
61 | |
62 | wl_priv_signal_init(signal: &signal); |
63 | |
64 | wl_priv_signal_add(signal: &signal, listener: &l1); |
65 | wl_priv_signal_add(signal: &signal, listener: &l2); |
66 | wl_priv_signal_add(signal: &signal, listener: &l3); |
67 | wl_priv_signal_add(signal: &signal, listener: &l4); |
68 | |
69 | assert(wl_priv_signal_get(&signal, signal_notify) == &l4); |
70 | assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); |
71 | assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); |
72 | assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); |
73 | |
74 | /* get should not be destructive */ |
75 | assert(wl_priv_signal_get(&signal, signal_notify) == &l4); |
76 | assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); |
77 | assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); |
78 | assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); |
79 | } |
80 | |
81 | TEST(signal_emit_to_one_listener) |
82 | { |
83 | int count = 0; |
84 | int counter; |
85 | |
86 | struct wl_priv_signal signal; |
87 | struct wl_listener l1 = {.notify = signal_notify}; |
88 | |
89 | wl_priv_signal_init(signal: &signal); |
90 | wl_priv_signal_add(signal: &signal, listener: &l1); |
91 | |
92 | for (counter = 0; counter < 100; counter++) |
93 | wl_priv_signal_emit(signal: &signal, data: &count); |
94 | |
95 | assert(counter == count); |
96 | } |
97 | |
98 | TEST(signal_emit_to_more_listeners) |
99 | { |
100 | int count = 0; |
101 | int counter; |
102 | |
103 | struct wl_priv_signal signal; |
104 | struct wl_listener l1 = {.notify = signal_notify}; |
105 | struct wl_listener l2 = {.notify = signal_notify}; |
106 | struct wl_listener l3 = {.notify = signal_notify}; |
107 | |
108 | wl_priv_signal_init(signal: &signal); |
109 | wl_priv_signal_add(signal: &signal, listener: &l1); |
110 | wl_priv_signal_add(signal: &signal, listener: &l2); |
111 | wl_priv_signal_add(signal: &signal, listener: &l3); |
112 | |
113 | for (counter = 0; counter < 100; counter++) |
114 | wl_priv_signal_emit(signal: &signal, data: &count); |
115 | |
116 | assert(3 * counter == count); |
117 | } |
118 | |
119 | struct signal |
120 | { |
121 | struct wl_priv_signal signal; |
122 | struct wl_listener l1, l2, l3; |
123 | int count; |
124 | struct wl_listener *current; |
125 | }; |
126 | |
127 | static void notify_remove(struct wl_listener *l, void *data) |
128 | { |
129 | struct signal *sig = data; |
130 | wl_list_remove(elm: &sig->current->link); |
131 | wl_list_init(list: &sig->current->link); |
132 | sig->count++; |
133 | } |
134 | |
135 | #define INIT \ |
136 | wl_priv_signal_init(&signal.signal); \ |
137 | wl_list_init(&signal.l1.link); \ |
138 | wl_list_init(&signal.l2.link); \ |
139 | wl_list_init(&signal.l3.link); |
140 | #define CHECK_EMIT(expected) \ |
141 | signal.count = 0; \ |
142 | wl_priv_signal_emit(&signal.signal, &signal); \ |
143 | assert(signal.count == expected); |
144 | |
145 | TEST(signal_remove_listener) |
146 | { |
147 | test_set_timeout(4); |
148 | |
149 | struct signal signal; |
150 | |
151 | signal.l1.notify = notify_remove; |
152 | signal.l2.notify = notify_remove; |
153 | signal.l3.notify = notify_remove; |
154 | |
155 | INIT |
156 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
157 | |
158 | signal.current = &signal.l1; |
159 | CHECK_EMIT(1) |
160 | CHECK_EMIT(0) |
161 | |
162 | INIT |
163 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
164 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
165 | |
166 | CHECK_EMIT(2) |
167 | CHECK_EMIT(1) |
168 | |
169 | INIT |
170 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
171 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
172 | |
173 | signal.current = &signal.l2; |
174 | CHECK_EMIT(1) |
175 | CHECK_EMIT(1) |
176 | |
177 | INIT |
178 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
179 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
180 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l3); |
181 | |
182 | signal.current = &signal.l1; |
183 | CHECK_EMIT(3) |
184 | CHECK_EMIT(2) |
185 | |
186 | INIT |
187 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
188 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
189 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l3); |
190 | |
191 | signal.current = &signal.l2; |
192 | CHECK_EMIT(2) |
193 | CHECK_EMIT(2) |
194 | |
195 | INIT |
196 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
197 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
198 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l3); |
199 | |
200 | signal.current = &signal.l3; |
201 | CHECK_EMIT(2) |
202 | CHECK_EMIT(2) |
203 | } |
204 | |
205 | static void notify_readd(struct wl_listener *l, void *data) |
206 | { |
207 | struct signal *signal = data; |
208 | if (signal->current) { |
209 | wl_list_remove(elm: &signal->current->link); |
210 | wl_list_init(list: &signal->current->link); |
211 | wl_priv_signal_add(signal: &signal->signal, listener: signal->current); |
212 | } |
213 | signal->count++; |
214 | } |
215 | |
216 | static void notify_empty(struct wl_listener *l, void *data) |
217 | { |
218 | struct signal *signal = data; |
219 | signal->count++; |
220 | } |
221 | |
222 | TEST(signal_readd_listener) |
223 | { |
224 | /* Readding a listener is supported, that is it doesn't trigger an |
225 | * infinite loop or other weird things, but if in a listener you |
226 | * re-add another listener, that will not be fired in the current |
227 | * signal emission. */ |
228 | |
229 | test_set_timeout(4); |
230 | |
231 | struct signal signal; |
232 | |
233 | signal.l1.notify = notify_readd; |
234 | signal.l2.notify = notify_readd; |
235 | |
236 | INIT |
237 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
238 | |
239 | signal.current = &signal.l1; |
240 | CHECK_EMIT(1) |
241 | CHECK_EMIT(1) |
242 | |
243 | INIT |
244 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
245 | |
246 | signal.current = &signal.l2; |
247 | CHECK_EMIT(1) |
248 | signal.current = NULL; |
249 | CHECK_EMIT(2) |
250 | |
251 | INIT |
252 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
253 | |
254 | signal.current = &signal.l1; |
255 | CHECK_EMIT(1) |
256 | /* l2 was added before l1, so l2 is fired first, which by readding l1 |
257 | * removes it from the current list that is being fired, so 1 is correct */ |
258 | CHECK_EMIT(1) |
259 | |
260 | INIT |
261 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
262 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
263 | |
264 | signal.l1.notify = notify_empty; |
265 | signal.current = &signal.l2; |
266 | CHECK_EMIT(2) |
267 | CHECK_EMIT(2) |
268 | |
269 | INIT |
270 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
271 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
272 | |
273 | signal.l1.notify = notify_empty; |
274 | signal.current = &signal.l1; |
275 | CHECK_EMIT(2) |
276 | /* same as before, by readding l1 in the first emit, it now is fired |
277 | * after l2, so on the second emit it is not fired at all. */ |
278 | CHECK_EMIT(1) |
279 | } |
280 | |
281 | static void notify_addandget(struct wl_listener *l, void *data) |
282 | { |
283 | struct signal *signal = data; |
284 | wl_list_remove(elm: &signal->current->link); |
285 | wl_list_init(list: &signal->current->link); |
286 | wl_priv_signal_add(signal: &signal->signal, listener: signal->current); |
287 | |
288 | assert(wl_priv_signal_get(&signal->signal, signal->current->notify) != NULL); |
289 | |
290 | signal->count++; |
291 | } |
292 | |
293 | static void notify_get(struct wl_listener *l, void *data) |
294 | { |
295 | struct signal *signal = data; |
296 | assert(wl_priv_signal_get(&signal->signal, signal->current->notify) == signal->current); |
297 | signal->count++; |
298 | } |
299 | |
300 | TEST(signal_get_listener) |
301 | { |
302 | test_set_timeout(4); |
303 | |
304 | struct signal signal; |
305 | |
306 | signal.l1.notify = notify_addandget; |
307 | signal.l2.notify = notify_get; |
308 | |
309 | INIT |
310 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
311 | |
312 | signal.current = &signal.l2; |
313 | CHECK_EMIT(1) |
314 | |
315 | INIT |
316 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
317 | |
318 | signal.current = &signal.l2; |
319 | CHECK_EMIT(1) |
320 | |
321 | INIT |
322 | signal.l1.notify = notify_get; |
323 | signal.l2.notify = notify_empty; |
324 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
325 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
326 | |
327 | CHECK_EMIT(2) |
328 | |
329 | INIT |
330 | signal.l1.notify = notify_empty; |
331 | signal.l2.notify = notify_get; |
332 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l1); |
333 | wl_priv_signal_add(signal: &signal.signal, listener: &signal.l2); |
334 | |
335 | signal.current = &signal.l1; |
336 | CHECK_EMIT(2) |
337 | } |
338 | |