Home | History | Annotate | Download | only in api
      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 = -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)
    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 }
    350