[test/object] Test user_data with destroy() callback that calls user_data
[framework/uifw/harfbuzz.git] / test / test-object.c
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 #ifdef HAVE_FREETYPE
33 #include <hb-ft.h>
34 #endif
35
36
37 static void *
38 create_blob (void)
39 {
40   static char data[] = "test data";
41   return hb_blob_create (data, sizeof (data), HB_MEMORY_MODE_READONLY, NULL, NULL);
42 }
43 static void *
44 create_blob_inert (void)
45 {
46   return hb_blob_get_empty ();
47 }
48
49 static void *
50 create_buffer (void)
51 {
52   return hb_buffer_create (0);
53 }
54 static void *
55 create_buffer_inert (void)
56 {
57   return hb_buffer_create (-1);
58 }
59
60 static void *
61 create_face (void)
62 {
63   hb_blob_t *blob = (hb_blob_t *) create_blob ();
64   hb_face_t *face = hb_face_create_for_data (blob, 0);
65   hb_blob_destroy (blob);
66   return face;
67 }
68 static void *
69 create_face_inert (void)
70 {
71   return hb_face_create_for_data ((hb_blob_t *) create_blob_inert (), 0);
72 }
73
74 static void *
75 create_font (void)
76 {
77   hb_face_t *face = (hb_face_t *) create_face ();
78   hb_font_t *font = hb_font_create (face);
79   hb_face_destroy (face);
80   return font;
81 }
82 static void *
83 create_font_inert (void)
84 {
85   return hb_font_create (create_face_inert ());
86 }
87
88 static void *
89 create_font_funcs (void)
90 {
91   return hb_font_funcs_create ();
92 }
93 static void *
94 create_font_funcs_inert (void)
95 {
96 #ifdef HAVE_FREETYPE
97   return hb_ft_get_font_funcs ();
98 #else
99   return NULL;
100 #endif
101 }
102
103 static void *
104 create_unicode_funcs (void)
105 {
106   return hb_unicode_funcs_create (NULL);
107 }
108 static void *
109 create_unicode_funcs_inert (void)
110 {
111   return hb_unicode_funcs_get_default ();
112 }
113
114
115
116 typedef void     *(*create_func_t)         (void);
117 typedef void     *(*reference_func_t)      (void *obj);
118 typedef void      (*destroy_func_t)        (void *obj);
119 typedef hb_bool_t (*set_user_data_func_t)  (void *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy);
120 typedef void *    (*get_user_data_func_t)  (void *obj, hb_user_data_key_t *key);
121 typedef void      (*make_immutable_func_t) (void *obj);
122 typedef hb_bool_t (*is_immutable_func_t)   (void *obj);
123
124 typedef struct {
125   create_func_t          create;
126   create_func_t          create_inert;
127   reference_func_t       reference;
128   destroy_func_t         destroy;
129   set_user_data_func_t   set_user_data;
130   get_user_data_func_t   get_user_data;
131   make_immutable_func_t  make_immutable;
132   is_immutable_func_t    is_immutable;
133   const char            *name;
134 } object_t;
135
136 #define OBJECT_WITHOUT_IMMUTABILITY(name) \
137   { \
138     (create_func_t)         create_##name, \
139     (create_func_t)         create_##name##_inert, \
140     (reference_func_t)      hb_##name##_reference, \
141     (destroy_func_t)        hb_##name##_destroy, \
142     (set_user_data_func_t)  hb_##name##_set_user_data, \
143     (get_user_data_func_t)  hb_##name##_get_user_data, \
144     (make_immutable_func_t) NULL, \
145     (is_immutable_func_t)   NULL, \
146     #name, \
147   }
148 #define OBJECT_WITH_IMMUTABILITY(name) \
149   { \
150     (create_func_t)         create_##name, \
151     (create_func_t)         create_##name##_inert, \
152     (reference_func_t)      hb_##name##_reference, \
153     (destroy_func_t)        hb_##name##_destroy, \
154     (set_user_data_func_t)  hb_##name##_set_user_data, \
155     (get_user_data_func_t)  hb_##name##_get_user_data, \
156     (make_immutable_func_t) hb_##name##_make_immutable, \
157     (is_immutable_func_t)   hb_##name##_is_immutable, \
158     #name, \
159   }
160 static const object_t objects[] =
161 {
162   OBJECT_WITHOUT_IMMUTABILITY (buffer),
163   OBJECT_WITHOUT_IMMUTABILITY (face),
164   OBJECT_WITHOUT_IMMUTABILITY (font),
165   OBJECT_WITH_IMMUTABILITY (blob),
166   OBJECT_WITH_IMMUTABILITY (font_funcs),
167   OBJECT_WITH_IMMUTABILITY (unicode_funcs)
168 };
169 #undef OBJECT
170
171
172 #define MAGIC0 0x12345678
173 #define MAGIC1 0x76543210
174
175 typedef struct {
176   int value;
177   gboolean freed;
178 } data_t;
179
180 static int global_data;
181
182 static void global_free_up (void *p G_GNUC_UNUSED)
183 {
184   global_data++;
185 }
186
187 static void free_up0 (void *p)
188 {
189   data_t *data = (data_t *) p;
190
191   g_assert_cmphex (data->value, ==, MAGIC0);
192   g_assert (!data->freed);
193   data->freed = TRUE;
194 }
195
196 static void free_up1 (void *p)
197 {
198   data_t *data = (data_t *) p;
199
200   g_assert_cmphex (data->value, ==, MAGIC1);
201   g_assert (!data->freed);
202   data->freed = TRUE;
203 }
204
205
206 typedef struct {
207   const object_t *klass;
208   void *object;
209   hb_user_data_key_t key;
210 } deadlock_test_t;
211
212 static void free_deadlock_test (void *p)
213 {
214   deadlock_test_t *t = (deadlock_test_t *) p;
215
216   g_assert (NULL == t->klass->get_user_data (t->object, &t->key));
217 }
218
219
220 static void
221 test_object (void)
222 {
223   unsigned int i;
224
225   for (i = 0; i < G_N_ELEMENTS (objects); i++) {
226     const object_t *o = &objects[i];
227     void *obj;
228     hb_user_data_key_t key[2];
229
230     {
231       unsigned int i;
232       data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
233       deadlock_test_t deadlock_test;
234
235       g_test_message ("Testing object %s", o->name);
236
237       g_test_message ("->create()");
238       obj = o->create ();
239       g_assert (obj);
240
241       g_assert (obj == o->reference (obj));
242       o->destroy (obj);
243
244       if (o->is_immutable)
245         g_assert (!o->is_immutable (obj));
246
247       g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
248       g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
249
250       if (o->is_immutable) {
251         o->make_immutable (obj);
252         g_assert (o->is_immutable (obj));
253       }
254
255       /* Should still work even if object is made immutable */
256       g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1));
257       g_assert (o->get_user_data (obj, &key[1]) == &data[1]);
258
259       g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0));
260       g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
261       g_assert (o->set_user_data (obj, &key[0], &data[1], NULL));
262       g_assert (data[0].freed);
263       g_assert (o->get_user_data (obj, &key[0]) == &data[1]);
264       g_assert (!data[1].freed);
265
266       data[0].freed = FALSE;
267       g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
268       g_assert (!data[0].freed);
269       g_assert (o->set_user_data (obj, &key[0], NULL, NULL));
270       g_assert (data[0].freed);
271
272       data[0].freed = FALSE;
273       global_data = 0;
274       g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
275       g_assert_cmpuint (global_data, ==, 0);
276       g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up));
277       g_assert_cmpuint (global_data, ==, 0);
278       g_assert (o->set_user_data (obj, &key[0], NULL, NULL));
279       g_assert_cmpuint (global_data, ==, 1);
280
281       global_data = 0;
282       for (i = 2; i < 1000; i++)
283         g_assert (o->set_user_data (obj, &key[i], &data[i], global_free_up));
284       for (i = 2; i < 1000; i++)
285         g_assert (o->get_user_data (obj, &key[i]) == &data[i]);
286       for (i = 100; i < 1000; i++)
287         g_assert (o->set_user_data (obj, &key[i], NULL, NULL));
288       for (i = 2; i < 100; i++)
289         g_assert (o->get_user_data (obj, &key[i]) == &data[i]);
290       for (i = 100; i < 1000; i++)
291         g_assert (!o->get_user_data (obj, &key[i]));
292       g_assert_cmpuint (global_data, ==, 900);
293
294       /* Test set_user_data where the destroy() func calls user_data functions.
295        * Make sure it doesn't deadlock or corrupt memory. */
296       deadlock_test.klass = o;
297       deadlock_test.object = obj;
298       g_assert (o->set_user_data (obj, &deadlock_test.key, &deadlock_test, free_deadlock_test));
299       g_assert (o->set_user_data (obj, &deadlock_test.key, NULL, NULL));
300
301       g_assert (!data[1].freed);
302       o->destroy (obj);
303       g_assert (data[0].freed);
304       g_assert (data[1].freed);
305       g_assert_cmpuint (global_data, ==, 1000-2);
306     }
307
308     {
309       data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
310
311       g_test_message ("->create_inert()");
312       obj = o->create_inert ();
313       if (!obj)
314         continue;
315
316       g_assert (obj == o->reference (obj));
317       o->destroy (obj);
318
319       if (o->is_immutable)
320         g_assert (o->is_immutable (obj));
321
322       g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0));
323       g_assert (!o->get_user_data (obj, &key[0]));
324
325       o->destroy (obj);
326       o->destroy (obj);
327       o->destroy (obj);
328       o->destroy (obj);
329       o->destroy (obj);
330
331       g_assert (!data[0].freed);
332     }
333   }
334 }
335
336
337 int
338 main (int argc, char **argv)
339 {
340   hb_test_init (&argc, &argv);
341
342   hb_test_add (test_object);
343
344   return hb_test_run ();
345 }