• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012 Collabora, Ltd.
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 "config.h"
27 
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "weston-test-client-helper.h"
32 #include "weston-test-fixture-compositor.h"
33 
34 static enum test_result_code
fixture_setup(struct weston_test_harness * harness)35 fixture_setup(struct weston_test_harness *harness)
36 {
37 	struct compositor_setup setup;
38 
39 	compositor_setup_defaults(&setup);
40 
41 	return weston_test_harness_execute_as_client(harness, &setup);
42 }
43 DECLARE_FIXTURE_SETUP(fixture_setup);
44 
45 #define NUM_SUBSURFACES 3
46 
47 struct compound_surface {
48 	struct wl_subcompositor *subco;
49 	struct wl_surface *parent;
50 	struct wl_surface *child[NUM_SUBSURFACES];
51 	struct wl_subsurface *sub[NUM_SUBSURFACES];
52 };
53 
54 static struct wl_subcompositor *
get_subcompositor(struct client * client)55 get_subcompositor(struct client *client)
56 {
57 	struct global *g;
58 	struct global *global_sub = NULL;
59 	struct wl_subcompositor *sub;
60 
61 	wl_list_for_each(g, &client->global_list, link) {
62 		if (strcmp(g->interface, "wl_subcompositor"))
63 			continue;
64 
65 		if (global_sub)
66 			assert(0 && "multiple wl_subcompositor objects");
67 
68 		global_sub = g;
69 	}
70 
71 	assert(global_sub && "no wl_subcompositor found");
72 
73 	assert(global_sub->version == 1);
74 
75 	sub = wl_registry_bind(client->wl_registry, global_sub->name,
76 			       &wl_subcompositor_interface, 1);
77 	assert(sub);
78 
79 	return sub;
80 }
81 
82 static void
populate_compound_surface(struct compound_surface * com,struct client * client)83 populate_compound_surface(struct compound_surface *com, struct client *client)
84 {
85 	int i;
86 
87 	com->subco = get_subcompositor(client);
88 
89 	com->parent = wl_compositor_create_surface(client->wl_compositor);
90 
91 	for (i = 0; i < NUM_SUBSURFACES; i++) {
92 		com->child[i] =
93 			wl_compositor_create_surface(client->wl_compositor);
94 		com->sub[i] =
95 			wl_subcompositor_get_subsurface(com->subco,
96 							com->child[i],
97 							com->parent);
98 	}
99 }
100 
TEST(test_subsurface_basic_protocol)101 TEST(test_subsurface_basic_protocol)
102 {
103 	struct client *client;
104 	struct compound_surface com1;
105 	struct compound_surface com2;
106 
107 	client = create_client_and_test_surface(100, 50, 123, 77);
108 	assert(client);
109 
110 	populate_compound_surface(&com1, client);
111 	populate_compound_surface(&com2, client);
112 
113 	client_roundtrip(client);
114 }
115 
TEST(test_subsurface_position_protocol)116 TEST(test_subsurface_position_protocol)
117 {
118 	struct client *client;
119 	struct compound_surface com;
120 	int i;
121 
122 	client = create_client_and_test_surface(100, 50, 123, 77);
123 	assert(client);
124 
125 	populate_compound_surface(&com, client);
126 	for (i = 0; i < NUM_SUBSURFACES; i++)
127 		wl_subsurface_set_position(com.sub[i],
128 					   (i + 2) * 20, (i + 2) * 10);
129 
130 	client_roundtrip(client);
131 }
132 
TEST(test_subsurface_placement_protocol)133 TEST(test_subsurface_placement_protocol)
134 {
135 	struct client *client;
136 	struct compound_surface com;
137 
138 	client = create_client_and_test_surface(100, 50, 123, 77);
139 	assert(client);
140 
141 	populate_compound_surface(&com, client);
142 
143 	wl_subsurface_place_above(com.sub[0], com.child[1]);
144 	wl_subsurface_place_above(com.sub[1], com.parent);
145 	wl_subsurface_place_below(com.sub[2], com.child[0]);
146 	wl_subsurface_place_below(com.sub[1], com.parent);
147 
148 	client_roundtrip(client);
149 }
150 
TEST(test_subsurface_paradox)151 TEST(test_subsurface_paradox)
152 {
153 	struct client *client;
154 	struct wl_surface *parent;
155 	struct wl_subcompositor *subco;
156 
157 	client = create_client_and_test_surface(100, 50, 123, 77);
158 	assert(client);
159 
160 	subco = get_subcompositor(client);
161 	parent = wl_compositor_create_surface(client->wl_compositor);
162 
163 	/* surface is its own parent */
164 	wl_subcompositor_get_subsurface(subco, parent, parent);
165 
166 	expect_protocol_error(client, &wl_subcompositor_interface,
167 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
168 }
169 
TEST(test_subsurface_identical_link)170 TEST(test_subsurface_identical_link)
171 {
172 	struct client *client;
173 	struct compound_surface com;
174 
175 	client = create_client_and_test_surface(100, 50, 123, 77);
176 	assert(client);
177 
178 	populate_compound_surface(&com, client);
179 
180 	/* surface is already a subsurface */
181 	wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
182 
183 	expect_protocol_error(client, &wl_subcompositor_interface,
184 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
185 }
186 
TEST(test_subsurface_change_link)187 TEST(test_subsurface_change_link)
188 {
189 	struct client *client;
190 	struct compound_surface com;
191 	struct wl_surface *stranger;
192 
193 	client = create_client_and_test_surface(100, 50, 123, 77);
194 	assert(client);
195 
196 	stranger = wl_compositor_create_surface(client->wl_compositor);
197 	populate_compound_surface(&com, client);
198 
199 	/* surface is already a subsurface */
200 	wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
201 
202 	expect_protocol_error(client, &wl_subcompositor_interface,
203 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
204 }
205 
TEST(test_subsurface_nesting)206 TEST(test_subsurface_nesting)
207 {
208 	struct client *client;
209 	struct compound_surface com;
210 	struct wl_surface *stranger;
211 
212 	client = create_client_and_test_surface(100, 50, 123, 77);
213 	assert(client);
214 
215 	stranger = wl_compositor_create_surface(client->wl_compositor);
216 	populate_compound_surface(&com, client);
217 
218 	/* parent is a sub-surface */
219 	wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
220 
221 	client_roundtrip(client);
222 }
223 
TEST(test_subsurface_nesting_parent)224 TEST(test_subsurface_nesting_parent)
225 {
226 	struct client *client;
227 	struct compound_surface com;
228 	struct wl_surface *stranger;
229 
230 	client = create_client_and_test_surface(100, 50, 123, 77);
231 	assert(client);
232 
233 	stranger = wl_compositor_create_surface(client->wl_compositor);
234 	populate_compound_surface(&com, client);
235 
236 	/* surface is already a parent */
237 	wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
238 
239 	client_roundtrip(client);
240 }
241 
TEST(test_subsurface_loop_paradox)242 TEST(test_subsurface_loop_paradox)
243 {
244 	struct client *client;
245 	struct wl_surface *surface[3];
246 	struct wl_subcompositor *subco;
247 
248 	client = create_client_and_test_surface(100, 50, 123, 77);
249 	assert(client);
250 
251 	subco = get_subcompositor(client);
252 	surface[0] = wl_compositor_create_surface(client->wl_compositor);
253 	surface[1] = wl_compositor_create_surface(client->wl_compositor);
254 	surface[2] = wl_compositor_create_surface(client->wl_compositor);
255 
256 	/* create a nesting loop */
257 	wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
258 	wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
259 	wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
260 
261 	expect_protocol_error(client, &wl_subcompositor_interface,
262 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
263 }
264 
TEST(test_subsurface_place_above_nested_parent)265 TEST(test_subsurface_place_above_nested_parent)
266 {
267 	struct client *client;
268 	struct compound_surface com;
269 	struct wl_surface *grandchild;
270 	struct wl_subcompositor *subco;
271 	struct wl_subsurface *sub;
272 
273 	client = create_client_and_test_surface(100, 50, 123, 77);
274 	assert(client);
275 
276 	populate_compound_surface(&com, client);
277 
278 	subco = get_subcompositor(client);
279 	grandchild = wl_compositor_create_surface(client->wl_compositor);
280 	sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
281 
282 	wl_subsurface_place_above(sub, com.child[0]);
283 
284 	client_roundtrip(client);
285 }
286 
TEST(test_subsurface_place_above_grandparent)287 TEST(test_subsurface_place_above_grandparent)
288 {
289 	struct client *client;
290 	struct compound_surface com;
291 	struct wl_surface *grandchild;
292 	struct wl_subsurface *sub;
293 	struct wl_subcompositor *subco;
294 
295 	client = create_client_and_test_surface(100, 50, 123, 77);
296 	assert(client);
297 
298 	populate_compound_surface(&com, client);
299 
300 	subco = get_subcompositor(client);
301 	grandchild = wl_compositor_create_surface(client->wl_compositor);
302 	sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
303 
304 	/* can't place a subsurface above its grandparent */
305 	wl_subsurface_place_above(sub, com.parent);
306 
307 	expect_protocol_error(client, &wl_subsurface_interface,
308 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
309 }
310 
TEST(test_subsurface_place_above_great_aunt)311 TEST(test_subsurface_place_above_great_aunt)
312 {
313 	struct client *client;
314 	struct compound_surface com;
315 	struct wl_surface *grandchild;
316 	struct wl_subsurface *sub;
317 	struct wl_subcompositor *subco;
318 
319 	client = create_client_and_test_surface(100, 50, 123, 77);
320 	assert(client);
321 
322 	populate_compound_surface(&com, client);
323 
324 	subco = get_subcompositor(client);
325 	grandchild = wl_compositor_create_surface(client->wl_compositor);
326 	sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
327 
328 	/* can't place a subsurface above its parents' siblings */
329 	wl_subsurface_place_above(sub, com.child[1]);
330 
331 	expect_protocol_error(client, &wl_subsurface_interface,
332 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
333 }
334 
TEST(test_subsurface_place_above_child)335 TEST(test_subsurface_place_above_child)
336 {
337 	struct client *client;
338 	struct compound_surface com;
339 	struct wl_surface *grandchild;
340 	struct wl_subcompositor *subco;
341 
342 	client = create_client_and_test_surface(100, 50, 123, 77);
343 	assert(client);
344 
345 	populate_compound_surface(&com, client);
346 
347 	subco = get_subcompositor(client);
348 	grandchild = wl_compositor_create_surface(client->wl_compositor);
349 	wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
350 
351 	/* can't place a subsurface above its own child subsurface */
352 	wl_subsurface_place_above(com.sub[0], grandchild);
353 
354 	expect_protocol_error(client, &wl_subsurface_interface,
355 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
356 }
357 
TEST(test_subsurface_place_below_nested_parent)358 TEST(test_subsurface_place_below_nested_parent)
359 {
360 	struct client *client;
361 	struct compound_surface com;
362 	struct wl_subcompositor *subco;
363 	struct wl_surface *grandchild;
364 	struct wl_subsurface *sub;
365 
366 	client = create_client_and_test_surface(100, 50, 123, 77);
367 	assert(client);
368 
369 	populate_compound_surface(&com, client);
370 
371 	subco = get_subcompositor(client);
372 	grandchild = wl_compositor_create_surface(client->wl_compositor);
373 	sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
374 
375 	wl_subsurface_place_below(sub, com.child[0]);
376 
377 	client_roundtrip(client);
378 }
379 
TEST(test_subsurface_place_below_grandparent)380 TEST(test_subsurface_place_below_grandparent)
381 {
382 	struct client *client;
383 	struct compound_surface com;
384 	struct wl_surface *grandchild;
385 	struct wl_subsurface *sub;
386 	struct wl_subcompositor *subco;
387 
388 	client = create_client_and_test_surface(100, 50, 123, 77);
389 	assert(client);
390 
391 	populate_compound_surface(&com, client);
392 
393 	subco = get_subcompositor(client);
394 	grandchild = wl_compositor_create_surface(client->wl_compositor);
395 	sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
396 
397 	/* can't place a subsurface below its grandparent */
398 	wl_subsurface_place_below(sub, com.parent);
399 
400 	expect_protocol_error(client, &wl_subsurface_interface,
401 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
402 }
403 
TEST(test_subsurface_place_below_great_aunt)404 TEST(test_subsurface_place_below_great_aunt)
405 {
406 	struct client *client;
407 	struct compound_surface com;
408 	struct wl_surface *grandchild;
409 	struct wl_subsurface *sub;
410 	struct wl_subcompositor *subco;
411 
412 	client = create_client_and_test_surface(100, 50, 123, 77);
413 	assert(client);
414 
415 	populate_compound_surface(&com, client);
416 
417 	subco = get_subcompositor(client);
418 	grandchild = wl_compositor_create_surface(client->wl_compositor);
419 	sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
420 
421 	/* can't place a subsurface below its parents' siblings */
422 	wl_subsurface_place_below(sub, com.child[1]);
423 
424 	expect_protocol_error(client, &wl_subsurface_interface,
425 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
426 }
427 
TEST(test_subsurface_place_below_child)428 TEST(test_subsurface_place_below_child)
429 {
430 	struct client *client;
431 	struct compound_surface com;
432 	struct wl_surface *grandchild;
433 	struct wl_subcompositor *subco;
434 
435 	client = create_client_and_test_surface(100, 50, 123, 77);
436 	assert(client);
437 
438 	populate_compound_surface(&com, client);
439 
440 	subco = get_subcompositor(client);
441 	grandchild = wl_compositor_create_surface(client->wl_compositor);
442 	wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
443 
444 	/* can't place a subsurface below its own child subsurface */
445 	wl_subsurface_place_below(com.sub[0], grandchild);
446 
447 	expect_protocol_error(client, &wl_subsurface_interface,
448 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
449 }
450 
TEST(test_subsurface_place_above_stranger)451 TEST(test_subsurface_place_above_stranger)
452 {
453 	struct client *client;
454 	struct compound_surface com;
455 	struct wl_surface *stranger;
456 
457 	client = create_client_and_test_surface(100, 50, 123, 77);
458 	assert(client);
459 
460 	stranger = wl_compositor_create_surface(client->wl_compositor);
461 	populate_compound_surface(&com, client);
462 
463 	/* bad sibling */
464 	wl_subsurface_place_above(com.sub[0], stranger);
465 
466 	expect_protocol_error(client, &wl_subsurface_interface,
467 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
468 }
469 
TEST(test_subsurface_place_below_stranger)470 TEST(test_subsurface_place_below_stranger)
471 {
472 	struct client *client;
473 	struct compound_surface com;
474 	struct wl_surface *stranger;
475 
476 	client = create_client_and_test_surface(100, 50, 123, 77);
477 	assert(client);
478 
479 	stranger = wl_compositor_create_surface(client->wl_compositor);
480 	populate_compound_surface(&com, client);
481 
482 	/* bad sibling */
483 	wl_subsurface_place_below(com.sub[0], stranger);
484 
485 	expect_protocol_error(client, &wl_subsurface_interface,
486 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
487 }
488 
TEST(test_subsurface_place_above_foreign)489 TEST(test_subsurface_place_above_foreign)
490 {
491 	struct client *client;
492 	struct compound_surface com1;
493 	struct compound_surface com2;
494 
495 	client = create_client_and_test_surface(100, 50, 123, 77);
496 	assert(client);
497 
498 	populate_compound_surface(&com1, client);
499 	populate_compound_surface(&com2, client);
500 
501 	/* bad sibling */
502 	wl_subsurface_place_above(com1.sub[0], com2.child[0]);
503 
504 	expect_protocol_error(client, &wl_subsurface_interface,
505 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
506 }
507 
TEST(test_subsurface_place_below_foreign)508 TEST(test_subsurface_place_below_foreign)
509 {
510 	struct client *client;
511 	struct compound_surface com1;
512 	struct compound_surface com2;
513 
514 	client = create_client_and_test_surface(100, 50, 123, 77);
515 	assert(client);
516 
517 	populate_compound_surface(&com1, client);
518 	populate_compound_surface(&com2, client);
519 
520 	/* bad sibling */
521 	wl_subsurface_place_below(com1.sub[0], com2.child[0]);
522 
523 	expect_protocol_error(client, &wl_subsurface_interface,
524 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
525 }
526 
TEST(test_subsurface_destroy_protocol)527 TEST(test_subsurface_destroy_protocol)
528 {
529 	struct client *client;
530 	struct compound_surface com;
531 
532 	client = create_client_and_test_surface(100, 50, 123, 77);
533 	assert(client);
534 
535 	populate_compound_surface(&com, client);
536 
537 	/* not needed anymore */
538 	wl_subcompositor_destroy(com.subco);
539 
540 	/* detach child from parent */
541 	wl_subsurface_destroy(com.sub[0]);
542 
543 	/* destroy: child, parent */
544 	wl_surface_destroy(com.child[1]);
545 	wl_surface_destroy(com.parent);
546 
547 	/* destroy: parent, child */
548 	wl_surface_destroy(com.child[2]);
549 
550 	/* destroy: sub, child */
551 	wl_surface_destroy(com.child[0]);
552 
553 	/* 2x destroy: child, sub */
554 	wl_subsurface_destroy(com.sub[2]);
555 	wl_subsurface_destroy(com.sub[1]);
556 
557 	client_roundtrip(client);
558 }
559 
560 static void
create_subsurface_tree(struct client * client,struct wl_surface ** surfs,struct wl_subsurface ** subs,int n)561 create_subsurface_tree(struct client *client, struct wl_surface **surfs,
562 		       struct wl_subsurface **subs, int n)
563 {
564 	struct wl_subcompositor *subco;
565 	int i;
566 
567 	subco = get_subcompositor(client);
568 
569 	for (i = 0; i < n; i++)
570 		surfs[i] = wl_compositor_create_surface(client->wl_compositor);
571 
572 	/*
573 	 * The tree of sub-surfaces:
574 	 *                            0
575 	 *                           / \
576 	 *                          1   2 - 10
577 	 *                         / \  |\
578 	 *                        3   5 9 6
579 	 *                       /       / \
580 	 *                      4       7   8
581 	 * Surface 0 has no wl_subsurface, others do.
582 	 */
583 
584 	switch (n) {
585 	default:
586 		assert(0);
587 		break;
588 
589 #define SUB_LINK(s,p) \
590 	subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
591 
592 	case 11:
593 		SUB_LINK(10, 2);
594 		/* fallthrough */
595 	case 10:
596 		SUB_LINK(9, 2);
597 		/* fallthrough */
598 	case 9:
599 		SUB_LINK(8, 6);
600 		/* fallthrough */
601 	case 8:
602 		SUB_LINK(7, 6);
603 		/* fallthrough */
604 	case 7:
605 		SUB_LINK(6, 2);
606 		/* fallthrough */
607 	case 6:
608 		SUB_LINK(5, 1);
609 		/* fallthrough */
610 	case 5:
611 		SUB_LINK(4, 3);
612 		/* fallthrough */
613 	case 4:
614 		SUB_LINK(3, 1);
615 		/* fallthrough */
616 	case 3:
617 		SUB_LINK(2, 0);
618 		/* fallthrough */
619 	case 2:
620 		SUB_LINK(1, 0);
621 
622 #undef SUB_LINK
623 	};
624 }
625 
626 static void
destroy_subsurface_tree(struct wl_surface ** surfs,struct wl_subsurface ** subs,int n)627 destroy_subsurface_tree(struct wl_surface **surfs,
628 			struct wl_subsurface **subs, int n)
629 {
630 	int i;
631 
632 	for (i = n; i-- > 0; ) {
633 		if (surfs[i])
634 			wl_surface_destroy(surfs[i]);
635 
636 		if (subs[i])
637 			wl_subsurface_destroy(subs[i]);
638 	}
639 }
640 
641 static int
has_dupe(int * cnt,int n)642 has_dupe(int *cnt, int n)
643 {
644 	int i;
645 
646 	for (i = 0; i < n; i++)
647 		if (cnt[i] == cnt[n])
648 			return 1;
649 
650 	return 0;
651 }
652 
653 /* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
654  */
655 #define NSTEPS 3
656 
657 struct permu_state {
658 	int set_size;
659 	int cnt[NSTEPS];
660 };
661 
662 static void
permu_init(struct permu_state * s,int set_size)663 permu_init(struct permu_state *s, int set_size)
664 {
665 	int i;
666 
667 	s->set_size = set_size;
668 	for (i = 0; i < NSTEPS; i++)
669 		s->cnt[i] = 0;
670 }
671 
672 static int
permu_next(struct permu_state * s)673 permu_next(struct permu_state *s)
674 {
675 	int k;
676 
677 	s->cnt[NSTEPS - 1]++;
678 
679 	while (1) {
680 		if (s->cnt[0] >= s->set_size) {
681 			return -1;
682 		}
683 
684 		for (k = 1; k < NSTEPS; k++) {
685 			if (s->cnt[k] >= s->set_size) {
686 				s->cnt[k - 1]++;
687 				s->cnt[k] = 0;
688 				break;
689 			}
690 
691 			if (has_dupe(s->cnt, k)) {
692 				s->cnt[k]++;
693 				break;
694 			}
695 		}
696 
697 		if (k == NSTEPS)
698 			return 0;
699 	}
700 }
701 
702 static void
destroy_permu_object(struct wl_surface ** surfs,struct wl_subsurface ** subs,int i)703 destroy_permu_object(struct wl_surface **surfs,
704 		     struct wl_subsurface **subs, int i)
705 {
706 	int h = (i + 1) / 2;
707 
708 	if (i & 1) {
709 		testlog(" [sub  %2d]", h);
710 		wl_subsurface_destroy(subs[h]);
711 		subs[h] = NULL;
712 	} else {
713 		testlog(" [surf %2d]", h);
714 		wl_surface_destroy(surfs[h]);
715 		surfs[h] = NULL;
716 	}
717 }
718 
TEST(test_subsurface_destroy_permutations)719 TEST(test_subsurface_destroy_permutations)
720 {
721 	/*
722 	 * Test wl_surface and wl_subsurface destruction orders in a
723 	 * complex tree of sub-surfaces.
724 	 *
725 	 * In the tree of sub-surfaces, go through every possible
726 	 * permutation of destroying all wl_surface and wl_subsurface
727 	 * objects. Execpt, to limit running time to a reasonable level,
728 	 * execute only the first NSTEPS destructions from each
729 	 * permutation, and ignore identical cases.
730 	 */
731 
732 	const int test_size = 11;
733 	struct client *client;
734 	struct wl_surface *surfs[test_size];
735 	struct wl_subsurface *subs[test_size];
736 	struct permu_state per;
737 	int counter = 0;
738 	int i;
739 
740 	client = create_client_and_test_surface(100, 50, 123, 77);
741 	assert(client);
742 
743 	permu_init(&per, test_size * 2 - 1);
744 	while (permu_next(&per) != -1) {
745 		/* for each permutation of NSTEPS out of test_size */
746 		memset(surfs, 0, sizeof surfs);
747 		memset(subs, 0, sizeof subs);
748 
749 		create_subsurface_tree(client, surfs, subs, test_size);
750 
751 		testlog("permu");
752 
753 		for (i = 0; i < NSTEPS; i++)
754 			testlog(" %2d", per.cnt[i]);
755 
756 		for (i = 0; i < NSTEPS; i++)
757 			destroy_permu_object(surfs, subs, per.cnt[i]);
758 
759 		testlog("\n");
760 		client_roundtrip(client);
761 
762 		destroy_subsurface_tree(surfs, subs, test_size);
763 		counter++;
764 	}
765 
766 	client_roundtrip(client);
767 	testlog("tried %d destroy permutations\n", counter);
768 }
769