1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5*
6*   Copyright (C) 2002-2016, International Business Machines
7*   Corporation and others.  All Rights Reserved.
8*
9*******************************************************************************
10*   file name:  cstrcase.c
11*   encoding:   UTF-8
12*   tab size:   8 (not used)
13*   indentation:4
14*
15*   created on: 2002feb21
16*   created by: Markus W. Scherer
17*
18*   Test file for string casing C API functions.
19*/
20
21#include <string.h>
22#include "unicode/utypes.h"
23#include "unicode/uchar.h"
24#include "unicode/ustring.h"
25#include "unicode/uloc.h"
26#include "unicode/ubrk.h"
27#include "unicode/ucasemap.h"
28#include "cmemory.h"
29#include "cintltst.h"
30#include "ucasemap_imp.h"
31#include "ustr_imp.h"
32
33/* test string case mapping functions --------------------------------------- */
34
35static void
36TestCaseLower(void) {
37    static const UChar
38
39    beforeLower[]= { 0x61, 0x42, 0x49,  0x3a3, 0xdf, 0x3a3, 0x2f, 0xd93f, 0xdfff },
40    lowerRoot[]=   { 0x61, 0x62, 0x69,  0x3c3, 0xdf, 0x3c2, 0x2f, 0xd93f, 0xdfff },
41    lowerTurkish[]={ 0x61, 0x62, 0x131, 0x3c3, 0xdf, 0x3c2, 0x2f, 0xd93f, 0xdfff };
42
43    UChar buffer[32];
44    int32_t length;
45    UErrorCode errorCode;
46
47    /* lowercase with root locale and separate buffers */
48    buffer[0]=0xabcd;
49    errorCode=U_ZERO_ERROR;
50    length=u_strToLower(buffer, UPRV_LENGTHOF(buffer),
51                        beforeLower, UPRV_LENGTHOF(beforeLower),
52                        "",
53                        &errorCode);
54    if( U_FAILURE(errorCode) ||
55        length!=(UPRV_LENGTHOF(lowerRoot)) ||
56        uprv_memcmp(lowerRoot, buffer, length*U_SIZEOF_UCHAR)!=0 ||
57        buffer[length]!=0
58    ) {
59        log_err("error in u_strToLower(root locale)=%ld error=%s string matches: %s\t\nlowerRoot=%s\t\nbuffer=%s\n",
60            length,
61            u_errorName(errorCode),
62            uprv_memcmp(lowerRoot, buffer, length*U_SIZEOF_UCHAR)==0 &&
63buffer[length]==0 ? "yes" : "no",
64            aescstrdup(lowerRoot,-1),
65            aescstrdup(buffer,-1));
66    }
67
68    /* lowercase with turkish locale and in the same buffer */
69    uprv_memcpy(buffer, beforeLower, sizeof(beforeLower));
70    buffer[UPRV_LENGTHOF(beforeLower)]=0;
71    errorCode=U_ZERO_ERROR;
72    length=u_strToLower(buffer, UPRV_LENGTHOF(buffer),
73                        buffer, -1, /* implicit srcLength */
74                        "tr",
75                        &errorCode);
76    if( U_FAILURE(errorCode) ||
77        length!=(UPRV_LENGTHOF(lowerTurkish)) ||
78        uprv_memcmp(lowerTurkish, buffer, length*U_SIZEOF_UCHAR)!=0 ||
79        buffer[length]!=0
80    ) {
81        log_err("error in u_strToLower(turkish locale)=%ld error=%s string matches: %s\n",
82            length,
83            u_errorName(errorCode),
84            uprv_memcmp(lowerTurkish, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
85    }
86
87    /* test preflighting */
88    buffer[0]=buffer[2]=0xabcd;
89    errorCode=U_ZERO_ERROR;
90    length=u_strToLower(buffer, 2, /* set destCapacity=2 */
91                        beforeLower, UPRV_LENGTHOF(beforeLower),
92                        "",
93                        &errorCode);
94    if( errorCode!=U_BUFFER_OVERFLOW_ERROR ||
95        length!=(UPRV_LENGTHOF(lowerRoot)) ||
96        uprv_memcmp(lowerRoot, buffer, 2*U_SIZEOF_UCHAR)!=0 ||
97        buffer[2]!=0xabcd
98    ) {
99        log_err("error in u_strToLower(root locale preflighting)=%ld error=%s string matches: %s\n",
100            length,
101            u_errorName(errorCode),
102            uprv_memcmp(lowerRoot, buffer, 2*U_SIZEOF_UCHAR)==0 && buffer[2]==0xabcd ? "yes" : "no");
103    }
104
105    /* test error handling */
106    errorCode=U_ZERO_ERROR;
107    length=u_strToLower(NULL, UPRV_LENGTHOF(buffer),
108                        beforeLower, UPRV_LENGTHOF(beforeLower),
109                        "",
110                        &errorCode);
111    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
112        log_err("error in u_strToLower(root locale dest=NULL)=%ld error=%s\n",
113            length,
114            u_errorName(errorCode));
115    }
116
117    buffer[0]=0xabcd;
118    errorCode=U_ZERO_ERROR;
119    length=u_strToLower(buffer, -1,
120                        beforeLower, UPRV_LENGTHOF(beforeLower),
121                        "",
122                        &errorCode);
123    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
124        buffer[0]!=0xabcd
125    ) {
126        log_err("error in u_strToLower(root locale destCapacity=-1)=%ld error=%s buffer[0]==0x%lx\n",
127            length,
128            u_errorName(errorCode),
129            buffer[0]);
130    }
131}
132
133static void
134TestCaseUpper(void) {
135    static const UChar
136
137    beforeUpper[]= { 0x61, 0x42, 0x69,  0x3c2, 0xdf,       0x3c3, 0x2f, 0xfb03,           0xd93f, 0xdfff },
138    upperRoot[]=   { 0x41, 0x42, 0x49,  0x3a3, 0x53, 0x53, 0x3a3, 0x2f, 0x46, 0x46, 0x49, 0xd93f, 0xdfff },
139    upperTurkish[]={ 0x41, 0x42, 0x130, 0x3a3, 0x53, 0x53, 0x3a3, 0x2f, 0x46, 0x46, 0x49, 0xd93f, 0xdfff };
140
141    UChar buffer[32];
142    int32_t length;
143    UErrorCode errorCode;
144
145    /* uppercase with root locale and in the same buffer */
146    uprv_memcpy(buffer, beforeUpper, sizeof(beforeUpper));
147    errorCode=U_ZERO_ERROR;
148    length=u_strToUpper(buffer, UPRV_LENGTHOF(buffer),
149                        buffer, UPRV_LENGTHOF(beforeUpper),
150                        "",
151                        &errorCode);
152    if( U_FAILURE(errorCode) ||
153        length!=(UPRV_LENGTHOF(upperRoot)) ||
154        uprv_memcmp(upperRoot, buffer, length*U_SIZEOF_UCHAR)!=0 ||
155        buffer[length]!=0
156    ) {
157        log_err("error in u_strToUpper(root locale)=%ld error=%s string matches: %s\n",
158            length,
159            u_errorName(errorCode),
160            uprv_memcmp(upperRoot, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
161    }
162
163    /* uppercase with turkish locale and separate buffers */
164    buffer[0]=0xabcd;
165    errorCode=U_ZERO_ERROR;
166    length=u_strToUpper(buffer, UPRV_LENGTHOF(buffer),
167                        beforeUpper, UPRV_LENGTHOF(beforeUpper),
168                        "tr",
169                        &errorCode);
170    if( U_FAILURE(errorCode) ||
171        length!=(UPRV_LENGTHOF(upperTurkish)) ||
172        uprv_memcmp(upperTurkish, buffer, length*U_SIZEOF_UCHAR)!=0 ||
173        buffer[length]!=0
174    ) {
175        log_err("error in u_strToUpper(turkish locale)=%ld error=%s string matches: %s\n",
176            length,
177            u_errorName(errorCode),
178            uprv_memcmp(upperTurkish, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
179    }
180
181    /* test preflighting */
182    errorCode=U_ZERO_ERROR;
183    length=u_strToUpper(NULL, 0,
184                        beforeUpper, UPRV_LENGTHOF(beforeUpper),
185                        "tr",
186                        &errorCode);
187    if( errorCode!=U_BUFFER_OVERFLOW_ERROR ||
188        length!=(UPRV_LENGTHOF(upperTurkish))
189    ) {
190        log_err("error in u_strToUpper(turkish locale pure preflighting)=%ld error=%s\n",
191            length,
192            u_errorName(errorCode));
193    }
194
195    /* test error handling */
196    buffer[0]=0xabcd;
197    errorCode=U_ZERO_ERROR;
198    length=u_strToUpper(buffer, UPRV_LENGTHOF(buffer),
199                        NULL, UPRV_LENGTHOF(beforeUpper),
200                        "tr",
201                        &errorCode);
202    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
203        buffer[0]!=0xabcd
204    ) {
205        log_err("error in u_strToUpper(turkish locale src=NULL)=%ld error=%s buffer[0]==0x%lx\n",
206            length,
207            u_errorName(errorCode),
208            buffer[0]);
209    }
210
211    buffer[0]=0xabcd;
212    errorCode=U_ZERO_ERROR;
213    length=u_strToUpper(buffer, UPRV_LENGTHOF(buffer),
214                        beforeUpper, -2,
215                        "tr",
216                        &errorCode);
217    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
218        buffer[0]!=0xabcd
219    ) {
220        log_err("error in u_strToUpper(turkish locale srcLength=-2)=%ld error=%s buffer[0]==0x%lx\n",
221            length,
222            u_errorName(errorCode),
223            buffer[0]);
224    }
225}
226
227#if !UCONFIG_NO_BREAK_ITERATION
228
229static void
230TestCaseTitle(void) {
231    static const UChar
232
233    beforeTitle[]= { 0x61, 0x42, 0x20, 0x69,  0x3c2, 0x20, 0xdf,       0x3c3, 0x2f, 0xfb03,           0xd93f, 0xdfff },
234    titleWord[]=   { 0x41, 0x62, 0x20, 0x49,  0x3c2, 0x20, 0x53, 0x73, 0x3c3, 0x2f, 0x46, 0x66, 0x69, 0xd93f, 0xdfff },
235    titleChar[]=   { 0x41, 0x42, 0x20, 0x49,  0x3a3, 0x20, 0x53, 0x73, 0x3a3, 0x2f, 0x46, 0x66, 0x69, 0xd93f, 0xdfff };
236
237    UChar buffer[32];
238    UBreakIterator *titleIterChars;
239    int32_t length;
240    UErrorCode errorCode;
241
242    errorCode=U_ZERO_ERROR;
243    titleIterChars=ubrk_open(UBRK_CHARACTER, "", beforeTitle, UPRV_LENGTHOF(beforeTitle), &errorCode);
244    if(U_FAILURE(errorCode)) {
245        log_err_status(errorCode, "error: ubrk_open(UBRK_CHARACTER)->%s\n", u_errorName(errorCode));
246        return;
247    }
248
249    /* titlecase with standard break iterator and in the same buffer */
250    uprv_memcpy(buffer, beforeTitle, sizeof(beforeTitle));
251    errorCode=U_ZERO_ERROR;
252    length=u_strToTitle(buffer, UPRV_LENGTHOF(buffer),
253                        buffer, UPRV_LENGTHOF(beforeTitle),
254                        NULL, "",
255                        &errorCode);
256    if( U_FAILURE(errorCode) ||
257        length!=(UPRV_LENGTHOF(titleWord)) ||
258        uprv_memcmp(titleWord, buffer, length*U_SIZEOF_UCHAR)!=0 ||
259        buffer[length]!=0
260    ) {
261        log_err("error in u_strToTitle(standard iterator)=%ld error=%s string matches: %s\n",
262            length,
263            u_errorName(errorCode),
264            uprv_memcmp(titleWord, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
265    }
266
267    /* titlecase with UBRK_CHARACTERS and separate buffers */
268    buffer[0]=0xabcd;
269    errorCode=U_ZERO_ERROR;
270    length=u_strToTitle(buffer, UPRV_LENGTHOF(buffer),
271                        beforeTitle, UPRV_LENGTHOF(beforeTitle),
272                        titleIterChars, "",
273                        &errorCode);
274    if( U_FAILURE(errorCode) ||
275        length!=(UPRV_LENGTHOF(titleChar)) ||
276        uprv_memcmp(titleChar, buffer, length*U_SIZEOF_UCHAR)!=0 ||
277        buffer[length]!=0
278    ) {
279        log_err("error in u_strToTitle(UBRK_CHARACTERS)=%ld error=%s string matches: %s\n",
280            length,
281            u_errorName(errorCode),
282            uprv_memcmp(titleChar, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
283    }
284
285    /* test preflighting */
286    errorCode=U_ZERO_ERROR;
287    length=u_strToTitle(NULL, 0,
288                        beforeTitle, UPRV_LENGTHOF(beforeTitle),
289                        titleIterChars, "",
290                        &errorCode);
291    if( errorCode!=U_BUFFER_OVERFLOW_ERROR ||
292        length!=(UPRV_LENGTHOF(titleChar))
293    ) {
294        log_err("error in u_strToTitle(UBRK_CHARACTERS pure preflighting)=%ld error=%s\n",
295            length,
296            u_errorName(errorCode));
297    }
298
299    /* test error handling */
300    buffer[0]=0xabcd;
301    errorCode=U_ZERO_ERROR;
302    length=u_strToTitle(buffer, UPRV_LENGTHOF(buffer),
303                        NULL, UPRV_LENGTHOF(beforeTitle),
304                        titleIterChars, "",
305                        &errorCode);
306    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
307        buffer[0]!=0xabcd
308    ) {
309        log_err("error in u_strToTitle(UBRK_CHARACTERS src=NULL)=%ld error=%s buffer[0]==0x%lx\n",
310            length,
311            u_errorName(errorCode),
312            buffer[0]);
313    }
314
315    buffer[0]=0xabcd;
316    errorCode=U_ZERO_ERROR;
317    length=u_strToTitle(buffer, UPRV_LENGTHOF(buffer),
318                        beforeTitle, -2,
319                        titleIterChars, "",
320                        &errorCode);
321    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
322        buffer[0]!=0xabcd
323    ) {
324        log_err("error in u_strToTitle(UBRK_CHARACTERS srcLength=-2)=%ld error=%s buffer[0]==0x%lx\n",
325            length,
326            u_errorName(errorCode),
327            buffer[0]);
328    }
329
330    ubrk_close(titleIterChars);
331}
332
333static void
334TestCaseDutchTitle(void) {
335    static const UChar
336
337    beforeTitle[]= { 0x69, 0x6A, 0x73, 0x73,  0x45, 0x6c, 0x20, 0x69, 0x67, 0x6c, 0x4f, 0x6f , 0x20 , 0x49, 0x4A, 0x53, 0x53, 0x45, 0x4C },
338    titleRoot[]=   { 0x49, 0x6A, 0x73, 0x73,  0x65, 0x6c, 0x20, 0x49, 0x67, 0x6c, 0x6f, 0x6f , 0x20 , 0x49, 0x6A, 0x73, 0x73, 0x65, 0x6C },
339    titleDutch[]=  { 0x49, 0x4A, 0x73, 0x73,  0x65, 0x6c, 0x20, 0x49, 0x67, 0x6c, 0x6f, 0x6f , 0x20 , 0x49, 0x4A, 0x73, 0x73, 0x65, 0x6C };
340
341    UChar buffer[32];
342    UBreakIterator *titleIterWord;
343    int32_t length;
344    UErrorCode errorCode;
345
346    errorCode=U_ZERO_ERROR;
347    titleIterWord=ubrk_open(UBRK_WORD, "", beforeTitle, UPRV_LENGTHOF(beforeTitle), &errorCode);
348    if(U_FAILURE(errorCode)) {
349        log_err_status(errorCode, "error: ubrk_open(UBRK_WORD)->%s\n", u_errorName(errorCode));
350        return;
351    }
352
353    /* titlecase with default locale */
354    buffer[0]=0xabcd;
355    errorCode=U_ZERO_ERROR;
356    length=u_strToTitle(buffer, UPRV_LENGTHOF(buffer),
357                        beforeTitle, UPRV_LENGTHOF(beforeTitle),
358                        titleIterWord, "",
359                        &errorCode);
360    if( U_FAILURE(errorCode) ||
361        length!=(UPRV_LENGTHOF(titleRoot)) ||
362        uprv_memcmp(titleRoot, buffer, length*U_SIZEOF_UCHAR)!=0 ||
363        buffer[length]!=0
364    ) {
365        char charsOut[21];
366        u_UCharsToChars(buffer,charsOut,sizeof(charsOut));
367        log_err("error in u_strToTitle(UBRK_CHARACTERS)=%ld error=%s root locale string matches: %s\noutput buffer is {%s}\n",
368            length,
369            u_errorName(errorCode),
370            uprv_memcmp(titleRoot, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no", charsOut);
371    }
372    /* titlecase with Dutch locale */
373    buffer[0]=0xabcd;
374    errorCode=U_ZERO_ERROR;
375    length=u_strToTitle(buffer, UPRV_LENGTHOF(buffer),
376                        beforeTitle, UPRV_LENGTHOF(beforeTitle),
377                        titleIterWord, "nl",
378                        &errorCode);
379    if( U_FAILURE(errorCode) ||
380        length!=(UPRV_LENGTHOF(titleDutch)) ||
381        uprv_memcmp(titleDutch, buffer, length*U_SIZEOF_UCHAR)!=0 ||
382        buffer[length]!=0
383    ) {
384        char charsOut[21];
385        u_UCharsToChars(buffer,charsOut,sizeof(charsOut));
386        log_err("error in u_strToTitle(UBRK_CHARACTERS)=%ld error=%s dutch locale string matches: %s\noutput buffer is {%s}\n",
387            length,
388            u_errorName(errorCode),
389            uprv_memcmp(titleDutch, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no", charsOut);
390    }
391
392    ubrk_close(titleIterWord);
393}
394
395#endif
396
397/* test case folding and case-insensitive string compare -------------------- */
398
399static void
400TestCaseFolding(void) {
401    /*
402     * CaseFolding.txt says about i and its cousins:
403     *   0049; C; 0069; # LATIN CAPITAL LETTER I
404     *   0049; T; 0131; # LATIN CAPITAL LETTER I
405     *
406     *   0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE
407     *   0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE
408     * That's all.
409     * See CaseFolding.txt and the Unicode Standard for how to apply the case foldings.
410     */
411    static const UChar32
412    simple[]={
413        /* input, default, exclude special i */
414        0x61,   0x61,  0x61,
415        0x49,   0x69,  0x131,
416        0x130,  0x130, 0x69,
417        0x131,  0x131, 0x131,
418        0xdf,   0xdf,  0xdf,
419        0xfb03, 0xfb03, 0xfb03,
420        0x1040e,0x10436,0x10436,
421        0x5ffff,0x5ffff,0x5ffff
422    };
423
424    static const UChar
425    mixed[]=                { 0x61, 0x42, 0x130,       0x49,  0x131, 0x3d0, 0xdf,       0xfb03,           0xd93f, 0xdfff },
426    foldedDefault[]=        { 0x61, 0x62, 0x69, 0x307, 0x69,  0x131, 0x3b2, 0x73, 0x73, 0x66, 0x66, 0x69, 0xd93f, 0xdfff },
427    foldedExcludeSpecialI[]={ 0x61, 0x62, 0x69,        0x131, 0x131, 0x3b2, 0x73, 0x73, 0x66, 0x66, 0x69, 0xd93f, 0xdfff };
428
429    UVersionInfo unicodeVersion={ 0, 0, 17, 89 }, unicode_3_1={ 3, 1, 0, 0 };
430
431    const UChar32 *p;
432    int32_t i;
433
434    UChar buffer[32];
435    int32_t length;
436    UErrorCode errorCode;
437    UBool isUnicode_3_1;
438
439    /* if unicodeVersion()>=3.1 then test exclude-special-i cases as well */
440    u_getUnicodeVersion(unicodeVersion);
441    isUnicode_3_1= uprv_memcmp(unicodeVersion, unicode_3_1, 4)>=0;
442
443    /* test simple case folding */
444    p=simple;
445    for(i=0; i<sizeof(simple)/12; p+=3, ++i) {
446        if(u_foldCase(p[0], U_FOLD_CASE_DEFAULT)!=p[1]) {
447            log_err("error: u_foldCase(0x%04lx, default)=0x%04lx instead of 0x%04lx\n",
448                    p[0], u_foldCase(p[0], U_FOLD_CASE_DEFAULT), p[1]);
449            return;
450        }
451
452        if(isUnicode_3_1 && u_foldCase(p[0], U_FOLD_CASE_EXCLUDE_SPECIAL_I)!=p[2]) {
453            log_err("error: u_foldCase(0x%04lx, exclude special i)=0x%04lx instead of 0x%04lx\n",
454                    p[0], u_foldCase(p[0], U_FOLD_CASE_EXCLUDE_SPECIAL_I), p[2]);
455            return;
456        }
457    }
458
459    /* test full string case folding with default option and separate buffers */
460    buffer[0]=0xabcd;
461    errorCode=U_ZERO_ERROR;
462    length=u_strFoldCase(buffer, UPRV_LENGTHOF(buffer),
463                        mixed, UPRV_LENGTHOF(mixed),
464                        U_FOLD_CASE_DEFAULT,
465                        &errorCode);
466    if( U_FAILURE(errorCode) ||
467        length!=(UPRV_LENGTHOF(foldedDefault)) ||
468        uprv_memcmp(foldedDefault, buffer, length*U_SIZEOF_UCHAR)!=0 ||
469        buffer[length]!=0
470    ) {
471        log_err("error in u_strFoldCase(default)=%ld error=%s string matches: %s\n",
472            length,
473            u_errorName(errorCode),
474            uprv_memcmp(foldedDefault, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
475    }
476
477    /* exclude special i */
478    if(isUnicode_3_1) {
479        buffer[0]=0xabcd;
480        errorCode=U_ZERO_ERROR;
481        length=u_strFoldCase(buffer, UPRV_LENGTHOF(buffer),
482                            mixed, UPRV_LENGTHOF(mixed),
483                            U_FOLD_CASE_EXCLUDE_SPECIAL_I,
484                            &errorCode);
485        if( U_FAILURE(errorCode) ||
486            length!=(UPRV_LENGTHOF(foldedExcludeSpecialI)) ||
487            uprv_memcmp(foldedExcludeSpecialI, buffer, length*U_SIZEOF_UCHAR)!=0 ||
488            buffer[length]!=0
489        ) {
490            log_err("error in u_strFoldCase(exclude special i)=%ld error=%s string matches: %s\n",
491                length,
492                u_errorName(errorCode),
493                uprv_memcmp(foldedExcludeSpecialI, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
494        }
495    }
496
497    /* test full string case folding with default option and in the same buffer */
498    uprv_memcpy(buffer, mixed, sizeof(mixed));
499    buffer[UPRV_LENGTHOF(mixed)]=0;
500    errorCode=U_ZERO_ERROR;
501    length=u_strFoldCase(buffer, UPRV_LENGTHOF(buffer),
502                        buffer, -1, /* implicit srcLength */
503                        U_FOLD_CASE_DEFAULT,
504                        &errorCode);
505    if( U_FAILURE(errorCode) ||
506        length!=(UPRV_LENGTHOF(foldedDefault)) ||
507        uprv_memcmp(foldedDefault, buffer, length*U_SIZEOF_UCHAR)!=0 ||
508        buffer[length]!=0
509    ) {
510        log_err("error in u_strFoldCase(default same buffer)=%ld error=%s string matches: %s\n",
511            length,
512            u_errorName(errorCode),
513            uprv_memcmp(foldedDefault, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
514    }
515
516    /* test full string case folding, exclude special i, in the same buffer */
517    if(isUnicode_3_1) {
518        uprv_memcpy(buffer, mixed, sizeof(mixed));
519        errorCode=U_ZERO_ERROR;
520        length=u_strFoldCase(buffer, UPRV_LENGTHOF(buffer),
521                            buffer, UPRV_LENGTHOF(mixed),
522                            U_FOLD_CASE_EXCLUDE_SPECIAL_I,
523                            &errorCode);
524        if( U_FAILURE(errorCode) ||
525            length!=UPRV_LENGTHOF(foldedExcludeSpecialI) ||
526            uprv_memcmp(foldedExcludeSpecialI, buffer, length*U_SIZEOF_UCHAR)!=0 ||
527            buffer[length]!=0
528        ) {
529            log_err("error in u_strFoldCase(exclude special i same buffer)=%ld error=%s string matches: %s\n",
530                length,
531                u_errorName(errorCode),
532                uprv_memcmp(foldedExcludeSpecialI, buffer, length*U_SIZEOF_UCHAR)==0 && buffer[length]==0 ? "yes" : "no");
533        }
534    }
535
536    /* test preflighting */
537    buffer[0]=buffer[2]=0xabcd;
538    errorCode=U_ZERO_ERROR;
539    length=u_strFoldCase(buffer, 2, /* set destCapacity=2 */
540                        mixed, UPRV_LENGTHOF(mixed),
541                        U_FOLD_CASE_DEFAULT,
542                        &errorCode);
543    if( errorCode!=U_BUFFER_OVERFLOW_ERROR ||
544        length!=UPRV_LENGTHOF(foldedDefault) ||
545        uprv_memcmp(foldedDefault, buffer, 2*U_SIZEOF_UCHAR)!=0 ||
546        buffer[2]!=0xabcd
547    ) {
548        log_err("error in u_strFoldCase(default preflighting)=%ld error=%s string matches: %s\n",
549            length,
550            u_errorName(errorCode),
551            uprv_memcmp(foldedDefault, buffer, 2*U_SIZEOF_UCHAR)==0 && buffer[2]==0xabcd ? "yes" : "no");
552    }
553
554    errorCode=U_ZERO_ERROR;
555    length=u_strFoldCase(NULL, 0,
556                        mixed, UPRV_LENGTHOF(mixed),
557                        U_FOLD_CASE_DEFAULT,
558                        &errorCode);
559    if( errorCode!=U_BUFFER_OVERFLOW_ERROR ||
560        length!=UPRV_LENGTHOF(foldedDefault)
561    ) {
562        log_err("error in u_strFoldCase(default pure preflighting)=%ld error=%s\n",
563            length,
564            u_errorName(errorCode));
565    }
566
567    /* test error handling */
568    errorCode=U_ZERO_ERROR;
569    length=u_strFoldCase(NULL, UPRV_LENGTHOF(buffer),
570                        mixed, UPRV_LENGTHOF(mixed),
571                        U_FOLD_CASE_DEFAULT,
572                        &errorCode);
573    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
574        log_err("error in u_strFoldCase(default dest=NULL)=%ld error=%s\n",
575            length,
576            u_errorName(errorCode));
577    }
578
579    buffer[0]=0xabcd;
580    errorCode=U_ZERO_ERROR;
581    length=u_strFoldCase(buffer, -1,
582                        mixed, UPRV_LENGTHOF(mixed),
583                        U_FOLD_CASE_DEFAULT,
584                        &errorCode);
585    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
586        buffer[0]!=0xabcd
587    ) {
588        log_err("error in u_strFoldCase(default destCapacity=-1)=%ld error=%s buffer[0]==0x%lx\n",
589            length,
590            u_errorName(errorCode),
591            buffer[0]);
592    }
593
594    buffer[0]=0xabcd;
595    errorCode=U_ZERO_ERROR;
596    length=u_strFoldCase(buffer, UPRV_LENGTHOF(buffer),
597                        NULL, UPRV_LENGTHOF(mixed),
598                        U_FOLD_CASE_EXCLUDE_SPECIAL_I,
599                        &errorCode);
600    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
601        buffer[0]!=0xabcd
602    ) {
603        log_err("error in u_strFoldCase(exclude special i src=NULL)=%ld error=%s buffer[0]==0x%lx\n",
604            length,
605            u_errorName(errorCode),
606            buffer[0]);
607    }
608
609    buffer[0]=0xabcd;
610    errorCode=U_ZERO_ERROR;
611    length=u_strFoldCase(buffer, UPRV_LENGTHOF(buffer),
612                        mixed, -2,
613                        U_FOLD_CASE_EXCLUDE_SPECIAL_I,
614                        &errorCode);
615    if( errorCode!=U_ILLEGAL_ARGUMENT_ERROR ||
616        buffer[0]!=0xabcd
617    ) {
618        log_err("error in u_strFoldCase(exclude special i srcLength=-2)=%ld error=%s buffer[0]==0x%lx\n",
619            length,
620            u_errorName(errorCode),
621            buffer[0]);
622    }
623}
624
625static void
626TestCaseCompare(void) {
627    static const UChar
628
629    mixed[]=               { 0x61, 0x42, 0x131, 0x3a3, 0xdf,       0xfb03,           0xd93f, 0xdfff, 0 },
630    otherDefault[]=        { 0x41, 0x62, 0x131, 0x3c3, 0x73, 0x53, 0x46, 0x66, 0x49, 0xd93f, 0xdfff, 0 },
631    otherExcludeSpecialI[]={ 0x41, 0x62, 0x131, 0x3c3, 0x53, 0x73, 0x66, 0x46, 0x69, 0xd93f, 0xdfff, 0 },
632    different[]=           { 0x41, 0x62, 0x131, 0x3c3, 0x73, 0x53, 0x46, 0x66, 0x49, 0xd93f, 0xdffd, 0 };
633
634    UVersionInfo unicodeVersion={ 0, 0, 17, 89 }, unicode_3_1={ 3, 1, 0, 0 };
635
636    int32_t result, lenMixed, lenOtherDefault, lenOtherExcludeSpecialI, lenDifferent;
637    UErrorCode errorCode;
638    UBool isUnicode_3_1;
639
640    errorCode=U_ZERO_ERROR;
641
642    lenMixed=u_strlen(mixed);
643    lenOtherDefault=u_strlen(otherDefault);
644    (void)lenOtherDefault;    /* Suppress set but not used warning. */
645    lenOtherExcludeSpecialI=u_strlen(otherExcludeSpecialI);
646    lenDifferent=u_strlen(different);
647
648    /* if unicodeVersion()>=3.1 then test exclude-special-i cases as well */
649    u_getUnicodeVersion(unicodeVersion);
650    isUnicode_3_1= uprv_memcmp(unicodeVersion, unicode_3_1, 4)>=0;
651    (void)isUnicode_3_1;    /* Suppress set but not used warning. */
652
653    /* test u_strcasecmp() */
654    result=u_strcasecmp(mixed, otherDefault, U_FOLD_CASE_DEFAULT);
655    if(result!=0) {
656        log_err("error: u_strcasecmp(mixed, other, default)=%ld instead of 0\n", result);
657    }
658    result=u_strCaseCompare(mixed, -1, otherDefault, -1, U_FOLD_CASE_DEFAULT, &errorCode);
659    if(result!=0) {
660        log_err("error: u_strCaseCompare(mixed, other, default)=%ld instead of 0\n", result);
661    }
662
663    /* test u_strcasecmp() - exclude special i */
664    result=u_strcasecmp(mixed, otherExcludeSpecialI, U_FOLD_CASE_EXCLUDE_SPECIAL_I);
665    if(result!=0) {
666        log_err("error: u_strcasecmp(mixed, other, exclude special i)=%ld instead of 0\n", result);
667    }
668    result=u_strCaseCompare(mixed, lenMixed, otherExcludeSpecialI, lenOtherExcludeSpecialI, U_FOLD_CASE_EXCLUDE_SPECIAL_I, &errorCode);
669    if(result!=0) {
670        log_err("error: u_strCaseCompare(mixed, other, exclude special i)=%ld instead of 0\n", result);
671    }
672
673    /* test u_strcasecmp() */
674    result=u_strcasecmp(mixed, different, U_FOLD_CASE_DEFAULT);
675    if(result<=0) {
676        log_err("error: u_strcasecmp(mixed, different, default)=%ld instead of positive\n", result);
677    }
678    result=u_strCaseCompare(mixed, -1, different, lenDifferent, U_FOLD_CASE_DEFAULT, &errorCode);
679    if(result<=0) {
680        log_err("error: u_strCaseCompare(mixed, different, default)=%ld instead of positive\n", result);
681    }
682
683    /* test u_strncasecmp() - stop before the sharp s (U+00df) */
684    result=u_strncasecmp(mixed, different, 4, U_FOLD_CASE_DEFAULT);
685    if(result!=0) {
686        log_err("error: u_strncasecmp(mixed, different, 4, default)=%ld instead of 0\n", result);
687    }
688    result=u_strCaseCompare(mixed, 4, different, 4, U_FOLD_CASE_DEFAULT, &errorCode);
689    if(result!=0) {
690        log_err("error: u_strCaseCompare(mixed, 4, different, 4, default)=%ld instead of 0\n", result);
691    }
692
693    /* test u_strncasecmp() - stop in the middle of the sharp s (U+00df) */
694    result=u_strncasecmp(mixed, different, 5, U_FOLD_CASE_DEFAULT);
695    if(result<=0) {
696        log_err("error: u_strncasecmp(mixed, different, 5, default)=%ld instead of positive\n", result);
697    }
698    result=u_strCaseCompare(mixed, 5, different, 5, U_FOLD_CASE_DEFAULT, &errorCode);
699    if(result<=0) {
700        log_err("error: u_strCaseCompare(mixed, 5, different, 5, default)=%ld instead of positive\n", result);
701    }
702
703    /* test u_memcasecmp() - stop before the sharp s (U+00df) */
704    result=u_memcasecmp(mixed, different, 4, U_FOLD_CASE_DEFAULT);
705    if(result!=0) {
706        log_err("error: u_memcasecmp(mixed, different, 4, default)=%ld instead of 0\n", result);
707    }
708
709    /* test u_memcasecmp() - stop in the middle of the sharp s (U+00df) */
710    result=u_memcasecmp(mixed, different, 5, U_FOLD_CASE_DEFAULT);
711    if(result<=0) {
712        log_err("error: u_memcasecmp(mixed, different, 5, default)=%ld instead of positive\n", result);
713    }
714}
715
716/* test UCaseMap ------------------------------------------------------------ */
717
718/*
719 * API test for UCaseMap;
720 * test cases for actual case mappings using UCaseMap see
721 * intltest utility/UnicodeStringTest/StringCaseTest/TestCasing
722 */
723static void
724TestUCaseMap(void) {
725    static const char
726        aBc[] ={ 0x61, 0x42, 0x63, 0 },
727        abc[] ={ 0x61, 0x62, 0x63, 0 },
728        ABCg[]={ 0x41, 0x42, 0x43, 0x67, 0 },
729        defg[]={ 0x64, 0x65, 0x66, 0x67, 0 };
730    char utf8Out[8];
731
732    UCaseMap *csm;
733    const char *locale;
734    uint32_t options;
735    int32_t length;
736    UErrorCode errorCode;
737
738    errorCode=U_ZERO_ERROR;
739    csm=ucasemap_open("tur", 0xa5, &errorCode);
740    if(U_FAILURE(errorCode)) {
741        log_err("ucasemap_open(\"tur\") failed - %s\n", u_errorName(errorCode));
742        return;
743    }
744    locale=ucasemap_getLocale(csm);
745    if(0!=strcmp(locale, "tr")) {
746        log_err("ucasemap_getLocale(ucasemap_open(\"tur\"))==%s!=\"tr\"\n", locale);
747    }
748    /* overly long locale IDs may get truncated to their language code to avoid unnecessary allocation */
749    ucasemap_setLocale(csm, "I-kLInGOn-the-quick-brown-fox-jumps-over-the-lazy-dog", &errorCode);
750    locale=ucasemap_getLocale(csm);
751    if(0!=strncmp(locale, "i-klingon", 9)) {
752        log_err("ucasemap_getLocale(ucasemap_setLocale(\"I-kLInGOn-the-quick-br...\"))==%s\n"
753                "    does not start with \"i-klingon\"\n", locale);
754    }
755
756    errorCode=U_ZERO_ERROR;
757    options=ucasemap_getOptions(csm);
758    if(options!=0xa5) {
759        log_err("ucasemap_getOptions(ucasemap_open(0xa5))==0x%lx!=0xa5\n", (long)options);
760    }
761    ucasemap_setOptions(csm, 0x333333, &errorCode);
762    options=ucasemap_getOptions(csm);
763    if(options!=0x333333) {
764        log_err("ucasemap_getOptions(ucasemap_setOptions(0x333333))==0x%lx!=0x333333\n", (long)options);
765    }
766
767    /* test case mapping API; not all permutations necessary due to shared implementation code */
768
769    /* NUL terminated source */
770    errorCode=U_ZERO_ERROR;
771    length=ucasemap_utf8ToLower(csm, utf8Out, (int32_t)sizeof(utf8Out), aBc, -1, &errorCode);
772    if(U_FAILURE(errorCode) || length!=3 || 0!=strcmp(abc, utf8Out)) {
773        log_err("ucasemap_utf8ToLower(aBc\\0) failed\n");
774    }
775
776    /* incoming failure code */
777    errorCode=U_PARSE_ERROR;
778    strcpy(utf8Out, defg);
779    length=ucasemap_utf8ToLower(csm, utf8Out, (int32_t)sizeof(utf8Out), aBc, -1, &errorCode);
780    if(errorCode!=U_PARSE_ERROR || 0!=strcmp(defg, utf8Out)) {
781        log_err("ucasemap_utf8ToLower(failure) failed\n");
782    }
783
784    /* overlapping input & output */
785    errorCode=U_ZERO_ERROR;
786    strcpy(utf8Out, aBc);
787    length=ucasemap_utf8ToUpper(csm, utf8Out, 2, utf8Out+1, 2, &errorCode);
788    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || 0!=strcmp(aBc, utf8Out)) {
789        log_err("ucasemap_utf8ToUpper(overlap 1) failed\n");
790    }
791
792    /* overlap in the other direction */
793    errorCode=U_ZERO_ERROR;
794    strcpy(utf8Out, aBc);
795    length=ucasemap_utf8ToUpper(csm, utf8Out+1, 2, utf8Out, 2, &errorCode);
796    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || 0!=strcmp(aBc, utf8Out)) {
797        log_err("ucasemap_utf8ToUpper(overlap 2) failed\n");
798    }
799
800    /* NULL destination */
801    errorCode=U_ZERO_ERROR;
802    strcpy(utf8Out, defg);
803    length=ucasemap_utf8ToLower(csm, NULL, (int32_t)sizeof(utf8Out), aBc, -1, &errorCode);
804    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || 0!=strcmp(defg, utf8Out)) {
805        log_err("ucasemap_utf8ToLower(dest=NULL) failed\n");
806    }
807
808    /* destCapacity<0 */
809    errorCode=U_ZERO_ERROR;
810    strcpy(utf8Out, defg);
811    length=ucasemap_utf8ToLower(csm, utf8Out, -2, aBc, -1, &errorCode);
812    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || 0!=strcmp(defg, utf8Out)) {
813        log_err("ucasemap_utf8ToLower(destCapacity<0) failed\n");
814    }
815
816    /* NULL source */
817    errorCode=U_ZERO_ERROR;
818    strcpy(utf8Out, defg);
819    length=ucasemap_utf8ToLower(csm, utf8Out, (int32_t)sizeof(utf8Out), NULL, -1, &errorCode);
820    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || 0!=strcmp(defg, utf8Out)) {
821        log_err("ucasemap_utf8ToLower(src=NULL) failed\n");
822    }
823
824    /* srcLength<-1 */
825    errorCode=U_ZERO_ERROR;
826    strcpy(utf8Out, defg);
827    length=ucasemap_utf8ToLower(csm, utf8Out, (int32_t)sizeof(utf8Out), aBc, -2, &errorCode);
828    if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || 0!=strcmp(defg, utf8Out)) {
829        log_err("ucasemap_utf8ToLower(srcLength<-1) failed\n");
830    }
831
832    /* buffer overflow */
833    errorCode=U_ZERO_ERROR;
834    strcpy(utf8Out, defg);
835    length=ucasemap_utf8ToUpper(csm, utf8Out, 2, aBc, 3, &errorCode);
836    if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=3 || 0!=strcmp(defg+2, utf8Out+2)) {
837        log_err("ucasemap_utf8ToUpper(overflow) failed\n");
838    }
839
840    /* dest not terminated (leaves g from defg alone) */
841    errorCode=U_ZERO_ERROR;
842    strcpy(utf8Out, defg);
843    length=ucasemap_utf8ToUpper(csm, utf8Out, 3, aBc, 3, &errorCode);
844    if(errorCode!=U_STRING_NOT_TERMINATED_WARNING || length!=3 || 0!=strcmp(ABCg, utf8Out)) {
845        log_err("ucasemap_utf8ToUpper(overflow) failed\n");
846    }
847
848    /* C API coverage for case folding. More thorough test via C++ intltest's StringCaseTest::TestCasing(). */
849    errorCode=U_ZERO_ERROR;
850    utf8Out[0]=0;
851    length=ucasemap_utf8FoldCase(csm, utf8Out, (int32_t)sizeof(utf8Out), aBc, 3, &errorCode);
852    if(U_FAILURE(errorCode) || length!=3 || 0!=strcmp(abc, utf8Out)) {
853        log_err("ucasemap_utf8FoldCase(aBc) failed\n");
854    }
855
856    ucasemap_close(csm);
857}
858
859#if !UCONFIG_NO_BREAK_ITERATION
860
861/* Try titlecasing with options. */
862static void
863TestUCaseMapToTitle(void) {
864    /* "a 'CaT. A 'dOg! 'eTc." where '=U+02BB */
865    /*
866     * Note: The sentence BreakIterator does not recognize a '.'
867     * as a sentence terminator if it is followed by lowercase.
868     * That is why the example has the '!'.
869     */
870    static const UChar
871
872    beforeTitle[]=      { 0x61, 0x20, 0x2bb, 0x43, 0x61, 0x54, 0x2e, 0x20, 0x41, 0x20, 0x2bb, 0x64, 0x4f, 0x67, 0x21, 0x20, 0x2bb, 0x65, 0x54, 0x63, 0x2e },
873    titleWord[]=        { 0x41, 0x20, 0x2bb, 0x43, 0x61, 0x74, 0x2e, 0x20, 0x41, 0x20, 0x2bb, 0x44, 0x6f, 0x67, 0x21, 0x20, 0x2bb, 0x45, 0x74, 0x63, 0x2e },
874    titleWordNoAdjust[]={ 0x41, 0x20, 0x2bb, 0x63, 0x61, 0x74, 0x2e, 0x20, 0x41, 0x20, 0x2bb, 0x64, 0x6f, 0x67, 0x21, 0x20, 0x2bb, 0x65, 0x74, 0x63, 0x2e },
875    titleSentNoLower[]= { 0x41, 0x20, 0x2bb, 0x43, 0x61, 0x54, 0x2e, 0x20, 0x41, 0x20, 0x2bb, 0x64, 0x4f, 0x67, 0x21, 0x20, 0x2bb, 0x45, 0x54, 0x63, 0x2e };
876
877    UChar buffer[32];
878    UCaseMap *csm;
879    UBreakIterator *sentenceIter;
880    const UBreakIterator *iter;
881    int32_t length;
882    UErrorCode errorCode;
883
884    errorCode=U_ZERO_ERROR;
885    csm=ucasemap_open("", 0, &errorCode);
886    if(U_FAILURE(errorCode)) {
887        log_err("ucasemap_open(\"\") failed - %s\n", u_errorName(errorCode));
888        return;
889    }
890
891    iter=ucasemap_getBreakIterator(csm);
892    if(iter!=NULL) {
893        log_err("ucasemap_getBreakIterator() returns %p!=NULL before setting any iterator or titlecasing\n", iter);
894    }
895
896    /* Use default UBreakIterator: Word breaks. */
897    length=ucasemap_toTitle(csm, buffer, UPRV_LENGTHOF(buffer), beforeTitle, UPRV_LENGTHOF(beforeTitle), &errorCode);
898    if( U_FAILURE(errorCode) ||
899        length!=UPRV_LENGTHOF(titleWord) ||
900        0!=u_memcmp(buffer, titleWord, length) ||
901        buffer[length]!=0
902    ) {
903        log_err_status(errorCode, "ucasemap_toTitle(default iterator)=%ld failed - %s\n", (long)length, u_errorName(errorCode));
904    }
905    if (U_SUCCESS(errorCode)) {
906        iter=ucasemap_getBreakIterator(csm);
907        if(iter==NULL) {
908            log_err("ucasemap_getBreakIterator() returns NULL after titlecasing\n");
909        }
910    }
911
912    /* Try U_TITLECASE_NO_BREAK_ADJUSTMENT. */
913    ucasemap_setOptions(csm, U_TITLECASE_NO_BREAK_ADJUSTMENT, &errorCode);
914    if(U_FAILURE(errorCode)) {
915        log_err_status(errorCode, "error: ucasemap_setOptions(U_TITLECASE_NO_BREAK_ADJUSTMENT) failed - %s\n", u_errorName(errorCode));
916        return;
917    }
918
919    length=ucasemap_toTitle(csm, buffer, UPRV_LENGTHOF(buffer), beforeTitle, UPRV_LENGTHOF(beforeTitle), &errorCode);
920    if( U_FAILURE(errorCode) ||
921        length!=UPRV_LENGTHOF(titleWordNoAdjust) ||
922        0!=u_memcmp(buffer, titleWordNoAdjust, length) ||
923        buffer[length]!=0
924    ) {
925        log_err("ucasemap_toTitle(default iterator, no break adjustment)=%ld failed - %s\n", (long)length, u_errorName(errorCode));
926    }
927
928    /* Set a sentence break iterator. */
929    errorCode=U_ZERO_ERROR;
930    sentenceIter=ubrk_open(UBRK_SENTENCE, "", NULL, 0, &errorCode);
931    if(U_FAILURE(errorCode)) {
932        log_err("error: ubrk_open(UBRK_SENTENCE) failed - %s\n", u_errorName(errorCode));
933        ucasemap_close(csm);
934        return;
935    }
936    ucasemap_setBreakIterator(csm, sentenceIter, &errorCode);
937    if(U_FAILURE(errorCode)) {
938        log_err("error: ucasemap_setBreakIterator(sentence iterator) failed - %s\n", u_errorName(errorCode));
939        ubrk_close(sentenceIter);
940        ucasemap_close(csm);
941        return;
942    }
943    iter=ucasemap_getBreakIterator(csm);
944    if(iter!=sentenceIter) {
945        log_err("ucasemap_getBreakIterator() returns %p!=%p after setting the iterator\n", iter, sentenceIter);
946    }
947
948    ucasemap_setOptions(csm, U_TITLECASE_NO_LOWERCASE, &errorCode);
949    if(U_FAILURE(errorCode)) {
950        log_err("error: ucasemap_setOptions(U_TITLECASE_NO_LOWERCASE) failed - %s\n", u_errorName(errorCode));
951        return;
952    }
953
954    /* Use the sentence break iterator with the option. Preflight first. */
955    length=ucasemap_toTitle(csm, NULL, 0, beforeTitle, UPRV_LENGTHOF(beforeTitle), &errorCode);
956    if( errorCode!=U_BUFFER_OVERFLOW_ERROR ||
957        length!=UPRV_LENGTHOF(titleSentNoLower)
958    ) {
959        log_err("ucasemap_toTitle(preflight sentence break iterator, no lowercasing)=%ld failed - %s\n", (long)length, u_errorName(errorCode));
960    }
961
962    errorCode=U_ZERO_ERROR;
963    buffer[0]=0;
964    length=ucasemap_toTitle(csm, buffer, UPRV_LENGTHOF(buffer), beforeTitle, UPRV_LENGTHOF(beforeTitle), &errorCode);
965    if( U_FAILURE(errorCode) ||
966        length!=UPRV_LENGTHOF(titleSentNoLower) ||
967        0!=u_memcmp(buffer, titleSentNoLower, length) ||
968        buffer[length]!=0
969    ) {
970        log_err("ucasemap_toTitle(sentence break iterator, no lowercasing)=%ld failed - %s\n", (long)length, u_errorName(errorCode));
971    }
972
973    /* UTF-8 C API coverage. More thorough test via C++ intltest's StringCaseTest::TestCasing(). */
974    {
975        char utf8BeforeTitle[64], utf8TitleSentNoLower[64], utf8[64];
976        int32_t utf8BeforeTitleLength, utf8TitleSentNoLowerLength;
977
978        errorCode=U_ZERO_ERROR;
979        u_strToUTF8(utf8BeforeTitle, (int32_t)sizeof(utf8BeforeTitle), &utf8BeforeTitleLength, beforeTitle, UPRV_LENGTHOF(beforeTitle), &errorCode);
980        u_strToUTF8(utf8TitleSentNoLower, (int32_t)sizeof(utf8TitleSentNoLower), &utf8TitleSentNoLowerLength, titleSentNoLower, UPRV_LENGTHOF(titleSentNoLower), &errorCode);
981
982        length=ucasemap_utf8ToTitle(csm, utf8, (int32_t)sizeof(utf8), utf8BeforeTitle, utf8BeforeTitleLength, &errorCode);
983        if( U_FAILURE(errorCode) ||
984            length!=utf8TitleSentNoLowerLength ||
985            0!=uprv_memcmp(utf8, utf8TitleSentNoLower, length) ||
986            utf8[length]!=0
987        ) {
988            log_err("ucasemap_utf8ToTitle(sentence break iterator, no lowercasing)=%ld failed - %s\n", (long)length, u_errorName(errorCode));
989        }
990    }
991
992    ucasemap_close(csm);
993}
994
995#endif
996
997/* Test case for internal API u_caseInsensitivePrefixMatch */
998static void
999TestUCaseInsensitivePrefixMatch(void) {
1000    struct {
1001        const char     *s1;
1002        const char     *s2;
1003        int32_t         r1;
1004        int32_t         r2;
1005    } testCases[] = {
1006        {"ABC", "ab", 2, 2},
1007        {"ABCD", "abcx", 3, 3},
1008        {"ABC", "xyz", 0, 0},
1009        /* U+00DF LATIN SMALL LETTER SHARP S */
1010        {"A\\u00dfBC", "Ass", 2, 3},
1011        {"Fust", "Fu\\u00dfball", 2, 2},
1012        {"\\u00dfsA", "s\\u00dfB", 2, 2},
1013        {"\\u00dfs", "s\\u00df", 2, 2},
1014        /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */
1015        {"XYZ\\u0130i\\u0307xxx", "xyzi\\u0307\\u0130yyy", 6, 6},
1016        {0, 0, 0, 0}
1017    };
1018    int32_t i;
1019
1020    for (i = 0; testCases[i].s1 != 0; i++) {
1021        UErrorCode sts = U_ZERO_ERROR;
1022        UChar u1[64], u2[64];
1023        int32_t matchLen1, matchLen2;
1024
1025        u_unescape(testCases[i].s1, u1, 64);
1026        u_unescape(testCases[i].s2, u2, 64);
1027
1028        u_caseInsensitivePrefixMatch(u1, -1, u2, -1, 0, &matchLen1, &matchLen2, &sts);
1029        if (U_FAILURE(sts)) {
1030            log_err("error: %s, s1=%s, s2=%s", u_errorName(sts), testCases[i].s1, testCases[i].s2);
1031        } else if (matchLen1 != testCases[i].r1 || matchLen2 != testCases[i].r2) {
1032            log_err("s1=%s, s2=%2 / match len1=%d, len2=%d / expected len1=%d, len2=%d",
1033                testCases[i].s1, testCases[i].s2,
1034                matchLen1, matchLen2,
1035                testCases[i].r1, testCases[i].r2);
1036        }
1037    }
1038}
1039
1040void addCaseTest(TestNode** root);
1041
1042void addCaseTest(TestNode** root) {
1043    /* cstrcase.c functions, declared in cucdtst.h */
1044    addTest(root, &TestCaseLower, "tsutil/cstrcase/TestCaseLower");
1045    addTest(root, &TestCaseUpper, "tsutil/cstrcase/TestCaseUpper");
1046#if !UCONFIG_NO_BREAK_ITERATION && !UCONFIG_NO_FILE_IO
1047    addTest(root, &TestCaseTitle, "tsutil/cstrcase/TestCaseTitle");
1048    addTest(root, &TestCaseDutchTitle, "tsutil/cstrcase/TestCaseDutchTitle");
1049#endif
1050    addTest(root, &TestCaseFolding, "tsutil/cstrcase/TestCaseFolding");
1051    addTest(root, &TestCaseCompare, "tsutil/cstrcase/TestCaseCompare");
1052    addTest(root, &TestUCaseMap, "tsutil/cstrcase/TestUCaseMap");
1053#if !UCONFIG_NO_BREAK_ITERATION && !UCONFIG_NO_FILE_IO
1054    addTest(root, &TestUCaseMapToTitle, "tsutil/cstrcase/TestUCaseMapToTitle");
1055#endif
1056    addTest(root, &TestUCaseInsensitivePrefixMatch, "tsutil/cstrcase/TestUCaseInsensitivePrefixMatch");
1057}
1058