(root)/
harfbuzz-8.3.0/
test/
api/
test-blob.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-blob.h */
      30  
      31  #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) && defined(HAVE_MMAP)
      32  
      33  # define TEST_MMAP 1
      34  
      35  #ifdef HAVE_SYS_MMAN_H
      36  #ifdef HAVE_UNISTD_H
      37  #include <unistd.h>
      38  #endif /* HAVE_UNISTD_H */
      39  #include <sys/mman.h>
      40  #endif /* HAVE_SYS_MMAN_H */
      41  
      42  #endif
      43  
      44  
      45  static void
      46  test_blob_empty (void)
      47  {
      48    hb_blob_t *blob;
      49    unsigned int len;
      50    const char *data;
      51    char *data_writable;
      52  
      53    g_assert (hb_blob_is_immutable (hb_blob_get_empty ()));
      54    g_assert (hb_blob_get_empty () != NULL);
      55    g_assert (hb_blob_get_empty () == hb_blob_create (NULL, 0, HB_MEMORY_MODE_READONLY, NULL, NULL));
      56    g_assert (hb_blob_get_empty () == hb_blob_create ("asdf", 0, HB_MEMORY_MODE_READONLY, NULL, NULL));
      57    g_assert (hb_blob_get_empty () == hb_blob_create (NULL, -1, HB_MEMORY_MODE_READONLY, NULL, NULL));
      58    g_assert (hb_blob_get_empty () == hb_blob_create ("asdfg", -1, HB_MEMORY_MODE_READONLY, NULL, NULL));
      59  
      60    blob = hb_blob_get_empty ();
      61    g_assert (blob == hb_blob_get_empty ());
      62  
      63    len = hb_blob_get_length (blob);
      64    g_assert_cmpint (len, ==, 0);
      65  
      66    data = hb_blob_get_data (blob, NULL);
      67    g_assert (data == NULL);
      68  
      69    data = hb_blob_get_data (blob, &len);
      70    g_assert (data == NULL);
      71    g_assert_cmpint (len, ==, 0);
      72  
      73    data_writable = hb_blob_get_data_writable (blob, NULL);
      74    g_assert (data_writable == NULL);
      75  
      76    data_writable = hb_blob_get_data_writable (blob, &len);
      77    g_assert (data_writable == NULL);
      78    g_assert_cmpint (len, ==, 0);
      79  }
      80  
      81  static const char test_data[] = "test\0data";
      82  
      83  static const char *blob_names[] = {
      84    "duplicate",
      85    "readonly",
      86    "writable"
      87  #ifdef TEST_MMAP
      88     , "readonly-may-make-writable"
      89  #endif
      90  };
      91  
      92  typedef struct
      93  {
      94    hb_blob_t *blob;
      95    int freed;
      96    char *data;
      97    unsigned int len;
      98  } fixture_t;
      99  
     100  static void
     101  free_up (fixture_t *fixture)
     102  {
     103    g_assert_cmpint (fixture->freed, ==, 0);
     104    fixture->freed++;
     105  }
     106  
     107  static void
     108  free_up_free (fixture_t *fixture)
     109  {
     110    free_up (fixture);
     111    free (fixture->data);
     112  }
     113  
     114  
     115  #ifdef TEST_MMAP
     116  static uintptr_t
     117  get_pagesize (void)
     118  {
     119    uintptr_t pagesize = (uintptr_t) -1;
     120  
     121  #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
     122    pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
     123  #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
     124    pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
     125  #elif defined(HAVE_GETPAGESIZE)
     126    pagesize = (uintptr_t) getpagesize ();
     127  #endif
     128  
     129    g_assert (pagesize != (uintptr_t) -1);
     130  
     131    return pagesize;
     132  }
     133  
     134  static void
     135  free_up_munmap (fixture_t *fixture)
     136  {
     137    free_up (fixture);
     138    munmap (fixture->data, get_pagesize ());
     139  }
     140  #endif
     141  
     142  #include <errno.h>
     143  static void
     144  fixture_init (fixture_t *fixture, gconstpointer user_data)
     145  {
     146    hb_memory_mode_t mm = (hb_memory_mode_t) GPOINTER_TO_INT (user_data);
     147    unsigned int len;
     148    const char *data;
     149    hb_destroy_func_t free_func;
     150  
     151    switch (GPOINTER_TO_INT (user_data))
     152    {
     153      case HB_MEMORY_MODE_DUPLICATE:
     154        data = test_data;
     155        len = sizeof (test_data);
     156        free_func = (hb_destroy_func_t) free_up;
     157        break;
     158  
     159      case HB_MEMORY_MODE_READONLY:
     160        data = test_data;
     161        len = sizeof (test_data);
     162        free_func = (hb_destroy_func_t) free_up;
     163        break;
     164  
     165      case HB_MEMORY_MODE_WRITABLE:
     166        data = malloc (sizeof (test_data));
     167        memcpy ((char *) data, test_data, sizeof (test_data));
     168        len = sizeof (test_data);
     169        free_func = (hb_destroy_func_t) free_up_free;
     170        break;
     171  
     172  #ifdef TEST_MMAP
     173      case HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE:
     174      {
     175        uintptr_t pagesize = get_pagesize ();
     176  
     177        data = mmap (NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     178        g_assert (data != (char *) -1);
     179        memcpy ((char *) data, test_data, sizeof (test_data));
     180        mprotect ((char *) data, pagesize, PROT_READ);
     181        len = sizeof (test_data);
     182        free_func = (hb_destroy_func_t) free_up_munmap;
     183        break;
     184      }
     185  #endif
     186  
     187      default:
     188        g_assert_not_reached ();
     189    }
     190  
     191    fixture->freed = 0;
     192    fixture->data = (char *) data;
     193    fixture->len = len;
     194    fixture->blob = hb_blob_create (data, len, mm, fixture, free_func);
     195  }
     196  
     197  static void
     198  fixture_finish (fixture_t *fixture, gconstpointer user_data HB_UNUSED)
     199  {
     200    hb_blob_destroy (fixture->blob);
     201    g_assert_cmpint (fixture->freed, ==, 1);
     202  }
     203  
     204  
     205  static void
     206  test_blob (fixture_t *fixture, gconstpointer user_data)
     207  {
     208    hb_blob_t *b = fixture->blob;
     209    hb_memory_mode_t mm = GPOINTER_TO_INT (user_data);
     210    unsigned int len;
     211    const char *data;
     212    char *data_writable;
     213    unsigned int i;
     214  
     215    g_assert (b);
     216  
     217    len = hb_blob_get_length (b);
     218    g_assert_cmpint (len, ==, fixture->len);
     219  
     220    data = hb_blob_get_data (b, &len);
     221    g_assert_cmpint (len, ==, fixture->len);
     222    if (mm == HB_MEMORY_MODE_DUPLICATE) {
     223      g_assert (data != fixture->data);
     224      g_assert_cmpint (fixture->freed, ==, 1);
     225      mm = HB_MEMORY_MODE_WRITABLE;
     226    } else {
     227      g_assert (data == fixture->data);
     228      g_assert_cmpint (fixture->freed, ==, 0);
     229    }
     230  
     231    data_writable = hb_blob_get_data_writable (b, &len);
     232    g_assert_cmpint (len, ==, fixture->len);
     233    g_assert (data_writable);
     234    g_assert (0 == memcmp (data_writable, fixture->data, fixture->len));
     235    if (mm == HB_MEMORY_MODE_READONLY) {
     236      g_assert (data_writable != data);
     237      g_assert_cmpint (fixture->freed, ==, 1);
     238    } else {
     239      g_assert (data_writable == data);
     240    }
     241  
     242    data = hb_blob_get_data (b, &len);
     243    g_assert_cmpint (len, ==, fixture->len);
     244    g_assert (data == data_writable);
     245  
     246    memset (data_writable, 0, fixture->len);
     247  
     248    /* Now, make it immutable and watch get_data_writable() fail */
     249  
     250    g_assert (!hb_blob_is_immutable (b));
     251    hb_blob_make_immutable (b);
     252    g_assert (hb_blob_is_immutable (b));
     253  
     254    data_writable = hb_blob_get_data_writable (b, &len);
     255    g_assert (!data_writable);
     256    g_assert_cmpint (len, ==, 0);
     257  
     258    data = hb_blob_get_data (b, &len);
     259    g_assert_cmpint (len, ==, fixture->len);
     260    for (i = 0; i < len; i++)
     261      g_assert ('\0' == data[i]);
     262  }
     263  
     264  static void
     265  test_blob_subblob (fixture_t *fixture, gconstpointer user_data)
     266  {
     267    hb_blob_t *b = fixture->blob;
     268    hb_memory_mode_t mm = GPOINTER_TO_INT (user_data);
     269    unsigned int len;
     270    const char *data;
     271    char *data_writable;
     272    unsigned int i;
     273  
     274    if (mm == HB_MEMORY_MODE_DUPLICATE) {
     275      g_assert_cmpint (fixture->freed, ==, 1);
     276      fixture->data = (char *) hb_blob_get_data (b, NULL);
     277    } else {
     278      g_assert_cmpint (fixture->freed, ==, 0);
     279    }
     280    fixture->blob = hb_blob_create_sub_blob (b, 1, fixture->len - 2);
     281    hb_blob_destroy (b);
     282    b = fixture->blob;
     283  
     284    /* A sub-blob is always created READONLY. */
     285  
     286    g_assert (b);
     287  
     288    len = hb_blob_get_length (b);
     289    g_assert_cmpint (len, ==, fixture->len - 2);
     290  
     291    data = hb_blob_get_data (b, &len);
     292    g_assert_cmpint (len, ==, fixture->len - 2);
     293    g_assert (data == fixture->data + 1);
     294  
     295    data_writable = hb_blob_get_data_writable (b, &len);
     296    g_assert_cmpint (len, ==, fixture->len - 2);
     297    g_assert (data_writable);
     298    if (mm == HB_MEMORY_MODE_READONLY)
     299      g_assert (0 == memcmp (data_writable, fixture->data + 1, fixture->len - 2));
     300    g_assert (data_writable != data);
     301    g_assert_cmpint (fixture->freed, ==, 1);
     302  
     303    data = hb_blob_get_data (b, &len);
     304    g_assert_cmpint (len, ==, fixture->len - 2);
     305    g_assert (data == data_writable);
     306  
     307    memset (data_writable, 0, fixture->len - 2);
     308  
     309    /* Now, make it immutable and watch get_data_writable() fail */
     310  
     311    g_assert (!hb_blob_is_immutable (b));
     312    hb_blob_make_immutable (b);
     313    g_assert (hb_blob_is_immutable (b));
     314  
     315    data_writable = hb_blob_get_data_writable (b, &len);
     316    g_assert (!data_writable);
     317    g_assert_cmpint (len, ==, 0);
     318  
     319    data = hb_blob_get_data (b, &len);
     320    g_assert_cmpint (len, ==, fixture->len - 2);
     321    for (i = 0; i < len; i++)
     322      g_assert ('\0' == data[i]);
     323  }
     324  
     325  
     326  int
     327  main (int argc, char **argv)
     328  {
     329    unsigned int i;
     330  
     331    hb_test_init (&argc, &argv);
     332  
     333    hb_test_add (test_blob_empty);
     334  
     335    for (i = 0; i < G_N_ELEMENTS (blob_names); i++)
     336    {
     337      const void *blob_type = GINT_TO_POINTER (i);
     338      const char *blob_name = blob_names[i];
     339  
     340      hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob);
     341      hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob_subblob);
     342    }
     343  
     344    /*
     345     * create_sub_blob
     346     */
     347  
     348    return hb_test_run ();
     349  }