[test/unicode] Better test chainup
[profile/ivi/org.tizen.video-player.git] / test / test-unicode.c
1 /*
2  * Copyright © 2011  Codethink Limited
3  * Copyright © 2011  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Codethink Author(s): Ryan Lortie
26  * Google Author(s): Behdad Esfahbod
27  */
28
29 #include "hb-test.h"
30
31 /* Unit tests for hb-unicode.h */
32
33
34 #ifdef HAVE_GLIB
35 #include <hb-glib.h>
36 #endif
37 #ifdef HAVE_ICU
38 #include <hb-icu.h>
39 #endif
40
41
42 /* Some useful stuff */
43
44 #define MAGIC0 0x12345678
45 #define MAGIC1 0x76543210
46
47 typedef struct {
48   int value;
49   gboolean freed;
50 } data_t;
51
52 static void free_up (void *p)
53 {
54   data_t *data = (data_t *) p;
55
56   g_assert (data->value == MAGIC0 || data->value == MAGIC1);
57   g_assert (data->freed == FALSE);
58   data->freed = TRUE;
59 }
60
61 static hb_script_t
62 simple_get_script (hb_unicode_funcs_t *ufuncs,
63                    hb_codepoint_t      codepoint,
64                    void               *user_data)
65 {
66   data_t *data = (data_t *) user_data;
67
68   g_assert (hb_unicode_funcs_get_parent (ufuncs) == NULL);
69   g_assert (data->value == MAGIC0);
70   g_assert (data->freed == FALSE);
71
72   if ('a' <= codepoint && codepoint <= 'z')
73     return HB_SCRIPT_LATIN;
74   else
75     return HB_SCRIPT_UNKNOWN;
76 }
77
78 static hb_script_t
79 a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs,
80                             hb_codepoint_t      codepoint,
81                             void               *user_data)
82 {
83   data_t *data = (data_t *) user_data;
84
85   g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
86   g_assert (data->value == MAGIC1);
87   g_assert (data->freed == FALSE);
88
89   if (codepoint == 'a') {
90     return HB_SCRIPT_ARABIC;
91   } else {
92     hb_unicode_funcs_t *parent = hb_unicode_funcs_get_parent (ufuncs);
93
94     return hb_unicode_get_script (parent, codepoint);
95   }
96 }
97
98
99
100 /* Check all properties */
101
102 /* Some of the following tables where adapted from glib/glib/tests/utf8-misc.c.
103  * The license is compatible. */
104
105 typedef struct {
106   hb_codepoint_t unicode;
107   unsigned int   value;
108 } test_pair_t;
109
110 static const test_pair_t combining_class_tests[] =
111 {
112   {   0x0020, 0 },
113   {   0x0334, 1 },
114   {   0x093C, 7 },
115   {   0x3099, 8 },
116   {   0x094D, 9 },
117   {   0x05B0, 10 },
118   {   0x05B1, 11 },
119   {   0x05B2, 12 },
120   {   0x05B3, 13 },
121   {   0x05B4, 14 },
122   {   0x05B5, 15 },
123   {   0x05B6, 16 },
124   {   0x05B7, 17 },
125   {   0x05B8, 18 },
126   {   0x05B9, 19 },
127   {   0x05BB, 20 },
128   {   0x05BC, 21 },
129   {   0x05BD, 22 },
130   {   0x05BF, 23 },
131   {   0x05C1, 24 },
132   {   0x05C2, 25 },
133   {   0xFB1E, 26 },
134   {   0x064B, 27 },
135   {   0x064C, 28 },
136   {   0x064D, 29 },
137   /* ... */
138   {   0x05AE, 228 },
139   {   0x0300, 230 },
140   {   0x302C, 232 },
141   {   0x0362, 233 },
142   {   0x0360, 234 },
143   {   0x1DCD, 234 },
144   {   0x0345, 240 },
145
146   { 0x111111, 0 }
147 };
148 static const test_pair_t combining_class_tests_more[] =
149 {
150   /* Unicode-5.2 character additions */
151   {   0xA8E0, 230 },
152
153   /* Unicode-6.0 character additions */
154   {   0x135D, 230 },
155
156   { 0x111111, 0 }
157 };
158
159 static const test_pair_t eastasian_width_tests[] =
160 {
161   /* Neutral */
162   {   0x0000, 1 },
163   {   0x0483, 1 },
164   {   0x0641, 1 },
165   {   0xFFFC, 1 },
166   {  0x10000, 1 },
167   {  0xE0001, 1 },
168
169   /* Narrow */
170   {   0x0020, 1 },
171   {   0x0041, 1 },
172   {   0x27E6, 1 },
173
174   /* Halfwidth */
175   {   0x20A9, 1 },
176   {   0xFF61, 1 },
177   {   0xFF69, 1 },
178   {   0xFFEE, 1 },
179
180   /* Ambiguous */
181   {   0x00A1, 1 },
182   {   0x00D8, 1 },
183   {   0x02DD, 1 },
184   {  0xE0100, 1 },
185   { 0x100000, 1 },
186
187   /* Fullwidth */
188   {   0x3000, 2 },
189   {   0xFF60, 2 },
190
191   /* Wide */
192   {   0x2329, 2 },
193   {   0x3001, 2 },
194   {   0xFE69, 2 },
195   {  0x30000, 2 },
196   {  0x3FFFD, 2 },
197
198   { 0x111111, 1 }
199 };
200 static const test_pair_t eastasian_width_tests_more[] =
201 {
202   /* Default Wide blocks */
203   {   0x4DBF, 2 },
204   {   0x9FFF, 2 },
205   {   0xFAFF, 2 },
206   {  0x2A6DF, 2 },
207   {  0x2B73F, 2 },
208   {  0x2B81F, 2 },
209   {  0x2FA1F, 2 },
210
211   /* Uniode-5.2 character additions */
212   /* Wide */
213   {   0x115F, 2 },
214
215   /* Uniode-6.0 character additions */
216   /* Wide */
217   {  0x2B740, 2 },
218   {  0x1B000, 2 },
219
220   { 0x111111, 1 }
221 };
222
223 static const test_pair_t general_category_tests[] =
224 {
225   {   0x000D, HB_UNICODE_GENERAL_CATEGORY_CONTROL },
226   {   0x200E, HB_UNICODE_GENERAL_CATEGORY_FORMAT },
227   {   0x0378, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED },
228   {   0xE000, HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE },
229   {   0xD800, HB_UNICODE_GENERAL_CATEGORY_SURROGATE },
230   {   0x0061, HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER },
231   {   0x02B0, HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER },
232   {   0x3400, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
233   {   0x01C5, HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER },
234   {   0xFF21, HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER },
235   {   0x0903, HB_UNICODE_GENERAL_CATEGORY_COMBINING_MARK },
236   {   0x20DD, HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK },
237   {   0xA806, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK },
238   {   0xFF10, HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER },
239   {   0x16EE, HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER },
240   {   0x17F0, HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER },
241   {   0x005F, HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION },
242   {   0x058A, HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION },
243   {   0x0F3B, HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION },
244   {   0x2019, HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION },
245   {   0x2018, HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION },
246   {   0x2016, HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION },
247   {   0x0F3A, HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION },
248   {   0x20A0, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
249   {   0x309B, HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL },
250   {   0xFB29, HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL },
251   {   0x00A6, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
252   {   0x2028, HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR },
253   {   0x2029, HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR },
254   {   0x202F, HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR },
255
256   { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
257 };
258 static const test_pair_t general_category_tests_more[] =
259 {
260   /* Unicode-5.2 character additions */
261   {  0x1F131, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
262
263   /* Unicode-6.0 character additions */
264   {   0x0620, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
265
266   { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
267 };
268
269 static const test_pair_t mirroring_tests[] =
270 {
271   /* Some characters that do NOT mirror */
272   {   0x0020, 0x0020 },
273   {   0x0041, 0x0041 },
274   {   0x00F0, 0x00F0 },
275   {   0x27CC, 0x27CC },
276   {  0xE01EF, 0xE01EF },
277   {  0x1D7C3, 0x1D7C3 },
278   { 0x100000, 0x100000 },
279
280   /* Some characters that do mirror */
281   {   0x0029, 0x0028 },
282   {   0x0028, 0x0029 },
283   {   0x003E, 0x003C },
284   {   0x003C, 0x003E },
285   {   0x005D, 0x005B },
286   {   0x005B, 0x005D },
287   {   0x007D, 0x007B },
288   {   0x007B, 0x007D },
289   {   0x00BB, 0x00AB },
290   {   0x00AB, 0x00BB },
291   {   0x226B, 0x226A },
292   {   0x226A, 0x226B },
293   {   0x22F1, 0x22F0 },
294   {   0x22F0, 0x22F1 },
295   {   0xFF60, 0xFF5F },
296   {   0xFF5F, 0xFF60 },
297   {   0xFF63, 0xFF62 },
298   {   0xFF62, 0xFF63 },
299
300   { 0x111111, 0x111111 },
301 };
302 static const test_pair_t mirroring_tests_more[] =
303 {
304   /* No new mirroring characters have been encoded in recent Unicode versions. */
305   { 0x111111, 0x111111 }
306 };
307
308 static const test_pair_t script_tests[] =
309 {
310   {   0x002A, HB_SCRIPT_COMMON },
311   {   0x0670, HB_SCRIPT_INHERITED },
312   {   0x060D, HB_SCRIPT_ARABIC },
313   {   0x0559, HB_SCRIPT_ARMENIAN },
314   {   0x09CD, HB_SCRIPT_BENGALI },
315   {   0x31B6, HB_SCRIPT_BOPOMOFO },
316   {   0x13A2, HB_SCRIPT_CHEROKEE },
317   {   0x2CFD, HB_SCRIPT_COPTIC },
318   {   0x0482, HB_SCRIPT_CYRILLIC },
319   {  0x10401, HB_SCRIPT_DESERET },
320   {   0x094D, HB_SCRIPT_DEVANAGARI },
321   {   0x1258, HB_SCRIPT_ETHIOPIC },
322   {   0x10FC, HB_SCRIPT_GEORGIAN },
323   {  0x10341, HB_SCRIPT_GOTHIC },
324   {   0x0375, HB_SCRIPT_GREEK },
325   {   0x0A83, HB_SCRIPT_GUJARATI },
326   {   0x0A3C, HB_SCRIPT_GURMUKHI },
327   {   0x3005, HB_SCRIPT_HAN },
328   {   0x1100, HB_SCRIPT_HANGUL },
329   {   0x05BF, HB_SCRIPT_HEBREW },
330   {   0x309F, HB_SCRIPT_HIRAGANA },
331   {   0x0CBC, HB_SCRIPT_KANNADA },
332   {   0x30FF, HB_SCRIPT_KATAKANA },
333   {   0x17DD, HB_SCRIPT_KHMER },
334   {   0x0EDD, HB_SCRIPT_LAO },
335   {   0x0061, HB_SCRIPT_LATIN },
336   {   0x0D3D, HB_SCRIPT_MALAYALAM },
337   {   0x1843, HB_SCRIPT_MONGOLIAN },
338   {   0x1031, HB_SCRIPT_MYANMAR },
339   {   0x169C, HB_SCRIPT_OGHAM },
340   {  0x10322, HB_SCRIPT_OLD_ITALIC },
341   {   0x0B3C, HB_SCRIPT_ORIYA },
342   {   0x16EF, HB_SCRIPT_RUNIC },
343   {   0x0DBD, HB_SCRIPT_SINHALA },
344   {   0x0711, HB_SCRIPT_SYRIAC },
345   {   0x0B82, HB_SCRIPT_TAMIL },
346   {   0x0C03, HB_SCRIPT_TELUGU },
347   {   0x07B1, HB_SCRIPT_THAANA },
348   {   0x0E31, HB_SCRIPT_THAI },
349   {   0x0FD4, HB_SCRIPT_TIBETAN },
350   {   0x1401, HB_SCRIPT_CANADIAN_ABORIGINAL },
351   {   0xA015, HB_SCRIPT_YI },
352   {   0x1700, HB_SCRIPT_TAGALOG },
353   {   0x1720, HB_SCRIPT_HANUNOO },
354   {   0x1740, HB_SCRIPT_BUHID },
355   {   0x1760, HB_SCRIPT_TAGBANWA },
356
357   /* Unicode-4.0 additions */
358   {   0x2800, HB_SCRIPT_BRAILLE },
359   {  0x10808, HB_SCRIPT_CYPRIOT },
360   {   0x1932, HB_SCRIPT_LIMBU },
361   {  0x10480, HB_SCRIPT_OSMANYA },
362   {  0x10450, HB_SCRIPT_SHAVIAN },
363   {  0x10000, HB_SCRIPT_LINEAR_B },
364   {   0x1950, HB_SCRIPT_TAI_LE },
365   {  0x1039F, HB_SCRIPT_UGARITIC },
366
367   /* Unicode-4.1 additions */
368   {   0x1980, HB_SCRIPT_NEW_TAI_LUE },
369   {   0x1A1F, HB_SCRIPT_BUGINESE },
370   {   0x2C00, HB_SCRIPT_GLAGOLITIC },
371   {   0x2D6F, HB_SCRIPT_TIFINAGH },
372   {   0xA800, HB_SCRIPT_SYLOTI_NAGRI },
373   {  0x103D0, HB_SCRIPT_OLD_PERSIAN },
374   {  0x10A3F, HB_SCRIPT_KHAROSHTHI },
375
376   /* Unicode-5.0 additions */
377   {   0x0378, HB_SCRIPT_UNKNOWN },
378   {   0x1B04, HB_SCRIPT_BALINESE },
379   {  0x12000, HB_SCRIPT_CUNEIFORM },
380   {  0x10900, HB_SCRIPT_PHOENICIAN },
381   {   0xA840, HB_SCRIPT_PHAGS_PA },
382   {   0x07C0, HB_SCRIPT_NKO },
383
384   /* Unicode-5.1 additions */
385   {   0xA900, HB_SCRIPT_KAYAH_LI },
386   {   0x1C00, HB_SCRIPT_LEPCHA },
387   {   0xA930, HB_SCRIPT_REJANG },
388   {   0x1B80, HB_SCRIPT_SUNDANESE },
389   {   0xA880, HB_SCRIPT_SAURASHTRA },
390   {   0xAA00, HB_SCRIPT_CHAM },
391   {   0x1C50, HB_SCRIPT_OL_CHIKI },
392   {   0xA500, HB_SCRIPT_VAI },
393   {  0x102A0, HB_SCRIPT_CARIAN },
394   {  0x10280, HB_SCRIPT_LYCIAN },
395   {  0x1093F, HB_SCRIPT_LYDIAN },
396
397   { 0x111111, HB_SCRIPT_UNKNOWN }
398 };
399 static const test_pair_t script_tests_more[] =
400 {
401   /* Unicode-5.2 additions */
402   {  0x10B00, HB_SCRIPT_AVESTAN },
403   {   0xA6A0, HB_SCRIPT_BAMUM },
404   {  0x13000, HB_SCRIPT_EGYPTIAN_HIEROGLYPHS },
405   {  0x10840, HB_SCRIPT_IMPERIAL_ARAMAIC },
406   {  0x10B60, HB_SCRIPT_INSCRIPTIONAL_PAHLAVI },
407   {  0x10B40, HB_SCRIPT_INSCRIPTIONAL_PARTHIAN },
408   {   0xA980, HB_SCRIPT_JAVANESE },
409   {  0x11082, HB_SCRIPT_KAITHI },
410   {   0xA4D0, HB_SCRIPT_LISU },
411   {   0xABE5, HB_SCRIPT_MEETEI_MAYEK },
412   {  0x10A60, HB_SCRIPT_OLD_SOUTH_ARABIAN },
413   {  0x10C00, HB_SCRIPT_OLD_TURKIC },
414   {   0x0800, HB_SCRIPT_SAMARITAN },
415   {   0x1A20, HB_SCRIPT_TAI_THAM },
416   {   0xAA80, HB_SCRIPT_TAI_VIET },
417
418   /* Unicode-6.0 additions */
419   {   0x1BC0, HB_SCRIPT_BATAK },
420   {  0x11000, HB_SCRIPT_BRAHMI },
421   {   0x0840, HB_SCRIPT_MANDAIC },
422
423   /* Unicode-5.2 character additions */
424   {   0x1CED, HB_SCRIPT_INHERITED },
425   {   0x1400, HB_SCRIPT_CANADIAN_ABORIGINAL },
426
427   { 0x111111, HB_SCRIPT_UNKNOWN }
428 };
429
430
431 typedef unsigned int (*get_func_t)         (hb_unicode_funcs_t *ufuncs,
432                                             hb_codepoint_t      unicode,
433                                             void               *user_data);
434 typedef unsigned int (*func_setter_func_t) (hb_unicode_funcs_t *ufuncs,
435                                             get_func_t          func,
436                                             void               *user_data,
437                                             hb_destroy_func_t   destroy);
438 typedef unsigned int (*getter_func_t)      (hb_unicode_funcs_t *ufuncs,
439                                             hb_codepoint_t      unicode);
440
441 typedef struct {
442   const char         *name;
443   func_setter_func_t  func_setter;
444   getter_func_t       getter;
445   const test_pair_t  *tests;
446   unsigned int        num_tests;
447   const test_pair_t  *tests_more;
448   unsigned int        num_tests_more;
449   unsigned int        default_value;
450 } property_t;
451
452 #define RETURNS_UNICODE_ITSELF ((unsigned int) -1)
453
454 #define PROPERTY(name, DEFAULT) \
455   { \
456     #name, \
457     (func_setter_func_t) hb_unicode_funcs_set_##name##_func, \
458     (getter_func_t) hb_unicode_get_##name, \
459     name##_tests, \
460     G_N_ELEMENTS (name##_tests), \
461     name##_tests_more, \
462     G_N_ELEMENTS (name##_tests_more), \
463     DEFAULT \
464   }
465 static const property_t properties[] =
466 {
467   PROPERTY (combining_class, 0),
468   PROPERTY (eastasian_width, 1),
469   PROPERTY (general_category, (unsigned int) HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER),
470   PROPERTY (mirroring, RETURNS_UNICODE_ITSELF),
471   PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN),
472 };
473 #undef PROPERTY
474
475 static void
476 test_unicode_properties (gconstpointer user_data)
477 {
478   hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
479   unsigned int i, j;
480   gboolean failed = TRUE;
481
482   g_assert (hb_unicode_funcs_is_immutable (uf));
483
484   for (i = 0; i < G_N_ELEMENTS (properties); i++) {
485     const property_t *p = &properties[i];
486     const test_pair_t *tests;
487
488     g_test_message ("Testing property %s", p->name);
489     tests = p->tests;
490     for (j = 0; j < p->num_tests; j++) {
491       g_test_message ("Test %s #%d: U+%04X", p->name, j, tests[j].unicode);
492       g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, tests[j].value);
493     }
494     /* These tests are from Unicode 5.2 onward and older glib/ICU
495      * don't get them right.  Just warn instead of assert. */
496     tests = p->tests_more;
497     for (j = 0; j < p->num_tests_more; j++) {
498       g_test_message ("Test %s more #%d: U+%04X", p->name, j, tests[j].unicode);
499       if (p->getter (uf, tests[j].unicode) != tests[j].value) {
500         g_test_message ("Soft fail: Received %x, expected %x", p->getter (uf, tests[j].unicode), tests[j].value);
501         failed = TRUE;
502       }
503     }
504   }
505
506   if (failed)
507     g_message ("Some property tests failed.  You probably have an old version of one of the libraries used.  Rerun with --verbose for details");
508 }
509
510 static hb_codepoint_t
511 default_value (hb_codepoint_t default_value, hb_codepoint_t unicode)
512 {
513   return default_value == RETURNS_UNICODE_ITSELF ?  unicode : default_value;
514 }
515
516 static void
517 _test_unicode_properties_nil (hb_unicode_funcs_t *uf)
518 {
519   unsigned int i, j;
520
521   for (i = 0; i < G_N_ELEMENTS (properties); i++) {
522     const property_t *p = &properties[i];
523     const test_pair_t *tests;
524
525     g_test_message ("Testing property %s", p->name);
526     tests = p->tests;
527     for (j = 0; j < p->num_tests; j++) {
528       g_test_message ("Test %s #%d: U+%04X", p->name, j, tests[j].unicode);
529       g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, default_value (p->default_value, tests[j].unicode));
530     }
531     tests = p->tests_more;
532     for (j = 0; j < p->num_tests_more; j++) {
533       g_test_message ("Test %s more #%d: U+%04X", p->name, j, tests[j].unicode);
534       g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, default_value (p->default_value, tests[j].unicode));
535     }
536   }
537 }
538
539 static void
540 test_unicode_properties_nil (void)
541 {
542   hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
543
544   g_assert (!hb_unicode_funcs_is_immutable (uf));
545   _test_unicode_properties_nil (uf);
546
547   hb_unicode_funcs_destroy (uf);
548 }
549
550
551 static void
552 test_unicode_chainup (void)
553 {
554   hb_unicode_funcs_t *uf, *uf2;
555
556   /* Chain-up to nil */
557
558   uf = hb_unicode_funcs_create (NULL);
559   g_assert (!hb_unicode_funcs_is_immutable (uf));
560
561   uf2 = hb_unicode_funcs_create (uf);
562   g_assert (hb_unicode_funcs_is_immutable (uf));
563   hb_unicode_funcs_destroy (uf);
564
565   g_assert (!hb_unicode_funcs_is_immutable (uf2));
566   _test_unicode_properties_nil (uf2);
567
568   hb_unicode_funcs_destroy (uf2);
569
570   /* Chain-up to default */
571
572   uf = hb_unicode_funcs_create (hb_unicode_funcs_get_default ());
573   g_assert (!hb_unicode_funcs_is_immutable (uf));
574
575   uf2 = hb_unicode_funcs_create (uf);
576   g_assert (hb_unicode_funcs_is_immutable (uf));
577   hb_unicode_funcs_destroy (uf);
578
579   g_assert (!hb_unicode_funcs_is_immutable (uf2));
580   hb_unicode_funcs_make_immutable (uf2);
581   test_unicode_properties (uf2);
582
583   hb_unicode_funcs_destroy (uf2);
584
585 }
586
587 static void
588 test_unicode_setters (void)
589 {
590   hb_unicode_funcs_t *uf;
591   unsigned int i;
592
593   /* This is cruel: we use script-returning functions to test all properties,
594    * but it works. */
595
596   for (i = 0; i < G_N_ELEMENTS (properties); i++) {
597     const property_t *p = &properties[i];
598     data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
599
600     g_test_message ("Testing property %s", p->name);
601
602     uf = hb_unicode_funcs_create (NULL);
603     g_assert (!hb_unicode_funcs_is_immutable (uf));
604
605     p->func_setter (uf, (get_func_t) simple_get_script, &data[0], free_up);
606
607     g_assert_cmphex (p->getter (uf, 'a'), ==, HB_SCRIPT_LATIN);
608     g_assert_cmphex (p->getter (uf, '0'), ==, HB_SCRIPT_UNKNOWN);
609
610     g_assert (!hb_unicode_funcs_is_immutable (uf));
611     hb_unicode_funcs_make_immutable (uf);
612     g_assert (hb_unicode_funcs_is_immutable (uf));
613
614     /* Since uf is immutable now, the following setter should do nothing. */
615     p->func_setter (uf, (get_func_t) a_is_for_arabic_get_script, &data[1], free_up);
616
617     g_assert (!data[0].freed && !data[1].freed);
618     hb_unicode_funcs_destroy (uf);
619     g_assert (data[0].freed && !data[1].freed);
620
621     hb_unicode_funcs_destroy (uf);
622   }
623 }
624
625
626
627 typedef struct {
628   data_t data[2];
629 } data_fixture_t;
630
631 static void
632 data_fixture_init (data_fixture_t *f, gconstpointer user_data)
633 {
634   f->data[0].value = MAGIC0;
635   f->data[1].value = MAGIC1;
636 }
637 static void
638 data_fixture_finish (data_fixture_t *f, gconstpointer user_data)
639 {
640 }
641
642 static void
643 test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data)
644 {
645   hb_unicode_funcs_t *uf, *aa;
646
647   uf = hb_unicode_funcs_create (NULL);
648
649   aa = hb_unicode_funcs_create (uf);
650
651   hb_unicode_funcs_destroy (uf);
652
653   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
654                                     &f->data[1], free_up);
655
656   g_assert_cmphex (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
657   g_assert_cmphex (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
658
659   g_assert (!f->data[0].freed && !f->data[1].freed);
660   hb_unicode_funcs_destroy (aa);
661   g_assert (!f->data[0].freed && f->data[1].freed);
662 }
663
664 static void
665 test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data)
666 {
667   hb_unicode_funcs_t *uf, *aa;
668
669   uf = hb_unicode_funcs_get_default ();
670   aa = hb_unicode_funcs_create (uf);
671
672   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
673                                     &f->data[1], free_up);
674
675   g_assert_cmphex (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
676   g_assert_cmphex (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
677
678   g_assert (!f->data[0].freed && !f->data[1].freed);
679   hb_unicode_funcs_destroy (aa);
680   g_assert (!f->data[0].freed && f->data[1].freed);
681 }
682
683 static void
684 test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data)
685 {
686   hb_unicode_funcs_t *uf, *aa;
687
688   uf = hb_unicode_funcs_create (NULL);
689
690   hb_unicode_funcs_set_script_func (uf, simple_get_script,
691                                     &f->data[0], free_up);
692
693   aa = hb_unicode_funcs_create (uf);
694
695   hb_unicode_funcs_destroy (uf);
696
697   /* make sure the 'uf' didn't get freed, since 'aa' holds a ref */
698   g_assert (!f->data[0].freed);
699
700   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
701                                     &f->data[1], free_up);
702
703   g_assert_cmphex (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
704   g_assert_cmphex (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
705   g_assert_cmphex (hb_unicode_get_script (aa, '0'), ==, HB_SCRIPT_UNKNOWN);
706
707   g_assert (!f->data[0].freed && !f->data[1].freed);
708   hb_unicode_funcs_destroy (aa);
709   g_assert (f->data[0].freed && f->data[1].freed);
710 }
711
712
713 int
714 main (int argc, char **argv)
715 {
716   hb_test_init (&argc, &argv);
717
718   hb_test_add (test_unicode_properties_nil);
719
720   hb_test_add_data_flavor (hb_unicode_funcs_get_default (), "default", test_unicode_properties);
721 #ifdef HAVE_GLIB
722   hb_test_add_data_flavor (hb_glib_get_unicode_funcs (),    "glib",    test_unicode_properties);
723 #endif
724 #ifdef HAVE_ICU
725   hb_test_add_data_flavor (hb_icu_get_unicode_funcs (),     "icu",    test_unicode_properties);
726 #endif
727
728   hb_test_add (test_unicode_chainup);
729
730   hb_test_add (test_unicode_setters);
731
732   hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_nil);
733   hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_default);
734   hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_deep);
735
736   /* XXX test glib & icu two-way script conversion */
737
738   return hb_test_run ();
739 }