Imported Upstream version 1.2.7
[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_from_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_from_inert (void)
51 {
52   return NULL;
53 }
54
55 static void *
56 create_set (void)
57 {
58   return hb_set_create ();
59 }
60 static void *
61 create_set_from_inert (void)
62 {
63   return NULL;
64 }
65
66 static 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 *
75 create_face_from_inert (void)
76 {
77   return hb_face_create (hb_blob_get_empty (), 0);
78 }
79
80 static 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 *
89 create_font_from_inert (void)
90 {
91   return hb_font_create (hb_face_get_empty ());
92 }
93
94 static void *
95 create_font_funcs (void)
96 {
97   return hb_font_funcs_create ();
98 }
99 static void *
100 create_font_funcs_from_inert (void)
101 {
102   return NULL;
103 }
104
105 static void *
106 create_unicode_funcs (void)
107 {
108   return hb_unicode_funcs_create (NULL);
109 }
110 static void *
111 create_unicode_funcs_from_inert (void)
112 {
113   return hb_unicode_funcs_create (hb_unicode_funcs_get_empty ());
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_from_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##_from_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##_from_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
188 static void global_free_up (void *p G_GNUC_UNUSED)
189 {
190   global_data++;
191 }
192
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
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
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
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_from_inert()");
344       obj = o->create_from_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
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 }