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[1000] = {{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