1 /*
2 * Copyright © 2011 Google, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
27 #include "hb-test.h"
28
29 /* Unit tests for hb-object-private.h */
30
31
32 static void *
create_blob(void)33 create_blob (void)
34 {
35 static char data[] = "test data";
36 return hb_blob_create (data, sizeof (data), HB_MEMORY_MODE_READONLY, NULL, NULL);
37 }
38 static void *
create_blob_inert(void)39 create_blob_inert (void)
40 {
41 return hb_blob_create (NULL, 0, HB_MEMORY_MODE_DUPLICATE, NULL, NULL);
42 }
43
44 static void *
create_buffer(void)45 create_buffer (void)
46 {
47 return hb_buffer_create ();
48 }
49 static void *
create_buffer_inert(void)50 create_buffer_inert (void)
51 {
52 return NULL;
53 }
54
55 static void *
create_set(void)56 create_set (void)
57 {
58 return hb_set_create ();
59 }
60 static void *
create_set_inert(void)61 create_set_inert (void)
62 {
63 return NULL;
64 }
65
66 static void *
create_face(void)67 create_face (void)
68 {
69 hb_blob_t *blob = (hb_blob_t *) create_blob ();
70 hb_face_t *face = hb_face_create (blob, 0);
71 hb_blob_destroy (blob);
72 return face;
73 }
74 static void *
create_face_inert(void)75 create_face_inert (void)
76 {
77 return hb_face_create (hb_blob_get_empty (), 0);
78 }
79
80 static void *
create_font(void)81 create_font (void)
82 {
83 hb_face_t *face = (hb_face_t *) create_face ();
84 hb_font_t *font = hb_font_create (face);
85 hb_face_destroy (face);
86 return font;
87 }
88 static void *
create_font_inert(void)89 create_font_inert (void)
90 {
91 return hb_font_create (hb_face_get_empty ());
92 }
93
94 static void *
create_font_funcs(void)95 create_font_funcs (void)
96 {
97 return hb_font_funcs_create ();
98 }
99 static void *
create_font_funcs_inert(void)100 create_font_funcs_inert (void)
101 {
102 return NULL;
103 }
104
105 static void *
create_unicode_funcs(void)106 create_unicode_funcs (void)
107 {
108 return hb_unicode_funcs_create (NULL);
109 }
110 static void *
create_unicode_funcs_inert(void)111 create_unicode_funcs_inert (void)
112 {
113 return hb_unicode_funcs_get_default ();
114 }
115
116
117
118 typedef void *(*create_func_t) (void);
119 typedef void *(*reference_func_t) (void *obj);
120 typedef void (*destroy_func_t) (void *obj);
121 typedef hb_bool_t (*set_user_data_func_t) (void *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
122 typedef void * (*get_user_data_func_t) (void *obj, hb_user_data_key_t *key);
123 typedef void (*make_immutable_func_t) (void *obj);
124 typedef hb_bool_t (*is_immutable_func_t) (void *obj);
125
126 typedef struct {
127 create_func_t create;
128 create_func_t create_inert;
129 create_func_t get_empty;
130 reference_func_t reference;
131 destroy_func_t destroy;
132 set_user_data_func_t set_user_data;
133 get_user_data_func_t get_user_data;
134 make_immutable_func_t make_immutable;
135 is_immutable_func_t is_immutable;
136 const char *name;
137 } object_t;
138
139 #define OBJECT_WITHOUT_IMMUTABILITY(name) \
140 { \
141 (create_func_t) create_##name, \
142 (create_func_t) create_##name##_inert, \
143 (create_func_t) hb_##name##_get_empty, \
144 (reference_func_t) hb_##name##_reference, \
145 (destroy_func_t) hb_##name##_destroy, \
146 (set_user_data_func_t) hb_##name##_set_user_data, \
147 (get_user_data_func_t) hb_##name##_get_user_data, \
148 (make_immutable_func_t) NULL, \
149 (is_immutable_func_t) NULL, \
150 #name, \
151 }
152 #define OBJECT_WITH_IMMUTABILITY(name) \
153 { \
154 (create_func_t) create_##name, \
155 (create_func_t) create_##name##_inert, \
156 (create_func_t) hb_##name##_get_empty, \
157 (reference_func_t) hb_##name##_reference, \
158 (destroy_func_t) hb_##name##_destroy, \
159 (set_user_data_func_t) hb_##name##_set_user_data, \
160 (get_user_data_func_t) hb_##name##_get_user_data, \
161 (make_immutable_func_t) hb_##name##_make_immutable, \
162 (is_immutable_func_t) hb_##name##_is_immutable, \
163 #name, \
164 }
165 static const object_t objects[] =
166 {
167 OBJECT_WITHOUT_IMMUTABILITY (buffer),
168 OBJECT_WITHOUT_IMMUTABILITY (set),
169 OBJECT_WITH_IMMUTABILITY (blob),
170 OBJECT_WITH_IMMUTABILITY (face),
171 OBJECT_WITH_IMMUTABILITY (font),
172 OBJECT_WITH_IMMUTABILITY (font_funcs),
173 OBJECT_WITH_IMMUTABILITY (unicode_funcs)
174 };
175 #undef OBJECT
176
177
178 #define MAGIC0 0x12345678
179 #define MAGIC1 0x76543210
180
181 typedef struct {
182 int value;
183 gboolean freed;
184 } data_t;
185
186 static int global_data;
187
global_free_up(void * p G_GNUC_UNUSED)188 static void global_free_up (void *p G_GNUC_UNUSED)
189 {
190 global_data++;
191 }
192
free_up0(void * p)193 static void free_up0 (void *p)
194 {
195 data_t *data = (data_t *) p;
196
197 g_assert_cmphex (data->value, ==, MAGIC0);
198 g_assert (!data->freed);
199 data->freed = TRUE;
200 }
201
free_up1(void * p)202 static void free_up1 (void *p)
203 {
204 data_t *data = (data_t *) p;
205
206 g_assert_cmphex (data->value, ==, MAGIC1);
207 g_assert (!data->freed);
208 data->freed = TRUE;
209 }
210
211
212 typedef struct {
213 const object_t *klass;
214 void *object;
215 hb_user_data_key_t key;
216 } deadlock_test_t;
217
free_deadlock_test(void * p)218 static void free_deadlock_test (void *p)
219 {
220 deadlock_test_t *t = (deadlock_test_t *) p;
221
222 g_assert (NULL == t->klass->get_user_data (t->object, &t->key));
223 }
224
225
226 static void
test_object(void)227 test_object (void)
228 {
229 unsigned int i;
230
231 for (i = 0; i < G_N_ELEMENTS (objects); i++) {
232 const object_t *o = &objects[i];
233 void *obj;
234 hb_user_data_key_t key[1001];
235
236 {
237 unsigned int j;
238 data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
239 deadlock_test_t deadlock_test;
240
241 g_test_message ("Testing object %s", o->name);
242
243 g_test_message ("->create()");
244 obj = o->create ();
245 g_assert (obj);
246
247 g_assert (obj == o->reference (obj));
248 o->destroy (obj);
249
250 if (o->is_immutable)
251 g_assert (!o->is_immutable (obj));
252
253 g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
254 g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
255
256 if (o->is_immutable) {
257 o->make_immutable (obj);
258 g_assert (o->is_immutable (obj));
259 }
260
261 /* Should still work even if object is made immutable */
262 g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1, TRUE));
263 g_assert (o->get_user_data (obj, &key[1]) == &data[1]);
264
265 g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0, TRUE));
266 g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
267 g_assert (o->set_user_data (obj, &key[0], &data[1], NULL, TRUE));
268 g_assert (data[0].freed);
269 g_assert (o->get_user_data (obj, &key[0]) == &data[1]);
270 g_assert (!data[1].freed);
271
272 data[0].freed = FALSE;
273 g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
274 g_assert (!data[0].freed);
275 g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
276 g_assert (data[0].freed);
277
278 data[0].freed = FALSE;
279 global_data = 0;
280 g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
281 g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, FALSE));
282 g_assert_cmpuint (global_data, ==, 0);
283 g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up, TRUE));
284 g_assert_cmpuint (global_data, ==, 0);
285 g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
286 g_assert_cmpuint (global_data, ==, 1);
287
288 global_data = 0;
289 for (j = 2; j < 1000; j++)
290 g_assert (o->set_user_data (obj, &key[j], &data[j], global_free_up, TRUE));
291 for (j = 2; j < 1000; j++)
292 g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
293 for (j = 100; j < 1000; j++)
294 g_assert (o->set_user_data (obj, &key[j], NULL, NULL, TRUE));
295 for (j = 2; j < 100; j++)
296 g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
297 for (j = 100; j < 1000; j++)
298 g_assert (!o->get_user_data (obj, &key[j]));
299 g_assert_cmpuint (global_data, ==, 900);
300
301 /* Test set_user_data where the destroy() func calls user_data functions.
302 * Make sure it doesn't deadlock or corrupt memory. */
303 deadlock_test.klass = o;
304 deadlock_test.object = obj;
305 g_assert (o->set_user_data (obj, &deadlock_test.key, &deadlock_test, free_deadlock_test, TRUE));
306 g_assert (o->set_user_data (obj, &deadlock_test.key, NULL, NULL, TRUE));
307
308 g_assert (!data[1].freed);
309 o->destroy (obj);
310 g_assert (data[0].freed);
311 g_assert (data[1].freed);
312 g_assert_cmpuint (global_data, ==, 1000-2);
313 }
314
315 {
316 data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
317
318 g_test_message ("->get_empty()");
319 obj = o->get_empty ();
320 g_assert (obj);
321
322 g_assert (obj == o->reference (obj));
323 o->destroy (obj);
324
325 if (o->is_immutable)
326 g_assert (o->is_immutable (obj));
327
328 g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
329 g_assert (!o->get_user_data (obj, &key[0]));
330
331 o->destroy (obj);
332 o->destroy (obj);
333 o->destroy (obj);
334 o->destroy (obj);
335 o->destroy (obj);
336
337 g_assert (!data[0].freed);
338 }
339
340 {
341 data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
342
343 g_test_message ("->create_inert()");
344 obj = o->create_inert ();
345 if (!obj)
346 continue;
347 if (obj == o->get_empty ())
348 continue; /* Tested already */
349
350 g_assert (obj == o->reference (obj));
351 o->destroy (obj);
352
353 if (o->is_immutable)
354 g_assert (o->is_immutable (obj));
355
356 g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
357 g_assert (!o->get_user_data (obj, &key[0]));
358
359 o->destroy (obj);
360 o->destroy (obj);
361 o->destroy (obj);
362 o->destroy (obj);
363 o->destroy (obj);
364
365 g_assert (!data[0].freed);
366 }
367 }
368 }
369
370
371 int
main(int argc,char ** argv)372 main (int argc, char **argv)
373 {
374 hb_test_init (&argc, &argv);
375
376 hb_test_add (test_object);
377
378 return hb_test_run ();
379 }
380