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