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 | #include <sys/socket.h> |
28 | #include <unistd.h> |
29 | #include <stdint.h> |
30 | |
31 | #include "wayland-server.h" |
32 | #include "test-runner.h" |
33 | |
34 | TEST(create_resource_tst) |
35 | { |
36 | struct wl_display *display; |
37 | struct wl_client *client; |
38 | struct wl_resource *res; |
39 | struct wl_list *link; |
40 | int s[2]; |
41 | uint32_t id; |
42 | |
43 | assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); |
44 | display = wl_display_create(); |
45 | assert(display); |
46 | client = wl_client_create(display, fd: s[0]); |
47 | assert(client); |
48 | |
49 | res = wl_resource_create(client, interface: &wl_seat_interface, version: 4, id: 0); |
50 | assert(res); |
51 | |
52 | /* setters/getters */ |
53 | assert(wl_resource_get_version(res) == 4); |
54 | |
55 | assert(client == wl_resource_get_client(res)); |
56 | id = wl_resource_get_id(resource: res); |
57 | assert(wl_client_get_object(client, id) == res); |
58 | |
59 | link = wl_resource_get_link(resource: res); |
60 | assert(link); |
61 | assert(wl_resource_from_link(link) == res); |
62 | |
63 | wl_resource_set_user_data(resource: res, data: (void *) 0xbee); |
64 | assert(wl_resource_get_user_data(res) == (void *) 0xbee); |
65 | |
66 | wl_resource_destroy(resource: res); |
67 | wl_client_destroy(client); |
68 | wl_display_destroy(display); |
69 | close(fd: s[1]); |
70 | } |
71 | |
72 | static void |
73 | res_destroy_func(struct wl_resource *res) |
74 | { |
75 | assert(res); |
76 | |
77 | _Bool *destr = wl_resource_get_user_data(resource: res); |
78 | *destr = 1; |
79 | } |
80 | |
81 | static _Bool notify_called = 0; |
82 | static void |
83 | destroy_notify(struct wl_listener *l, void *data) |
84 | { |
85 | assert(l && data); |
86 | notify_called = 1; |
87 | |
88 | /* In real code it's common to free the structure holding the |
89 | * listener at this point, but not to remove it from the list. |
90 | * |
91 | * That's fine since this is a destruction notification and |
92 | * it's the last time this signal can fire. We set these |
93 | * to NULL so we can check them later to ensure no write after |
94 | * "free" occurred. |
95 | */ |
96 | l->link.prev = NULL; |
97 | l->link.next = NULL; |
98 | } |
99 | |
100 | TEST(destroy_res_tst) |
101 | { |
102 | struct wl_display *display; |
103 | struct wl_client *client; |
104 | struct wl_resource *res; |
105 | int s[2]; |
106 | unsigned id; |
107 | struct wl_list *link; |
108 | |
109 | _Bool destroyed = 0; |
110 | struct wl_listener destroy_listener = { |
111 | .notify = &destroy_notify |
112 | }; |
113 | |
114 | assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); |
115 | display = wl_display_create(); |
116 | assert(display); |
117 | client = wl_client_create(display, fd: s[0]); |
118 | assert(client); |
119 | |
120 | res = wl_resource_create(client, interface: &wl_seat_interface, version: 4, id: 0); |
121 | assert(res); |
122 | wl_resource_set_implementation(resource: res, NULL, data: &destroyed, destroy: res_destroy_func); |
123 | wl_resource_add_destroy_listener(resource: res, listener: &destroy_listener); |
124 | |
125 | id = wl_resource_get_id(resource: res); |
126 | link = wl_resource_get_link(resource: res); |
127 | assert(link); |
128 | |
129 | wl_resource_destroy(resource: res); |
130 | assert(destroyed); |
131 | assert(notify_called); /* check if signal was emitted */ |
132 | assert(wl_client_get_object(client, id) == NULL); |
133 | assert(destroy_listener.link.prev == NULL); |
134 | assert(destroy_listener.link.next == NULL); |
135 | |
136 | res = wl_resource_create(client, interface: &wl_seat_interface, version: 2, id: 0); |
137 | assert(res); |
138 | destroyed = 0; |
139 | notify_called = 0; |
140 | wl_resource_set_destructor(resource: res, destroy: res_destroy_func); |
141 | wl_resource_set_user_data(resource: res, data: &destroyed); |
142 | wl_resource_add_destroy_listener(resource: res, listener: &destroy_listener); |
143 | /* client should destroy the resource upon its destruction */ |
144 | wl_client_destroy(client); |
145 | assert(destroyed); |
146 | assert(notify_called); |
147 | assert(destroy_listener.link.prev == NULL); |
148 | assert(destroy_listener.link.next == NULL); |
149 | |
150 | wl_display_destroy(display); |
151 | close(fd: s[1]); |
152 | } |
153 | |
154 | TEST(create_resource_with_same_id) |
155 | { |
156 | struct wl_display *display; |
157 | struct wl_client *client; |
158 | struct wl_resource *res, *res2; |
159 | int s[2]; |
160 | uint32_t id; |
161 | |
162 | assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); |
163 | display = wl_display_create(); |
164 | assert(display); |
165 | client = wl_client_create(display, fd: s[0]); |
166 | assert(client); |
167 | |
168 | res = wl_resource_create(client, interface: &wl_seat_interface, version: 2, id: 0); |
169 | assert(res); |
170 | id = wl_resource_get_id(resource: res); |
171 | assert(wl_client_get_object(client, id) == res); |
172 | |
173 | /* this one should replace the old one */ |
174 | res2 = wl_resource_create(client, interface: &wl_seat_interface, version: 1, id); |
175 | assert(res2 != NULL); |
176 | assert(wl_client_get_object(client, id) == res2); |
177 | |
178 | wl_resource_destroy(resource: res2); |
179 | wl_resource_destroy(resource: res); |
180 | |
181 | wl_client_destroy(client); |
182 | wl_display_destroy(display); |
183 | close(fd: s[1]); |
184 | } |
185 | |
186 | static void |
187 | display_destroy_notify(struct wl_listener *l, void *data) |
188 | { |
189 | l->link.prev = l->link.next = NULL; |
190 | } |
191 | |
192 | TEST(free_without_remove) |
193 | { |
194 | struct wl_display *display; |
195 | struct wl_listener a, b; |
196 | |
197 | display = wl_display_create(); |
198 | a.notify = display_destroy_notify; |
199 | b.notify = display_destroy_notify; |
200 | |
201 | wl_display_add_destroy_listener(display, listener: &a); |
202 | wl_display_add_destroy_listener(display, listener: &b); |
203 | |
204 | wl_display_destroy(display); |
205 | |
206 | assert(a.link.next == a.link.prev && a.link.next == NULL); |
207 | assert(b.link.next == b.link.prev && b.link.next == NULL); |
208 | } |
209 | |