Blame test/api/test-object.c

Packit Service 5bcba8
/*
Packit Service 5bcba8
 * Copyright © 2011  Google, Inc.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 *  This is part of HarfBuzz, a text shaping library.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * Permission is hereby granted, without written agreement and without
Packit Service 5bcba8
 * license or royalty fees, to use, copy, modify, and distribute this
Packit Service 5bcba8
 * software and its documentation for any purpose, provided that the
Packit Service 5bcba8
 * above copyright notice and the following two paragraphs appear in
Packit Service 5bcba8
 * all copies of this software.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
Packit Service 5bcba8
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
Packit Service 5bcba8
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
Packit Service 5bcba8
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
Packit Service 5bcba8
 * DAMAGE.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
Packit Service 5bcba8
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
Packit Service 5bcba8
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
Packit Service 5bcba8
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
Packit Service 5bcba8
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * Google Author(s): Behdad Esfahbod
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
#include "hb-test.h"
Packit Service 5bcba8
Packit Service 5bcba8
/* Unit tests for hb-object-private.h */
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_blob (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  static char data[] = "test data";
Packit Service 5bcba8
  return hb_blob_create (data, sizeof (data), HB_MEMORY_MODE_READONLY, NULL, NULL);
Packit Service 5bcba8
}
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_blob_from_inert (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_blob_create (NULL, 0, HB_MEMORY_MODE_DUPLICATE, NULL, NULL);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_buffer (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_buffer_create ();
Packit Service 5bcba8
}
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_buffer_from_inert (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return NULL;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_set (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_set_create ();
Packit Service 5bcba8
}
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_set_from_inert (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return NULL;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_face (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  hb_blob_t *blob = (hb_blob_t *) create_blob ();
Packit Service 5bcba8
  hb_face_t *face = hb_face_create (blob, 0);
Packit Service 5bcba8
  hb_blob_destroy (blob);
Packit Service 5bcba8
  return face;
Packit Service 5bcba8
}
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_face_from_inert (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_face_create (hb_blob_get_empty (), 0);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_font (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  hb_face_t *face = (hb_face_t *) create_face ();
Packit Service 5bcba8
  hb_font_t *font = hb_font_create (face);
Packit Service 5bcba8
  hb_face_destroy (face);
Packit Service 5bcba8
  return font;
Packit Service 5bcba8
}
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_font_from_inert (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_font_create (hb_face_get_empty ());
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_font_funcs (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_font_funcs_create ();
Packit Service 5bcba8
}
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_font_funcs_from_inert (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return NULL;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_unicode_funcs (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_unicode_funcs_create (NULL);
Packit Service 5bcba8
}
Packit Service 5bcba8
static void *
Packit Service 5bcba8
create_unicode_funcs_from_inert (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return hb_unicode_funcs_create (hb_unicode_funcs_get_empty ());
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
typedef void     *(*create_func_t)         (void);
Packit Service 5bcba8
typedef void     *(*reference_func_t)      (void *obj);
Packit Service 5bcba8
typedef void      (*destroy_func_t)        (void *obj);
Packit Service 5bcba8
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);
Packit Service 5bcba8
typedef void *    (*get_user_data_func_t)  (void *obj, hb_user_data_key_t *key);
Packit Service 5bcba8
typedef void      (*make_immutable_func_t) (void *obj);
Packit Service 5bcba8
typedef hb_bool_t (*is_immutable_func_t)   (void *obj);
Packit Service 5bcba8
Packit Service 5bcba8
typedef struct {
Packit Service 5bcba8
  create_func_t          create;
Packit Service 5bcba8
  create_func_t          create_from_inert;
Packit Service 5bcba8
  create_func_t          get_empty;
Packit Service 5bcba8
  reference_func_t       reference;
Packit Service 5bcba8
  destroy_func_t         destroy;
Packit Service 5bcba8
  set_user_data_func_t   set_user_data;
Packit Service 5bcba8
  get_user_data_func_t   get_user_data;
Packit Service 5bcba8
  make_immutable_func_t  make_immutable;
Packit Service 5bcba8
  is_immutable_func_t    is_immutable;
Packit Service 5bcba8
  const char            *name;
Packit Service 5bcba8
} object_t;
Packit Service 5bcba8
Packit Service 5bcba8
#define OBJECT_WITHOUT_IMMUTABILITY(name) \
Packit Service 5bcba8
  { \
Packit Service 5bcba8
    (create_func_t)         create_##name, \
Packit Service 5bcba8
    (create_func_t)         create_##name##_from_inert, \
Packit Service 5bcba8
    (create_func_t)         hb_##name##_get_empty, \
Packit Service 5bcba8
    (reference_func_t)      hb_##name##_reference, \
Packit Service 5bcba8
    (destroy_func_t)        hb_##name##_destroy, \
Packit Service 5bcba8
    (set_user_data_func_t)  hb_##name##_set_user_data, \
Packit Service 5bcba8
    (get_user_data_func_t)  hb_##name##_get_user_data, \
Packit Service 5bcba8
    (make_immutable_func_t) NULL, \
Packit Service 5bcba8
    (is_immutable_func_t)   NULL, \
Packit Service 5bcba8
    #name, \
Packit Service 5bcba8
  }
Packit Service 5bcba8
#define OBJECT_WITH_IMMUTABILITY(name) \
Packit Service 5bcba8
  { \
Packit Service 5bcba8
    (create_func_t)         create_##name, \
Packit Service 5bcba8
    (create_func_t)         create_##name##_from_inert, \
Packit Service 5bcba8
    (create_func_t)         hb_##name##_get_empty, \
Packit Service 5bcba8
    (reference_func_t)      hb_##name##_reference, \
Packit Service 5bcba8
    (destroy_func_t)        hb_##name##_destroy, \
Packit Service 5bcba8
    (set_user_data_func_t)  hb_##name##_set_user_data, \
Packit Service 5bcba8
    (get_user_data_func_t)  hb_##name##_get_user_data, \
Packit Service 5bcba8
    (make_immutable_func_t) hb_##name##_make_immutable, \
Packit Service 5bcba8
    (is_immutable_func_t)   hb_##name##_is_immutable, \
Packit Service 5bcba8
    #name, \
Packit Service 5bcba8
  }
Packit Service 5bcba8
static const object_t objects[] =
Packit Service 5bcba8
{
Packit Service 5bcba8
  OBJECT_WITHOUT_IMMUTABILITY (buffer),
Packit Service 5bcba8
  OBJECT_WITHOUT_IMMUTABILITY (set),
Packit Service 5bcba8
  OBJECT_WITH_IMMUTABILITY (blob),
Packit Service 5bcba8
  OBJECT_WITH_IMMUTABILITY (face),
Packit Service 5bcba8
  OBJECT_WITH_IMMUTABILITY (font),
Packit Service 5bcba8
  OBJECT_WITH_IMMUTABILITY (font_funcs),
Packit Service 5bcba8
  OBJECT_WITH_IMMUTABILITY (unicode_funcs)
Packit Service 5bcba8
};
Packit Service 5bcba8
#undef OBJECT
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
#define MAGIC0 0x12345678
Packit Service 5bcba8
#define MAGIC1 0x76543210
Packit Service 5bcba8
Packit Service 5bcba8
typedef struct {
Packit Service 5bcba8
  int value;
Packit Service 5bcba8
  gboolean freed;
Packit Service 5bcba8
} data_t;
Packit Service 5bcba8
Packit Service 5bcba8
static int global_data;
Packit Service 5bcba8
Packit Service 5bcba8
static void global_free_up (void *p G_GNUC_UNUSED)
Packit Service 5bcba8
{
Packit Service 5bcba8
  global_data++;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void free_up0 (void *p)
Packit Service 5bcba8
{
Packit Service 5bcba8
  data_t *data = (data_t *) p;
Packit Service 5bcba8
Packit Service 5bcba8
  g_assert_cmphex (data->value, ==, MAGIC0);
Packit Service 5bcba8
  g_assert (!data->freed);
Packit Service 5bcba8
  data->freed = TRUE;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static void free_up1 (void *p)
Packit Service 5bcba8
{
Packit Service 5bcba8
  data_t *data = (data_t *) p;
Packit Service 5bcba8
Packit Service 5bcba8
  g_assert_cmphex (data->value, ==, MAGIC1);
Packit Service 5bcba8
  g_assert (!data->freed);
Packit Service 5bcba8
  data->freed = TRUE;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
typedef struct {
Packit Service 5bcba8
  const object_t *klass;
Packit Service 5bcba8
  void *object;
Packit Service 5bcba8
  hb_user_data_key_t key;
Packit Service 5bcba8
} deadlock_test_t;
Packit Service 5bcba8
Packit Service 5bcba8
static void free_deadlock_test (void *p)
Packit Service 5bcba8
{
Packit Service 5bcba8
  deadlock_test_t *t = (deadlock_test_t *) p;
Packit Service 5bcba8
Packit Service 5bcba8
  g_assert (NULL == t->klass->get_user_data (t->object, &t->key));
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
static void
Packit Service 5bcba8
test_object (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  unsigned int i;
Packit Service 5bcba8
Packit Service 5bcba8
  for (i = 0; i < G_N_ELEMENTS (objects); i++) {
Packit Service 5bcba8
    const object_t *o = &objects[i];
Packit Service 5bcba8
    void *obj;
Packit Service 5bcba8
    hb_user_data_key_t key[1001];
Packit Service 5bcba8
Packit Service 5bcba8
    {
Packit Service 5bcba8
      unsigned int j;
Packit Service 5bcba8
      data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
Packit Service 5bcba8
      deadlock_test_t deadlock_test;
Packit Service 5bcba8
Packit Service 5bcba8
      g_test_message ("Testing object %s", o->name);
Packit Service 5bcba8
Packit Service 5bcba8
      g_test_message ("->create()");
Packit Service 5bcba8
      obj = o->create ();
Packit Service 5bcba8
      g_assert (obj);
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (obj == o->reference (obj));
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
Packit Service 5bcba8
      if (o->is_immutable)
Packit Service 5bcba8
	g_assert (!o->is_immutable (obj));
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
Packit Service 5bcba8
      g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
Packit Service 5bcba8
Packit Service 5bcba8
      if (o->is_immutable) {
Packit Service 5bcba8
	o->make_immutable (obj);
Packit Service 5bcba8
	g_assert (o->is_immutable (obj));
Packit Service 5bcba8
      }
Packit Service 5bcba8
Packit Service 5bcba8
      /* Should still work even if object is made immutable */
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1, TRUE));
Packit Service 5bcba8
      g_assert (o->get_user_data (obj, &key[1]) == &data[1]);
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0, TRUE));
Packit Service 5bcba8
      g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], &data[1], NULL, TRUE));
Packit Service 5bcba8
      g_assert (data[0].freed);
Packit Service 5bcba8
      g_assert (o->get_user_data (obj, &key[0]) == &data[1]);
Packit Service 5bcba8
      g_assert (!data[1].freed);
Packit Service 5bcba8
Packit Service 5bcba8
      data[0].freed = FALSE;
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
Packit Service 5bcba8
      g_assert (!data[0].freed);
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
Packit Service 5bcba8
      g_assert (data[0].freed);
Packit Service 5bcba8
Packit Service 5bcba8
      data[0].freed = FALSE;
Packit Service 5bcba8
      global_data = 0;
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
Packit Service 5bcba8
      g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, FALSE));
Packit Service 5bcba8
      g_assert_cmpuint (global_data, ==, 0);
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up, TRUE));
Packit Service 5bcba8
      g_assert_cmpuint (global_data, ==, 0);
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
Packit Service 5bcba8
      g_assert_cmpuint (global_data, ==, 1);
Packit Service 5bcba8
Packit Service 5bcba8
      global_data = 0;
Packit Service 5bcba8
      for (j = 2; j < 1000; j++)
Packit Service 5bcba8
	g_assert (o->set_user_data (obj, &key[j], &data[j], global_free_up, TRUE));
Packit Service 5bcba8
      for (j = 2; j < 1000; j++)
Packit Service 5bcba8
	g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
Packit Service 5bcba8
      for (j = 100; j < 1000; j++)
Packit Service 5bcba8
	g_assert (o->set_user_data (obj, &key[j], NULL, NULL, TRUE));
Packit Service 5bcba8
      for (j = 2; j < 100; j++)
Packit Service 5bcba8
	g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
Packit Service 5bcba8
      for (j = 100; j < 1000; j++)
Packit Service 5bcba8
	g_assert (!o->get_user_data (obj, &key[j]));
Packit Service 5bcba8
      g_assert_cmpuint (global_data, ==, 900);
Packit Service 5bcba8
Packit Service 5bcba8
      /* Test set_user_data where the destroy() func calls user_data functions.
Packit Service 5bcba8
       * Make sure it doesn't deadlock or corrupt memory. */
Packit Service 5bcba8
      deadlock_test.klass = o;
Packit Service 5bcba8
      deadlock_test.object = obj;
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &deadlock_test.key, &deadlock_test, free_deadlock_test, TRUE));
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &deadlock_test.key, NULL, NULL, TRUE));
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (!data[1].freed);
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
      g_assert (data[0].freed);
