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