Home | History | Annotate | Download | only in cintltst
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1997-2011, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ********************************************************************/
      6 /********************************************************************************
      7 *
      8 * File CNORMTST.C
      9 *
     10 * Modification History:
     11 *        Name                     Description
     12 *     Madhu Katragadda            Ported for C API
     13 *     synwee                      added test for quick check
     14 *     synwee                      added test for checkFCD
     15 *********************************************************************************/
     16 /*tests for u_normalization*/
     17 #include "unicode/utypes.h"
     18 #include "unicode/unorm.h"
     19 #include "cintltst.h"
     20 
     21 #if UCONFIG_NO_NORMALIZATION
     22 
     23 void addNormTest(TestNode** root) {
     24     /* no normalization - nothing to do */
     25 }
     26 
     27 #else
     28 
     29 #include <stdlib.h>
     30 #include <time.h>
     31 #include "unicode/uchar.h"
     32 #include "unicode/ustring.h"
     33 #include "unicode/unorm.h"
     34 #include "cnormtst.h"
     35 
     36 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof ((array)[0]))
     37 
     38 static void
     39 TestAPI(void);
     40 
     41 static void
     42 TestNormCoverage(void);
     43 
     44 static void
     45 TestConcatenate(void);
     46 
     47 static void
     48 TestNextPrevious(void);
     49 
     50 static void TestIsNormalized(void);
     51 
     52 static void
     53 TestFCNFKCClosure(void);
     54 
     55 static void
     56 TestQuickCheckPerCP(void);
     57 
     58 static void
     59 TestComposition(void);
     60 
     61 static void
     62 TestFCD(void);
     63 
     64 static void
     65 TestGetDecomposition(void);
     66 
     67 static void TestAppendRestoreMiddle(void);
     68 
     69 static const char* const canonTests[][3] = {
     70     /* Input*/                    /*Decomposed*/                /*Composed*/
     71     { "cat",                    "cat",                        "cat"                    },
     72     { "\\u00e0ardvark",            "a\\u0300ardvark",            "\\u00e0ardvark",        },
     73 
     74     { "\\u1e0a",                "D\\u0307",                    "\\u1e0a"                }, /* D-dot_above*/
     75     { "D\\u0307",                "D\\u0307",                    "\\u1e0a"                }, /* D dot_above*/
     76 
     77     { "\\u1e0c\\u0307",            "D\\u0323\\u0307",            "\\u1e0c\\u0307"        }, /* D-dot_below dot_above*/
     78     { "\\u1e0a\\u0323",            "D\\u0323\\u0307",            "\\u1e0c\\u0307"        }, /* D-dot_above dot_below */
     79     { "D\\u0307\\u0323",        "D\\u0323\\u0307",            "\\u1e0c\\u0307"        }, /* D dot_below dot_above */
     80 
     81     { "\\u1e10\\u0307\\u0323",    "D\\u0327\\u0323\\u0307",    "\\u1e10\\u0323\\u0307"    }, /*D dot_below cedilla dot_above*/
     82     { "D\\u0307\\u0328\\u0323",    "D\\u0328\\u0323\\u0307",    "\\u1e0c\\u0328\\u0307"    }, /* D dot_above ogonek dot_below*/
     83 
     84     { "\\u1E14",                "E\\u0304\\u0300",            "\\u1E14"                }, /* E-macron-grave*/
     85     { "\\u0112\\u0300",            "E\\u0304\\u0300",            "\\u1E14"                }, /* E-macron + grave*/
     86     { "\\u00c8\\u0304",            "E\\u0300\\u0304",            "\\u00c8\\u0304"        }, /* E-grave + macron*/
     87 
     88     { "\\u212b",                "A\\u030a",                    "\\u00c5"                }, /* angstrom_sign*/
     89     { "\\u00c5",                "A\\u030a",                    "\\u00c5"                }, /* A-ring*/
     90 
     91     { "\\u00C4ffin",            "A\\u0308ffin",                "\\u00C4ffin"                    },
     92     { "\\u00C4\\uFB03n",        "A\\u0308\\uFB03n",            "\\u00C4\\uFB03n"                },
     93 
     94     { "Henry IV",                "Henry IV",                    "Henry IV"                },
     95     { "Henry \\u2163",            "Henry \\u2163",            "Henry \\u2163"            },
     96 
     97     { "\\u30AC",                "\\u30AB\\u3099",            "\\u30AC"                }, /* ga (Katakana)*/
     98     { "\\u30AB\\u3099",            "\\u30AB\\u3099",            "\\u30AC"                }, /*ka + ten*/
     99     { "\\uFF76\\uFF9E",            "\\uFF76\\uFF9E",            "\\uFF76\\uFF9E"        }, /* hw_ka + hw_ten*/
    100     { "\\u30AB\\uFF9E",            "\\u30AB\\uFF9E",            "\\u30AB\\uFF9E"        }, /* ka + hw_ten*/
    101     { "\\uFF76\\u3099",            "\\uFF76\\u3099",            "\\uFF76\\u3099"        },  /* hw_ka + ten*/
    102     { "A\\u0300\\u0316",           "A\\u0316\\u0300",           "\\u00C0\\u0316"        },  /* hw_ka + ten*/
    103     { "", "", "" }
    104 };
    105 
    106 static const char* const compatTests[][3] = {
    107     /* Input*/                        /*Decomposed    */                /*Composed*/
    108     { "cat",                        "cat",                            "cat"                },
    109 
    110     { "\\uFB4f",                    "\\u05D0\\u05DC",                "\\u05D0\\u05DC"    }, /* Alef-Lamed vs. Alef, Lamed*/
    111 
    112     { "\\u00C4ffin",                "A\\u0308ffin",                    "\\u00C4ffin"             },
    113     { "\\u00C4\\uFB03n",            "A\\u0308ffin",                    "\\u00C4ffin"                }, /* ffi ligature -> f + f + i*/
    114 
    115     { "Henry IV",                    "Henry IV",                        "Henry IV"            },
    116     { "Henry \\u2163",                "Henry IV",                        "Henry IV"            },
    117 
    118     { "\\u30AC",                    "\\u30AB\\u3099",                "\\u30AC"            }, /* ga (Katakana)*/
    119     { "\\u30AB\\u3099",                "\\u30AB\\u3099",                "\\u30AC"            }, /*ka + ten*/
    120 
    121     { "\\uFF76\\u3099",                "\\u30AB\\u3099",                "\\u30AC"            }, /* hw_ka + ten*/
    122 
    123     /*These two are broken in Unicode 2.1.2 but fixed in 2.1.5 and later*/
    124     { "\\uFF76\\uFF9E",                "\\u30AB\\u3099",                "\\u30AC"            }, /* hw_ka + hw_ten*/
    125     { "\\u30AB\\uFF9E",                "\\u30AB\\u3099",                "\\u30AC"            }, /* ka + hw_ten*/
    126     { "", "", "" }
    127 };
    128 
    129 static const char* const fcdTests[][3] = {
    130     /* Added for testing the below-U+0300 prefix of a NUL-terminated string. */
    131     { "\\u010e\\u0327", "D\\u0327\\u030c", NULL },  /* D-caron + cedilla */
    132     { "\\u010e", "\\u010e", NULL }  /* D-caron */
    133 };
    134 
    135 void addNormTest(TestNode** root);
    136 
    137 void addNormTest(TestNode** root)
    138 {
    139     addTest(root, &TestAPI, "tsnorm/cnormtst/TestAPI");
    140     addTest(root, &TestDecomp, "tsnorm/cnormtst/TestDecomp");
    141     addTest(root, &TestCompatDecomp, "tsnorm/cnormtst/TestCompatDecomp");
    142     addTest(root, &TestCanonDecompCompose, "tsnorm/cnormtst/TestCanonDecompCompose");
    143     addTest(root, &TestCompatDecompCompose, "tsnorm/cnormtst/TestCompatDecompCompose");
    144     addTest(root, &TestFCD, "tsnorm/cnormtst/TestFCD");
    145     addTest(root, &TestNull, "tsnorm/cnormtst/TestNull");
    146     addTest(root, &TestQuickCheck, "tsnorm/cnormtst/TestQuickCheck");
    147     addTest(root, &TestQuickCheckPerCP, "tsnorm/cnormtst/TestQuickCheckPerCP");
    148     addTest(root, &TestIsNormalized, "tsnorm/cnormtst/TestIsNormalized");
    149     addTest(root, &TestCheckFCD, "tsnorm/cnormtst/TestCheckFCD");
    150     addTest(root, &TestNormCoverage, "tsnorm/cnormtst/TestNormCoverage");
    151     addTest(root, &TestConcatenate, "tsnorm/cnormtst/TestConcatenate");
    152     addTest(root, &TestNextPrevious, "tsnorm/cnormtst/TestNextPrevious");
    153     addTest(root, &TestFCNFKCClosure, "tsnorm/cnormtst/TestFCNFKCClosure");
    154     addTest(root, &TestComposition, "tsnorm/cnormtst/TestComposition");
    155     addTest(root, &TestGetDecomposition, "tsnorm/cnormtst/TestGetDecomposition");
    156     addTest(root, &TestAppendRestoreMiddle, "tsnorm/cnormtst/TestAppendRestoreMiddle");
    157 }
    158 
    159 static const char* const modeStrings[]={
    160     "UNORM_NONE",
    161     "UNORM_NFD",
    162     "UNORM_NFKD",
    163     "UNORM_NFC",
    164     "UNORM_NFKC",
    165     "UNORM_FCD",
    166     "UNORM_MODE_COUNT"
    167 };
    168 
    169 static void TestNormCases(UNormalizationMode mode,
    170                           const char* const cases[][3], int32_t lengthOfCases) {
    171     int32_t x, neededLen, length2;
    172     int32_t expIndex= (mode==UNORM_NFC || mode==UNORM_NFKC) ? 2 : 1;
    173     UChar *source=NULL;
    174     UChar result[16];
    175     log_verbose("Testing unorm_normalize(%s)\n", modeStrings[mode]);
    176     for(x=0; x < lengthOfCases; x++)
    177     {
    178         UErrorCode status = U_ZERO_ERROR, status2 = U_ZERO_ERROR;
    179         source=CharsToUChars(cases[x][0]);
    180         neededLen= unorm_normalize(source, u_strlen(source), mode, 0, NULL, 0, &status);
    181         length2= unorm_normalize(source, -1, mode, 0, NULL, 0, &status2);
    182         if(neededLen!=length2) {
    183           log_err("ERROR in unorm_normalize(%s)[%d]: "
    184                   "preflight length/NUL %d!=%d preflight length/srcLength\n",
    185                   modeStrings[mode], (int)x, (int)neededLen, (int)length2);
    186         }
    187         if(status==U_BUFFER_OVERFLOW_ERROR)
    188         {
    189             status=U_ZERO_ERROR;
    190         }
    191         length2=unorm_normalize(source, u_strlen(source), mode, 0, result, LENGTHOF(result), &status);
    192         if(U_FAILURE(status) || neededLen!=length2) {
    193             log_data_err("ERROR in unorm_normalize(%s/NUL) at %s:  %s - (Are you missing data?)\n",
    194                          modeStrings[mode], austrdup(source), myErrorName(status));
    195         } else {
    196             assertEqual(result, cases[x][expIndex], x);
    197         }
    198         length2=unorm_normalize(source, -1, mode, 0, result, LENGTHOF(result), &status);
    199         if(U_FAILURE(status) || neededLen!=length2) {
    200             log_data_err("ERROR in unorm_normalize(%s/srcLength) at %s:  %s - (Are you missing data?)\n",
    201                          modeStrings[mode], austrdup(source), myErrorName(status));
    202         } else {
    203             assertEqual(result, cases[x][expIndex], x);
    204         }
    205         free(source);
    206     }
    207 }
    208 
    209 void TestDecomp() {
    210     TestNormCases(UNORM_NFD, canonTests, LENGTHOF(canonTests));
    211 }
    212 
    213 void TestCompatDecomp() {
    214     TestNormCases(UNORM_NFKD, compatTests, LENGTHOF(compatTests));
    215 }
    216 
    217 void TestCanonDecompCompose() {
    218     TestNormCases(UNORM_NFC, canonTests, LENGTHOF(canonTests));
    219 }
    220 
    221 void TestCompatDecompCompose() {
    222     TestNormCases(UNORM_NFKC, compatTests, LENGTHOF(compatTests));
    223 }
    224 
    225 void TestFCD() {
    226     TestNormCases(UNORM_FCD, fcdTests, LENGTHOF(fcdTests));
    227 }
    228 
    229 static void assertEqual(const UChar* result, const char* expected, int32_t index)
    230 {
    231     UChar *expectedUni = CharsToUChars(expected);
    232     if(u_strcmp(result, expectedUni)!=0){
    233         log_err("ERROR in decomposition at index = %d. EXPECTED: %s , GOT: %s\n", index, expected,
    234             austrdup(result) );
    235     }
    236     free(expectedUni);
    237 }
    238 
    239 static void TestNull_check(UChar *src, int32_t srcLen,
    240                     UChar *exp, int32_t expLen,
    241                     UNormalizationMode mode,
    242                     const char *name)
    243 {
    244     UErrorCode status = U_ZERO_ERROR;
    245     int32_t len, i;
    246 
    247     UChar   result[50];
    248 
    249 
    250     status = U_ZERO_ERROR;
    251 
    252     for(i=0;i<50;i++)
    253       {
    254         result[i] = 0xFFFD;
    255       }
    256 
    257     len = unorm_normalize(src, srcLen, mode, 0, result, 50, &status);
    258 
    259     if(U_FAILURE(status)) {
    260       log_data_err("unorm_normalize(%s) with 0x0000 failed: %s - (Are you missing data?)\n", name, u_errorName(status));
    261     } else if (len != expLen) {
    262       log_err("unorm_normalize(%s) with 0x0000 failed: Expected len %d, got %d\n", name, expLen, len);
    263     }
    264 
    265     {
    266       for(i=0;i<len;i++){
    267         if(exp[i] != result[i]) {
    268           log_err("unorm_normalize(%s): @%d, expected \\u%04X got \\u%04X\n",
    269                   name,
    270                   i,
    271                   exp[i],
    272                   result[i]);
    273           return;
    274         }
    275         log_verbose("     %d: \\u%04X\n", i, result[i]);
    276       }
    277     }
    278 
    279     log_verbose("unorm_normalize(%s) with 0x0000: OK\n", name);
    280 }
    281 
    282 void TestNull()
    283 {
    284 
    285     UChar   source_comp[] = { 0x0061, 0x0000, 0x0044, 0x0307 };
    286     int32_t source_comp_len = 4;
    287     UChar   expect_comp[] = { 0x0061, 0x0000, 0x1e0a };
    288     int32_t expect_comp_len = 3;
    289 
    290     UChar   source_dcmp[] = { 0x1e0A, 0x0000, 0x0929 };
    291     int32_t source_dcmp_len = 3;
    292     UChar   expect_dcmp[] = { 0x0044, 0x0307, 0x0000, 0x0928, 0x093C };
    293     int32_t expect_dcmp_len = 5;
    294 
    295     TestNull_check(source_comp,
    296                    source_comp_len,
    297                    expect_comp,
    298                    expect_comp_len,
    299                    UNORM_NFC,
    300                    "UNORM_NFC");
    301 
    302     TestNull_check(source_dcmp,
    303                    source_dcmp_len,
    304                    expect_dcmp,
    305                    expect_dcmp_len,
    306                    UNORM_NFD,
    307                    "UNORM_NFD");
    308 
    309     TestNull_check(source_comp,
    310                    source_comp_len,
    311                    expect_comp,
    312                    expect_comp_len,
    313                    UNORM_NFKC,
    314                    "UNORM_NFKC");
    315 
    316 
    317 }
    318 
    319 static void TestQuickCheckResultNO()
    320 {
    321   const UChar CPNFD[] = {0x00C5, 0x0407, 0x1E00, 0x1F57, 0x220C,
    322                          0x30AE, 0xAC00, 0xD7A3, 0xFB36, 0xFB4E};
    323   const UChar CPNFC[] = {0x0340, 0x0F93, 0x1F77, 0x1FBB, 0x1FEB,
    324                           0x2000, 0x232A, 0xF900, 0xFA1E, 0xFB4E};
    325   const UChar CPNFKD[] = {0x00A0, 0x02E4, 0x1FDB, 0x24EA, 0x32FE,
    326                            0xAC00, 0xFB4E, 0xFA10, 0xFF3F, 0xFA2D};
    327   const UChar CPNFKC[] = {0x00A0, 0x017F, 0x2000, 0x24EA, 0x32FE,
    328                            0x33FE, 0xFB4E, 0xFA10, 0xFF3F, 0xFA2D};
    329 
    330 
    331   const int SIZE = 10;
    332 
    333   int count = 0;
    334   UErrorCode error = U_ZERO_ERROR;
    335 
    336   for (; count < SIZE; count ++)
    337   {
    338     if (unorm_quickCheck(&(CPNFD[count]), 1, UNORM_NFD, &error) !=
    339                                                               UNORM_NO)
    340     {
    341       log_err("ERROR in NFD quick check at U+%04x\n", CPNFD[count]);
    342       return;
    343     }
    344     if (unorm_quickCheck(&(CPNFC[count]), 1, UNORM_NFC, &error) !=
    345                                                               UNORM_NO)
    346     {
    347       log_err("ERROR in NFC quick check at U+%04x\n", CPNFC[count]);
    348       return;
    349     }
    350     if (unorm_quickCheck(&(CPNFKD[count]), 1, UNORM_NFKD, &error) !=
    351                                                               UNORM_NO)
    352     {
    353       log_err("ERROR in NFKD quick check at U+%04x\n", CPNFKD[count]);
    354       return;
    355     }
    356     if (unorm_quickCheck(&(CPNFKC[count]), 1, UNORM_NFKC, &error) !=
    357                                                               UNORM_NO)
    358     {
    359       log_err("ERROR in NFKC quick check at U+%04x\n", CPNFKC[count]);
    360       return;
    361     }
    362   }
    363 }
    364 
    365 
    366 static void TestQuickCheckResultYES()
    367 {
    368   const UChar CPNFD[] = {0x00C6, 0x017F, 0x0F74, 0x1000, 0x1E9A,
    369                          0x2261, 0x3075, 0x4000, 0x5000, 0xF000};
    370   const UChar CPNFC[] = {0x0400, 0x0540, 0x0901, 0x1000, 0x1500,
    371                          0x1E9A, 0x3000, 0x4000, 0x5000, 0xF000};
    372   const UChar CPNFKD[] = {0x00AB, 0x02A0, 0x1000, 0x1027, 0x2FFB,
    373                           0x3FFF, 0x4FFF, 0xA000, 0xF000, 0xFA27};
    374   const UChar CPNFKC[] = {0x00B0, 0x0100, 0x0200, 0x0A02, 0x1000,
    375                           0x2010, 0x3030, 0x4000, 0xA000, 0xFA0E};
    376 
    377   const int SIZE = 10;
    378   int count = 0;
    379   UErrorCode error = U_ZERO_ERROR;
    380 
    381   UChar cp = 0;
    382   while (cp < 0xA0)
    383   {
    384     if (unorm_quickCheck(&cp, 1, UNORM_NFD, &error) != UNORM_YES)
    385     {
    386       log_data_err("ERROR in NFD quick check at U+%04x - (Are you missing data?)\n", cp);
    387       return;
    388     }
    389     if (unorm_quickCheck(&cp, 1, UNORM_NFC, &error) !=
    390                                                              UNORM_YES)
    391     {
    392       log_err("ERROR in NFC quick check at U+%04x\n", cp);
    393       return;
    394     }
    395     if (unorm_quickCheck(&cp, 1, UNORM_NFKD, &error) != UNORM_YES)
    396     {
    397       log_err("ERROR in NFKD quick check at U+%04x\n", cp);
    398       return;
    399     }
    400     if (unorm_quickCheck(&cp, 1, UNORM_NFKC, &error) !=
    401                                                              UNORM_YES)
    402     {
    403       log_err("ERROR in NFKC quick check at U+%04x\n", cp);
    404       return;
    405     }
    406     cp ++;
    407   }
    408 
    409   for (; count < SIZE; count ++)
    410   {
    411     if (unorm_quickCheck(&(CPNFD[count]), 1, UNORM_NFD, &error) !=
    412                                                              UNORM_YES)
    413     {
    414       log_err("ERROR in NFD quick check at U+%04x\n", CPNFD[count]);
    415       return;
    416     }
    417     if (unorm_quickCheck(&(CPNFC[count]), 1, UNORM_NFC, &error)
    418                                                           != UNORM_YES)
    419     {
    420       log_err("ERROR in NFC quick check at U+%04x\n", CPNFC[count]);
    421       return;
    422     }
    423     if (unorm_quickCheck(&(CPNFKD[count]), 1, UNORM_NFKD, &error) !=
    424                                                              UNORM_YES)
    425     {
    426       log_err("ERROR in NFKD quick check at U+%04x\n", CPNFKD[count]);
    427       return;
    428     }
    429     if (unorm_quickCheck(&(CPNFKC[count]), 1, UNORM_NFKC, &error) !=
    430                                                              UNORM_YES)
    431     {
    432       log_err("ERROR in NFKC quick check at U+%04x\n", CPNFKC[count]);
    433       return;
    434     }
    435   }
    436 }
    437 
    438 static void TestQuickCheckResultMAYBE()
    439 {
    440   const UChar CPNFC[] = {0x0306, 0x0654, 0x0BBE, 0x102E, 0x1161,
    441                          0x116A, 0x1173, 0x1175, 0x3099, 0x309A};
    442   const UChar CPNFKC[] = {0x0300, 0x0654, 0x0655, 0x09D7, 0x0B3E,
    443                           0x0DCF, 0xDDF, 0x102E, 0x11A8, 0x3099};
    444 
    445 
    446   const int SIZE = 10;
    447 
    448   int count = 0;
    449   UErrorCode error = U_ZERO_ERROR;
    450 
    451   /* NFD and NFKD does not have any MAYBE codepoints */
    452   for (; count < SIZE; count ++)
    453   {
    454     if (unorm_quickCheck(&(CPNFC[count]), 1, UNORM_NFC, &error) !=
    455                                                            UNORM_MAYBE)
    456     {
    457       log_data_err("ERROR in NFC quick check at U+%04x - (Are you missing data?)\n", CPNFC[count]);
    458       return;
    459     }
    460     if (unorm_quickCheck(&(CPNFKC[count]), 1, UNORM_NFKC, &error) !=
    461                                                            UNORM_MAYBE)
    462     {
    463       log_err("ERROR in NFKC quick check at U+%04x\n", CPNFKC[count]);
    464       return;
    465     }
    466   }
    467 }
    468 
    469 static void TestQuickCheckStringResult()
    470 {
    471   int count;
    472   UChar *d = NULL;
    473   UChar *c = NULL;
    474   UErrorCode error = U_ZERO_ERROR;
    475 
    476   for (count = 0; count < LENGTHOF(canonTests); count ++)
    477   {
    478     d = CharsToUChars(canonTests[count][1]);
    479     c = CharsToUChars(canonTests[count][2]);
    480     if (unorm_quickCheck(d, u_strlen(d), UNORM_NFD, &error) !=
    481                                                             UNORM_YES)
    482     {
    483       log_data_err("ERROR in NFD quick check for string at count %d - (Are you missing data?)\n", count);
    484       return;
    485     }
    486 
    487     if (unorm_quickCheck(c, u_strlen(c), UNORM_NFC, &error) ==
    488                                                             UNORM_NO)
    489     {
    490       log_err("ERROR in NFC quick check for string at count %d\n", count);
    491       return;
    492     }
    493 
    494     free(d);
    495     free(c);
    496   }
    497 
    498   for (count = 0; count < LENGTHOF(compatTests); count ++)
    499   {
    500     d = CharsToUChars(compatTests[count][1]);
    501     c = CharsToUChars(compatTests[count][2]);
    502     if (unorm_quickCheck(d, u_strlen(d), UNORM_NFKD, &error) !=
    503                                                             UNORM_YES)
    504     {
    505       log_err("ERROR in NFKD quick check for string at count %d\n", count);
    506       return;
    507     }
    508 
    509     if (unorm_quickCheck(c, u_strlen(c), UNORM_NFKC, &error) !=
    510                                                             UNORM_YES)
    511     {
    512       log_err("ERROR in NFKC quick check for string at count %d\n", count);
    513       return;
    514     }
    515 
    516     free(d);
    517     free(c);
    518   }
    519 }
    520 
    521 void TestQuickCheck()
    522 {
    523   TestQuickCheckResultNO();
    524   TestQuickCheckResultYES();
    525   TestQuickCheckResultMAYBE();
    526   TestQuickCheckStringResult();
    527 }
    528 
    529 /*
    530  * The intltest/NormalizerConformanceTest tests a lot of strings that _are_
    531  * normalized, and some that are not.
    532  * Here we pick some specific cases and test the C API.
    533  */
    534 static void TestIsNormalized(void) {
    535     static const UChar notNFC[][8]={            /* strings that are not in NFC */
    536         { 0x62, 0x61, 0x300, 0x63, 0 },         /* 0061 0300 compose */
    537         { 0xfb1d, 0 },                          /* excluded from composition */
    538         { 0x0627, 0x0653, 0 },                  /* 0627 0653 compose */
    539         { 0x3071, 0x306f, 0x309a, 0x3073, 0 }   /* 306F 309A compose */
    540     };
    541     static const UChar notNFKC[][8]={           /* strings that are not in NFKC */
    542         { 0x1100, 0x1161, 0 },                  /* Jamo compose */
    543         { 0x1100, 0x314f, 0 },                  /* compatibility Jamo compose */
    544         { 0x03b1, 0x1f00, 0x0345, 0x03b3, 0 }   /* 1F00 0345 compose */
    545     };
    546 
    547     int32_t i;
    548     UErrorCode errorCode;
    549 
    550     /* API test */
    551 
    552     /* normal case with length>=0 (length -1 used for special cases below) */
    553     errorCode=U_ZERO_ERROR;
    554     if(!unorm_isNormalized(notNFC[0]+2, 1, UNORM_NFC, &errorCode) || U_FAILURE(errorCode)) {
    555         log_data_err("error: !isNormalized(<U+0300>, NFC) (%s) - (Are you missing data?)\n", u_errorName(errorCode));
    556     }
    557 
    558     /* incoming U_FAILURE */
    559     errorCode=U_TRUNCATED_CHAR_FOUND;
    560     (void)unorm_isNormalized(notNFC[0]+2, 1, UNORM_NFC, &errorCode);
    561     if(errorCode!=U_TRUNCATED_CHAR_FOUND) {
    562         log_err("error: isNormalized(U_TRUNCATED_CHAR_FOUND) changed the error code to %s\n", u_errorName(errorCode));
    563     }
    564 
    565     /* NULL source */
    566     errorCode=U_ZERO_ERROR;
    567     (void)unorm_isNormalized(NULL, 1, UNORM_NFC, &errorCode);
    568     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
    569         log_data_err("error: isNormalized(NULL) did not set U_ILLEGAL_ARGUMENT_ERROR but %s - (Are you missing data?)\n", u_errorName(errorCode));
    570     }
    571 
    572     /* bad length */
    573     errorCode=U_ZERO_ERROR;
    574     (void)unorm_isNormalized(notNFC[0]+2, -2, UNORM_NFC, &errorCode);
    575     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
    576         log_data_err("error: isNormalized([-2]) did not set U_ILLEGAL_ARGUMENT_ERROR but %s - (Are you missing data?)\n", u_errorName(errorCode));
    577     }
    578 
    579     /* specific cases */
    580     for(i=0; i<LENGTHOF(notNFC); ++i) {
    581         errorCode=U_ZERO_ERROR;
    582         if(unorm_isNormalized(notNFC[i], -1, UNORM_NFC, &errorCode) || U_FAILURE(errorCode)) {
    583             log_data_err("error: isNormalized(notNFC[%d], NFC) is wrong (%s) - (Are you missing data?)\n", i, u_errorName(errorCode));
    584         }
    585         errorCode=U_ZERO_ERROR;
    586         if(unorm_isNormalized(notNFC[i], -1, UNORM_NFKC, &errorCode) || U_FAILURE(errorCode)) {
    587             log_data_err("error: isNormalized(notNFC[%d], NFKC) is wrong (%s) - (Are you missing data?)\n", i, u_errorName(errorCode));
    588         }
    589     }
    590     for(i=0; i<LENGTHOF(notNFKC); ++i) {
    591         errorCode=U_ZERO_ERROR;
    592         if(unorm_isNormalized(notNFKC[i], -1, UNORM_NFKC, &errorCode) || U_FAILURE(errorCode)) {
    593             log_data_err("error: isNormalized(notNFKC[%d], NFKC) is wrong (%s) - (Are you missing data?)\n", i, u_errorName(errorCode));
    594         }
    595     }
    596 }
    597 
    598 void TestCheckFCD()
    599 {
    600   UErrorCode status = U_ZERO_ERROR;
    601   static const UChar FAST_[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
    602                          0x0A};
    603   static const UChar FALSE_[] = {0x0001, 0x0002, 0x02EA, 0x03EB, 0x0300, 0x0301,
    604                           0x02B9, 0x0314, 0x0315, 0x0316};
    605   static const UChar TRUE_[] = {0x0030, 0x0040, 0x0440, 0x056D, 0x064F, 0x06E7,
    606                          0x0050, 0x0730, 0x09EE, 0x1E10};
    607 
    608   static const UChar datastr[][5] =
    609   { {0x0061, 0x030A, 0x1E05, 0x0302, 0},
    610     {0x0061, 0x030A, 0x00E2, 0x0323, 0},
    611     {0x0061, 0x0323, 0x00E2, 0x0323, 0},
    612     {0x0061, 0x0323, 0x1E05, 0x0302, 0} };
    613   static const UBool result[] = {UNORM_YES, UNORM_NO, UNORM_NO, UNORM_YES};
    614 
    615   static const UChar datachar[] = {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
    616                             0x6a,
    617                             0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
    618                             0xea,
    619                             0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306,
    620                             0x0307, 0x0308, 0x0309, 0x030a,
    621                             0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326,
    622                             0x0327, 0x0328, 0x0329, 0x032a,
    623                             0x1e00, 0x1e01, 0x1e02, 0x1e03, 0x1e04, 0x1e05, 0x1e06,
    624                             0x1e07, 0x1e08, 0x1e09, 0x1e0a};
    625 
    626   int count = 0;
    627 
    628   if (unorm_quickCheck(FAST_, 10, UNORM_FCD, &status) != UNORM_YES)
    629     log_data_err("unorm_quickCheck(FCD) failed: expected value for fast unorm_quickCheck is UNORM_YES - (Are you missing data?)\n");
    630   if (unorm_quickCheck(FALSE_, 10, UNORM_FCD, &status) != UNORM_NO)
    631     log_err("unorm_quickCheck(FCD) failed: expected value for error unorm_quickCheck is UNORM_NO\n");
    632   if (unorm_quickCheck(TRUE_, 10, UNORM_FCD, &status) != UNORM_YES)
    633     log_data_err("unorm_quickCheck(FCD) failed: expected value for correct unorm_quickCheck is UNORM_YES - (Are you missing data?)\n");
    634 
    635   if (U_FAILURE(status))
    636     log_data_err("unorm_quickCheck(FCD) failed: %s - (Are you missing data?)\n", u_errorName(status));
    637 
    638   while (count < 4)
    639   {
    640     UBool fcdresult = unorm_quickCheck(datastr[count], 4, UNORM_FCD, &status);
    641     if (U_FAILURE(status)) {
    642       log_data_err("unorm_quickCheck(FCD) failed: exception occured at data set %d - (Are you missing data?)\n", count);
    643       break;
    644     }
    645     else {
    646       if (result[count] != fcdresult) {
    647         log_err("unorm_quickCheck(FCD) failed: Data set %d expected value %d\n", count,
    648                  result[count]);
    649       }
    650     }
    651     count ++;
    652   }
    653 
    654   /* random checks of long strings */
    655   status = U_ZERO_ERROR;
    656   srand((unsigned)time( NULL ));
    657 
    658   for (count = 0; count < 50; count ++)
    659   {
    660     int size = 0;
    661     UBool testresult = UNORM_YES;
    662     UChar data[20];
    663     UChar norm[100];
    664     UChar nfd[100];
    665     int normsize = 0;
    666     int nfdsize = 0;
    667 
    668     while (size != 19) {
    669       data[size] = datachar[(rand() * 50) / RAND_MAX];
    670       log_verbose("0x%x", data[size]);
    671       normsize += unorm_normalize(data + size, 1, UNORM_NFD, 0,
    672                                   norm + normsize, 100 - normsize, &status);
    673       if (U_FAILURE(status)) {
    674         log_data_err("unorm_quickCheck(FCD) failed: exception occured at data generation - (Are you missing data?)\n");
    675         break;
    676       }
    677       size ++;
    678     }
    679     log_verbose("\n");
    680 
    681     nfdsize = unorm_normalize(data, size, UNORM_NFD, 0,
    682                               nfd, 100, &status);
    683     if (U_FAILURE(status)) {
    684       log_data_err("unorm_quickCheck(FCD) failed: exception occured at normalized data generation - (Are you missing data?)\n");
    685     }
    686 
    687     if (nfdsize != normsize || u_memcmp(nfd, norm, nfdsize) != 0) {
    688       testresult = UNORM_NO;
    689     }
    690     if (testresult == UNORM_YES) {
    691       log_verbose("result UNORM_YES\n");
    692     }
    693     else {
    694       log_verbose("result UNORM_NO\n");
    695     }
    696 
    697     if (unorm_quickCheck(data, size, UNORM_FCD, &status) != testresult || U_FAILURE(status)) {
    698       log_data_err("unorm_quickCheck(FCD) failed: expected %d for random data - (Are you missing data?)\n", testresult);
    699     }
    700   }
    701 }
    702 
    703 static void
    704 TestAPI() {
    705     static const UChar in[]={ 0x68, 0xe4 };
    706     UChar out[20]={ 0xffff, 0xffff, 0xffff, 0xffff };
    707     UErrorCode errorCode;
    708     int32_t length;
    709 
    710     /* try preflighting */
    711     errorCode=U_ZERO_ERROR;
    712     length=unorm_normalize(in, 2, UNORM_NFD, 0, NULL, 0, &errorCode);
    713     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=3) {
    714         log_data_err("unorm_normalize(pure preflighting NFD)=%ld failed with %s - (Are you missing data?)\n", length, u_errorName(errorCode));
    715         return;
    716     }
    717 
    718     errorCode=U_ZERO_ERROR;
    719     length=unorm_normalize(in, 2, UNORM_NFD, 0, out, 3, &errorCode);
    720     if(U_FAILURE(errorCode)) {
    721         log_err("unorm_normalize(NFD)=%ld failed with %s\n", length, u_errorName(errorCode));
    722         return;
    723     }
    724     if(length!=3 || out[2]!=0x308 || out[3]!=0xffff) {
    725         log_err("unorm_normalize(NFD ma<umlaut>)=%ld failed with out[]=U+%04x U+%04x U+%04x U+%04x\n", length, out[0], out[1], out[2], out[3]);
    726         return;
    727     }
    728     length=unorm_normalize(NULL, 0, UNORM_NFC, 0, NULL, 0, &errorCode);
    729     if(U_FAILURE(errorCode)) {
    730         log_err("unorm_normalize(src NULL[0], NFC, dest NULL[0])=%ld failed with %s\n", (long)length, u_errorName(errorCode));
    731         return;
    732     }
    733     length=unorm_normalize(NULL, 0, UNORM_NFC, 0, out, 20, &errorCode);
    734     if(U_FAILURE(errorCode)) {
    735         log_err("unorm_normalize(src NULL[0], NFC, dest out[20])=%ld failed with %s\n", (long)length, u_errorName(errorCode));
    736         return;
    737     }
    738 }
    739 
    740 /* test cases to improve test code coverage */
    741 enum {
    742     HANGUL_K_KIYEOK=0x3131,         /* NFKD->Jamo L U+1100 */
    743     HANGUL_K_WEO=0x315d,            /* NFKD->Jamo V U+116f */
    744     HANGUL_K_KIYEOK_SIOS=0x3133,    /* NFKD->Jamo T U+11aa */
    745 
    746     HANGUL_KIYEOK=0x1100,           /* Jamo L U+1100 */
    747     HANGUL_WEO=0x116f,              /* Jamo V U+116f */
    748     HANGUL_KIYEOK_SIOS=0x11aa,      /* Jamo T U+11aa */
    749 
    750     HANGUL_AC00=0xac00,             /* Hangul syllable = Jamo LV U+ac00 */
    751     HANGUL_SYLLABLE=0xac00+14*28+3, /* Hangul syllable = U+1100 * U+116f * U+11aa */
    752 
    753     MUSICAL_VOID_NOTEHEAD=0x1d157,
    754     MUSICAL_HALF_NOTE=0x1d15e,  /* NFC/NFD->Notehead+Stem */
    755     MUSICAL_STEM=0x1d165,       /* cc=216 */
    756     MUSICAL_STACCATO=0x1d17c    /* cc=220 */
    757 };
    758 
    759 static void
    760 TestNormCoverage() {
    761     UChar input[1000], expect[1000], output[1000];
    762     UErrorCode errorCode;
    763     int32_t i, length, inLength, expectLength, hangulPrefixLength, preflightLength;
    764 
    765     /* create a long and nasty string with NFKC-unsafe characters */
    766     inLength=0;
    767 
    768     /* 3 Jamos L/V/T, all 8 combinations normal/compatibility */
    769     input[inLength++]=HANGUL_KIYEOK;
    770     input[inLength++]=HANGUL_WEO;
    771     input[inLength++]=HANGUL_KIYEOK_SIOS;
    772 
    773     input[inLength++]=HANGUL_KIYEOK;
    774     input[inLength++]=HANGUL_WEO;
    775     input[inLength++]=HANGUL_K_KIYEOK_SIOS;
    776 
    777     input[inLength++]=HANGUL_KIYEOK;
    778     input[inLength++]=HANGUL_K_WEO;
    779     input[inLength++]=HANGUL_KIYEOK_SIOS;
    780 
    781     input[inLength++]=HANGUL_KIYEOK;
    782     input[inLength++]=HANGUL_K_WEO;
    783     input[inLength++]=HANGUL_K_KIYEOK_SIOS;
    784 
    785     input[inLength++]=HANGUL_K_KIYEOK;
    786     input[inLength++]=HANGUL_WEO;
    787     input[inLength++]=HANGUL_KIYEOK_SIOS;
    788 
    789     input[inLength++]=HANGUL_K_KIYEOK;
    790     input[inLength++]=HANGUL_WEO;
    791     input[inLength++]=HANGUL_K_KIYEOK_SIOS;
    792 
    793     input[inLength++]=HANGUL_K_KIYEOK;
    794     input[inLength++]=HANGUL_K_WEO;
    795     input[inLength++]=HANGUL_KIYEOK_SIOS;
    796 
    797     input[inLength++]=HANGUL_K_KIYEOK;
    798     input[inLength++]=HANGUL_K_WEO;
    799     input[inLength++]=HANGUL_K_KIYEOK_SIOS;
    800 
    801     /* Hangul LV with normal/compatibility Jamo T */
    802     input[inLength++]=HANGUL_AC00;
    803     input[inLength++]=HANGUL_KIYEOK_SIOS;
    804 
    805     input[inLength++]=HANGUL_AC00;
    806     input[inLength++]=HANGUL_K_KIYEOK_SIOS;
    807 
    808     /* compatibility Jamo L, V */
    809     input[inLength++]=HANGUL_K_KIYEOK;
    810     input[inLength++]=HANGUL_K_WEO;
    811 
    812     hangulPrefixLength=inLength;
    813 
    814     input[inLength++]=UTF16_LEAD(MUSICAL_HALF_NOTE);
    815     input[inLength++]=UTF16_TRAIL(MUSICAL_HALF_NOTE);
    816     for(i=0; i<200; ++i) {
    817         input[inLength++]=UTF16_LEAD(MUSICAL_STACCATO);
    818         input[inLength++]=UTF16_TRAIL(MUSICAL_STACCATO);
    819         input[inLength++]=UTF16_LEAD(MUSICAL_STEM);
    820         input[inLength++]=UTF16_TRAIL(MUSICAL_STEM);
    821     }
    822 
    823     /* (compatibility) Jamo L, T do not compose */
    824     input[inLength++]=HANGUL_K_KIYEOK;
    825     input[inLength++]=HANGUL_K_KIYEOK_SIOS;
    826 
    827     /* quick checks */
    828     errorCode=U_ZERO_ERROR;
    829     if(UNORM_NO!=unorm_quickCheck(input, inLength, UNORM_NFD, &errorCode) || U_FAILURE(errorCode)) {
    830         log_data_err("error unorm_quickCheck(long input, UNORM_NFD)!=NO (%s) - (Are you missing data?)\n", u_errorName(errorCode));
    831     }
    832     errorCode=U_ZERO_ERROR;
    833     if(UNORM_NO!=unorm_quickCheck(input, inLength, UNORM_NFKD, &errorCode) || U_FAILURE(errorCode)) {
    834         log_data_err("error unorm_quickCheck(long input, UNORM_NFKD)!=NO (%s) - (Are you missing data?)\n", u_errorName(errorCode));
    835     }
    836     errorCode=U_ZERO_ERROR;
    837     if(UNORM_NO!=unorm_quickCheck(input, inLength, UNORM_NFC, &errorCode) || U_FAILURE(errorCode)) {
    838         log_data_err("error unorm_quickCheck(long input, UNORM_NFC)!=NO (%s) - (Are you missing data?)\n", u_errorName(errorCode));
    839     }
    840     errorCode=U_ZERO_ERROR;
    841     if(UNORM_NO!=unorm_quickCheck(input, inLength, UNORM_NFKC, &errorCode) || U_FAILURE(errorCode)) {
    842         log_data_err("error unorm_quickCheck(long input, UNORM_NFKC)!=NO (%s) - (Are you missing data?)\n", u_errorName(errorCode));
    843     }
    844     errorCode=U_ZERO_ERROR;
    845     if(UNORM_NO!=unorm_quickCheck(input, inLength, UNORM_FCD, &errorCode) || U_FAILURE(errorCode)) {
    846         log_data_err("error unorm_quickCheck(long input, UNORM_FCD)!=NO (%s) - (Are you missing data?)\n", u_errorName(errorCode));
    847     }
    848 
    849     /* NFKC */
    850     expectLength=0;
    851     expect[expectLength++]=HANGUL_SYLLABLE;
    852 
    853     expect[expectLength++]=HANGUL_SYLLABLE;
    854 
    855     expect[expectLength++]=HANGUL_SYLLABLE;
    856 
    857     expect[expectLength++]=HANGUL_SYLLABLE;
    858 
    859     expect[expectLength++]=HANGUL_SYLLABLE;
    860 
    861     expect[expectLength++]=HANGUL_SYLLABLE;
    862 
    863     expect[expectLength++]=HANGUL_SYLLABLE;
    864 
    865     expect[expectLength++]=HANGUL_SYLLABLE;
    866 
    867     expect[expectLength++]=HANGUL_AC00+3;
    868 
    869     expect[expectLength++]=HANGUL_AC00+3;
    870 
    871     expect[expectLength++]=HANGUL_AC00+14*28;
    872 
    873     expect[expectLength++]=UTF16_LEAD(MUSICAL_VOID_NOTEHEAD);
    874     expect[expectLength++]=UTF16_TRAIL(MUSICAL_VOID_NOTEHEAD);
    875     expect[expectLength++]=UTF16_LEAD(MUSICAL_STEM);
    876     expect[expectLength++]=UTF16_TRAIL(MUSICAL_STEM);
    877     for(i=0; i<200; ++i) {
    878         expect[expectLength++]=UTF16_LEAD(MUSICAL_STEM);
    879         expect[expectLength++]=UTF16_TRAIL(MUSICAL_STEM);
    880     }
    881     for(i=0; i<200; ++i) {
    882         expect[expectLength++]=UTF16_LEAD(MUSICAL_STACCATO);
    883         expect[expectLength++]=UTF16_TRAIL(MUSICAL_STACCATO);
    884     }
    885 
    886     expect[expectLength++]=HANGUL_KIYEOK;
    887     expect[expectLength++]=HANGUL_KIYEOK_SIOS;
    888 
    889     /* try destination overflow first */
    890     errorCode=U_ZERO_ERROR;
    891     preflightLength=unorm_normalize(input, inLength,
    892                            UNORM_NFKC, 0,
    893                            output, 100, /* too short */
    894                            &errorCode);
    895     if(errorCode!=U_BUFFER_OVERFLOW_ERROR) {
    896         log_data_err("error unorm_normalize(long input, output too short, UNORM_NFKC) did not overflow but %s - (Are you missing data?)\n", u_errorName(errorCode));
    897     }
    898 
    899     /* real NFKC */
    900     errorCode=U_ZERO_ERROR;
    901     length=unorm_normalize(input, inLength,
    902                            UNORM_NFKC, 0,
    903                            output, sizeof(output)/U_SIZEOF_UCHAR,
    904                            &errorCode);
    905     if(U_FAILURE(errorCode)) {
    906         log_data_err("error unorm_normalize(long input, UNORM_NFKC) failed with %s - (Are you missing data?)\n", u_errorName(errorCode));
    907     } else if(length!=expectLength || u_memcmp(output, expect, length)!=0) {
    908         log_err("error unorm_normalize(long input, UNORM_NFKC) produced wrong result\n");
    909         for(i=0; i<length; ++i) {
    910             if(output[i]!=expect[i]) {
    911                 log_err("    NFKC[%d]==U+%04lx expected U+%04lx\n", i, output[i], expect[i]);
    912                 break;
    913             }
    914         }
    915     }
    916     if(length!=preflightLength) {
    917         log_err("error unorm_normalize(long input, UNORM_NFKC)==%ld but preflightLength==%ld\n", length, preflightLength);
    918     }
    919 
    920     /* FCD */
    921     u_memcpy(expect, input, hangulPrefixLength);
    922     expectLength=hangulPrefixLength;
    923 
    924     expect[expectLength++]=UTF16_LEAD(MUSICAL_VOID_NOTEHEAD);
    925     expect[expectLength++]=UTF16_TRAIL(MUSICAL_VOID_NOTEHEAD);
    926     expect[expectLength++]=UTF16_LEAD(MUSICAL_STEM);
    927     expect[expectLength++]=UTF16_TRAIL(MUSICAL_STEM);
    928     for(i=0; i<200; ++i) {
    929         expect[expectLength++]=UTF16_LEAD(MUSICAL_STEM);
    930         expect[expectLength++]=UTF16_TRAIL(MUSICAL_STEM);
    931     }
    932     for(i=0; i<200; ++i) {
    933         expect[expectLength++]=UTF16_LEAD(MUSICAL_STACCATO);
    934         expect[expectLength++]=UTF16_TRAIL(MUSICAL_STACCATO);
    935     }
    936 
    937     expect[expectLength++]=HANGUL_K_KIYEOK;
    938     expect[expectLength++]=HANGUL_K_KIYEOK_SIOS;
    939 
    940     errorCode=U_ZERO_ERROR;
    941     length=unorm_normalize(input, inLength,
    942                            UNORM_FCD, 0,
    943                            output, sizeof(output)/U_SIZEOF_UCHAR,
    944                            &errorCode);
    945     if(U_FAILURE(errorCode)) {
    946         log_data_err("error unorm_normalize(long input, UNORM_FCD) failed with %s - (Are you missing data?)\n", u_errorName(errorCode));
    947     } else if(length!=expectLength || u_memcmp(output, expect, length)!=0) {
    948         log_err("error unorm_normalize(long input, UNORM_FCD) produced wrong result\n");
    949         for(i=0; i<length; ++i) {
    950             if(output[i]!=expect[i]) {
    951                 log_err("    FCD[%d]==U+%04lx expected U+%04lx\n", i, output[i], expect[i]);
    952                 break;
    953             }
    954         }
    955     }
    956 }
    957 
    958 /* API test for unorm_concatenate() - for real test strings see intltest/tstnorm.cpp */
    959 static void
    960 TestConcatenate(void) {
    961     /* "re + 'sume'" */
    962     static const UChar
    963     left[]={
    964         0x72, 0x65, 0
    965     },
    966     right[]={
    967         0x301, 0x73, 0x75, 0x6d, 0xe9, 0
    968     },
    969     expect[]={
    970         0x72, 0xe9, 0x73, 0x75, 0x6d, 0xe9, 0
    971     };
    972 
    973     UChar buffer[100];
    974     UErrorCode errorCode;
    975     int32_t length;
    976 
    977     /* left with length, right NUL-terminated */
    978     errorCode=U_ZERO_ERROR;
    979     length=unorm_concatenate(left, 2, right, -1, buffer, 100, UNORM_NFC, 0, &errorCode);
    980     if(U_FAILURE(errorCode) || length!=6 || 0!=u_memcmp(buffer, expect, length)) {
    981         log_data_err("error: unorm_concatenate()=%ld (expect 6) failed with %s - (Are you missing data?)\n", length, u_errorName(errorCode));
    982     }
    983 
    984     /* preflighting */
    985     errorCode=U_ZERO_ERROR;
    986     length=unorm_concatenate(left, 2, right, -1, NULL, 0, UNORM_NFC, 0, &errorCode);
    987     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=6) {
    988         log_data_err("error: unorm_concatenate(preflighting)=%ld (expect 6) failed with %s - (Are you missing data?)\n", length, u_errorName(errorCode));
    989     }
    990 
    991     buffer[2]=0x5555;
    992     errorCode=U_ZERO_ERROR;
    993     length=unorm_concatenate(left, 2, right, -1, buffer, 1, UNORM_NFC, 0, &errorCode);
    994     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=6 || buffer[2]!=0x5555) {
    995         log_data_err("error: unorm_concatenate(preflighting 2)=%ld (expect 6) failed with %s - (Are you missing data?)\n", length, u_errorName(errorCode));
    996     }
    997 
    998     /* enter with U_FAILURE */
    999     buffer[2]=0xaaaa;
   1000     errorCode=U_UNEXPECTED_TOKEN;
   1001     length=unorm_concatenate(left, 2, right, -1, buffer, 100, UNORM_NFC, 0, &errorCode);
   1002     if(errorCode!=U_UNEXPECTED_TOKEN || buffer[2]!=0xaaaa) {
   1003         log_err("error: unorm_concatenate(failure)=%ld failed with %s\n", length, u_errorName(errorCode));
   1004     }
   1005 
   1006     /* illegal arguments */
   1007     buffer[2]=0xaaaa;
   1008     errorCode=U_ZERO_ERROR;
   1009     length=unorm_concatenate(NULL, 2, right, -1, buffer, 100, UNORM_NFC, 0, &errorCode);
   1010     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || buffer[2]!=0xaaaa) {
   1011         log_data_err("error: unorm_concatenate(left=NULL)=%ld failed with %s - (Are you missing data?)\n", length, u_errorName(errorCode));
   1012     }
   1013 
   1014     errorCode=U_ZERO_ERROR;
   1015     length=unorm_concatenate(left, 2, right, -1, NULL, 100, UNORM_NFC, 0, &errorCode);
   1016     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   1017         log_data_err("error: unorm_concatenate(buffer=NULL)=%ld failed with %s - (Are you missing data?)\n", length, u_errorName(errorCode));
   1018     }
   1019 }
   1020 
   1021 enum {
   1022     _PLUS=0x2b
   1023 };
   1024 
   1025 static const char *const _modeString[UNORM_MODE_COUNT]={
   1026     "0", "NONE", "NFD", "NFKD", "NFC", "NFKC", "FCD"
   1027 };
   1028 
   1029 static void
   1030 _testIter(const UChar *src, int32_t srcLength,
   1031           UCharIterator *iter, UNormalizationMode mode, UBool forward,
   1032           const UChar *out, int32_t outLength,
   1033           const int32_t *srcIndexes, int32_t srcIndexesLength) {
   1034     UChar buffer[4];
   1035     const UChar *expect, *outLimit, *in;
   1036     int32_t length, i, expectLength, expectIndex, prevIndex, index, inLength;
   1037     UErrorCode errorCode;
   1038     UBool neededToNormalize, expectNeeded;
   1039 
   1040     errorCode=U_ZERO_ERROR;
   1041     outLimit=out+outLength;
   1042     if(forward) {
   1043         expect=out;
   1044         i=index=0;
   1045     } else {
   1046         expect=outLimit;
   1047         i=srcIndexesLength-2;
   1048         index=srcLength;
   1049     }
   1050 
   1051     for(;;) {
   1052         prevIndex=index;
   1053         if(forward) {
   1054             if(!iter->hasNext(iter)) {
   1055                 return;
   1056             }
   1057             length=unorm_next(iter,
   1058                               buffer, sizeof(buffer)/U_SIZEOF_UCHAR,
   1059                               mode, 0,
   1060                               (UBool)(out!=NULL), &neededToNormalize,
   1061                               &errorCode);
   1062             expectIndex=srcIndexes[i+1];
   1063             in=src+prevIndex;
   1064             inLength=expectIndex-prevIndex;
   1065 
   1066             if(out!=NULL) {
   1067                 /* get output piece from between plus signs */
   1068                 expectLength=0;
   1069                 while((expect+expectLength)!=outLimit && expect[expectLength]!=_PLUS) {
   1070                     ++expectLength;
   1071                 }
   1072                 expectNeeded=(UBool)(0!=u_memcmp(buffer, in, inLength));
   1073             } else {
   1074                 expect=in;
   1075                 expectLength=inLength;
   1076                 expectNeeded=FALSE;
   1077             }
   1078         } else {
   1079             if(!iter->hasPrevious(iter)) {
   1080                 return;
   1081             }
   1082             length=unorm_previous(iter,
   1083                                   buffer, sizeof(buffer)/U_SIZEOF_UCHAR,
   1084                                   mode, 0,
   1085                                   (UBool)(out!=NULL), &neededToNormalize,
   1086                                   &errorCode);
   1087             expectIndex=srcIndexes[i];
   1088             in=src+expectIndex;
   1089             inLength=prevIndex-expectIndex;
   1090 
   1091             if(out!=NULL) {
   1092                 /* get output piece from between plus signs */
   1093                 expectLength=0;
   1094                 while(expect!=out && expect[-1]!=_PLUS) {
   1095                     ++expectLength;
   1096                     --expect;
   1097                 }
   1098                 expectNeeded=(UBool)(0!=u_memcmp(buffer, in, inLength));
   1099             } else {
   1100                 expect=in;
   1101                 expectLength=inLength;
   1102                 expectNeeded=FALSE;
   1103             }
   1104         }
   1105         index=iter->getIndex(iter, UITER_CURRENT);
   1106 
   1107         if(U_FAILURE(errorCode)) {
   1108             log_data_err("error unorm iteration (next/previous %d %s)[%d]: %s - (Are you missing data?)\n",
   1109                     forward, _modeString[mode], i, u_errorName(errorCode));
   1110             return;
   1111         }
   1112         if(expectIndex!=index) {
   1113             log_err("error unorm iteration (next/previous %d %s): index[%d] wrong, got %d expected %d\n",
   1114                     forward, _modeString[mode], i, index, expectIndex);
   1115             return;
   1116         }
   1117         if(expectLength!=length) {
   1118             log_err("error unorm iteration (next/previous %d %s): length[%d] wrong, got %d expected %d\n",
   1119                     forward, _modeString[mode], i, length, expectLength);
   1120             return;
   1121         }
   1122         if(0!=u_memcmp(expect, buffer, length)) {
   1123             log_err("error unorm iteration (next/previous %d %s): output string[%d] wrong\n",
   1124                     forward, _modeString[mode], i);
   1125             return;
   1126         }
   1127         if(neededToNormalize!=expectNeeded) {
   1128         }
   1129 
   1130         if(forward) {
   1131             expect+=expectLength+1; /* go after the + */
   1132             ++i;
   1133         } else {
   1134             --expect; /* go before the + */
   1135             --i;
   1136         }
   1137     }
   1138 }
   1139 
   1140 static void
   1141 TestNextPrevious() {
   1142     static const UChar
   1143     src[]={ /* input string */
   1144         0xa0, 0xe4, 0x63, 0x302, 0x327, 0xac00, 0x3133
   1145     },
   1146     nfd[]={ /* + separates expected output pieces */
   1147         0xa0, _PLUS, 0x61, 0x308, _PLUS, 0x63, 0x327, 0x302, _PLUS, 0x1100, 0x1161, _PLUS, 0x3133
   1148     },
   1149     nfkd[]={
   1150         0x20, _PLUS, 0x61, 0x308, _PLUS, 0x63, 0x327, 0x302, _PLUS, 0x1100, 0x1161, _PLUS, 0x11aa
   1151     },
   1152     nfc[]={
   1153         0xa0, _PLUS, 0xe4, _PLUS, 0xe7, 0x302, _PLUS, 0xac00, _PLUS, 0x3133
   1154     },
   1155     nfkc[]={
   1156         0x20, _PLUS, 0xe4, _PLUS, 0xe7, 0x302, _PLUS, 0xac03
   1157     },
   1158     fcd[]={
   1159         0xa0, _PLUS, 0xe4, _PLUS, 0x63, 0x327, 0x302, _PLUS, 0xac00, _PLUS, 0x3133
   1160     };
   1161 
   1162     /* expected iterator indexes in the source string for each iteration piece */
   1163     static const int32_t
   1164     nfdIndexes[]={
   1165         0, 1, 2, 5, 6, 7
   1166     },
   1167     nfkdIndexes[]={
   1168         0, 1, 2, 5, 6, 7
   1169     },
   1170     nfcIndexes[]={
   1171         0, 1, 2, 5, 6, 7
   1172     },
   1173     nfkcIndexes[]={
   1174         0, 1, 2, 5, 7
   1175     },
   1176     fcdIndexes[]={
   1177         0, 1, 2, 5, 6, 7
   1178     };
   1179 
   1180     UCharIterator iter;
   1181 
   1182     UChar buffer[4];
   1183     int32_t length;
   1184 
   1185     UBool neededToNormalize;
   1186     UErrorCode errorCode;
   1187 
   1188     uiter_setString(&iter, src, sizeof(src)/U_SIZEOF_UCHAR);
   1189 
   1190     /* test iteration with doNormalize */
   1191     iter.index=0;
   1192     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFD, TRUE, nfd, sizeof(nfd)/U_SIZEOF_UCHAR, nfdIndexes, sizeof(nfdIndexes)/4);
   1193     iter.index=0;
   1194     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKD, TRUE, nfkd, sizeof(nfkd)/U_SIZEOF_UCHAR, nfkdIndexes, sizeof(nfkdIndexes)/4);
   1195     iter.index=0;
   1196     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFC, TRUE, nfc, sizeof(nfc)/U_SIZEOF_UCHAR, nfcIndexes, sizeof(nfcIndexes)/4);
   1197     iter.index=0;
   1198     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKC, TRUE, nfkc, sizeof(nfkc)/U_SIZEOF_UCHAR, nfkcIndexes, sizeof(nfkcIndexes)/4);
   1199     iter.index=0;
   1200     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_FCD, TRUE, fcd, sizeof(fcd)/U_SIZEOF_UCHAR, fcdIndexes, sizeof(fcdIndexes)/4);
   1201 
   1202     iter.index=iter.length;
   1203     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFD, FALSE, nfd, sizeof(nfd)/U_SIZEOF_UCHAR, nfdIndexes, sizeof(nfdIndexes)/4);
   1204     iter.index=iter.length;
   1205     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKD, FALSE, nfkd, sizeof(nfkd)/U_SIZEOF_UCHAR, nfkdIndexes, sizeof(nfkdIndexes)/4);
   1206     iter.index=iter.length;
   1207     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFC, FALSE, nfc, sizeof(nfc)/U_SIZEOF_UCHAR, nfcIndexes, sizeof(nfcIndexes)/4);
   1208     iter.index=iter.length;
   1209     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKC, FALSE, nfkc, sizeof(nfkc)/U_SIZEOF_UCHAR, nfkcIndexes, sizeof(nfkcIndexes)/4);
   1210     iter.index=iter.length;
   1211     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_FCD, FALSE, fcd, sizeof(fcd)/U_SIZEOF_UCHAR, fcdIndexes, sizeof(fcdIndexes)/4);
   1212 
   1213     /* test iteration without doNormalize */
   1214     iter.index=0;
   1215     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFD, TRUE, NULL, 0, nfdIndexes, sizeof(nfdIndexes)/4);
   1216     iter.index=0;
   1217     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKD, TRUE, NULL, 0, nfkdIndexes, sizeof(nfkdIndexes)/4);
   1218     iter.index=0;
   1219     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFC, TRUE, NULL, 0, nfcIndexes, sizeof(nfcIndexes)/4);
   1220     iter.index=0;
   1221     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKC, TRUE, NULL, 0, nfkcIndexes, sizeof(nfkcIndexes)/4);
   1222     iter.index=0;
   1223     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_FCD, TRUE, NULL, 0, fcdIndexes, sizeof(fcdIndexes)/4);
   1224 
   1225     iter.index=iter.length;
   1226     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFD, FALSE, NULL, 0, nfdIndexes, sizeof(nfdIndexes)/4);
   1227     iter.index=iter.length;
   1228     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKD, FALSE, NULL, 0, nfkdIndexes, sizeof(nfkdIndexes)/4);
   1229     iter.index=iter.length;
   1230     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFC, FALSE, NULL, 0, nfcIndexes, sizeof(nfcIndexes)/4);
   1231     iter.index=iter.length;
   1232     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_NFKC, FALSE, NULL, 0, nfkcIndexes, sizeof(nfkcIndexes)/4);
   1233     iter.index=iter.length;
   1234     _testIter(src, sizeof(src)/U_SIZEOF_UCHAR, &iter, UNORM_FCD, FALSE, NULL, 0, fcdIndexes, sizeof(fcdIndexes)/4);
   1235 
   1236     /* try without neededToNormalize */
   1237     errorCode=U_ZERO_ERROR;
   1238     buffer[0]=5;
   1239     iter.index=1;
   1240     length=unorm_next(&iter, buffer, sizeof(buffer)/U_SIZEOF_UCHAR,
   1241                       UNORM_NFD, 0, TRUE, NULL,
   1242                       &errorCode);
   1243     if(U_FAILURE(errorCode) || length!=2 || buffer[0]!=nfd[2] || buffer[1]!=nfd[3]) {
   1244         log_data_err("error unorm_next(without needed) %s - (Are you missing data?)\n", u_errorName(errorCode));
   1245         return;
   1246     }
   1247 
   1248     /* preflight */
   1249     neededToNormalize=9;
   1250     iter.index=1;
   1251     length=unorm_next(&iter, NULL, 0,
   1252                       UNORM_NFD, 0, TRUE, &neededToNormalize,
   1253                       &errorCode);
   1254     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || neededToNormalize!=FALSE || length!=2) {
   1255         log_err("error unorm_next(pure preflighting) %s\n", u_errorName(errorCode));
   1256         return;
   1257     }
   1258 
   1259     errorCode=U_ZERO_ERROR;
   1260     buffer[0]=buffer[1]=5;
   1261     neededToNormalize=9;
   1262     iter.index=1;
   1263     length=unorm_next(&iter, buffer, 1,
   1264                       UNORM_NFD, 0, TRUE, &neededToNormalize,
   1265                       &errorCode);
   1266     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || neededToNormalize!=FALSE || length!=2 || buffer[1]!=5) {
   1267         log_err("error unorm_next(preflighting) %s\n", u_errorName(errorCode));
   1268         return;
   1269     }
   1270 
   1271     /* no iterator */
   1272     errorCode=U_ZERO_ERROR;
   1273     buffer[0]=buffer[1]=5;
   1274     neededToNormalize=9;
   1275     iter.index=1;
   1276     length=unorm_next(NULL, buffer, sizeof(buffer)/U_SIZEOF_UCHAR,
   1277                       UNORM_NFD, 0, TRUE, &neededToNormalize,
   1278                       &errorCode);
   1279     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   1280         log_err("error unorm_next(no iterator) %s\n", u_errorName(errorCode));
   1281         return;
   1282     }
   1283 
   1284     /* illegal mode */
   1285     buffer[0]=buffer[1]=5;
   1286     neededToNormalize=9;
   1287     iter.index=1;
   1288     length=unorm_next(&iter, buffer, sizeof(buffer)/U_SIZEOF_UCHAR,
   1289                       (UNormalizationMode)0, 0, TRUE, &neededToNormalize,
   1290                       &errorCode);
   1291     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   1292         log_err("error unorm_next(illegal mode) %s\n", u_errorName(errorCode));
   1293         return;
   1294     }
   1295 
   1296     /* error coming in */
   1297     errorCode=U_MISPLACED_QUANTIFIER;
   1298     buffer[0]=5;
   1299     iter.index=1;
   1300     length=unorm_next(&iter, buffer, sizeof(buffer)/U_SIZEOF_UCHAR,
   1301                       UNORM_NFD, 0, TRUE, NULL,
   1302                       &errorCode);
   1303     if(errorCode!=U_MISPLACED_QUANTIFIER) {
   1304         log_err("error unorm_next(U_MISPLACED_QUANTIFIER) %s\n", u_errorName(errorCode));
   1305         return;
   1306     }
   1307 }
   1308 
   1309 static void
   1310 TestFCNFKCClosure(void) {
   1311     static const struct {
   1312         UChar32 c;
   1313         const UChar s[6];
   1314     } tests[]={
   1315         { 0x00C4, { 0 } },
   1316         { 0x00E4, { 0 } },
   1317         { 0x037A, { 0x0020, 0x03B9, 0 } },
   1318         { 0x03D2, { 0x03C5, 0 } },
   1319         { 0x20A8, { 0x0072, 0x0073, 0 } },
   1320         { 0x210B, { 0x0068, 0 } },
   1321         { 0x210C, { 0x0068, 0 } },
   1322         { 0x2121, { 0x0074, 0x0065, 0x006C, 0 } },
   1323         { 0x2122, { 0x0074, 0x006D, 0 } },
   1324         { 0x2128, { 0x007A, 0 } },
   1325         { 0x1D5DB, { 0x0068, 0 } },
   1326         { 0x1D5ED, { 0x007A, 0 } },
   1327         { 0x0061, { 0 } }
   1328     };
   1329 
   1330     UChar buffer[8];
   1331     UErrorCode errorCode;
   1332     int32_t i, length;
   1333 
   1334     for(i=0; i<LENGTHOF(tests); ++i) {
   1335         errorCode=U_ZERO_ERROR;
   1336         length=u_getFC_NFKC_Closure(tests[i].c, buffer, LENGTHOF(buffer), &errorCode);
   1337         if(U_FAILURE(errorCode) || length!=u_strlen(buffer) || 0!=u_strcmp(tests[i].s, buffer)) {
   1338             log_data_err("u_getFC_NFKC_Closure(U+%04lx) is wrong (%s) - (Are you missing data?)\n", tests[i].c, u_errorName(errorCode));
   1339         }
   1340     }
   1341 
   1342     /* error handling */
   1343     errorCode=U_ZERO_ERROR;
   1344     length=u_getFC_NFKC_Closure(0x5c, NULL, LENGTHOF(buffer), &errorCode);
   1345     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   1346         log_err("u_getFC_NFKC_Closure(dest=NULL) is wrong (%s)\n", u_errorName(errorCode));
   1347     }
   1348 
   1349     length=u_getFC_NFKC_Closure(0x5c, buffer, LENGTHOF(buffer), &errorCode);
   1350     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   1351         log_err("u_getFC_NFKC_Closure(U_FAILURE) is wrong (%s)\n", u_errorName(errorCode));
   1352     }
   1353 }
   1354 
   1355 static void
   1356 TestQuickCheckPerCP() {
   1357     UErrorCode errorCode;
   1358     UChar32 c, lead, trail;
   1359     UChar s[U16_MAX_LENGTH], nfd[16];
   1360     int32_t length, lccc1, lccc2, tccc1, tccc2;
   1361     int32_t qc1, qc2;
   1362 
   1363     if(
   1364         u_getIntPropertyMaxValue(UCHAR_NFD_QUICK_CHECK)!=(int32_t)UNORM_YES ||
   1365         u_getIntPropertyMaxValue(UCHAR_NFKD_QUICK_CHECK)!=(int32_t)UNORM_YES ||
   1366         u_getIntPropertyMaxValue(UCHAR_NFC_QUICK_CHECK)!=(int32_t)UNORM_MAYBE ||
   1367         u_getIntPropertyMaxValue(UCHAR_NFKC_QUICK_CHECK)!=(int32_t)UNORM_MAYBE ||
   1368         u_getIntPropertyMaxValue(UCHAR_LEAD_CANONICAL_COMBINING_CLASS)!=u_getIntPropertyMaxValue(UCHAR_CANONICAL_COMBINING_CLASS) ||
   1369         u_getIntPropertyMaxValue(UCHAR_TRAIL_CANONICAL_COMBINING_CLASS)!=u_getIntPropertyMaxValue(UCHAR_CANONICAL_COMBINING_CLASS)
   1370     ) {
   1371         log_err("wrong result from one of the u_getIntPropertyMaxValue(UCHAR_NF*_QUICK_CHECK) or UCHAR_*_CANONICAL_COMBINING_CLASS\n");
   1372     }
   1373 
   1374     /*
   1375      * compare the quick check property values for some code points
   1376      * to the quick check results for checking same-code point strings
   1377      */
   1378     errorCode=U_ZERO_ERROR;
   1379     c=0;
   1380     while(c<0x110000) {
   1381         length=0;
   1382         U16_APPEND_UNSAFE(s, length, c);
   1383 
   1384         qc1=u_getIntPropertyValue(c, UCHAR_NFC_QUICK_CHECK);
   1385         qc2=unorm_quickCheck(s, length, UNORM_NFC, &errorCode);
   1386         if(qc1!=qc2) {
   1387             log_data_err("u_getIntPropertyValue(NFC)=%d != %d=unorm_quickCheck(NFC) for U+%04x - (Are you missing data?)\n", qc1, qc2, c);
   1388         }
   1389 
   1390         qc1=u_getIntPropertyValue(c, UCHAR_NFD_QUICK_CHECK);
   1391         qc2=unorm_quickCheck(s, length, UNORM_NFD, &errorCode);
   1392         if(qc1!=qc2) {
   1393             log_data_err("u_getIntPropertyValue(NFD)=%d != %d=unorm_quickCheck(NFD) for U+%04x - (Are you missing data?)\n", qc1, qc2, c);
   1394         }
   1395 
   1396         qc1=u_getIntPropertyValue(c, UCHAR_NFKC_QUICK_CHECK);
   1397         qc2=unorm_quickCheck(s, length, UNORM_NFKC, &errorCode);
   1398         if(qc1!=qc2) {
   1399             log_data_err("u_getIntPropertyValue(NFKC)=%d != %d=unorm_quickCheck(NFKC) for U+%04x - (Are you missing data?)\n", qc1, qc2, c);
   1400         }
   1401 
   1402         qc1=u_getIntPropertyValue(c, UCHAR_NFKD_QUICK_CHECK);
   1403         qc2=unorm_quickCheck(s, length, UNORM_NFKD, &errorCode);
   1404         if(qc1!=qc2) {
   1405             log_data_err("u_getIntPropertyValue(NFKD)=%d != %d=unorm_quickCheck(NFKD) for U+%04x - (Are you missing data?)\n", qc1, qc2, c);
   1406         }
   1407 
   1408         length=unorm_normalize(s, length, UNORM_NFD, 0, nfd, LENGTHOF(nfd), &errorCode);
   1409         /* length-length == 0 is used to get around a compiler warning. */
   1410         U16_GET(nfd, 0, length-length, length, lead);
   1411         U16_GET(nfd, 0, length-1, length, trail);
   1412 
   1413         lccc1=u_getIntPropertyValue(c, UCHAR_LEAD_CANONICAL_COMBINING_CLASS);
   1414         lccc2=u_getCombiningClass(lead);
   1415         tccc1=u_getIntPropertyValue(c, UCHAR_TRAIL_CANONICAL_COMBINING_CLASS);
   1416         tccc2=u_getCombiningClass(trail);
   1417 
   1418         if(lccc1!=lccc2) {
   1419             log_err("u_getIntPropertyValue(lccc)=%d != %d=u_getCombiningClass(lead) for U+%04x\n",
   1420                     lccc1, lccc2, c);
   1421         }
   1422         if(tccc1!=tccc2) {
   1423             log_err("u_getIntPropertyValue(tccc)=%d != %d=u_getCombiningClass(trail) for U+%04x\n",
   1424                     tccc1, tccc2, c);
   1425         }
   1426 
   1427         /* skip some code points */
   1428         c=(20*c)/19+1;
   1429     }
   1430 }
   1431 
   1432 static void
   1433 TestComposition(void) {
   1434     static const struct {
   1435         UNormalizationMode mode;
   1436         uint32_t options;
   1437         UChar input[12];
   1438         UChar expect[12];
   1439     } cases[]={
   1440         /*
   1441          * special cases for UAX #15 bug
   1442          * see Unicode Corrigendum #5: Normalization Idempotency
   1443          * at http://unicode.org/versions/corrigendum5.html
   1444          * (was Public Review Issue #29)
   1445          */
   1446         { UNORM_NFC, 0, { 0x1100, 0x0300, 0x1161, 0x0327 },         { 0x1100, 0x0300, 0x1161, 0x0327 } },
   1447         { UNORM_NFC, 0, { 0x1100, 0x0300, 0x1161, 0x0327, 0x11a8 }, { 0x1100, 0x0300, 0x1161, 0x0327, 0x11a8 } },
   1448         { UNORM_NFC, 0, { 0xac00, 0x0300, 0x0327, 0x11a8 },         { 0xac00, 0x0327, 0x0300, 0x11a8 } },
   1449         { UNORM_NFC, 0, { 0x0b47, 0x0300, 0x0b3e },                 { 0x0b47, 0x0300, 0x0b3e } },
   1450 
   1451         /* TODO: add test cases for UNORM_FCC here (j2151) */
   1452     };
   1453 
   1454     UChar output[16];
   1455     UErrorCode errorCode;
   1456     int32_t i, length;
   1457 
   1458     for(i=0; i<LENGTHOF(cases); ++i) {
   1459         errorCode=U_ZERO_ERROR;
   1460         length=unorm_normalize(
   1461                     cases[i].input, -1,
   1462                     cases[i].mode, cases[i].options,
   1463                     output, LENGTHOF(output),
   1464                     &errorCode);
   1465         if( U_FAILURE(errorCode) ||
   1466             length!=u_strlen(cases[i].expect) ||
   1467             0!=u_memcmp(output, cases[i].expect, length)
   1468         ) {
   1469             log_data_err("unexpected result for case %d - (Are you missing data?)\n", i);
   1470         }
   1471     }
   1472 }
   1473 
   1474 static void
   1475 TestGetDecomposition() {
   1476     UChar decomp[32];
   1477     int32_t length;
   1478 
   1479     UErrorCode errorCode=U_ZERO_ERROR;
   1480     const UNormalizer2 *n2=unorm2_getInstance(NULL, "nfc", UNORM2_COMPOSE_CONTIGUOUS, &errorCode);
   1481     if(U_FAILURE(errorCode)) {
   1482         log_err_status(errorCode, "unorm2_getInstance(nfc/FCC) failed: %s\n", u_errorName(errorCode));
   1483         return;
   1484     }
   1485 
   1486     length=unorm2_getDecomposition(n2, 0x20, decomp, LENGTHOF(decomp), &errorCode);
   1487     if(U_FAILURE(errorCode) || length>=0) {
   1488         log_err("unorm2_getDecomposition(space) failed\n");
   1489     }
   1490     errorCode=U_ZERO_ERROR;
   1491     length=unorm2_getDecomposition(n2, 0xe4, decomp, LENGTHOF(decomp), &errorCode);
   1492     if(U_FAILURE(errorCode) || length!=2 || decomp[0]!=0x61 || decomp[1]!=0x308 || decomp[2]!=0) {
   1493         log_err("unorm2_getDecomposition(a-umlaut) failed\n");
   1494     }
   1495     errorCode=U_ZERO_ERROR;
   1496     length=unorm2_getDecomposition(n2, 0xac01, decomp, LENGTHOF(decomp), &errorCode);
   1497     if(U_FAILURE(errorCode) || length!=3 || decomp[0]!=0x1100 || decomp[1]!=0x1161 || decomp[2]!=0x11a8 || decomp[3]!=0) {
   1498         log_err("unorm2_getDecomposition(Hangul syllable U+AC01) failed\n");
   1499     }
   1500     errorCode=U_ZERO_ERROR;
   1501     length=unorm2_getDecomposition(n2, 0xac01, NULL, 0, &errorCode);
   1502     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=3) {
   1503         log_err("unorm2_getDecomposition(Hangul syllable U+AC01) overflow failed\n");
   1504     }
   1505     errorCode=U_ZERO_ERROR;
   1506     length=unorm2_getDecomposition(n2, 0xac01, decomp, -1, &errorCode);
   1507     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   1508         log_err("unorm2_getDecomposition(capacity<0) failed\n");
   1509     }
   1510     errorCode=U_ZERO_ERROR;
   1511     length=unorm2_getDecomposition(n2, 0xac01, NULL, 4, &errorCode);
   1512     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   1513         log_err("unorm2_getDecomposition(decomposition=NULL) failed\n");
   1514     }
   1515 }
   1516 
   1517 static void
   1518 TestAppendRestoreMiddle() {
   1519     UChar a[20]={ 0x61, 0x62, 0x63, 0x41, 0x327, 0 };  /* last chars are 'A' and 'cedilla' NFC */
   1520     static const UChar b[]={ 0x30A, 0x64, 0x65, 0x66, 0 };  /* first char is 'ring above' NFC */
   1521     /* NFC: C5 is 'A with ring above' */
   1522     static const UChar expected[]={ 0x61, 0x62, 0x63, 0xC5, 0x327, 0x64, 0x65, 0x66 };
   1523     int32_t length;
   1524     UErrorCode errorCode=U_ZERO_ERROR;
   1525     const UNormalizer2 *n2=unorm2_getInstance(NULL, "nfc", UNORM2_COMPOSE, &errorCode);
   1526     if(U_FAILURE(errorCode)) {
   1527         log_err_status(errorCode, "unorm2_getInstance(nfc/COMPOSE) failed: %s\n", u_errorName(errorCode));
   1528         return;
   1529     }
   1530     /*
   1531      * Use length=-1 to fool the estimate of the ReorderingBuffer capacity.
   1532      * Use a capacity of 6 or 7 so that the middle sequence <41 327 30A>
   1533      * still fits into a[] but the full result still overflows this capacity.
   1534      * (Let it modify the destination buffer before reallocating internally.)
   1535      */
   1536     length=unorm2_append(n2, a, -1, 6, b, -1, &errorCode);
   1537     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=LENGTHOF(expected)) {
   1538         log_err("unorm2_append(preflight) returned wrong length of %d\n", (int)length);
   1539         return;
   1540     }
   1541     /* Verify that the middle is unchanged or restored. (ICU ticket #7848) */
   1542     if(a[0]!=0x61 || a[1]!=0x62 || a[2]!=0x63 || a[3]!=0x41 || a[4]!=0x327 || a[5]!=0) {
   1543         log_err("unorm2_append(overflow) modified the first string\n");
   1544         return;
   1545     }
   1546     errorCode=U_ZERO_ERROR;
   1547     length=unorm2_append(n2, a, -1, LENGTHOF(a), b, -1, &errorCode);
   1548     if(U_FAILURE(errorCode) || length!=LENGTHOF(expected) || 0!=u_memcmp(a, expected, length)) {
   1549         log_err("unorm2_append(real) failed - %s, length %d\n", u_errorName(errorCode), (int)length);
   1550         return;
   1551     }
   1552 }
   1553 
   1554 #endif /* #if !UCONFIG_NO_NORMALIZATION */
   1555