d0145c5a0fddac325bee7ecc68074f6d5deec074
[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_create (NULL, 0, HB_MEMORY_MODE_DUPLICATE, NULL, NULL);
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 (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 (hb_blob_get_empty (), 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 (hb_face_get_empty ());
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   create_func_t          get_empty;
128   reference_func_t       reference;
129   destroy_func_t         destroy;
130   set_user_data_func_t   set_user_data;
131   get_user_data_func_t   get_user_data;
132   make_immutable_func_t  make_immutable;
133   is_immutable_func_t    is_immutable;
134   const char            *name;
135 } object_t;
136
137 #define OBJECT_WITHOUT_IMMUTABILITY(name) \
138   { \
139     (create_func_t)         create_##name, \
140     (create_func_t)         create_##name##_inert, \
141     (create_func_t)         hb_##name##_get_empty, \
142     (reference_func_t)      hb_##name##_reference, \
143     (destroy_func_t)        hb_##name##_destroy, \
144     (set_user_data_func_t)  hb_##name##_set_user_data, \
145     (get_user_data_func_t)  hb_##name##_get_user_data, \
146     (make_immutable_func_t) NULL, \
147     (is_immutable_func_t)   NULL, \
148     #name, \
149   }
150 #define OBJECT_WITH_IMMUTABILITY(name) \
151   { \
152     (create_func_t)         create_##name, \
153     (create_func_t)         create_##name##_inert, \
154     (create_func_t)         hb_##name##_get_empty, \
155     (reference_func_t)      hb_##name##_reference, \
156     (destroy_func_t)        hb_##name##_destroy, \
157     (set_user_data_func_t)  hb_##name##_set_user_data, \
158     (get_user_data_func_t)  hb_##name##_get_user_data, \
159     (make_immutable_func_t) hb_##name##_make_immutable, \
160     (is_immutable_func_t)   hb_##name##_is_immutable, \
161     #name, \
162   }
163 static const object_t objects[] =
164 {
165   OBJECT_WITHOUT_IMMUTABILITY (buffer),
166   OBJECT_WITH_IMMUTABILITY (blob),
167   OBJECT_WITH_IMMUTABILITY (face),
168   OBJECT_WITH_IMMUTABILITY (font),
169   OBJECT_WITH_IMMUTABILITY (font_funcs),
170   OBJECT_WITH_IMMUTABILITY (unicode_funcs)
171 };
172 #undef OBJECT
173
174
175 #define MAGIC0 0x12345678
176 #define MAGIC1 0x76543210
177
178 typedef struct {
179   int value;
180   gboolean freed;
181 } data_t;
182
183 static int global_data;
184
185 static void global_free_up (void *p G_GNUC_UNUSED)
186 {
187   global_data++;
188 }
189
190 static void free_up0 (void *p)
191 {
192   data_t *data = (data_t *) p;
193
194   g_assert_cmphex (data->value, ==, MAGIC0);
195   g_assert (!data->freed);
196   data->freed = TRUE;
197 }
198
199 static void free_up1 (void *p)
200 {
201   data_t *data = (data_t *) p;
202
203   g_assert_cmphex (data->value, ==, MAGIC1);
204   g_assert (!data->freed);
205   data->freed = TRUE;
206 }
207
208
209 typedef struct {
210   const object_t *klass;
211   void *object;
212   hb_user_data_key_t key;
213 } deadlock_test_t;
214
215 static void free_deadlock_test (void *p)
216 {
217   deadlock_test_t *t = (deadlock_test_t *) p;
218
219   g_assert (NULL == t->klass->get_user_data (t->object, &t->key));
220 }
221
222
223 static void
224 test_object (void)
225 {
226   unsigned int i;
227
228   for (i = 0; i < G_N_ELEMENTS (objects); i++) {
229     const object_t *o = &objects[i];
230     void *obj;
231     hb_user_data_key_t key[2];
232
233     {
234       unsigned int j;
235       data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
236       deadlock_test_t deadlock_test;
237
238       g_test_message ("Testing object %s", o->name);
239
240       g_test_message ("->create()");
241       obj = o->create ();
242       g_assert (obj);
243
244       g_assert (obj == o->reference (obj));
245       o->destroy (obj);
246
247       if (o->is_immutable)
248         g_assert (!o->is_immutable (obj));
249
250       g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
251       g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
252
253       if (o->is_immutable) {
254         o->make_immutable (obj);
255         g_assert (o->is_immutable (obj));
256       }
257
258       /* Should still work even if object is made immutable */
259       g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1));
260       g_assert (o->get_user_data (obj, &key[1]) == &data[1]);
261
262       g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0));
263       g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
264       g_assert (o->set_user_data (obj, &key[0], &data[1], NULL));
265       g_assert (data[0].freed);
266       g_assert (o->get_user_data (obj, &key[0]) == &data[1]);
267       g_assert (!data[1].freed);
268
269       data[0].freed = FALSE;
270       g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
271       g_assert (!data[0].freed);
272       g_assert (o->set_user_data (obj, &key[0], NULL, NULL));
273       g_assert (data[0].freed);
274
275       data[0].freed = FALSE;
276       global_data = 0;
277       g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
278       g_assert_cmpuint (global_data, ==, 0);
279       g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up));
280       g_assert_cmpuint (global_data, ==, 0);
281       g_assert (o->set_user_data (obj, &key[0], NULL, NULL));
282       g_assert_cmpuint (global_data, ==, 1);
283
284       global_data = 0;
285       for (j = 2; j < 1000; j++)
286         g_assert (o->set_user_data (obj, &key[j], &data[j], global_free_up));
287       for (j = 2; j < 1000; j++)
288         g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
289       for (j = 100; j < 1000; j++)
290         g_assert (o->set_user_data (obj, &key[j], NULL, NULL));
291       for (j = 2; j < 100; j++)
292         g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
293       for (j = 100; j < 1000; j++)
294         g_assert (!o->get_user_data (obj, &key[j]));
295       g_assert_cmpuint (global_data, ==, 900);
296
297       /* Test set_user_data where the destroy() func calls user_data functions.
298        * Make sure it doesn't deadlock or corrupt memory. */
299       deadlock_test.klass = o;
300       deadlock_test.object = obj;
301       g_assert (o->set_user_data (obj, &deadlock_test.key, &deadlock_test, free_deadlock_test));
302       g_assert (o->set_user_data (obj, &deadlock_test.key, NULL, NULL));
303
304       g_assert (!data[1].freed);
305       o->destroy (obj);
306       g_assert (data[0].freed);
307       g_assert (data[1].freed);
308       g_assert_cmpuint (global_data, ==, 1000-2);
309     }
310
311     {
312       data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
313
314       g_test_message ("->get_empty()");
315       obj = o->get_empty ();
316       g_assert (obj);
317
318       g_assert (obj == o->reference (obj));
319       o->destroy (obj);
320
321       if (o->is_immutable)
322         g_assert (o->is_immutable (obj));
323
324       g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0));
325       g_assert (!o->get_user_data (obj, &key[0]));
326
327       o->destroy (obj);
328       o->destroy (obj);
329       o->destroy (obj);
330       o->destroy (obj);
331       o->destroy (obj);
332
333       g_assert (!data[0].freed);
334     }
335
336     {
337       data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
338
339       g_test_message ("->create_inert()");
340       obj = o->create_inert ();
341       if (!obj)
342         continue;
343       if (obj == o->get_empty ())
344         continue; /* Tested already */
345
346       g_assert (obj == o->reference (obj));
347       o->destroy (obj);
348
349       if (o->is_immutable)
350         g_assert (o->is_immutable (obj));
351
352       g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0));
353       g_assert (!o->get_user_data (obj, &key[0]));
354
355       o->destroy (obj);
356       o->destroy (obj);
357       o->destroy (obj);
358       o->destroy (obj);
359       o->destroy (obj);
360
361       g_assert (!data[0].freed);
362     }
363   }
364 }
365
366
367 int
368 main (int argc, char **argv)
369 {
370   hb_test_init (&argc, &argv);
371
372   hb_test_add (test_object);
373
374   return hb_test_run ();
375 }