(root)/
harfbuzz-8.3.0/
test/
api/
test-object.c
       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  }