/* * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Google Author(s): Behdad Esfahbod */ #include "hb-test.h" /* Unit tests for hb-object-private.h */ static hb_blob_t * create_blob (void) { static char data[] = "test data"; return hb_blob_create (data, sizeof (data), HB_MEMORY_MODE_READONLY, NULL, NULL); } static hb_blob_t * create_blob_from_inert (void) { return NULL; } static hb_buffer_t * create_buffer (void) { return hb_buffer_create (); } static hb_buffer_t * create_buffer_from_inert (void) { return NULL; } static hb_map_t * create_map (void) { return hb_map_create (); } static hb_map_t * create_map_from_inert (void) { return NULL; } static hb_set_t * create_set (void) { return hb_set_create (); } static hb_set_t * create_set_from_inert (void) { return NULL; } static hb_face_t * create_face (void) { hb_blob_t *blob = (hb_blob_t *) create_blob (); hb_face_t *face = hb_face_create (blob, 0); hb_blob_destroy (blob); return face; } static hb_face_t * create_face_from_inert (void) { return hb_face_create (hb_blob_get_empty (), 0); } static hb_font_t * create_font (void) { hb_face_t *face = (hb_face_t *) create_face (); hb_font_t *font = hb_font_create (face); hb_face_destroy (face); return font; } static hb_font_t * create_font_from_inert (void) { return hb_font_create (hb_face_get_empty ()); } static hb_font_funcs_t * create_font_funcs (void) { return hb_font_funcs_create (); } static hb_font_funcs_t * create_font_funcs_from_inert (void) { return NULL; } static hb_shape_plan_t * create_shape_plan (void) { hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; props.direction = HB_DIRECTION_LTR; hb_face_t *face = (hb_face_t *) create_face (); hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, NULL, 0, NULL); hb_face_destroy (face); return shape_plan; } static hb_shape_plan_t * create_shape_plan_from_inert (void) { return NULL; } static hb_unicode_funcs_t * create_unicode_funcs (void) { return hb_unicode_funcs_create (NULL); } static hb_unicode_funcs_t * create_unicode_funcs_from_inert (void) { return hb_unicode_funcs_create (hb_unicode_funcs_get_empty ()); } #define MAGIC0 0x12345678 #define MAGIC1 0x76543210 typedef struct { int value; gboolean freed; } data_t; static int global_data; static void global_free_up (void *p G_GNUC_UNUSED) { global_data++; } static void free_up0 (void *p) { data_t *data = (data_t *) p; g_assert_cmphex (data->value, ==, MAGIC0); g_assert_true (!data->freed); data->freed = TRUE; } static void free_up1 (void *p) { data_t *data = (data_t *) p; g_assert_cmphex (data->value, ==, MAGIC1); g_assert_true (!data->freed); data->freed = TRUE; } #define OBJECT(name, _hb_object_make_immutable, _hb_object_is_immutable) \ static void \ test_object_##name (void) \ { \ typedef hb_##name##_t type_t; \ typedef type_t *(*create_func_t) (void); \ typedef type_t *(*reference_func_t) (type_t *obj); \ typedef void (*destroy_func_t) (type_t *obj); \ typedef hb_bool_t (*set_user_data_func_t) (type_t *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace); \ typedef void * (*get_user_data_func_t) (const type_t *obj, hb_user_data_key_t *key); \ typedef void (*make_immutable_func_t) (type_t *obj); \ typedef hb_bool_t (*is_immutable_func_t) (type_t *obj); \ \ struct object_t { \ create_func_t create; \ create_func_t create_from_inert; \ create_func_t get_empty; \ reference_func_t reference; \ destroy_func_t destroy; \ set_user_data_func_t set_user_data; \ get_user_data_func_t get_user_data; \ make_immutable_func_t make_immutable; \ is_immutable_func_t is_immutable; \ const char *name; \ } o[1] = {{\ create_##name, \ create_##name##_from_inert, \ hb_##name##_get_empty, \ hb_##name##_reference, \ hb_##name##_destroy, \ hb_##name##_set_user_data, \ hb_##name##_get_user_data, \ _hb_object_make_immutable, \ _hb_object_is_immutable, \ #name, \ }}; \ \ void *obj; \ hb_user_data_key_t key[1001]; \ \ { \ unsigned int j; \ data_t data[1000] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}}; \ \ g_test_message ("Testing object %s", o->name); \ \ g_test_message ("->create()"); \ obj = o->create (); \ g_assert_true (obj); \ \ g_assert_true (obj == o->reference (obj)); \ o->destroy (obj); \ \ if (o->is_immutable) \ g_assert_true (!o->is_immutable (obj)); \ \ g_assert_true (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE)); \ g_assert_true (o->get_user_data (obj, &key[0]) == &data[0]); \ \ if (o->is_immutable) { \ o->make_immutable (obj); \ g_assert_true (o->is_immutable (obj)); \ } \ \ /* Should still work even if object is made immutable */ \ g_assert_true (o->set_user_data (obj, &key[1], &data[1], free_up1, TRUE)); \ g_assert_true (o->get_user_data (obj, &key[1]) == &data[1]); \ \ g_assert_true (!o->set_user_data (obj, NULL, &data[0], free_up0, TRUE)); \ g_assert_true (o->get_user_data (obj, &key[0]) == &data[0]); \ g_assert_true (o->set_user_data (obj, &key[0], &data[1], NULL, TRUE)); \ g_assert_true (data[0].freed); \ g_assert_true (o->get_user_data (obj, &key[0]) == &data[1]); \ g_assert_true (!data[1].freed); \ \ data[0].freed = FALSE; \ g_assert_true (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE)); \ g_assert_true (!data[0].freed); \ g_assert_true (o->set_user_data (obj, &key[0], NULL, NULL, TRUE)); \ g_assert_true (data[0].freed); \ \ data[0].freed = FALSE; \ global_data = 0; \ g_assert_true (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE)); \ g_assert_true (!o->set_user_data (obj, &key[0], &data[0], free_up0, FALSE)); \ g_assert_cmpuint (global_data, ==, 0); \ g_assert_true (o->set_user_data (obj, &key[0], NULL, global_free_up, TRUE)); \ g_assert_cmpuint (global_data, ==, 0); \ g_assert_true (o->set_user_data (obj, &key[0], NULL, NULL, TRUE)); \ g_assert_cmpuint (global_data, ==, 1); \ \ global_data = 0; \ for (j = 2; j < 1000; j++) \ g_assert_true (o->set_user_data (obj, &key[j], &data[j], global_free_up, TRUE)); \ for (j = 2; j < 1000; j++) \ g_assert_true (o->get_user_data (obj, &key[j]) == &data[j]); \ for (j = 100; j < 1000; j++) \ g_assert_true (o->set_user_data (obj, &key[j], NULL, NULL, TRUE)); \ for (j = 2; j < 100; j++) \ g_assert_true (o->get_user_data (obj, &key[j]) == &data[j]); \ for (j = 100; j < 1000; j++) \ g_assert_true (!o->get_user_data (obj, &key[j])); \ g_assert_cmpuint (global_data, ==, 900); \ \ g_assert_true (!data[1].freed); \ o->destroy (obj); \ g_assert_true (data[0].freed); \ g_assert_true (data[1].freed); \ g_assert_cmpuint (global_data, ==, 1000-2); \ } \ \ { \ data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}}; \ \ g_test_message ("->get_empty()"); \ obj = o->get_empty (); \ g_assert_true (obj); \ \ g_assert_true (obj == o->reference (obj)); \ o->destroy (obj); \ \ if (o->is_immutable) \ g_assert_true (o->is_immutable (obj)); \ \ g_assert_true (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE)); \ g_assert_true (!o->get_user_data (obj, &key[0])); \ \ o->destroy (obj); \ o->destroy (obj); \ o->destroy (obj); \ o->destroy (obj); \ o->destroy (obj); \ \ g_assert_true (!data[0].freed); \ } \ \ { \ data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}}; \ \ g_test_message ("->create_from_inert()"); \ obj = o->create_from_inert (); \ if (!obj) \ return; \ g_assert_true (obj != o->get_empty ()); \ \ g_assert_true (obj == o->reference (obj)); \ o->destroy (obj); \ \ if (o->is_immutable) \ g_assert_true (!o->is_immutable (obj)); \ \ g_assert_true (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE)); \ g_assert_true (o->get_user_data (obj, &key[0])); \ \ o->destroy (obj); \ \ g_assert_true (data[0].freed); \ } \ } #define OBJECT_WITH_IMMUTABILITY(name) \ OBJECT (name, hb_##name##_make_immutable, hb_##name##_is_immutable) #define OBJECT_WITHOUT_IMMUTABILITY(name) \ OBJECT (name, NULL, NULL) OBJECT_WITHOUT_IMMUTABILITY (buffer) OBJECT_WITHOUT_IMMUTABILITY (map) OBJECT_WITHOUT_IMMUTABILITY (set) OBJECT_WITHOUT_IMMUTABILITY (shape_plan) OBJECT_WITH_IMMUTABILITY (blob) OBJECT_WITH_IMMUTABILITY (face) OBJECT_WITH_IMMUTABILITY (font) OBJECT_WITH_IMMUTABILITY (font_funcs) OBJECT_WITH_IMMUTABILITY (unicode_funcs) int main (int argc, char **argv) { hb_test_init (&argc, &argv); hb_test_add (test_object_buffer); hb_test_add (test_object_map); hb_test_add (test_object_shape_plan); hb_test_add (test_object_set); hb_test_add (test_object_blob); hb_test_add (test_object_face); hb_test_add (test_object_font); hb_test_add (test_object_font_funcs); hb_test_add (test_object_unicode_funcs); return hb_test_run (); }