From db99589529a22a2113bcef1680ab6d9b934f382e Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 2 May 2011 19:52:47 -0400 Subject: [PATCH] [test/object] Add test for object lifecycle stuff Revealed many bugs in the (untested and known buggy) user_data support. --- test/Makefile.am | 4 + test/test-object.c | 316 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 320 insertions(+) create mode 100644 test/test-object.c diff --git a/test/Makefile.am b/test/Makefile.am index e48708b37..56d6118b3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -12,6 +12,7 @@ noinst_PROGRAMS = $(TEST_PROGS) TEST_PROGS += \ test-buffer \ test-common \ + test-object \ test-unicode \ $(NULL) @@ -31,6 +32,9 @@ endif if HAVE_FREETYPE test_c_CPPFLAGS += $(FREETYPE_CFLAGS) test_cplusplus_CPPFLAGS += $(FREETYPE_CFLAGS) +# TODO replace freetype with other stuff in the following test +test_object_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS) +test_object_LIBS = $(LDADD) $(FREETYPE_LIBS) endif diff --git a/test/test-object.c b/test/test-object.c new file mode 100644 index 000000000..0fbabd81f --- /dev/null +++ b/test/test-object.c @@ -0,0 +1,316 @@ +/* + * 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 */ + + +#ifdef HAVE_FREETYPE +#include +#endif + + +static void * +create_blob (void) +{ + static char data[] = "test data"; + return hb_blob_create (data, sizeof (data), HB_MEMORY_MODE_READONLY, NULL, NULL); +} +static void * +create_blob_inert (void) +{ + return hb_blob_get_empty (); +} + +static void * +create_buffer (void) +{ + return hb_buffer_create (0); +} +static void * +create_buffer_inert (void) +{ + return hb_buffer_create (-1); +} + +static void * +create_face (void) +{ + hb_blob_t *blob = (hb_blob_t *) create_blob (); + hb_face_t *face = hb_face_create_for_data (blob, 0); + hb_blob_destroy (blob); + return face; +} +static void * +create_face_inert (void) +{ + return hb_face_create_for_data ((hb_blob_t *) create_blob_inert (), 0); +} + +static void * +create_font (void) +{ + return hb_font_create (); +} +static void * +create_font_inert (void) +{ + return NULL; +} + +static void * +create_font_funcs (void) +{ + return hb_font_funcs_create (); +} +static void * +create_font_funcs_inert (void) +{ +#ifdef HAVE_FREETYPE + return hb_ft_get_font_funcs (); +#else + return NULL; +#endif +} + +static void * +create_unicode_funcs (void) +{ + return hb_unicode_funcs_create (NULL); +} +static void * +create_unicode_funcs_inert (void) +{ + return hb_unicode_funcs_get_default (); +} + + + +typedef void *(*create_func_t) (void); +typedef void *(*reference_func_t) (void *obj); +typedef void (*destroy_func_t) (void *obj); +typedef hb_bool_t (*set_user_data_func_t) (void *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy); +typedef void * (*get_user_data_func_t) (void *obj, hb_user_data_key_t *key); +typedef void (*make_immutable_func_t) (void *obj); +typedef hb_bool_t (*is_immutable_func_t) (void *obj); + +typedef struct { + create_func_t create; + create_func_t create_inert; + 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; +} object_t; + +#define OBJECT_WITHOUT_IMMUTABILITY(name) \ + { \ + (create_func_t) create_##name, \ + (create_func_t) create_##name##_inert, \ + (reference_func_t) hb_##name##_reference, \ + (destroy_func_t) hb_##name##_destroy, \ + (set_user_data_func_t) hb_##name##_set_user_data, \ + (get_user_data_func_t) hb_##name##_get_user_data, \ + (make_immutable_func_t) NULL, \ + (is_immutable_func_t) NULL, \ + #name, \ + } +#define OBJECT_WITH_IMMUTABILITY(name) \ + { \ + (create_func_t) create_##name, \ + (create_func_t) create_##name##_inert, \ + (reference_func_t) hb_##name##_reference, \ + (destroy_func_t) hb_##name##_destroy, \ + (set_user_data_func_t) hb_##name##_set_user_data, \ + (get_user_data_func_t) hb_##name##_get_user_data, \ + (make_immutable_func_t) hb_##name##_make_immutable, \ + (is_immutable_func_t) hb_##name##_is_immutable, \ + #name, \ + } +static const object_t objects[] = +{ + OBJECT_WITHOUT_IMMUTABILITY (blob), + OBJECT_WITHOUT_IMMUTABILITY (buffer), + OBJECT_WITHOUT_IMMUTABILITY (face), + OBJECT_WITHOUT_IMMUTABILITY (font), + OBJECT_WITH_IMMUTABILITY (font_funcs), + OBJECT_WITH_IMMUTABILITY (unicode_funcs) +}; +#undef OBJECT + + +#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 (!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 (!data->freed); + data->freed = TRUE; +} + +static void +test_object (void) +{ + unsigned int i; + + for (i = 0; i < G_N_ELEMENTS (objects); i++) { + const object_t *o = &objects[i]; + void *obj; + hb_user_data_key_t key[2]; + + { + unsigned int i; + data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}}; + + g_test_message ("Testing object %s", o->name); + + g_test_message ("->create()"); + obj = o->create (); + g_assert (obj); + + g_assert (obj == o->reference (obj)); + o->destroy (obj); + + if (o->is_immutable) + g_assert (!o->is_immutable (obj)); + + g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0)); + g_assert (o->get_user_data (obj, &key[0]) == &data[0]); + + if (o->is_immutable) { + o->make_immutable (obj); + g_assert (o->is_immutable (obj)); + } + + /* Should still work even if object is made immutable */ + g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1)); + g_assert (o->get_user_data (obj, &key[1]) == &data[1]); + + g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0)); + g_assert (o->get_user_data (obj, &key[0]) == &data[0]); + g_assert (o->set_user_data (obj, &key[0], &data[1], NULL)); + g_assert (data[0].freed); + g_assert (o->get_user_data (obj, &key[0]) == &data[1]); + g_assert (!data[1].freed); + + data[0].freed = FALSE; + g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0)); + g_assert (!data[0].freed); + g_assert (o->set_user_data (obj, &key[0], NULL, NULL)); + g_assert (data[0].freed); + + data[0].freed = FALSE; + global_data = 0; + g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0)); + g_assert_cmpuint (global_data, ==, 0); + g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up)); + g_assert_cmpuint (global_data, ==, 0); + g_assert (o->set_user_data (obj, &key[0], NULL, NULL)); + g_assert_cmpuint (global_data, ==, 1); + + global_data = 0; + for (i = 2; i < 1000; i++) + g_assert (o->set_user_data (obj, &key[i], &data[i], global_free_up)); + for (i = 2; i < 1000; i++) + g_assert (o->get_user_data (obj, &key[i]) == &data[i]); + for (i = 100; i < 1000; i++) + g_assert (o->set_user_data (obj, &key[i], NULL, NULL)); + g_assert_cmpuint (global_data, ==, 900); + + + g_assert (!data[1].freed); + o->destroy (obj); + g_assert (data[0].freed); + g_assert (data[1].freed); + g_assert_cmpuint (global_data, ==, 1000-2); + } + + { + data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}}; + + g_test_message ("->create_inert()"); + obj = o->create_inert (); + if (!obj) + continue; + + g_assert (obj == o->reference (obj)); + o->destroy (obj); + + if (o->is_immutable) + g_assert (o->is_immutable (obj)); + + g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0)); + g_assert (!o->get_user_data (obj, &key[0])); + + o->destroy (obj); + o->destroy (obj); + o->destroy (obj); + o->destroy (obj); + o->destroy (obj); + + g_assert (!data[0].freed); + } + } +} + + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_object); + + return hb_test_run (); +}