Imported Upstream version 0.9.35
[platform/upstream/harfbuzz.git] / 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
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 = (char *) 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 }