Packit Service 5bcba8
      g_assert (data[1].freed);
Packit Service 5bcba8
      g_assert_cmpuint (global_data, ==, 1000-2);
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    {
Packit Service 5bcba8
      data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
Packit Service 5bcba8
Packit Service 5bcba8
      g_test_message ("->get_empty()");
Packit Service 5bcba8
      obj = o->get_empty ();
Packit Service 5bcba8
      g_assert (obj);
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (obj == o->reference (obj));
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
Packit Service 5bcba8
      if (o->is_immutable)
Packit Service 5bcba8
	g_assert (o->is_immutable (obj));
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
Packit Service 5bcba8
      g_assert (!o->get_user_data (obj, &key[0]));
Packit Service 5bcba8
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (!data[0].freed);
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    {
Packit Service 5bcba8
      data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
Packit Service 5bcba8
Packit Service 5bcba8
      g_test_message ("->create_from_inert()");
Packit Service 5bcba8
      obj = o->create_from_inert ();
Packit Service 5bcba8
      if (!obj)
Packit Service 5bcba8
	continue;
Packit Service 5bcba8
      if (obj == o->get_empty ())
Packit Service 5bcba8
        continue; /* Tested already */
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (obj == o->reference (obj));
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
Packit Service 5bcba8
      if (o->is_immutable)
Packit Service 5bcba8
	g_assert (!o->is_immutable (obj));
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
Packit Service 5bcba8
      g_assert (o->get_user_data (obj, &key[0]));
Packit Service 5bcba8
Packit Service 5bcba8
      o->destroy (obj);
Packit Service 5bcba8
Packit Service 5bcba8
      g_assert (data[0].freed);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
int
Packit Service 5bcba8
main (int argc, char **argv)
Packit Service 5bcba8
{
Packit Service 5bcba8
  hb_test_init (&argc, &argv);
Packit Service 5bcba8
Packit Service 5bcba8
  hb_test_add (test_object);
Packit Service 5bcba8
Packit Service 5bcba8
  return hb_test_run ();
Packit Service 5bcba8
}