[test/buffer] Add UTF-16 tests
[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 /* This file tests types defined in 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_test_t;
324
325 /* note: we skip the first and last byte when adding to buffer */
326 static const utf8_test_t utf8_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 (gconstpointer user_data)
335 {
336   const utf8_test_t *test = user_data;
337   hb_buffer_t *b;
338   hb_glyph_info_t *glyphs;
339   unsigned int bytes, chars, i, len;
340
341   bytes = strlen (test->utf8);
342   for (chars = 0; test->codepoints[chars]; chars++)
343     ;
344
345   b = hb_buffer_create (0);
346   hb_buffer_add_utf8 (b, test->utf8, bytes,  1, bytes - 2);
347
348   glyphs = hb_buffer_get_glyph_infos (b, &len);
349   g_assert_cmpint (len, ==, chars);
350   for (i = 0; i < chars; i++)
351     g_assert_cmphex (glyphs[i].codepoint, ==, test->codepoints[i]);
352
353   hb_buffer_destroy (b);
354 }
355
356
357
358 /* Following test table is adapted from glib/glib/tests/utf8-validate.c
359  * with relicensing permission from Matthias Clasen. */
360
361 typedef struct {
362   const char *text;
363   int max_len;
364   unsigned int offset;
365   gboolean valid;
366 } utf8_validity_test_t;
367
368 static const utf8_validity_test_t utf8_validity_tests[] = {
369   /* some tests to check max_len handling */
370   /* length 1 */
371   { "abcde", -1, 5, TRUE },
372   { "abcde", 3, 3, TRUE },
373   { "abcde", 5, 5, TRUE },
374   /* length 2 */
375   { "\xc2\xa9\xc2\xa9\xc2\xa9", -1, 6, TRUE },
376   { "\xc2\xa9\xc2\xa9\xc2\xa9",  1, 0, FALSE },
377   { "\xc2\xa9\xc2\xa9\xc2\xa9",  2, 2, TRUE },
378   { "\xc2\xa9\xc2\xa9\xc2\xa9",  3, 2, FALSE },
379   { "\xc2\xa9\xc2\xa9\xc2\xa9",  4, 4, TRUE },
380   { "\xc2\xa9\xc2\xa9\xc2\xa9",  5, 4, FALSE },
381   { "\xc2\xa9\xc2\xa9\xc2\xa9",  6, 6, TRUE },
382   /* length 3 */
383   { "\xe2\x89\xa0\xe2\x89\xa0", -1, 6, TRUE },
384   { "\xe2\x89\xa0\xe2\x89\xa0",  1, 0, FALSE },
385   { "\xe2\x89\xa0\xe2\x89\xa0",  2, 0, FALSE },
386   { "\xe2\x89\xa0\xe2\x89\xa0",  3, 3, TRUE },
387   { "\xe2\x89\xa0\xe2\x89\xa0",  4, 3, FALSE },
388   { "\xe2\x89\xa0\xe2\x89\xa0",  5, 3, FALSE },
389   { "\xe2\x89\xa0\xe2\x89\xa0",  6, 6, TRUE },
390
391   /* examples from http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt */
392   /* greek 'kosme' */
393   { "\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5", -1, 11, TRUE },
394   /* first sequence of each length */
395   { "\x00", -1, 0, TRUE },
396   { "\xc2\x80", -1, 2, TRUE },
397   { "\xe0\xa0\x80", -1, 3, TRUE },
398   { "\xf0\x90\x80\x80", -1, 4, TRUE },
399   { "\xf8\x88\x80\x80\x80", -1, 0, FALSE },
400   { "\xfc\x84\x80\x80\x80\x80", -1, 0, FALSE },
401   /* last sequence of each length */
402   { "\x7f", -1, 1, TRUE },
403   { "\xdf\xbf", -1, 2, TRUE },
404   { "\xef\xbf\xbf", -1, 0, TRUE },
405   { "\xf7\xbf\xbf\xbf", -1, 0, TRUE },
406   { "\xfb\xbf\xbf\xbf\xbf", -1, 0, FALSE },
407   { "\xfd\xbf\xbf\xbf\xbf\xbf", -1, 0, FALSE },
408   /* other boundary conditions */
409   { "\xed\x9f\xbf", -1, 3, TRUE },
410   { "\xee\x80\x80", -1, 3, TRUE },
411   { "\xef\xbf\xbd", -1, 3, TRUE },
412   { "\xf4\x8f\xbf\xbf", -1, 0, TRUE },
413   /* malformed sequences */
414   /* continuation bytes */
415   { "\x80", -1, 0, FALSE },
416   { "\xbf", -1, 0, FALSE },
417   { "\x80\xbf", -1, 0, FALSE },
418   { "\x80\xbf\x80", -1, 0, FALSE },
419   { "\x80\xbf\x80\xbf", -1, 0, FALSE },
420   { "\x80\xbf\x80\xbf\x80", -1, 0, FALSE },
421   { "\x80\xbf\x80\xbf\x80\xbf", -1, 0, FALSE },
422   { "\x80\xbf\x80\xbf\x80\xbf\x80", -1, 0, FALSE },
423
424   /* all possible continuation byte */
425   { "\x80", -1, 0, FALSE },
426   { "\x81", -1, 0, FALSE },
427   { "\x82", -1, 0, FALSE },
428   { "\x83", -1, 0, FALSE },
429   { "\x84", -1, 0, FALSE },
430   { "\x85", -1, 0, FALSE },
431   { "\x86", -1, 0, FALSE },
432   { "\x87", -1, 0, FALSE },
433   { "\x88", -1, 0, FALSE },
434   { "\x89", -1, 0, FALSE },
435   { "\x8a", -1, 0, FALSE },
436   { "\x8b", -1, 0, FALSE },
437   { "\x8c", -1, 0, FALSE },
438   { "\x8d", -1, 0, FALSE },
439   { "\x8e", -1, 0, FALSE },
440   { "\x8f", -1, 0, FALSE },
441   { "\x90", -1, 0, FALSE },
442   { "\x91", -1, 0, FALSE },
443   { "\x92", -1, 0, FALSE },
444   { "\x93", -1, 0, FALSE },
445   { "\x94", -1, 0, FALSE },
446   { "\x95", -1, 0, FALSE },
447   { "\x96", -1, 0, FALSE },
448   { "\x97", -1, 0, FALSE },
449   { "\x98", -1, 0, FALSE },
450   { "\x99", -1, 0, FALSE },
451   { "\x9a", -1, 0, FALSE },
452   { "\x9b", -1, 0, FALSE },
453   { "\x9c", -1, 0, FALSE },
454   { "\x9d", -1, 0, FALSE },
455   { "\x9e", -1, 0, FALSE },
456   { "\x9f", -1, 0, FALSE },
457   { "\xa0", -1, 0, FALSE },
458   { "\xa1", -1, 0, FALSE },
459   { "\xa2", -1, 0, FALSE },
460   { "\xa3", -1, 0, FALSE },
461   { "\xa4", -1, 0, FALSE },
462   { "\xa5", -1, 0, FALSE },
463   { "\xa6", -1, 0, FALSE },
464   { "\xa7", -1, 0, FALSE },
465   { "\xa8", -1, 0, FALSE },
466   { "\xa9", -1, 0, FALSE },
467   { "\xaa", -1, 0, FALSE },
468   { "\xab", -1, 0, FALSE },
469   { "\xac", -1, 0, FALSE },
470   { "\xad", -1, 0, FALSE },
471   { "\xae", -1, 0, FALSE },
472   { "\xaf", -1, 0, FALSE },
473   { "\xb0", -1, 0, FALSE },
474   { "\xb1", -1, 0, FALSE },
475   { "\xb2", -1, 0, FALSE },
476   { "\xb3", -1, 0, FALSE },
477   { "\xb4", -1, 0, FALSE },
478   { "\xb5", -1, 0, FALSE },
479   { "\xb6", -1, 0, FALSE },
480   { "\xb7", -1, 0, FALSE },
481   { "\xb8", -1, 0, FALSE },
482   { "\xb9", -1, 0, FALSE },
483   { "\xba", -1, 0, FALSE },
484   { "\xbb", -1, 0, FALSE },
485   { "\xbc", -1, 0, FALSE },
486   { "\xbd", -1, 0, FALSE },
487   { "\xbe", -1, 0, FALSE },
488   { "\xbf", -1, 0, FALSE },
489   /* lone start characters */
490   { "\xc0\x20", -1, 0, FALSE },
491   { "\xc1\x20", -1, 0, FALSE },
492   { "\xc2\x20", -1, 0, FALSE },
493   { "\xc3\x20", -1, 0, FALSE },
494   { "\xc4\x20", -1, 0, FALSE },
495   { "\xc5\x20", -1, 0, FALSE },
496   { "\xc6\x20", -1, 0, FALSE },
497   { "\xc7\x20", -1, 0, FALSE },
498   { "\xc8\x20", -1, 0, FALSE },
499   { "\xc9\x20", -1, 0, FALSE },
500   { "\xca\x20", -1, 0, FALSE },
501   { "\xcb\x20", -1, 0, FALSE },
502   { "\xcc\x20", -1, 0, FALSE },
503   { "\xcd\x20", -1, 0, FALSE },
504   { "\xce\x20", -1, 0, FALSE },
505   { "\xcf\x20", -1, 0, FALSE },
506   { "\xd0\x20", -1, 0, FALSE },
507   { "\xd1\x20", -1, 0, FALSE },
508   { "\xd2\x20", -1, 0, FALSE },
509   { "\xd3\x20", -1, 0, FALSE },
510   { "\xd4\x20", -1, 0, FALSE },
511   { "\xd5\x20", -1, 0, FALSE },
512   { "\xd6\x20", -1, 0, FALSE },
513   { "\xd7\x20", -1, 0, FALSE },
514   { "\xd8\x20", -1, 0, FALSE },
515   { "\xd9\x20", -1, 0, FALSE },
516   { "\xda\x20", -1, 0, FALSE },
517   { "\xdb\x20", -1, 0, FALSE },
518   { "\xdc\x20", -1, 0, FALSE },
519   { "\xdd\x20", -1, 0, FALSE },
520   { "\xde\x20", -1, 0, FALSE },
521   { "\xdf\x20", -1, 0, FALSE },
522   { "\xe0\x20", -1, 0, FALSE },
523   { "\xe1\x20", -1, 0, FALSE },
524   { "\xe2\x20", -1, 0, FALSE },
525   { "\xe3\x20", -1, 0, FALSE },
526   { "\xe4\x20", -1, 0, FALSE },
527   { "\xe5\x20", -1, 0, FALSE },
528   { "\xe6\x20", -1, 0, FALSE },
529   { "\xe7\x20", -1, 0, FALSE },
530   { "\xe8\x20", -1, 0, FALSE },
531   { "\xe9\x20", -1, 0, FALSE },
532   { "\xea\x20", -1, 0, FALSE },
533   { "\xeb\x20", -1, 0, FALSE },
534   { "\xec\x20", -1, 0, FALSE },
535   { "\xed\x20", -1, 0, FALSE },
536   { "\xee\x20", -1, 0, FALSE },
537   { "\xef\x20", -1, 0, FALSE },
538   { "\xf0\x20", -1, 0, FALSE },
539   { "\xf1\x20", -1, 0, FALSE },
540   { "\xf2\x20", -1, 0, FALSE },
541   { "\xf3\x20", -1, 0, FALSE },
542   { "\xf4\x20", -1, 0, FALSE },
543   { "\xf5\x20", -1, 0, FALSE },
544   { "\xf6\x20", -1, 0, FALSE },
545   { "\xf7\x20", -1, 0, FALSE },
546   { "\xf8\x20", -1, 0, FALSE },
547   { "\xf9\x20", -1, 0, FALSE },
548   { "\xfa\x20", -1, 0, FALSE },
549   { "\xfb\x20", -1, 0, FALSE },
550   { "\xfc\x20", -1, 0, FALSE },
551   { "\xfd\x20", -1, 0, FALSE },
552   /* missing continuation bytes */
553   { "\x20\xc0", -1, 1, FALSE },
554   { "\x20\xe0\x80", -1, 1, FALSE },
555   { "\x20\xf0\x80\x80", -1, 1, FALSE },
556   { "\x20\xf8\x80\x80\x80", -1, 1, FALSE },
557   { "\x20\xfc\x80\x80\x80\x80", -1, 1, FALSE },
558   { "\x20\xdf", -1, 1, FALSE },
559   { "\x20\xef\xbf", -1, 1, FALSE },
560   { "\x20\xf7\xbf\xbf", -1, 1, FALSE },
561   { "\x20\xfb\xbf\xbf\xbf", -1, 1, FALSE },
562   { "\x20\xfd\xbf\xbf\xbf\xbf", -1, 1, FALSE },
563   /* impossible bytes */
564   { "\x20\xfe\x20", -1, 1, FALSE },
565   { "\x20\xff\x20", -1, 1, FALSE },
566 #if 0
567   /* XXX fix these, or document that we don't detect them? */
568   /* overlong sequences */
569   { "\x20\xc0\xaf\x20", -1, 1, FALSE },
570   { "\x20\xe0\x80\xaf\x20", -1, 1, FALSE },
571   { "\x20\xf0\x80\x80\xaf\x20", -1, 1, FALSE },
572   { "\x20\xf8\x80\x80\x80\xaf\x20", -1, 1, FALSE },
573   { "\x20\xfc\x80\x80\x80\x80\xaf\x20", -1, 1, FALSE },
574   { "\x20\xc1\xbf\x20", -1, 1, FALSE },
575   { "\x20\xe0\x9f\xbf\x20", -1, 1, FALSE },
576   { "\x20\xf0\x8f\xbf\xbf\x20", -1, 1, FALSE },
577   { "\x20\xf8\x87\xbf\xbf\xbf\x20", -1, 1, FALSE },
578   { "\x20\xfc\x83\xbf\xbf\xbf\xbf\x20", -1, 1, FALSE },
579   { "\x20\xc0\x80\x20", -1, 1, FALSE },
580   { "\x20\xe0\x80\x80\x20", -1, 1, FALSE },
581   { "\x20\xf0\x80\x80\x80\x20", -1, 1, FALSE },
582   { "\x20\xf8\x80\x80\x80\x80\x20", -1, 1, FALSE },
583   { "\x20\xfc\x80\x80\x80\x80\x80\x20", -1, 1, FALSE },
584   /* illegal code positions */
585   { "\x20\xed\xa0\x80\x20", -1, 1, FALSE },
586   { "\x20\xed\xad\xbf\x20", -1, 1, FALSE },
587   { "\x20\xed\xae\x80\x20", -1, 1, FALSE },
588   { "\x20\xed\xaf\xbf\x20", -1, 1, FALSE },
589   { "\x20\xed\xb0\x80\x20", -1, 1, FALSE },
590   { "\x20\xed\xbe\x80\x20", -1, 1, FALSE },
591   { "\x20\xed\xbf\xbf\x20", -1, 1, FALSE },
592   { "\x20\xed\xa0\x80\xed\xb0\x80\x20", -1, 1, FALSE },
593   { "\x20\xed\xa0\x80\xed\xbf\xbf\x20", -1, 1, FALSE },
594   { "\x20\xed\xad\xbf\xed\xb0\x80\x20", -1, 1, FALSE },
595   { "\x20\xed\xad\xbf\xed\xbf\xbf\x20", -1, 1, FALSE },
596   { "\x20\xed\xae\x80\xed\xb0\x80\x20", -1, 1, FALSE },
597   { "\x20\xed\xae\x80\xed\xbf\xbf\x20", -1, 1, FALSE },
598   { "\x20\xed\xaf\xbf\xed\xb0\x80\x20", -1, 1, FALSE },
599   { "\x20\xed\xaf\xbf\xed\xbf\xbf\x20", -1, 1, FALSE },
600   { "\x20\xef\xbf\xbe\x20", -1, 1, FALSE },
601   { "\x20\xef\xbf\xbf\x20", -1, 1, FALSE },
602 #endif
603   { "", -1, 0, TRUE }
604 };
605
606 static void
607 test_buffer_utf8_validity (gconstpointer user_data)
608 {
609   const utf8_validity_test_t *test = user_data;
610   hb_buffer_t *b;
611   hb_glyph_info_t *glyphs;
612   unsigned int text_bytes, segment_bytes, i, len;
613
614   text_bytes = strlen (test->text);
615   if (test->max_len == -1)
616     segment_bytes = text_bytes;
617   else
618     segment_bytes = test->max_len;
619
620   b = hb_buffer_create (0);
621   hb_buffer_add_utf8 (b, test->text, text_bytes,  0, segment_bytes);
622
623   glyphs = hb_buffer_get_glyph_infos (b, &len);
624   for (i = 0; i < len; i++)
625     if (glyphs[i].codepoint == (hb_codepoint_t) -1)
626       break;
627
628   g_assert (test->valid ? i == len : i < len);
629   if (!test->valid)
630     g_assert (glyphs[i].cluster == test->offset);
631
632   hb_buffer_destroy (b);
633 }
634
635
636 typedef struct {
637   const uint16_t utf16[8];
638   const uint32_t codepoints[8];
639 } utf16_test_t;
640
641 /* note: we skip the first and last item from utf16 when adding to buffer */
642 static const utf16_test_t utf16_tests[] = {
643   {{0x41, 0x004D, 0x0430, 0x4E8C, 0xD800, 0xDF02, 0x61} , {0x004D, 0x0430, 0x4E8C, 0x10302}},
644   {{0x41, 0xD800, 0xDF02, 0x61}, {0x10302}},
645   {{0x41, 0xD800, 0xDF02}, {-1}},
646   {{0x41, 0x61, 0xD800, 0xDF02}, {0x61, -1}},
647   {{0x41, 0xD800, 0x61, 0xDF02}, {-1, 0x61}},
648   {{0x41, 0x61}, {}}
649 };
650
651 static void
652 test_buffer_utf16 (gconstpointer user_data)
653 {
654   const utf16_test_t *test = user_data;
655   hb_buffer_t *b;
656   hb_glyph_info_t *glyphs;
657   unsigned int u_len, chars, i, len;
658
659   for (u_len = 0; test->utf16[u_len]; u_len++)
660     ;
661   for (chars = 0; test->codepoints[chars]; chars++)
662     ;
663
664   b = hb_buffer_create (0);
665   hb_buffer_add_utf16 (b, test->utf16, u_len,  1, u_len - 2);
666
667   glyphs = hb_buffer_get_glyph_infos (b, &len);
668   g_assert_cmpint (len, ==, chars);
669   for (i = 0; i < chars; i++)
670     g_assert_cmphex (glyphs[i].codepoint, ==, test->codepoints[i]);
671
672   hb_buffer_destroy (b);
673 }
674
675
676 int
677 main (int argc, char **argv)
678 {
679   unsigned int i;
680
681   hb_test_init (&argc, &argv);
682
683   for (i = 0; i < BUFFER_NUM_TYPES; i++)
684   {
685     const void *buffer_type = GINT_TO_POINTER (i);
686     const char *buffer_name = buffer_names[i];
687
688     hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_properties);
689     hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_contents);
690     hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_positions);
691   }
692
693   hb_test_add_fixture (fixture, GINT_TO_POINTER (BUFFER_EMPTY), test_buffer_allocation);
694
695   for (i = 0; i < G_N_ELEMENTS (utf8_tests); i++)
696   {
697     char *flavor = g_strdup_printf ("%d", i);
698     hb_test_add_data_flavor (&utf8_tests[i], flavor, test_buffer_utf8);
699     g_free (flavor);
700   }
701   for (i = 0; i < G_N_ELEMENTS (utf8_validity_tests); i++)
702   {
703     char *flavor = g_strdup_printf ("%d", i);
704     hb_test_add_data_flavor (&utf8_validity_tests[i], flavor, test_buffer_utf8_validity);
705     g_free (flavor);
706   }
707
708   for (i = 0; i < G_N_ELEMENTS (utf16_tests); i++)
709   {
710     char *flavor = g_strdup_printf ("%d", i);
711     hb_test_add_data_flavor (&utf16_tests[i], flavor, test_buffer_utf16);
712     g_free (flavor);
713   }
714
715   return hb_test_run();
716 }