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