[API] Add version macros and functions
[apps/home/video-player.git] / test / test-buffer.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-buffer.h */
30
31
32 static const char utf8[10] = "ab\360\240\200\200defg";
33 static const uint16_t utf16[8] = {'a', 'b', 0xD840, 0xDC00, 'd', 'e', 'f', 'g'};
34 static const uint32_t utf32[7] = {'a', 'b', 0x20000, 'd', 'e', 'f', 'g'};
35
36
37 typedef enum {
38   BUFFER_EMPTY,
39   BUFFER_ONE_BY_ONE,
40   BUFFER_UTF32,
41   BUFFER_UTF16,
42   BUFFER_UTF8,
43   BUFFER_NUM_TYPES,
44 } buffer_type_t;
45
46 static const char *buffer_names[] = {
47   "empty",
48   "one-by-one",
49   "utf32",
50   "utf16",
51   "utf8"
52 };
53
54 typedef struct
55 {
56   hb_buffer_t *b;
57 } fixture_t;
58
59 static void
60 fixture_init (fixture_t *fixture, gconstpointer user_data)
61 {
62   unsigned int i;
63
64   fixture->b = hb_buffer_create (0);
65
66   switch (GPOINTER_TO_INT (user_data)) {
67     case BUFFER_EMPTY:
68       break;
69
70     case BUFFER_ONE_BY_ONE:
71       for (i = 1; i < G_N_ELEMENTS (utf32) - 1; i++)
72         hb_buffer_add (fixture->b, utf32[i], 1, i);
73       break;
74
75     case BUFFER_UTF32:
76       hb_buffer_add_utf32 (fixture->b, utf32, G_N_ELEMENTS (utf32), 1, G_N_ELEMENTS (utf32) - 2);
77       break;
78
79     case BUFFER_UTF16:
80       hb_buffer_add_utf16 (fixture->b, utf16, G_N_ELEMENTS (utf16), 1, G_N_ELEMENTS (utf16) - 2);
81       break;
82
83     case BUFFER_UTF8:
84       hb_buffer_add_utf8  (fixture->b, utf8,  G_N_ELEMENTS (utf8),  1, G_N_ELEMENTS (utf8)  - 2);
85       break;
86
87     default:
88       g_assert_not_reached ();
89   }
90 }
91
92 static void
93 fixture_finish (fixture_t *fixture, gconstpointer user_data)
94 {
95   hb_buffer_destroy (fixture->b);
96 }
97
98
99 static void
100 test_buffer_properties (fixture_t *fixture, gconstpointer user_data)
101 {
102   hb_unicode_funcs_t *ufuncs;
103
104   /* test default properties */
105
106   g_assert (hb_buffer_get_unicode_funcs (fixture->b) == hb_unicode_funcs_get_default ());
107   g_assert (hb_buffer_get_direction (fixture->b) == HB_DIRECTION_INVALID);
108   g_assert (hb_buffer_get_script (fixture->b) == HB_SCRIPT_INVALID);
109   g_assert (hb_buffer_get_language (fixture->b) == NULL);
110
111
112   /* test property changes are retained */
113   ufuncs = hb_unicode_funcs_create (NULL);
114   hb_buffer_set_unicode_funcs (fixture->b, ufuncs);
115   hb_unicode_funcs_destroy (ufuncs);
116   g_assert (hb_buffer_get_unicode_funcs (fixture->b) == ufuncs);
117
118   hb_buffer_set_direction (fixture->b, HB_DIRECTION_RTL);
119   g_assert (hb_buffer_get_direction (fixture->b) == HB_DIRECTION_RTL);
120
121   hb_buffer_set_script (fixture->b, HB_SCRIPT_ARABIC);
122   g_assert (hb_buffer_get_script (fixture->b) == HB_SCRIPT_ARABIC);
123
124   hb_buffer_set_language (fixture->b, hb_language_from_string ("fa"));
125   g_assert (hb_buffer_get_language (fixture->b) == hb_language_from_string ("Fa"));
126
127
128   /* test reset clears properties */
129
130   hb_buffer_reset (fixture->b);
131
132   g_assert (hb_buffer_get_unicode_funcs (fixture->b) == hb_unicode_funcs_get_default ());
133   g_assert (hb_buffer_get_direction (fixture->b) == HB_DIRECTION_INVALID);
134   g_assert (hb_buffer_get_script (fixture->b) == HB_SCRIPT_INVALID);
135   g_assert (hb_buffer_get_language (fixture->b) == NULL);
136 }
137
138 static void
139 test_buffer_contents (fixture_t *fixture, gconstpointer user_data)
140 {
141   unsigned int i, len, len2;
142   buffer_type_t buffer_type = GPOINTER_TO_INT (user_data);
143   hb_glyph_info_t *glyphs;
144
145   if (buffer_type == BUFFER_EMPTY) {
146     g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 0);
147     return;
148   }
149
150   len = hb_buffer_get_length (fixture->b);
151   glyphs = hb_buffer_get_glyph_infos (fixture->b, NULL); /* test NULL */
152   glyphs = hb_buffer_get_glyph_infos (fixture->b, &len2);
153   g_assert_cmpint (len, ==, len2);
154   g_assert_cmpint (len, ==, 5);
155
156   for (i = 0; i < len; i++) {
157     g_assert_cmphex (glyphs[i].mask,      ==, 1);
158     g_assert_cmphex (glyphs[i].var1.u32,  ==, 0);
159     g_assert_cmphex (glyphs[i].var2.u32,  ==, 0);
160   }
161
162   for (i = 0; i < len; i++) {
163     unsigned int cluster;
164     cluster = 1+i;
165     if (i >= 2) {
166       if (buffer_type == BUFFER_UTF16)
167         cluster++;
168       else if (buffer_type == BUFFER_UTF8)
169         cluster += 3;
170     }
171     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
172     g_assert_cmphex (glyphs[i].cluster,   ==, cluster);
173   }
174
175   /* reverse, test, and reverse back */
176
177   hb_buffer_reverse (fixture->b);
178   for (i = 0; i < len; i++)
179     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]);
180
181   hb_buffer_reverse (fixture->b);
182   for (i = 0; i < len; i++)
183     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
184
185   /* reverse_clusters works same as reverse for now since each codepoint is
186    * in its own cluster */
187
188   hb_buffer_reverse_clusters (fixture->b);
189   for (i = 0; i < len; i++)
190     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]);
191
192   hb_buffer_reverse_clusters (fixture->b);
193   for (i = 0; i < len; i++)
194     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
195
196   /* now form a cluster and test again */
197   glyphs[2].cluster = glyphs[1].cluster;
198
199   /* reverse, test, and reverse back */
200
201   hb_buffer_reverse (fixture->b);
202   for (i = 0; i < len; i++)
203     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]);
204
205   hb_buffer_reverse (fixture->b);
206   for (i = 0; i < len; i++)
207     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
208
209   /* reverse_clusters twice still should return the original string,
210    * but when applied once, the 1-2 cluster should be retained. */
211
212   hb_buffer_reverse_clusters (fixture->b);
213   for (i = 0; i < len; i++) {
214     unsigned int j = len-1-i;
215     if (j == 1)
216       j = 2;
217     else if (j == 2)
218       j = 1;
219     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+j]);
220   }
221
222   hb_buffer_reverse_clusters (fixture->b);
223   for (i = 0; i < len; i++)
224     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
225
226
227   /* test setting length */
228
229   /* enlarge */
230   g_assert (hb_buffer_set_length (fixture->b, 10));
231   glyphs = hb_buffer_get_glyph_infos (fixture->b, NULL);
232   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 10);
233   for (i = 0; i < 5; i++)
234     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
235   for (i = 5; i < 10; i++)
236     g_assert_cmphex (glyphs[i].codepoint, ==, 0);
237   /* shrink */
238   g_assert (hb_buffer_set_length (fixture->b, 3));
239   glyphs = hb_buffer_get_glyph_infos (fixture->b, NULL);
240   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 3);
241   for (i = 0; i < 3; i++)
242     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
243
244
245   g_assert (hb_buffer_allocation_successful (fixture->b));
246
247
248   /* test reset clears content */
249
250   hb_buffer_reset (fixture->b);
251   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 0);
252 }
253
254 static void
255 test_buffer_positions (fixture_t *fixture, gconstpointer user_data)
256 {
257   unsigned int i, len, len2;
258   hb_glyph_position_t *positions;
259
260   /* Without shaping, positions should all be zero */
261   len = hb_buffer_get_length (fixture->b);
262   positions = hb_buffer_get_glyph_positions (fixture->b, NULL); /* test NULL */
263   positions = hb_buffer_get_glyph_positions (fixture->b, &len2);
264   g_assert_cmpint (len, ==, len2);
265   for (i = 0; i < len; i++) {
266     g_assert_cmpint (0, ==, positions[i].x_advance);
267     g_assert_cmpint (0, ==, positions[i].y_advance);
268     g_assert_cmpint (0, ==, positions[i].x_offset);
269     g_assert_cmpint (0, ==, positions[i].y_offset);
270     g_assert_cmpint (0, ==, positions[i].var.i32);
271   }
272
273   /* test reset clears content */
274   hb_buffer_reset (fixture->b);
275   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 0);
276 }
277
278 static void
279 test_buffer_allocation (fixture_t *fixture, gconstpointer user_data)
280 {
281   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 0);
282
283   g_assert (hb_buffer_pre_allocate (fixture->b, 100));
284   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 0);
285   g_assert (hb_buffer_allocation_successful (fixture->b));
286
287   /* lets try a huge allocation, make sure it fails */
288   g_assert (!hb_buffer_pre_allocate (fixture->b, (unsigned int) -1));
289   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 0);
290   g_assert (!hb_buffer_allocation_successful (fixture->b));
291
292   /* small one again */
293   g_assert (hb_buffer_pre_allocate (fixture->b, 50));
294   g_assert_cmpint (hb_buffer_get_length (fixture->b), ==, 0);
295   g_assert (!hb_buffer_allocation_successful (fixture->b));
296
297   hb_buffer_reset (fixture->b);
298   g_assert (hb_buffer_allocation_successful (fixture->b));
299
300   /* all allocation and size  */
301   g_assert (!hb_buffer_pre_allocate (fixture->b, ((unsigned int) -1) / 20 + 1));
302   g_assert (!hb_buffer_allocation_successful (fixture->b));
303
304   hb_buffer_reset (fixture->b);
305   g_assert (hb_buffer_allocation_successful (fixture->b));
306
307   /* technically, this one can actually pass on 64bit machines, but
308    * I'm doubtful that any malloc allows 4GB allocations at a time.
309    * But let's only enable it on a 32-bit machine. */
310   if (sizeof (long) == 4) {
311     g_assert (!hb_buffer_pre_allocate (fixture->b, ((unsigned int) -1) / 20 - 1));
312     g_assert (!hb_buffer_allocation_successful (fixture->b));
313   }
314
315   hb_buffer_reset (fixture->b);
316   g_assert (hb_buffer_allocation_successful (fixture->b));
317 }
318
319
320 typedef struct {
321   const char utf8[8];
322   const uint32_t codepoints[8];
323 } utf8_conversion_test_t;
324
325 /* note: we skip the first and last byte when adding to buffer */
326 static const utf8_conversion_test_t utf8_conversion_tests[] = {
327   {"a\303\207", {-1}},
328   {"a\303\207b", {0xC7}},
329   {"ab\303cd", {'b', -1, 'c'}},
330   {"ab\303\302\301cd", {'b', -1, -1, -1, 'c'}}
331 };
332
333 static void
334 test_buffer_utf8_conversion (void)
335 {
336   hb_buffer_t *b;
337   hb_glyph_info_t *glyphs;
338   unsigned int bytes, chars, i, j, len;
339
340   b = hb_buffer_create (0);
341
342   for (i = 0; i < G_N_ELEMENTS (utf8_conversion_tests); i++)
343   {
344     const utf8_conversion_test_t *test = &utf8_conversion_tests[i];
345     char *escaped;
346
347     escaped = g_strescape (test->utf8, NULL);
348     g_test_message ("UTF-8 test #%d: %s", i, escaped);
349     g_free (escaped);
350
351     bytes = strlen (test->utf8);
352     for (chars = 0; test->codepoints[chars]; chars++)
353       ;
354
355     hb_buffer_reset (b);
356     hb_buffer_add_utf8 (b, test->utf8, bytes,  1, bytes - 2);
357
358     glyphs = hb_buffer_get_glyph_infos (b, &len);
359     g_assert_cmpint (len, ==, chars);
360     for (j = 0; j < chars; j++)
361       g_assert_cmphex (glyphs[j].codepoint, ==, test->codepoints[j]);
362   }
363
364   hb_buffer_destroy (b);
365 }
366
367
368
369 /* Following test table is adapted from glib/glib/tests/utf8-validate.c
370  * with relicensing permission from Matthias Clasen. */
371
372 typedef struct {
373   const char *utf8;
374   int max_len;
375   unsigned int offset;
376   gboolean valid;
377 } utf8_validity_test_t;
378
379 static const utf8_validity_test_t utf8_validity_tests[] = {
380   /* some tests to check max_len handling */
381   /* length 1 */
382   { "abcde", -1, 5, TRUE },
383   { "abcde", 3, 3, TRUE },
384   { "abcde", 5, 5, TRUE },
385   /* length 2 */
386   { "\xc2\xa9\xc2\xa9\xc2\xa9", -1, 6, TRUE },
387   { "\xc2\xa9\xc2\xa9\xc2\xa9",  1, 0, FALSE },
388   { "\xc2\xa9\xc2\xa9\xc2\xa9",  2, 2, TRUE },
389   { "\xc2\xa9\xc2\xa9\xc2\xa9",  3, 2, FALSE },
390   { "\xc2\xa9\xc2\xa9\xc2\xa9",  4, 4, TRUE },
391   { "\xc2\xa9\xc2\xa9\xc2\xa9",  5, 4, FALSE },
392   { "\xc2\xa9\xc2\xa9\xc2\xa9",  6, 6, TRUE },
393   /* length 3 */
394   { "\xe2\x89\xa0\xe2\x89\xa0", -1, 6, TRUE },
395   { "\xe2\x89\xa0\xe2\x89\xa0",  1, 0, FALSE },
396   { "\xe2\x89\xa0\xe2\x89\xa0",  2, 0, FALSE },
397   { "\xe2\x89\xa0\xe2\x89\xa0",  3, 3, TRUE },
398   { "\xe2\x89\xa0\xe2\x89\xa0",  4, 3, FALSE },
399   { "\xe2\x89\xa0\xe2\x89\xa0",  5, 3, FALSE },
400   { "\xe2\x89\xa0\xe2\x89\xa0",  6, 6, TRUE },
401
402   /* examples from http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt */
403   /* greek 'kosme' */
404   { "\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5", -1, 11, TRUE },
405   /* first sequence of each length */
406   { "\x00", -1, 0, TRUE },
407   { "\xc2\x80", -1, 2, TRUE },
408   { "\xe0\xa0\x80", -1, 3, TRUE },
409   { "\xf0\x90\x80\x80", -1, 4, TRUE },
410   { "\xf8\x88\x80\x80\x80", -1, 0, FALSE },
411   { "\xfc\x84\x80\x80\x80\x80", -1, 0, FALSE },
412   /* last sequence of each length */
413   { "\x7f", -1, 1, TRUE },
414   { "\xdf\xbf", -1, 2, TRUE },
415   { "\xef\xbf\xbf", -1, 0, TRUE },
416   { "\xf7\xbf\xbf\xbf", -1, 0, TRUE },
417   { "\xfb\xbf\xbf\xbf\xbf", -1, 0, FALSE },
418   { "\xfd\xbf\xbf\xbf\xbf\xbf", -1, 0, FALSE },
419   /* other boundary conditions */
420   { "\xed\x9f\xbf", -1, 3, TRUE },
421   { "\xee\x80\x80", -1, 3, TRUE },
422   { "\xef\xbf\xbd", -1, 3, TRUE },
423   { "\xf4\x8f\xbf\xbf", -1, 0, TRUE },
424   /* malformed sequences */
425   /* continuation bytes */
426   { "\x80", -1, 0, FALSE },
427   { "\xbf", -1, 0, FALSE },
428   { "\x80\xbf", -1, 0, FALSE },
429   { "\x80\xbf\x80", -1, 0, FALSE },
430   { "\x80\xbf\x80\xbf", -1, 0, FALSE },
431   { "\x80\xbf\x80\xbf\x80", -1, 0, FALSE },
432   { "\x80\xbf\x80\xbf\x80\xbf", -1, 0, FALSE },
433   { "\x80\xbf\x80\xbf\x80\xbf\x80", -1, 0, FALSE },
434
435   /* all possible continuation byte */
436   { "\x80", -1, 0, FALSE },
437   { "\x81", -1, 0, FALSE },
438   { "\x82", -1, 0, FALSE },
439   { "\x83", -1, 0, FALSE },
440   { "\x84", -1, 0, FALSE },
441   { "\x85", -1, 0, FALSE },
442   { "\x86", -1, 0, FALSE },
443   { "\x87", -1, 0, FALSE },
444   { "\x88", -1, 0, FALSE },
445   { "\x89", -1, 0, FALSE },
446   { "\x8a", -1, 0, FALSE },
447   { "\x8b", -1, 0, FALSE },
448   { "\x8c", -1, 0, FALSE },
449   { "\x8d", -1, 0, FALSE },
450   { "\x8e", -1, 0, FALSE },
451   { "\x8f", -1, 0, FALSE },
452   { "\x90", -1, 0, FALSE },
453   { "\x91", -1, 0, FALSE },
454   { "\x92", -1, 0, FALSE },
455   { "\x93", -1, 0, FALSE },
456   { "\x94", -1, 0, FALSE },
457   { "\x95", -1, 0, FALSE },
458   { "\x96", -1, 0, FALSE },
459   { "\x97", -1, 0, FALSE },
460   { "\x98", -1, 0, FALSE },
461   { "\x99", -1, 0, FALSE },
462   { "\x9a", -1, 0, FALSE },
463   { "\x9b", -1, 0, FALSE },
464   { "\x9c", -1, 0, FALSE },
465   { "\x9d", -1, 0, FALSE },
466   { "\x9e", -1, 0, FALSE },
467   { "\x9f", -1, 0, FALSE },
468   { "\xa0", -1, 0, FALSE },
469   { "\xa1", -1, 0, FALSE },
470   { "\xa2", -1, 0, FALSE },
471   { "\xa3", -1, 0, FALSE },
472   { "\xa4", -1, 0, FALSE },
473   { "\xa5", -1, 0, FALSE },
474   { "\xa6", -1, 0, FALSE },
475   { "\xa7", -1, 0, FALSE },
476   { "\xa8", -1, 0, FALSE },
477   { "\xa9", -1, 0, FALSE },
478   { "\xaa", -1, 0, FALSE },
479   { "\xab", -1, 0, FALSE },
480   { "\xac", -1, 0, FALSE },
481   { "\xad", -1, 0, FALSE },
482   { "\xae", -1, 0, FALSE },
483   { "\xaf", -1, 0, FALSE },
484   { "\xb0", -1, 0, FALSE },
485   { "\xb1", -1, 0, FALSE },
486   { "\xb2", -1, 0, FALSE },
487   { "\xb3", -1, 0, FALSE },
488   { "\xb4", -1, 0, FALSE },
489   { "\xb5", -1, 0, FALSE },
490   { "\xb6", -1, 0, FALSE },
491   { "\xb7", -1, 0, FALSE },
492   { "\xb8", -1, 0, FALSE },
493   { "\xb9", -1, 0, FALSE },
494   { "\xba", -1, 0, FALSE },
495   { "\xbb", -1, 0, FALSE },
496   { "\xbc", -1, 0, FALSE },
497   { "\xbd", -1, 0, FALSE },
498   { "\xbe", -1, 0, FALSE },
499   { "\xbf", -1, 0, FALSE },
500   /* lone start characters */
501   { "\xc0\x20", -1, 0, FALSE },
502   { "\xc1\x20", -1, 0, FALSE },
503   { "\xc2\x20", -1, 0, FALSE },
504   { "\xc3\x20", -1, 0, FALSE },
505   { "\xc4\x20", -1, 0, FALSE },
506   { "\xc5\x20", -1, 0, FALSE },
507   { "\xc6\x20", -1, 0, FALSE },
508   { "\xc7\x20", -1, 0, FALSE },
509   { "\xc8\x20", -1, 0, FALSE },
510   { "\xc9\x20", -1, 0, FALSE },
511   { "\xca\x20", -1, 0, FALSE },
512   { "\xcb\x20", -1, 0, FALSE },
513   { "\xcc\x20", -1, 0, FALSE },
514   { "\xcd\x20", -1, 0, FALSE },
515   { "\xce\x20", -1, 0, FALSE },
516   { "\xcf\x20", -1, 0, FALSE },
517   { "\xd0\x20", -1, 0, FALSE },
518   { "\xd1\x20", -1, 0, FALSE },
519   { "\xd2\x20", -1, 0, FALSE },
520   { "\xd3\x20", -1, 0, FALSE },
521   { "\xd4\x20", -1, 0, FALSE },
522   { "\xd5\x20", -1, 0, FALSE },
523   { "\xd6\x20", -1, 0, FALSE },
524   { "\xd7\x20", -1, 0, FALSE },
525   { "\xd8\x20", -1, 0, FALSE },
526   { "\xd9\x20", -1, 0, FALSE },
527   { "\xda\x20", -1, 0, FALSE },
528   { "\xdb\x20", -1, 0, FALSE },
529   { "\xdc\x20", -1, 0, FALSE },
530   { "\xdd\x20", -1, 0, FALSE },
531   { "\xde\x20", -1, 0, FALSE },
532   { "\xdf\x20", -1, 0, FALSE },
533   { "\xe0\x20", -1, 0, FALSE },
534   { "\xe1\x20", -1, 0, FALSE },
535   { "\xe2\x20", -1, 0, FALSE },
536   { "\xe3\x20", -1, 0, FALSE },
537   { "\xe4\x20", -1, 0, FALSE },
538   { "\xe5\x20", -1, 0, FALSE },
539   { "\xe6\x20", -1, 0, FALSE },
540   { "\xe7\x20", -1, 0, FALSE },
541   { "\xe8\x20", -1, 0, FALSE },
542   { "\xe9\x20", -1, 0, FALSE },
543   { "\xea\x20", -1, 0, FALSE },
544   { "\xeb\x20", -1, 0, FALSE },
545   { "\xec\x20", -1, 0, FALSE },
546   { "\xed\x20", -1, 0, FALSE },
547   { "\xee\x20", -1, 0, FALSE },
548   { "\xef\x20", -1, 0, FALSE },
549   { "\xf0\x20", -1, 0, FALSE },
550   { "\xf1\x20", -1, 0, FALSE },
551   { "\xf2\x20", -1, 0, FALSE },
552   { "\xf3\x20", -1, 0, FALSE },
553   { "\xf4\x20", -1, 0, FALSE },
554   { "\xf5\x20", -1, 0, FALSE },
555   { "\xf6\x20", -1, 0, FALSE },
556   { "\xf7\x20", -1, 0, FALSE },
557   { "\xf8\x20", -1, 0, FALSE },
558   { "\xf9\x20", -1, 0, FALSE },
559   { "\xfa\x20", -1, 0, FALSE },
560   { "\xfb\x20", -1, 0, FALSE },
561   { "\xfc\x20", -1, 0, FALSE },
562   { "\xfd\x20", -1, 0, FALSE },
563   /* missing continuation bytes */
564   { "\x20\xc0", -1, 1, FALSE },
565   { "\x20\xe0\x80", -1, 1, FALSE },
566   { "\x20\xf0\x80\x80", -1, 1, FALSE },
567   { "\x20\xf8\x80\x80\x80", -1, 1, FALSE },
568   { "\x20\xfc\x80\x80\x80\x80", -1, 1, FALSE },
569   { "\x20\xdf", -1, 1, FALSE },
570   { "\x20\xef\xbf", -1, 1, FALSE },
571   { "\x20\xf7\xbf\xbf", -1, 1, FALSE },
572   { "\x20\xfb\xbf\xbf\xbf", -1, 1, FALSE },
573   { "\x20\xfd\xbf\xbf\xbf\xbf", -1, 1, FALSE },
574   /* impossible bytes */
575   { "\x20\xfe\x20", -1, 1, FALSE },
576   { "\x20\xff\x20", -1, 1, FALSE },
577 #if 0
578   /* XXX fix these, or document that we don't detect them? */
579   /* overlong sequences */
580   { "\x20\xc0\xaf\x20", -1, 1, FALSE },
581   { "\x20\xe0\x80\xaf\x20", -1, 1, FALSE },
582   { "\x20\xf0\x80\x80\xaf\x20", -1, 1, FALSE },
583   { "\x20\xf8\x80\x80\x80\xaf\x20", -1, 1, FALSE },
584   { "\x20\xfc\x80\x80\x80\x80\xaf\x20", -1, 1, FALSE },
585   { "\x20\xc1\xbf\x20", -1, 1, FALSE },
586   { "\x20\xe0\x9f\xbf\x20", -1, 1, FALSE },
587   { "\x20\xf0\x8f\xbf\xbf\x20", -1, 1, FALSE },
588   { "\x20\xf8\x87\xbf\xbf\xbf\x20", -1, 1, FALSE },
589   { "\x20\xfc\x83\xbf\xbf\xbf\xbf\x20", -1, 1, FALSE },
590   { "\x20\xc0\x80\x20", -1, 1, FALSE },
591   { "\x20\xe0\x80\x80\x20", -1, 1, FALSE },
592   { "\x20\xf0\x80\x80\x80\x20", -1, 1, FALSE },
593   { "\x20\xf8\x80\x80\x80\x80\x20", -1, 1, FALSE },
594   { "\x20\xfc\x80\x80\x80\x80\x80\x20", -1, 1, FALSE },
595   /* illegal code positions */
596   { "\x20\xed\xa0\x80\x20", -1, 1, FALSE },
597   { "\x20\xed\xad\xbf\x20", -1, 1, FALSE },
598   { "\x20\xed\xae\x80\x20", -1, 1, FALSE },
599   { "\x20\xed\xaf\xbf\x20", -1, 1, FALSE },
600   { "\x20\xed\xb0\x80\x20", -1, 1, FALSE },
601   { "\x20\xed\xbe\x80\x20", -1, 1, FALSE },
602   { "\x20\xed\xbf\xbf\x20", -1, 1, FALSE },
603   { "\x20\xed\xa0\x80\xed\xb0\x80\x20", -1, 1, FALSE },
604   { "\x20\xed\xa0\x80\xed\xbf\xbf\x20", -1, 1, FALSE },
605   { "\x20\xed\xad\xbf\xed\xb0\x80\x20", -1, 1, FALSE },
606   { "\x20\xed\xad\xbf\xed\xbf\xbf\x20", -1, 1, FALSE },
607   { "\x20\xed\xae\x80\xed\xb0\x80\x20", -1, 1, FALSE },
608   { "\x20\xed\xae\x80\xed\xbf\xbf\x20", -1, 1, FALSE },
609   { "\x20\xed\xaf\xbf\xed\xb0\x80\x20", -1, 1, FALSE },
610   { "\x20\xed\xaf\xbf\xed\xbf\xbf\x20", -1, 1, FALSE },
611   { "\x20\xef\xbf\xbe\x20", -1, 1, FALSE },
612   { "\x20\xef\xbf\xbf\x20", -1, 1, FALSE },
613 #endif
614   { "", -1, 0, TRUE }
615 };
616
617 static void
618 test_buffer_utf8_validity (void)
619 {
620   hb_buffer_t *b;
621   unsigned int i;
622
623   b = hb_buffer_create (0);
624
625   for (i = 0; i < G_N_ELEMENTS (utf8_validity_tests); i++)
626   {
627     const utf8_validity_test_t *test = &utf8_validity_tests[i];
628     unsigned int text_bytes, segment_bytes, j, len;
629     hb_glyph_info_t *glyphs;
630     char *escaped;
631
632     escaped = g_strescape (test->utf8, NULL);
633     g_test_message ("UTF-8 test #%d: %s", i, escaped);
634     g_free (escaped);
635
636     text_bytes = strlen (test->utf8);
637     if (test->max_len == -1)
638       segment_bytes = text_bytes;
639     else
640       segment_bytes = test->max_len;
641
642     hb_buffer_reset (b);
643     hb_buffer_add_utf8 (b, test->utf8, text_bytes,  0, segment_bytes);
644
645     glyphs = hb_buffer_get_glyph_infos (b, &len);
646     for (j = 0; j < len; j++)
647       if (glyphs[j].codepoint == (hb_codepoint_t) -1)
648         break;
649
650     g_assert (test->valid ? j == len : j < len);
651     if (!test->valid)
652       g_assert (glyphs[j].cluster == test->offset);
653   }
654
655   hb_buffer_destroy (b);
656 }
657
658
659 typedef struct {
660   const uint16_t utf16[8];
661   const uint32_t codepoints[8];
662 } utf16_conversion_test_t;
663
664 /* note: we skip the first and last item from utf16 when adding to buffer */
665 static const utf16_conversion_test_t utf16_conversion_tests[] = {
666   {{0x41, 0x004D, 0x0430, 0x4E8C, 0xD800, 0xDF02, 0x61} , {0x004D, 0x0430, 0x4E8C, 0x10302}},
667   {{0x41, 0xD800, 0xDF02, 0x61}, {0x10302}},
668   {{0x41, 0xD800, 0xDF02}, {-1}},
669   {{0x41, 0x61, 0xD800, 0xDF02}, {0x61, -1}},
670   {{0x41, 0xD800, 0x61, 0xDF02}, {-1, 0x61}},
671   {{0x41, 0x61}, {}}
672 };
673
674 static void
675 test_buffer_utf16_conversion (void)
676 {
677   hb_buffer_t *b;
678   unsigned int i;
679
680   b = hb_buffer_create (0);
681
682   for (i = 0; i < G_N_ELEMENTS (utf16_conversion_tests); i++)
683   {
684     const utf16_conversion_test_t *test = &utf16_conversion_tests[i];
685     unsigned int u_len, chars, j, len;
686     hb_glyph_info_t *glyphs;
687
688     g_test_message ("UTF-16 test #%d", i);
689
690     for (u_len = 0; test->utf16[u_len]; u_len++)
691       ;
692     for (chars = 0; test->codepoints[chars]; chars++)
693       ;
694
695     hb_buffer_reset (b);
696     hb_buffer_add_utf16 (b, test->utf16, u_len,  1, u_len - 2);
697
698     glyphs = hb_buffer_get_glyph_infos (b, &len);
699     g_assert_cmpint (len, ==, chars);
700     for (j = 0; j < chars; j++)
701       g_assert_cmphex (glyphs[j].codepoint, ==, test->codepoints[j]);
702   }
703
704   hb_buffer_destroy (b);
705 }
706
707
708 int
709 main (int argc, char **argv)
710 {
711   unsigned int i;
712
713   hb_test_init (&argc, &argv);
714
715   for (i = 0; i < BUFFER_NUM_TYPES; i++)
716   {
717     const void *buffer_type = GINT_TO_POINTER (i);
718     const char *buffer_name = buffer_names[i];
719
720     hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_properties);
721     hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_contents);
722     hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_positions);
723   }
724
725   hb_test_add_fixture (fixture, GINT_TO_POINTER (BUFFER_EMPTY), test_buffer_allocation);
726
727   hb_test_add (test_buffer_utf8_conversion);
728   hb_test_add (test_buffer_utf8_validity);
729   hb_test_add (test_buffer_utf16_conversion);
730
731   return hb_test_run();
732 }