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