Home | History | Annotate | Download | only in api
      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 /* Unit tests for hb-glib.h */
     33 /* Unit tests for hb-icu.h */
     34 
     35 
     36 #ifdef HAVE_GLIB
     37 #include <hb-glib.h>
     38 #endif
     39 #ifdef HAVE_ICU
     40 #include <hb-icu.h>
     41 #endif
     42 
     43 
     44 /* Some useful stuff */
     45 
     46 #define MAGIC0 0x12345678
     47 #define MAGIC1 0x76543210
     48 
     49 typedef struct {
     50   int value;
     51   gboolean freed;
     52 } data_t;
     53 
     54 static void free_up (void *p)
     55 {
     56   data_t *data = (data_t *) p;
     57 
     58   g_assert (data->value == MAGIC0 || data->value == MAGIC1);
     59   g_assert (!data->freed);
     60   data->freed = TRUE;
     61 }
     62 
     63 static hb_script_t
     64 simple_get_script (hb_unicode_funcs_t *ufuncs,
     65                    hb_codepoint_t      codepoint,
     66                    void               *user_data)
     67 {
     68   data_t *data = (data_t *) user_data;
     69 
     70   g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
     71   g_assert_cmphex (data->value, ==, MAGIC0);
     72   g_assert (!data->freed);
     73 
     74   if ('a' <= codepoint && codepoint <= 'z')
     75     return HB_SCRIPT_LATIN;
     76   else
     77     return HB_SCRIPT_UNKNOWN;
     78 }
     79 
     80 static hb_script_t
     81 a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs,
     82                             hb_codepoint_t      codepoint,
     83                             void               *user_data)
     84 {
     85   data_t *data = (data_t *) user_data;
     86 
     87   g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
     88   g_assert_cmphex (data->value, ==, MAGIC1);
     89   g_assert (!data->freed);
     90 
     91   if (codepoint == 'a') {
     92     return HB_SCRIPT_ARABIC;
     93   } else {
     94     hb_unicode_funcs_t *parent = hb_unicode_funcs_get_parent (ufuncs);
     95 
     96     return hb_unicode_script (parent, codepoint);
     97   }
     98 }
     99 
    100 
    101 
    102 /* Check all properties */
    103 
    104 /* Some of the following tables where adapted from glib/glib/tests/utf8-misc.c.
    105  * The license is compatible. */
    106 
    107 typedef struct {
    108   hb_codepoint_t unicode;
    109   unsigned int   value;
    110 } test_pair_t;
    111 
    112 static const test_pair_t combining_class_tests[] =
    113 {
    114   {   0x0020, 0 },
    115   {   0x0334, 1 },
    116   {   0x093C, 7 },
    117   {   0x3099, 8 },
    118   {   0x094D, 9 },
    119   {   0x05B0, 10 },
    120   {   0x05B1, 11 },
    121   {   0x05B2, 12 },
    122   {   0x05B3, 13 },
    123   {   0x05B4, 14 },
    124   {   0x05B5, 15 },
    125   {   0x05B6, 16 },
    126   {   0x05B7, 17 },
    127   {   0x05B8, 18 },
    128   {   0x05B9, 19 },
    129   {   0x05BB, 20 },
    130   {   0x05BC, 21 },
    131   {   0x05BD, 22 },
    132   {   0x05BF, 23 },
    133   {   0x05C1, 24 },
    134   {   0x05C2, 25 },
    135   {   0xFB1E, 26 },
    136   {   0x064B, 27 },
    137   {   0x064C, 28 },
    138   {   0x064D, 29 },
    139   /* ... */
    140   {   0x05AE, 228 },
    141   {   0x0300, 230 },
    142   {   0x302C, 232 },
    143   {   0x0362, 233 },
    144   {   0x0360, 234 },
    145   {   0x0345, 240 },
    146 
    147   { 0x111111, 0 }
    148 };
    149 static const test_pair_t combining_class_tests_more[] =
    150 {
    151   /* Unicode-5.1 character additions */
    152   {   0x1DCD, 234 },
    153 
    154   /* Unicode-5.2 character additions */
    155   {   0xA8E0, 230 },
    156 
    157   /* Unicode-6.0 character additions */
    158   {   0x135D, 230 },
    159 
    160   { 0x111111, 0 }
    161 };
    162 
    163 static const test_pair_t eastasian_width_tests[] =
    164 {
    165   /* Neutral */
    166   {   0x0000, 1 },
    167   {   0x0483, 1 },
    168   {   0x0641, 1 },
    169   {   0xFFFC, 1 },
    170   {  0x10000, 1 },
    171   {  0xE0001, 1 },
    172 
    173   /* Narrow */
    174   {   0x0020, 1 },
    175   {   0x0041, 1 },
    176   {   0x27E6, 1 },
    177 
    178   /* Halfwidth */
    179   {   0x20A9, 1 },
    180   {   0xFF61, 1 },
    181   {   0xFF69, 1 },
    182   {   0xFFEE, 1 },
    183 
    184   /* Ambiguous */
    185   {   0x00A1, 1 },
    186   {   0x00D8, 1 },
    187   {   0x02DD, 1 },
    188   {  0xE0100, 1 },
    189   { 0x100000, 1 },
    190 
    191   /* Fullwidth */
    192   {   0x3000, 2 },
    193   {   0xFF60, 2 },
    194 
    195   /* Wide */
    196   {   0x2329, 2 },
    197   {   0x3001, 2 },
    198   {   0xFE69, 2 },
    199   {  0x30000, 2 },
    200   {  0x3FFFD, 2 },
    201 
    202   { 0x111111, 1 }
    203 };
    204 static const test_pair_t eastasian_width_tests_more[] =
    205 {
    206   /* Default Wide blocks */
    207   {   0x4DBF, 2 },
    208   {   0x9FFF, 2 },
    209   {   0xFAFF, 2 },
    210   {  0x2A6DF, 2 },
    211   {  0x2B73F, 2 },
    212   {  0x2B81F, 2 },
    213   {  0x2FA1F, 2 },
    214 
    215   /* Uniode-5.2 character additions */
    216   /* Wide */
    217   {   0x115F, 2 },
    218 
    219   /* Uniode-6.0 character additions */
    220   /* Wide */
    221   {  0x2B740, 2 },
    222   {  0x1B000, 2 },
    223 
    224   { 0x111111, 1 }
    225 };
    226 
    227 static const test_pair_t general_category_tests[] =
    228 {
    229   {   0x000D, HB_UNICODE_GENERAL_CATEGORY_CONTROL },
    230   {   0x200E, HB_UNICODE_GENERAL_CATEGORY_FORMAT },
    231   {   0x0378, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED },
    232   {   0xE000, HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE },
    233   {   0xD800, HB_UNICODE_GENERAL_CATEGORY_SURROGATE },
    234   {   0x0061, HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER },
    235   {   0x02B0, HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER },
    236   {   0x3400, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
    237   {   0x01C5, HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER },
    238   {   0xFF21, HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER },
    239   {   0x0903, HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK },
    240   {   0x20DD, HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK },
    241   {   0xA806, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK },
    242   {   0xFF10, HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER },
    243   {   0x16EE, HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER },
    244   {   0x17F0, HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER },
    245   {   0x005F, HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION },
    246   {   0x058A, HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION },
    247   {   0x0F3B, HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION },
    248   {   0x2019, HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION },
    249   {   0x2018, HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION },
    250   {   0x2016, HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION },
    251   {   0x0F3A, HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION },
    252   {   0x20A0, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
    253   {   0x309B, HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL },
    254   {   0xFB29, HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL },
    255   {   0x00A6, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
    256   {   0x2028, HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR },
    257   {   0x2029, HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR },
    258   {   0x202F, HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR },
    259 
    260   { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
    261 };
    262 static const test_pair_t general_category_tests_more[] =
    263 {
    264   /* Unicode-5.2 character additions */
    265   {  0x1F131, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
    266 
    267   /* Unicode-6.0 character additions */
    268   {   0x0620, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
    269 
    270   { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
    271 };
    272 
    273 static const test_pair_t mirroring_tests[] =
    274 {
    275   /* Some characters that do NOT mirror */
    276   {   0x0020, 0x0020 },
    277   {   0x0041, 0x0041 },
    278   {   0x00F0, 0x00F0 },
    279   {   0x27CC, 0x27CC },
    280   {  0xE01EF, 0xE01EF },
    281   {  0x1D7C3, 0x1D7C3 },
    282   { 0x100000, 0x100000 },
    283 
    284   /* Some characters that do mirror */
    285   {   0x0029, 0x0028 },
    286   {   0x0028, 0x0029 },
    287   {   0x003E, 0x003C },
    288   {   0x003C, 0x003E },
    289   {   0x005D, 0x005B },
    290   {   0x005B, 0x005D },
    291   {   0x007D, 0x007B },
    292   {   0x007B, 0x007D },
    293   {   0x00BB, 0x00AB },
    294   {   0x00AB, 0x00BB },
    295   {   0x226B, 0x226A },
    296   {   0x226A, 0x226B },
    297   {   0x22F1, 0x22F0 },
    298   {   0x22F0, 0x22F1 },
    299   {   0xFF60, 0xFF5F },
    300   {   0xFF5F, 0xFF60 },
    301   {   0xFF63, 0xFF62 },
    302   {   0xFF62, 0xFF63 },
    303 
    304   { 0x111111, 0x111111 },
    305 };
    306 static const test_pair_t mirroring_tests_more[] =
    307 {
    308   /* No new mirroring characters have been encoded in recent Unicode versions. */
    309   { 0x111111, 0x111111 }
    310 };
    311 
    312 static const test_pair_t script_tests[] =
    313 {
    314   {   0x002A, HB_SCRIPT_COMMON },
    315   {   0x0670, HB_SCRIPT_INHERITED },
    316   {   0x060D, HB_SCRIPT_ARABIC },
    317   {   0x0559, HB_SCRIPT_ARMENIAN },
    318   {   0x09CD, HB_SCRIPT_BENGALI },
    319   {   0x31B6, HB_SCRIPT_BOPOMOFO },
    320   {   0x13A2, HB_SCRIPT_CHEROKEE },
    321   {   0x2CFD, HB_SCRIPT_COPTIC },
    322   {   0x0482, HB_SCRIPT_CYRILLIC },
    323   {  0x10401, HB_SCRIPT_DESERET },
    324   {   0x094D, HB_SCRIPT_DEVANAGARI },
    325   {   0x1258, HB_SCRIPT_ETHIOPIC },
    326   {   0x10FC, HB_SCRIPT_GEORGIAN },
    327   {  0x10341, HB_SCRIPT_GOTHIC },
    328   {   0x0375, HB_SCRIPT_GREEK },
    329   {   0x0A83, HB_SCRIPT_GUJARATI },
    330   {   0x0A3C, HB_SCRIPT_GURMUKHI },
    331   {   0x3005, HB_SCRIPT_HAN },
    332   {   0x1100, HB_SCRIPT_HANGUL },
    333   {   0x05BF, HB_SCRIPT_HEBREW },
    334   {   0x309F, HB_SCRIPT_HIRAGANA },
    335   {   0x0CBC, HB_SCRIPT_KANNADA },
    336   {   0x30FF, HB_SCRIPT_KATAKANA },
    337   {   0x17DD, HB_SCRIPT_KHMER },
    338   {   0x0EDD, HB_SCRIPT_LAO },
    339   {   0x0061, HB_SCRIPT_LATIN },
    340   {   0x0D3D, HB_SCRIPT_MALAYALAM },
    341   {   0x1843, HB_SCRIPT_MONGOLIAN },
    342   {   0x1031, HB_SCRIPT_MYANMAR },
    343   {   0x169C, HB_SCRIPT_OGHAM },
    344   {  0x10322, HB_SCRIPT_OLD_ITALIC },
    345   {   0x0B3C, HB_SCRIPT_ORIYA },
    346   {   0x16EF, HB_SCRIPT_RUNIC },
    347   {   0x0DBD, HB_SCRIPT_SINHALA },
    348   {   0x0711, HB_SCRIPT_SYRIAC },
    349   {   0x0B82, HB_SCRIPT_TAMIL },
    350   {   0x0C03, HB_SCRIPT_TELUGU },
    351   {   0x07B1, HB_SCRIPT_THAANA },
    352   {   0x0E31, HB_SCRIPT_THAI },
    353   {   0x0FD4, HB_SCRIPT_TIBETAN },
    354   {   0x1401, HB_SCRIPT_CANADIAN_SYLLABICS },
    355   {   0xA015, HB_SCRIPT_YI },
    356   {   0x1700, HB_SCRIPT_TAGALOG },
    357   {   0x1720, HB_SCRIPT_HANUNOO },
    358   {   0x1740, HB_SCRIPT_BUHID },
    359   {   0x1760, HB_SCRIPT_TAGBANWA },
    360 
    361   /* Unicode-4.0 additions */
    362   {   0x2800, HB_SCRIPT_BRAILLE },
    363   {  0x10808, HB_SCRIPT_CYPRIOT },
    364   {   0x1932, HB_SCRIPT_LIMBU },
    365   {  0x10480, HB_SCRIPT_OSMANYA },
    366   {  0x10450, HB_SCRIPT_SHAVIAN },
    367   {  0x10000, HB_SCRIPT_LINEAR_B },
    368   {   0x1950, HB_SCRIPT_TAI_LE },
    369   {  0x1039F, HB_SCRIPT_UGARITIC },
    370 
    371   /* Unicode-4.1 additions */
    372   {   0x1980, HB_SCRIPT_NEW_TAI_LUE },
    373   {   0x1A1F, HB_SCRIPT_BUGINESE },
    374   {   0x2C00, HB_SCRIPT_GLAGOLITIC },
    375   {   0x2D6F, HB_SCRIPT_TIFINAGH },
    376   {   0xA800, HB_SCRIPT_SYLOTI_NAGRI },
    377   {  0x103D0, HB_SCRIPT_OLD_PERSIAN },
    378   {  0x10A3F, HB_SCRIPT_KHAROSHTHI },
    379 
    380   /* Unicode-5.0 additions */
    381   {   0x0378, HB_SCRIPT_UNKNOWN },
    382   {   0x1B04, HB_SCRIPT_BALINESE },
    383   {  0x12000, HB_SCRIPT_CUNEIFORM },
    384   {  0x10900, HB_SCRIPT_PHOENICIAN },
    385   {   0xA840, HB_SCRIPT_PHAGS_PA },
    386   {   0x07C0, HB_SCRIPT_NKO },
    387 
    388   /* Unicode-5.1 additions */
    389   {   0xA900, HB_SCRIPT_KAYAH_LI },
    390   {   0x1C00, HB_SCRIPT_LEPCHA },
    391   {   0xA930, HB_SCRIPT_REJANG },
    392   {   0x1B80, HB_SCRIPT_SUNDANESE },
    393   {   0xA880, HB_SCRIPT_SAURASHTRA },
    394   {   0xAA00, HB_SCRIPT_CHAM },
    395   {   0x1C50, HB_SCRIPT_OL_CHIKI },
    396   {   0xA500, HB_SCRIPT_VAI },
    397   {  0x102A0, HB_SCRIPT_CARIAN },
    398   {  0x10280, HB_SCRIPT_LYCIAN },
    399   {  0x1093F, HB_SCRIPT_LYDIAN },
    400 
    401   { 0x111111, HB_SCRIPT_UNKNOWN }
    402 };
    403 static const test_pair_t script_tests_more[] =
    404 {
    405   /* Unicode-5.2 additions */
    406   {  0x10B00, HB_SCRIPT_AVESTAN },
    407   {   0xA6A0, HB_SCRIPT_BAMUM },
    408   {  0x13000, HB_SCRIPT_EGYPTIAN_HIEROGLYPHS },
    409   {  0x10840, HB_SCRIPT_IMPERIAL_ARAMAIC },
    410   {  0x10B60, HB_SCRIPT_INSCRIPTIONAL_PAHLAVI },
    411   {  0x10B40, HB_SCRIPT_INSCRIPTIONAL_PARTHIAN },
    412   {   0xA980, HB_SCRIPT_JAVANESE },
    413   {  0x11082, HB_SCRIPT_KAITHI },
    414   {   0xA4D0, HB_SCRIPT_LISU },
    415   {   0xABE5, HB_SCRIPT_MEETEI_MAYEK },
    416   {  0x10A60, HB_SCRIPT_OLD_SOUTH_ARABIAN },
    417   {  0x10C00, HB_SCRIPT_OLD_TURKIC },
    418   {   0x0800, HB_SCRIPT_SAMARITAN },
    419   {   0x1A20, HB_SCRIPT_TAI_THAM },
    420   {   0xAA80, HB_SCRIPT_TAI_VIET },
    421 
    422   /* Unicode-6.0 additions */
    423   {   0x1BC0, HB_SCRIPT_BATAK },
    424   {  0x11000, HB_SCRIPT_BRAHMI },
    425   {   0x0840, HB_SCRIPT_MANDAIC },
    426 
    427   /* Unicode-5.2 character additions */
    428   {   0x1CED, HB_SCRIPT_INHERITED },
    429   {   0x1400, HB_SCRIPT_CANADIAN_ABORIGINAL },
    430 
    431   { 0x111111, HB_SCRIPT_UNKNOWN }
    432 };
    433 
    434 
    435 typedef unsigned int (*get_func_t)         (hb_unicode_funcs_t *ufuncs,
    436 					    hb_codepoint_t      unicode,
    437 					    void               *user_data);
    438 typedef unsigned int (*func_setter_func_t) (hb_unicode_funcs_t *ufuncs,
    439 					    get_func_t          func,
    440 					    void               *user_data,
    441 					    hb_destroy_func_t   destroy);
    442 typedef unsigned int (*getter_func_t)      (hb_unicode_funcs_t *ufuncs,
    443 					    hb_codepoint_t      unicode);
    444 
    445 typedef struct {
    446   const char         *name;
    447   func_setter_func_t  func_setter;
    448   getter_func_t       getter;
    449   const test_pair_t  *tests;
    450   unsigned int        num_tests;
    451   const test_pair_t  *tests_more;
    452   unsigned int        num_tests_more;
    453   unsigned int        default_value;
    454 } property_t;
    455 
    456 #define RETURNS_UNICODE_ITSELF ((unsigned int) -1)
    457 
    458 #define PROPERTY(name, DEFAULT) \
    459   { \
    460     #name, \
    461     (func_setter_func_t) hb_unicode_funcs_set_##name##_func, \
    462     (getter_func_t) hb_unicode_##name, \
    463     name##_tests, \
    464     G_N_ELEMENTS (name##_tests), \
    465     name##_tests_more, \
    466     G_N_ELEMENTS (name##_tests_more), \
    467     DEFAULT \
    468   }
    469 static const property_t properties[] =
    470 {
    471   PROPERTY (combining_class, 0),
    472   PROPERTY (eastasian_width, 1),
    473   PROPERTY (general_category, (unsigned int) HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER),
    474   PROPERTY (mirroring, RETURNS_UNICODE_ITSELF),
    475   PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN)
    476 };
    477 #undef PROPERTY
    478 
    479 static void
    480 test_unicode_properties (gconstpointer user_data)
    481 {
    482   hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
    483   unsigned int i, j;
    484   gboolean failed = TRUE;
    485 
    486   g_assert (hb_unicode_funcs_is_immutable (uf));
    487   g_assert (hb_unicode_funcs_get_parent (uf));
    488 
    489   for (i = 0; i < G_N_ELEMENTS (properties); i++) {
    490     const property_t *p = &properties[i];
    491     const test_pair_t *tests;
    492 
    493     g_test_message ("Testing property %s", p->name);
    494     tests = p->tests;
    495     for (j = 0; j < p->num_tests; j++) {
    496       g_test_message ("Test %s #%d: U+%04X", p->name, j, tests[j].unicode);
    497       g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, tests[j].value);
    498     }
    499     /* These tests are from Unicode 5.2 onward and older glib/ICU
    500      * don't get them right.  Just warn instead of assert. */
    501     tests = p->tests_more;
    502     for (j = 0; j < p->num_tests_more; j++) {
    503       g_test_message ("Test %s more #%d: U+%04X", p->name, j, tests[j].unicode);
    504       if (p->getter (uf, tests[j].unicode) != tests[j].value) {
    505 	g_test_message ("Soft fail: Received %x, expected %x", p->getter (uf, tests[j].unicode), tests[j].value);
    506         failed = TRUE;
    507       }
    508     }
    509   }
    510 
    511   if (failed)
    512     g_test_message ("Some property tests failed.  You probably have an old version of one of the libraries used.");
    513 }
    514 
    515 static hb_codepoint_t
    516 default_value (hb_codepoint_t _default_value, hb_codepoint_t unicode)
    517 {
    518   return _default_value == RETURNS_UNICODE_ITSELF ?  unicode : _default_value;
    519 }
    520 
    521 static void
    522 _test_unicode_properties_nil (hb_unicode_funcs_t *uf)
    523 {
    524   unsigned int i, j;
    525 
    526   for (i = 0; i < G_N_ELEMENTS (properties); i++) {
    527     const property_t *p = &properties[i];
    528     const test_pair_t *tests;
    529 
    530     g_test_message ("Testing property %s", p->name);
    531     tests = p->tests;
    532     for (j = 0; j < p->num_tests; j++) {
    533       g_test_message ("Test %s #%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     tests = p->tests_more;
    537     for (j = 0; j < p->num_tests_more; j++) {
    538       g_test_message ("Test %s more #%d: U+%04X", p->name, j, tests[j].unicode);
    539       g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, default_value (p->default_value, tests[j].unicode));
    540     }
    541   }
    542 }
    543 
    544 static void
    545 test_unicode_properties_nil (void)
    546 {
    547   hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
    548 
    549   g_assert (!hb_unicode_funcs_is_immutable (uf));
    550   _test_unicode_properties_nil (uf);
    551 
    552   hb_unicode_funcs_destroy (uf);
    553 }
    554 
    555 static void
    556 test_unicode_properties_empty (void)
    557 {
    558   hb_unicode_funcs_t *uf = hb_unicode_funcs_get_empty ();
    559 
    560   g_assert (uf);
    561   g_assert (hb_unicode_funcs_is_immutable (uf));
    562   _test_unicode_properties_nil (uf);
    563 }
    564 
    565 
    566 static void
    567 test_unicode_chainup (void)
    568 {
    569   hb_unicode_funcs_t *uf, *uf2;
    570 
    571   /* Chain-up to nil */
    572 
    573   uf = hb_unicode_funcs_create (NULL);
    574   g_assert (!hb_unicode_funcs_is_immutable (uf));
    575 
    576   uf2 = hb_unicode_funcs_create (uf);
    577   g_assert (hb_unicode_funcs_is_immutable (uf));
    578   hb_unicode_funcs_destroy (uf);
    579 
    580   g_assert (!hb_unicode_funcs_is_immutable (uf2));
    581   _test_unicode_properties_nil (uf2);
    582 
    583   hb_unicode_funcs_destroy (uf2);
    584 
    585   /* Chain-up to default */
    586 
    587   uf = hb_unicode_funcs_create (hb_unicode_funcs_get_default ());
    588   g_assert (!hb_unicode_funcs_is_immutable (uf));
    589 
    590   uf2 = hb_unicode_funcs_create (uf);
    591   g_assert (hb_unicode_funcs_is_immutable (uf));
    592   hb_unicode_funcs_destroy (uf);
    593 
    594   g_assert (!hb_unicode_funcs_is_immutable (uf2));
    595   hb_unicode_funcs_make_immutable (uf2);
    596   test_unicode_properties (uf2);
    597 
    598   hb_unicode_funcs_destroy (uf2);
    599 
    600 }
    601 
    602 static void
    603 test_unicode_setters (void)
    604 {
    605   hb_unicode_funcs_t *uf;
    606   unsigned int i;
    607 
    608   /* This is cruel: we use script-returning functions to test all properties,
    609    * but it works. */
    610 
    611   for (i = 0; i < G_N_ELEMENTS (properties); i++) {
    612     const property_t *p = &properties[i];
    613     data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
    614 
    615     g_test_message ("Testing property %s", p->name);
    616 
    617     uf = hb_unicode_funcs_create (NULL);
    618     g_assert (!hb_unicode_funcs_is_immutable (uf));
    619 
    620     p->func_setter (uf, (get_func_t) simple_get_script, &data[0], free_up);
    621 
    622     g_assert_cmphex (p->getter (uf, 'a'), ==, HB_SCRIPT_LATIN);
    623     g_assert_cmphex (p->getter (uf, '0'), ==, HB_SCRIPT_UNKNOWN);
    624 
    625     p->func_setter (uf, (get_func_t) NULL, NULL, NULL);
    626     g_assert (data[0].freed && !data[1].freed);
    627 
    628     g_assert (!hb_unicode_funcs_is_immutable (uf));
    629     hb_unicode_funcs_make_immutable (uf);
    630     g_assert (hb_unicode_funcs_is_immutable (uf));
    631 
    632     /* Since uf is immutable now, the following setter should do nothing. */
    633     p->func_setter (uf, (get_func_t) a_is_for_arabic_get_script, &data[1], free_up);
    634 
    635     g_assert (data[0].freed && !data[1].freed);
    636     hb_unicode_funcs_destroy (uf);
    637     g_assert (data[0].freed && !data[1].freed);
    638   }
    639 }
    640 
    641 
    642 
    643 typedef struct {
    644   data_t data[2];
    645 } data_fixture_t;
    646 
    647 static void
    648 data_fixture_init (data_fixture_t *f, gconstpointer user_data)
    649 {
    650   f->data[0].value = MAGIC0;
    651   f->data[1].value = MAGIC1;
    652 }
    653 static void
    654 data_fixture_finish (data_fixture_t *f, gconstpointer user_data)
    655 {
    656 }
    657 
    658 static void
    659 test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data)
    660 {
    661   hb_unicode_funcs_t *uf, *aa;
    662 
    663   uf = hb_unicode_funcs_create (NULL);
    664 
    665   aa = hb_unicode_funcs_create (uf);
    666 
    667   hb_unicode_funcs_destroy (uf);
    668 
    669   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
    670                                     &f->data[1], free_up);
    671 
    672   g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
    673   g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
    674 
    675   g_assert (!f->data[0].freed && !f->data[1].freed);
    676   hb_unicode_funcs_destroy (aa);
    677   g_assert (!f->data[0].freed && f->data[1].freed);
    678 }
    679 
    680 static void
    681 test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data)
    682 {
    683   hb_unicode_funcs_t *uf, *aa;
    684 
    685   uf = hb_unicode_funcs_get_default ();
    686   aa = hb_unicode_funcs_create (uf);
    687 
    688   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
    689                                     &f->data[1], free_up);
    690 
    691   g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
    692   g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
    693 
    694   g_assert (!f->data[0].freed && !f->data[1].freed);
    695   hb_unicode_funcs_destroy (aa);
    696   g_assert (!f->data[0].freed && f->data[1].freed);
    697 }
    698 
    699 static void
    700 test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data)
    701 {
    702   hb_unicode_funcs_t *uf, *aa;
    703 
    704   uf = hb_unicode_funcs_create (NULL);
    705 
    706   hb_unicode_funcs_set_script_func (uf, simple_get_script,
    707                                     &f->data[0], free_up);
    708 
    709   aa = hb_unicode_funcs_create (uf);
    710 
    711   hb_unicode_funcs_destroy (uf);
    712 
    713   /* make sure the 'uf' didn't get freed, since 'aa' holds a ref */
    714   g_assert (!f->data[0].freed);
    715 
    716   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
    717                                     &f->data[1], free_up);
    718 
    719   g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
    720   g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
    721   g_assert_cmphex (hb_unicode_script (aa, '0'), ==, HB_SCRIPT_UNKNOWN);
    722 
    723   g_assert (!f->data[0].freed && !f->data[1].freed);
    724   hb_unicode_funcs_destroy (aa);
    725   g_assert (f->data[0].freed && f->data[1].freed);
    726 }
    727 
    728 
    729 static hb_script_t
    730 script_roundtrip_default (hb_script_t script)
    731 {
    732   return hb_script_from_iso15924_tag (hb_script_to_iso15924_tag (script));
    733 }
    734 
    735 #ifdef HAVE_GLIB
    736 static hb_script_t
    737 script_roundtrip_glib (hb_script_t script)
    738 {
    739   return hb_glib_script_to_script (hb_glib_script_from_script (script));
    740 }
    741 #endif
    742 
    743 #ifdef HAVE_ICU
    744 static hb_script_t
    745 script_roundtrip_icu (hb_script_t script)
    746 {
    747   return hb_icu_script_to_script (hb_icu_script_from_script (script));
    748 }
    749 #endif
    750 
    751 static void
    752 test_unicode_script_roundtrip (gconstpointer user_data)
    753 {
    754   typedef hb_script_t (*roundtrip_func_t) (hb_script_t);
    755   roundtrip_func_t roundtrip_func = (roundtrip_func_t) user_data;
    756   unsigned int i;
    757   gboolean failed = FALSE;
    758 
    759   for (i = 0; i < G_N_ELEMENTS (script_tests); i++) {
    760     const test_pair_t *test = &script_tests[i];
    761     hb_script_t script = test->value;
    762 
    763     g_test_message ("Test script roundtrip #%d: %x", i, script);
    764     g_assert_cmphex (script, ==, roundtrip_func (script));
    765   }
    766   for (i = 0; i < G_N_ELEMENTS (script_tests_more); i++) {
    767     const test_pair_t *test = &script_tests_more[i];
    768     hb_script_t script = test->value;
    769 
    770     g_test_message ("Test script roundtrip more #%d: %x", i, script);
    771     if (script != roundtrip_func (script)) {
    772       g_test_message ("Soft fail: Received %x, expected %x", roundtrip_func (script), script);
    773       failed = TRUE;
    774     }
    775   }
    776 
    777   g_assert_cmphex (HB_SCRIPT_INVALID, ==, roundtrip_func (HB_SCRIPT_INVALID));
    778 
    779   if (failed)
    780     g_test_message ("Some script roundtrip tests failed.  You probably have an old version of one of the libraries used.");
    781 }
    782 
    783 
    784 static void
    785 test_unicode_normalization (gconstpointer user_data)
    786 {
    787   hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
    788   gunichar a, b, ab;
    789   hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
    790 
    791 
    792   /* Test compose() */
    793 
    794   /* Not composable */
    795   g_assert (!hb_unicode_compose (uf, 0x0041, 0x0042, &ab) && ab == 0);
    796   g_assert (!hb_unicode_compose (uf, 0x0041, 0, &ab) && ab == 0);
    797   g_assert (!hb_unicode_compose (uf, 0x0066, 0x0069, &ab) && ab == 0);
    798 
    799   /* Singletons should not compose */
    800   g_assert (!hb_unicode_compose (uf, 0x212B, 0, &ab) && ab == 0);
    801   g_assert (!hb_unicode_compose (uf, 0x00C5, 0, &ab) && ab == 0);
    802   g_assert (!hb_unicode_compose (uf, 0x2126, 0, &ab) && ab == 0);
    803   g_assert (!hb_unicode_compose (uf, 0x03A9, 0, &ab) && ab == 0);
    804 
    805   /* Non-starter pairs should not compose */
    806   g_assert (!hb_unicode_compose (uf, 0x0308, 0x0301, &ab) && ab == 0); /* !0x0344 */
    807   g_assert (!hb_unicode_compose (uf, 0x0F71, 0x0F72, &ab) && ab == 0); /* !0x0F73 */
    808 
    809   /* Pairs */
    810   g_assert (hb_unicode_compose (uf, 0x0041, 0x030A, &ab) && ab == 0x00C5);
    811   g_assert (hb_unicode_compose (uf, 0x006F, 0x0302, &ab) && ab == 0x00F4);
    812   g_assert (hb_unicode_compose (uf, 0x1E63, 0x0307, &ab) && ab == 0x1E69);
    813   g_assert (hb_unicode_compose (uf, 0x0073, 0x0323, &ab) && ab == 0x1E63);
    814   g_assert (hb_unicode_compose (uf, 0x0064, 0x0307, &ab) && ab == 0x1E0B);
    815   g_assert (hb_unicode_compose (uf, 0x0064, 0x0323, &ab) && ab == 0x1E0D);
    816 
    817   /* Hangul */
    818   g_assert (hb_unicode_compose (uf, 0xD4CC, 0x11B6, &ab) && ab == 0xD4DB);
    819   g_assert (hb_unicode_compose (uf, 0x1111, 0x1171, &ab) && ab == 0xD4CC);
    820   g_assert (hb_unicode_compose (uf, 0xCE20, 0x11B8, &ab) && ab == 0xCE31);
    821   g_assert (hb_unicode_compose (uf, 0x110E, 0x1173, &ab) && ab == 0xCE20);
    822 
    823 
    824   /* Test decompose() */
    825 
    826   /* Not decomposable */
    827   g_assert (!hb_unicode_decompose (uf, 0x0041, &a, &b) && a == 0x0041 && b == 0);
    828   g_assert (!hb_unicode_decompose (uf, 0xFB01, &a, &b) && a == 0xFB01 && b == 0);
    829   g_assert (!hb_unicode_decompose (uf, 0x1F1EF, &a, &b) && a == 0x1F1EF && b == 0);
    830 
    831   /* Singletons */
    832   g_assert (hb_unicode_decompose (uf, 0x212B, &a, &b) && a == 0x00C5 && b == 0);
    833   g_assert (hb_unicode_decompose (uf, 0x2126, &a, &b) && a == 0x03A9 && b == 0);
    834 
    835   /* Non-starter pairs decompose, but not compose */
    836   g_assert (hb_unicode_decompose (uf, 0x0344, &a, &b) && a == 0x0308 && b == 0x0301);
    837   g_assert (hb_unicode_decompose (uf, 0x0F73, &a, &b) && a == 0x0F71 && b == 0x0F72);
    838 
    839   /* Pairs */
    840   g_assert (hb_unicode_decompose (uf, 0x00C5, &a, &b) && a == 0x0041 && b == 0x030A);
    841   g_assert (hb_unicode_decompose (uf, 0x00F4, &a, &b) && a == 0x006F && b == 0x0302);
    842   g_assert (hb_unicode_decompose (uf, 0x1E69, &a, &b) && a == 0x1E63 && b == 0x0307);
    843   g_assert (hb_unicode_decompose (uf, 0x1E63, &a, &b) && a == 0x0073 && b == 0x0323);
    844   g_assert (hb_unicode_decompose (uf, 0x1E0B, &a, &b) && a == 0x0064 && b == 0x0307);
    845   g_assert (hb_unicode_decompose (uf, 0x1E0D, &a, &b) && a == 0x0064 && b == 0x0323);
    846 
    847   /* Hangul */
    848   g_assert (hb_unicode_decompose (uf, 0xD4DB, &a, &b) && a == 0xD4CC && b == 0x11B6);
    849   g_assert (hb_unicode_decompose (uf, 0xD4CC, &a, &b) && a == 0x1111 && b == 0x1171);
    850   g_assert (hb_unicode_decompose (uf, 0xCE31, &a, &b) && a == 0xCE20 && b == 0x11B8);
    851   g_assert (hb_unicode_decompose (uf, 0xCE20, &a, &b) && a == 0x110E && b == 0x1173);
    852 
    853 
    854   /* Test decompose_compatibility() */
    855 
    856   /* Not decomposable */
    857   g_assert (hb_unicode_decompose_compatibility (uf, 0x0041, decomposed) == 0);
    858   g_assert (hb_unicode_decompose_compatibility (uf, 0x1F632, decomposed) == 0);
    859 
    860   /* Singletons */
    861   g_assert (hb_unicode_decompose_compatibility (uf, 0x00B5, decomposed) == 1 && decomposed[0] == 0x03BC);
    862   g_assert (hb_unicode_decompose_compatibility (uf, 0x03D6, decomposed) == 1 && decomposed[0] == 0x03C0);
    863 
    864   /* Arabic compatibility */
    865   g_assert (hb_unicode_decompose_compatibility (uf, 0xFB54, decomposed) == 1 && decomposed[0] == 0x067B);
    866 
    867   /* Longest decomposition ever */
    868   g_assert (18 <= HB_UNICODE_MAX_DECOMPOSITION_LEN);
    869   g_assert (hb_unicode_decompose_compatibility (uf, 0xFDFA, decomposed) == 18 && decomposed[17] == 0x0645);
    870 
    871   /* Note: we deliberately don't test characters that have canonical decompositions but no
    872    * compatibility decomposition against the decompose_compatibility() function as that we
    873    * leave up to implementations (for now). */
    874 
    875   /* Spaces */
    876   g_assert (hb_unicode_decompose_compatibility (uf, 0x2002, decomposed) == 1 && decomposed[0] == 0x0020);
    877   g_assert (hb_unicode_decompose_compatibility (uf, 0x2003, decomposed) == 1 && decomposed[0] == 0x0020);
    878   g_assert (hb_unicode_decompose_compatibility (uf, 0x2004, decomposed) == 1 && decomposed[0] == 0x0020);
    879   g_assert (hb_unicode_decompose_compatibility (uf, 0x2005, decomposed) == 1 && decomposed[0] == 0x0020);
    880   g_assert (hb_unicode_decompose_compatibility (uf, 0x2006, decomposed) == 1 && decomposed[0] == 0x0020);
    881   g_assert (hb_unicode_decompose_compatibility (uf, 0x2008, decomposed) == 1 && decomposed[0] == 0x0020);
    882   g_assert (hb_unicode_decompose_compatibility (uf, 0x2009, decomposed) == 1 && decomposed[0] == 0x0020);
    883   g_assert (hb_unicode_decompose_compatibility (uf, 0x200A, decomposed) == 1 && decomposed[0] == 0x0020);
    884 
    885   /* Pairs */
    886   g_assert (hb_unicode_decompose_compatibility (uf, 0x0587, decomposed) == 2 &&
    887             decomposed[0] == 0x0565 && decomposed[1] == 0x0582);
    888   g_assert (hb_unicode_decompose_compatibility (uf, 0x2017, decomposed) == 2 &&
    889             decomposed[0] == 0x0020 && decomposed[1] == 0x0333);
    890   g_assert (hb_unicode_decompose_compatibility (uf, 0x2025, decomposed) == 2 &&
    891             decomposed[0] == 0x002E && decomposed[1] == 0x002E);
    892   g_assert (hb_unicode_decompose_compatibility (uf, 0x2033, decomposed) == 2 &&
    893             decomposed[0] == 0x2032 && decomposed[1] == 0x2032);
    894 
    895   /* Triples */
    896   g_assert (hb_unicode_decompose_compatibility (uf, 0x2026, decomposed) == 3 &&
    897             decomposed[0] == 0x002E && decomposed[1] == 0x002E && decomposed[2] == 0x002E);
    898   g_assert (hb_unicode_decompose_compatibility (uf, 0x2034, decomposed) == 3 &&
    899             decomposed[0] == 0x2032 && decomposed[1] == 0x2032 && decomposed[2] == 0x2032);
    900   g_assert (hb_unicode_decompose_compatibility (uf, 0x213B, decomposed) == 3 &&
    901             decomposed[0] == 0x0046 && decomposed[1] == 0x0041 && decomposed[2] == 0x0058);
    902 }
    903 
    904 
    905 
    906 int
    907 main (int argc, char **argv)
    908 {
    909   hb_test_init (&argc, &argv);
    910 
    911   hb_test_add (test_unicode_properties_nil);
    912   hb_test_add (test_unicode_properties_empty);
    913 
    914   hb_test_add_data_flavor (hb_unicode_funcs_get_default (),          "default", test_unicode_properties);
    915   hb_test_add_data_flavor (hb_unicode_funcs_get_default (),          "default", test_unicode_normalization);
    916   hb_test_add_data_flavor ((gconstpointer) script_roundtrip_default, "default", test_unicode_script_roundtrip);
    917 #ifdef HAVE_GLIB
    918   hb_test_add_data_flavor (hb_glib_get_unicode_funcs (),             "glib",    test_unicode_properties);
    919   hb_test_add_data_flavor (hb_glib_get_unicode_funcs (),             "glib",    test_unicode_normalization);
    920   hb_test_add_data_flavor ((gconstpointer) script_roundtrip_glib,    "glib",    test_unicode_script_roundtrip);
    921 #endif
    922 #ifdef HAVE_ICU
    923   hb_test_add_data_flavor (hb_icu_get_unicode_funcs (),              "icu",     test_unicode_properties);
    924   hb_test_add_data_flavor (hb_icu_get_unicode_funcs (),              "icu",     test_unicode_normalization);
    925   hb_test_add_data_flavor ((gconstpointer) script_roundtrip_icu,     "icu",     test_unicode_script_roundtrip);
    926 #endif
    927 
    928   hb_test_add (test_unicode_chainup);
    929 
    930   hb_test_add (test_unicode_setters);
    931 
    932   hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_nil);
    933   hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_default);
    934   hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_deep);
    935 
    936   return hb_test_run ();
    937 }
    938