Home | History | Annotate | Download | only in api
      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 }
    376