Home | History | Annotate | Download | only in intltest
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /********************************************************************
      4  * COPYRIGHT:
      5  * Copyright (c) 2005-2016, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  ********************************************************************/
      8 /************************************************************************
      9 *   Tests for the UText and UTextIterator text abstraction classses
     10 *
     11 ************************************************************************/
     12 
     13 #include <string.h>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include "unicode/utypes.h"
     17 #include "unicode/utext.h"
     18 #include "unicode/utf8.h"
     19 #include "unicode/utf16.h"
     20 #include "unicode/ustring.h"
     21 #include "unicode/uchriter.h"
     22 #include "cmemory.h"
     23 #include "cstr.h"
     24 #include "utxttest.h"
     25 
     26 static UBool  gFailed = FALSE;
     27 static int    gTestNum = 0;
     28 
     29 // Forward decl
     30 UText *openFragmentedUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status);
     31 
     32 #define TEST_ASSERT(x) \
     33 { if ((x)==FALSE) {errln("Test #%d failure in file %s at line %d\n", gTestNum, __FILE__, __LINE__);\
     34                      gFailed = TRUE;\
     35    }}
     36 
     37 
     38 #define TEST_SUCCESS(status) \
     39 { if (U_FAILURE(status)) {errln("Test #%d failure in file %s at line %d. Error = \"%s\"\n", \
     40        gTestNum, __FILE__, __LINE__, u_errorName(status)); \
     41        gFailed = TRUE;\
     42    }}
     43 
     44 UTextTest::UTextTest() {
     45 }
     46 
     47 UTextTest::~UTextTest() {
     48 }
     49 
     50 
     51 void
     52 UTextTest::runIndexedTest(int32_t index, UBool exec,
     53                           const char* &name, char* /*par*/) {
     54     TESTCASE_AUTO_BEGIN;
     55     TESTCASE_AUTO(TextTest);
     56     TESTCASE_AUTO(ErrorTest);
     57     TESTCASE_AUTO(FreezeTest);
     58     TESTCASE_AUTO(Ticket5560);
     59     TESTCASE_AUTO(Ticket6847);
     60     TESTCASE_AUTO(Ticket10562);
     61     TESTCASE_AUTO(Ticket10983);
     62     TESTCASE_AUTO(Ticket12130);
     63     TESTCASE_AUTO(Ticket13344);
     64     TESTCASE_AUTO_END;
     65 }
     66 
     67 //
     68 // Quick and dirty random number generator.
     69 //   (don't use library so that results are portable.
     70 static uint32_t m_seed = 1;
     71 static uint32_t m_rand()
     72 {
     73     m_seed = m_seed * 1103515245 + 12345;
     74     return (uint32_t)(m_seed/65536) % 32768;
     75 }
     76 
     77 
     78 //
     79 //   TextTest()
     80 //
     81 //       Top Level function for UText testing.
     82 //       Specifies the strings to be tested, with the acutal testing itself
     83 //       being carried out in another function, TestString().
     84 //
     85 void  UTextTest::TextTest() {
     86     int32_t i, j;
     87 
     88     TestString("abcd\\U00010001xyz");
     89     TestString("");
     90 
     91     // Supplementary chars at start or end
     92     TestString("\\U00010001");
     93     TestString("abc\\U00010001");
     94     TestString("\\U00010001abc");
     95 
     96     // Test simple strings of lengths 1 to 60, looking for glitches at buffer boundaries
     97     UnicodeString s;
     98     for (i=1; i<60; i++) {
     99         s.truncate(0);
    100         for (j=0; j<i; j++) {
    101             if (j+0x30 == 0x5c) {
    102                 // backslash.  Needs to be escaped
    103                 s.append((UChar)0x5c);
    104             }
    105             s.append(UChar(j+0x30));
    106         }
    107         TestString(s);
    108     }
    109 
    110    // Test strings with odd-aligned supplementary chars,
    111    //    looking for glitches at buffer boundaries
    112     for (i=1; i<60; i++) {
    113         s.truncate(0);
    114         s.append((UChar)0x41);
    115         for (j=0; j<i; j++) {
    116             s.append(UChar32(j+0x11000));
    117         }
    118         TestString(s);
    119     }
    120 
    121     // String of chars of randomly varying size in utf-8 representation.
    122     //   Exercise the mapping, and the varying sized buffer.
    123     //
    124     s.truncate(0);
    125     UChar32  c1 = 0;
    126     UChar32  c2 = 0x100;
    127     UChar32  c3 = 0xa000;
    128     UChar32  c4 = 0x11000;
    129     for (i=0; i<1000; i++) {
    130         int len8 = m_rand()%4 + 1;
    131         switch (len8) {
    132             case 1:
    133                 c1 = (c1+1)%0x80;
    134                 // don't put 0 into string (0 terminated strings for some tests)
    135                 // don't put '\', will cause unescape() to fail.
    136                 if (c1==0x5c || c1==0) {
    137                     c1++;
    138                 }
    139                 s.append(c1);
    140                 break;
    141             case 2:
    142                 s.append(c2++);
    143                 break;
    144             case 3:
    145                 s.append(c3++);
    146                 break;
    147             case 4:
    148                 s.append(c4++);
    149                 break;
    150         }
    151     }
    152     TestString(s);
    153 }
    154 
    155 
    156 //
    157 //  TestString()     Run a suite of UText tests on a string.
    158 //                   The test string is unescaped before use.
    159 //
    160 void UTextTest::TestString(const UnicodeString &s) {
    161     int32_t       i;
    162     int32_t       j;
    163     UChar32       c;
    164     int32_t       cpCount = 0;
    165     UErrorCode    status  = U_ZERO_ERROR;
    166     UText        *ut      = NULL;
    167     int32_t       saLen;
    168 
    169     UnicodeString sa = s.unescape();
    170     saLen = sa.length();
    171 
    172     //
    173     // Build up a mapping between code points and UTF-16 code unit indexes.
    174     //
    175     m *cpMap = new m[sa.length() + 1];
    176     j = 0;
    177     for (i=0; i<sa.length(); i=sa.moveIndex32(i, 1)) {
    178         c = sa.char32At(i);
    179         cpMap[j].nativeIdx = i;
    180         cpMap[j].cp = c;
    181         j++;
    182         cpCount++;
    183     }
    184     cpMap[j].nativeIdx = i;   // position following the last char in utf-16 string.
    185 
    186 
    187     // UChar * test, null terminated
    188     status = U_ZERO_ERROR;
    189     UChar *buf = new UChar[saLen+1];
    190     sa.extract(buf, saLen+1, status);
    191     TEST_SUCCESS(status);
    192     ut = utext_openUChars(NULL, buf, -1, &status);
    193     TEST_SUCCESS(status);
    194     TestAccess(sa, ut, cpCount, cpMap);
    195     utext_close(ut);
    196     delete [] buf;
    197 
    198     // UChar * test, with length
    199     status = U_ZERO_ERROR;
    200     buf = new UChar[saLen+1];
    201     sa.extract(buf, saLen+1, status);
    202     TEST_SUCCESS(status);
    203     ut = utext_openUChars(NULL, buf, saLen, &status);
    204     TEST_SUCCESS(status);
    205     TestAccess(sa, ut, cpCount, cpMap);
    206     utext_close(ut);
    207     delete [] buf;
    208 
    209 
    210     // UnicodeString test
    211     status = U_ZERO_ERROR;
    212     ut = utext_openUnicodeString(NULL, &sa, &status);
    213     TEST_SUCCESS(status);
    214     TestAccess(sa, ut, cpCount, cpMap);
    215     TestCMR(sa, ut, cpCount, cpMap, cpMap);
    216     utext_close(ut);
    217 
    218 
    219     // Const UnicodeString test
    220     status = U_ZERO_ERROR;
    221     ut = utext_openConstUnicodeString(NULL, &sa, &status);
    222     TEST_SUCCESS(status);
    223     TestAccess(sa, ut, cpCount, cpMap);
    224     utext_close(ut);
    225 
    226 
    227     // Replaceable test.  (UnicodeString inherits Replaceable)
    228     status = U_ZERO_ERROR;
    229     ut = utext_openReplaceable(NULL, &sa, &status);
    230     TEST_SUCCESS(status);
    231     TestAccess(sa, ut, cpCount, cpMap);
    232     TestCMR(sa, ut, cpCount, cpMap, cpMap);
    233     utext_close(ut);
    234 
    235     // Character Iterator Tests
    236     status = U_ZERO_ERROR;
    237     const UChar *cbuf = sa.getBuffer();
    238     CharacterIterator *ci = new UCharCharacterIterator(cbuf, saLen, status);
    239     TEST_SUCCESS(status);
    240     ut = utext_openCharacterIterator(NULL, ci, &status);
    241     TEST_SUCCESS(status);
    242     TestAccess(sa, ut, cpCount, cpMap);
    243     utext_close(ut);
    244     delete ci;
    245 
    246 
    247     // Fragmented UnicodeString  (Chunk size of one)
    248     //
    249     status = U_ZERO_ERROR;
    250     ut = openFragmentedUnicodeString(NULL, &sa, &status);
    251     TEST_SUCCESS(status);
    252     TestAccess(sa, ut, cpCount, cpMap);
    253     utext_close(ut);
    254 
    255     //
    256     // UTF-8 test
    257     //
    258 
    259     // Convert the test string from UnicodeString to (char *) in utf-8 format
    260     int32_t u8Len = sa.extract(0, sa.length(), NULL, 0, "utf-8");
    261     char *u8String = new char[u8Len + 1];
    262     sa.extract(0, sa.length(), u8String, u8Len+1, "utf-8");
    263 
    264     // Build up the map of code point indices in the utf-8 string
    265     m * u8Map = new m[sa.length() + 1];
    266     i = 0;   // native utf-8 index
    267     for (j=0; j<cpCount ; j++) {  // code point number
    268         u8Map[j].nativeIdx = i;
    269         U8_NEXT(u8String, i, u8Len, c)
    270         u8Map[j].cp = c;
    271     }
    272     u8Map[cpCount].nativeIdx = u8Len;   // position following the last char in utf-8 string.
    273 
    274     // Do the test itself
    275     status = U_ZERO_ERROR;
    276     ut = utext_openUTF8(NULL, u8String, -1, &status);
    277     TEST_SUCCESS(status);
    278     TestAccess(sa, ut, cpCount, u8Map);
    279     utext_close(ut);
    280 
    281 
    282 
    283     delete []cpMap;
    284     delete []u8Map;
    285     delete []u8String;
    286 }
    287 
    288 //  TestCMR   test Copy, Move and Replace operations.
    289 //              us         UnicodeString containing the test text.
    290 //              ut         UText containing the same test text.
    291 //              cpCount    number of code points in the test text.
    292 //              nativeMap  Mapping from code points to native indexes for the UText.
    293 //              u16Map     Mapping from code points to UTF-16 indexes, for use with the UnicodeString.
    294 //
    295 //     This function runs a whole series of opertions on each incoming UText.
    296 //     The UText is deep-cloned prior to each operation, so that the original UText remains unchanged.
    297 //
    298 void UTextTest::TestCMR(const UnicodeString &us, UText *ut, int cpCount, m *nativeMap, m *u16Map) {
    299     TEST_ASSERT(utext_isWritable(ut) == TRUE);
    300 
    301     int  srcLengthType;       // Loop variables for selecting the postion and length
    302     int  srcPosType;          //   of the block to operate on within the source text.
    303     int  destPosType;
    304 
    305     int  srcIndex  = 0;       // Code Point indexes of the block to operate on for
    306     int  srcLength = 0;       //   a specific test.
    307 
    308     int  destIndex = 0;       // Code point index of the destination for a copy/move test.
    309 
    310     int32_t  nativeStart = 0; // Native unit indexes for a test.
    311     int32_t  nativeLimit = 0;
    312     int32_t  nativeDest  = 0;
    313 
    314     int32_t  u16Start    = 0; // UTF-16 indexes for a test.
    315     int32_t  u16Limit    = 0; //   used when performing the same operation in a Unicode String
    316     int32_t  u16Dest     = 0;
    317 
    318     // Iterate over a whole series of source index, length and a target indexes.
    319     // This is done with code point indexes; these will be later translated to native
    320     //   indexes using the cpMap.
    321     for (srcLengthType=1; srcLengthType<=3; srcLengthType++) {
    322         switch (srcLengthType) {
    323             case 1: srcLength = 1; break;
    324             case 2: srcLength = 5; break;
    325             case 3: srcLength = cpCount / 3;
    326         }
    327         for (srcPosType=1; srcPosType<=5; srcPosType++) {
    328             switch (srcPosType) {
    329                 case 1: srcIndex = 0; break;
    330                 case 2: srcIndex = 1; break;
    331                 case 3: srcIndex = cpCount - srcLength; break;
    332                 case 4: srcIndex = cpCount - srcLength - 1; break;
    333                 case 5: srcIndex = cpCount / 2; break;
    334             }
    335             if (srcIndex < 0 || srcIndex + srcLength > cpCount) {
    336                 // filter out bogus test cases -
    337                 //   those with a source range that falls of an edge of the string.
    338                 continue;
    339             }
    340 
    341             //
    342             // Copy and move tests.
    343             //   iterate over a variety of destination positions.
    344             //
    345             for (destPosType=1; destPosType<=4; destPosType++) {
    346                 switch (destPosType) {
    347                     case 1: destIndex = 0; break;
    348                     case 2: destIndex = 1; break;
    349                     case 3: destIndex = srcIndex - 1; break;
    350                     case 4: destIndex = srcIndex + srcLength + 1; break;
    351                     case 5: destIndex = cpCount-1; break;
    352                     case 6: destIndex = cpCount; break;
    353                 }
    354                 if (destIndex<0 || destIndex>cpCount) {
    355                     // filter out bogus test cases.
    356                     continue;
    357                 }
    358 
    359                 nativeStart = nativeMap[srcIndex].nativeIdx;
    360                 nativeLimit = nativeMap[srcIndex+srcLength].nativeIdx;
    361                 nativeDest  = nativeMap[destIndex].nativeIdx;
    362 
    363                 u16Start    = u16Map[srcIndex].nativeIdx;
    364                 u16Limit    = u16Map[srcIndex+srcLength].nativeIdx;
    365                 u16Dest     = u16Map[destIndex].nativeIdx;
    366 
    367                 gFailed = FALSE;
    368                 TestCopyMove(us, ut, FALSE,
    369                     nativeStart, nativeLimit, nativeDest,
    370                     u16Start, u16Limit, u16Dest);
    371 
    372                 TestCopyMove(us, ut, TRUE,
    373                     nativeStart, nativeLimit, nativeDest,
    374                     u16Start, u16Limit, u16Dest);
    375 
    376                 if (gFailed) {
    377                     return;
    378                 }
    379             }
    380 
    381             //
    382             //  Replace tests.
    383             //
    384             UnicodeString fullRepString("This is an arbitrary string that will be used as replacement text");
    385             for (int32_t replStrLen=0; replStrLen<20; replStrLen++) {
    386                 UnicodeString repStr(fullRepString, 0, replStrLen);
    387                 TestReplace(us, ut,
    388                     nativeStart, nativeLimit,
    389                     u16Start, u16Limit,
    390                     repStr);
    391                 if (gFailed) {
    392                     return;
    393                 }
    394             }
    395 
    396         }
    397     }
    398 
    399 }
    400 
    401 //
    402 //   TestCopyMove    run a single test case for utext_copy.
    403 //                   Test cases are created in TestCMR and dispatched here for execution.
    404 //
    405 void UTextTest::TestCopyMove(const UnicodeString &us, UText *ut, UBool move,
    406                     int32_t nativeStart, int32_t nativeLimit, int32_t nativeDest,
    407                     int32_t u16Start, int32_t u16Limit, int32_t u16Dest)
    408 {
    409     UErrorCode      status   = U_ZERO_ERROR;
    410     UText          *targetUT = NULL;
    411     gTestNum++;
    412     gFailed = FALSE;
    413 
    414     //
    415     //  clone the UText.  The test will be run in the cloned copy
    416     //  so that we don't alter the original.
    417     //
    418     targetUT = utext_clone(NULL, ut, TRUE, FALSE, &status);
    419     TEST_SUCCESS(status);
    420     UnicodeString targetUS(us);    // And copy the reference string.
    421 
    422     // do the test operation first in the reference
    423     targetUS.copy(u16Start, u16Limit, u16Dest);
    424     if (move) {
    425         // delete out the source range.
    426         if (u16Limit < u16Dest) {
    427             targetUS.removeBetween(u16Start, u16Limit);
    428         } else {
    429             int32_t amtCopied = u16Limit - u16Start;
    430             targetUS.removeBetween(u16Start+amtCopied, u16Limit+amtCopied);
    431         }
    432     }
    433 
    434     // Do the same operation in the UText under test
    435     utext_copy(targetUT, nativeStart, nativeLimit, nativeDest, move, &status);
    436     if (nativeDest > nativeStart && nativeDest < nativeLimit) {
    437         TEST_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
    438     } else {
    439         TEST_SUCCESS(status);
    440 
    441         // Compare the results of the two parallel tests
    442         int32_t  usi = 0;    // UnicodeString postion, utf-16 index.
    443         int64_t  uti = 0;    // UText position, native index.
    444         int32_t  cpi;        // char32 position (code point index)
    445         UChar32  usc;        // code point from Unicode String
    446         UChar32  utc;        // code point from UText
    447         utext_setNativeIndex(targetUT, 0);
    448         for (cpi=0; ; cpi++) {
    449             usc = targetUS.char32At(usi);
    450             utc = utext_next32(targetUT);
    451             if (utc < 0) {
    452                 break;
    453             }
    454             TEST_ASSERT(uti == usi);
    455             TEST_ASSERT(utc == usc);
    456             usi = targetUS.moveIndex32(usi, 1);
    457             uti = utext_getNativeIndex(targetUT);
    458             if (gFailed) {
    459                 goto cleanupAndReturn;
    460             }
    461         }
    462         int64_t expectedNativeLength = utext_nativeLength(ut);
    463         if (move == FALSE) {
    464             expectedNativeLength += nativeLimit - nativeStart;
    465         }
    466         uti = utext_getNativeIndex(targetUT);
    467         TEST_ASSERT(uti == expectedNativeLength);
    468     }
    469 
    470 cleanupAndReturn:
    471     utext_close(targetUT);
    472 }
    473 
    474 
    475 //
    476 //  TestReplace   Test a single Replace operation.
    477 //
    478 void UTextTest::TestReplace(
    479             const UnicodeString &us,     // reference UnicodeString in which to do the replace
    480             UText         *ut,                // UnicodeText object under test.
    481             int32_t       nativeStart,        // Range to be replaced, in UText native units.
    482             int32_t       nativeLimit,
    483             int32_t       u16Start,           // Range to be replaced, in UTF-16 units
    484             int32_t       u16Limit,           //    for use in the reference UnicodeString.
    485             const UnicodeString &repStr)      // The replacement string
    486 {
    487     UErrorCode      status   = U_ZERO_ERROR;
    488     UText          *targetUT = NULL;
    489     gTestNum++;
    490     gFailed = FALSE;
    491 
    492     //
    493     //  clone the target UText.  The test will be run in the cloned copy
    494     //  so that we don't alter the original.
    495     //
    496     targetUT = utext_clone(NULL, ut, TRUE, FALSE, &status);
    497     TEST_SUCCESS(status);
    498     UnicodeString targetUS(us);    // And copy the reference string.
    499 
    500     //
    501     // Do the replace operation in the Unicode String, to
    502     //   produce a reference result.
    503     //
    504     targetUS.replace(u16Start, u16Limit-u16Start, repStr);
    505 
    506     //
    507     // Do the replace on the UText under test
    508     //
    509     const UChar *rs = repStr.getBuffer();
    510     int32_t  rsLen = repStr.length();
    511     int32_t actualDelta = utext_replace(targetUT, nativeStart, nativeLimit, rs, rsLen, &status);
    512     int32_t expectedDelta = repStr.length() - (nativeLimit - nativeStart);
    513     TEST_ASSERT(actualDelta == expectedDelta);
    514 
    515     //
    516     // Compare the results
    517     //
    518     int32_t  usi = 0;    // UnicodeString postion, utf-16 index.
    519     int64_t  uti = 0;    // UText position, native index.
    520     int32_t  cpi;        // char32 position (code point index)
    521     UChar32  usc;        // code point from Unicode String
    522     UChar32  utc;        // code point from UText
    523     int64_t  expectedNativeLength = 0;
    524     utext_setNativeIndex(targetUT, 0);
    525     for (cpi=0; ; cpi++) {
    526         usc = targetUS.char32At(usi);
    527         utc = utext_next32(targetUT);
    528         if (utc < 0) {
    529             break;
    530         }
    531         TEST_ASSERT(uti == usi);
    532         TEST_ASSERT(utc == usc);
    533         usi = targetUS.moveIndex32(usi, 1);
    534         uti = utext_getNativeIndex(targetUT);
    535         if (gFailed) {
    536             goto cleanupAndReturn;
    537         }
    538     }
    539     expectedNativeLength = utext_nativeLength(ut) + expectedDelta;
    540     uti = utext_getNativeIndex(targetUT);
    541     TEST_ASSERT(uti == expectedNativeLength);
    542 
    543 cleanupAndReturn:
    544     utext_close(targetUT);
    545 }
    546 
    547 //
    548 //  TestAccess      Test the read only access functions on a UText, including cloning.
    549 //                  The text is accessed in a variety of ways, and compared with
    550 //                  the reference UnicodeString.
    551 //
    552 void UTextTest::TestAccess(const UnicodeString &us, UText *ut, int cpCount, m *cpMap) {
    553     // Run the standard tests on the caller-supplied UText.
    554     TestAccessNoClone(us, ut, cpCount, cpMap);
    555 
    556     // Re-run tests on a shallow clone.
    557     utext_setNativeIndex(ut, 0);
    558     UErrorCode status = U_ZERO_ERROR;
    559     UText *shallowClone = utext_clone(NULL, ut, FALSE /*deep*/, FALSE /*readOnly*/, &status);
    560     TEST_SUCCESS(status);
    561     TestAccessNoClone(us, shallowClone, cpCount, cpMap);
    562 
    563     //
    564     // Rerun again on a deep clone.
    565     // Note that text providers are not required to provide deep cloning,
    566     //   so unsupported errors are ignored.
    567     //
    568     status = U_ZERO_ERROR;
    569     utext_setNativeIndex(shallowClone, 0);
    570     UText *deepClone = utext_clone(NULL, shallowClone, TRUE, FALSE, &status);
    571     utext_close(shallowClone);
    572     if (status != U_UNSUPPORTED_ERROR) {
    573         TEST_SUCCESS(status);
    574         TestAccessNoClone(us, deepClone, cpCount, cpMap);
    575     }
    576     utext_close(deepClone);
    577 }
    578 
    579 
    580 //
    581 //  TestAccessNoClone()    Test the read only access functions on a UText.
    582 //                         The text is accessed in a variety of ways, and compared with
    583 //                         the reference UnicodeString.
    584 //
    585 void UTextTest::TestAccessNoClone(const UnicodeString &us, UText *ut, int cpCount, m *cpMap) {
    586     UErrorCode  status = U_ZERO_ERROR;
    587     gTestNum++;
    588 
    589     //
    590     //  Check the length from the UText
    591     //
    592     int64_t expectedLen = cpMap[cpCount].nativeIdx;
    593     int64_t utlen = utext_nativeLength(ut);
    594     TEST_ASSERT(expectedLen == utlen);
    595 
    596     //
    597     //  Iterate forwards, verify that we get the correct code points
    598     //   at the correct native offsets.
    599     //
    600     int         i = 0;
    601     int64_t     index;
    602     int64_t     expectedIndex = 0;
    603     int64_t     foundIndex = 0;
    604     UChar32     expectedC;
    605     UChar32     foundC;
    606     int64_t     len;
    607 
    608     for (i=0; i<cpCount; i++) {
    609         expectedIndex = cpMap[i].nativeIdx;
    610         foundIndex    = utext_getNativeIndex(ut);
    611         TEST_ASSERT(expectedIndex == foundIndex);
    612         expectedC     = cpMap[i].cp;
    613         foundC        = utext_next32(ut);
    614         TEST_ASSERT(expectedC == foundC);
    615         foundIndex    = utext_getPreviousNativeIndex(ut);
    616         TEST_ASSERT(expectedIndex == foundIndex);
    617         if (gFailed) {
    618             return;
    619         }
    620     }
    621     foundC = utext_next32(ut);
    622     TEST_ASSERT(foundC == U_SENTINEL);
    623 
    624     // Repeat above, using macros
    625     utext_setNativeIndex(ut, 0);
    626     for (i=0; i<cpCount; i++) {
    627         expectedIndex = cpMap[i].nativeIdx;
    628         foundIndex    = UTEXT_GETNATIVEINDEX(ut);
    629         TEST_ASSERT(expectedIndex == foundIndex);
    630         expectedC     = cpMap[i].cp;
    631         foundC        = UTEXT_NEXT32(ut);
    632         TEST_ASSERT(expectedC == foundC);
    633         if (gFailed) {
    634             return;
    635         }
    636     }
    637     foundC = UTEXT_NEXT32(ut);
    638     TEST_ASSERT(foundC == U_SENTINEL);
    639 
    640     //
    641     //  Forward iteration (above) should have left index at the
    642     //   end of the input, which should == length().
    643     //
    644     len = utext_nativeLength(ut);
    645     foundIndex  = utext_getNativeIndex(ut);
    646     TEST_ASSERT(len == foundIndex);
    647 
    648     //
    649     // Iterate backwards over entire test string
    650     //
    651     len = utext_getNativeIndex(ut);
    652     utext_setNativeIndex(ut, len);
    653     for (i=cpCount-1; i>=0; i--) {
    654         expectedC     = cpMap[i].cp;
    655         expectedIndex = cpMap[i].nativeIdx;
    656         int64_t prevIndex = utext_getPreviousNativeIndex(ut);
    657         foundC        = utext_previous32(ut);
    658         foundIndex    = utext_getNativeIndex(ut);
    659         TEST_ASSERT(expectedIndex == foundIndex);
    660         TEST_ASSERT(expectedC == foundC);
    661         TEST_ASSERT(prevIndex == foundIndex);
    662         if (gFailed) {
    663             return;
    664         }
    665     }
    666 
    667     //
    668     //  Backwards iteration, above, should have left our iterator
    669     //   position at zero, and continued backwards iterationshould fail.
    670     //
    671     foundIndex = utext_getNativeIndex(ut);
    672     TEST_ASSERT(foundIndex == 0);
    673     foundIndex = utext_getPreviousNativeIndex(ut);
    674     TEST_ASSERT(foundIndex == 0);
    675 
    676 
    677     foundC = utext_previous32(ut);
    678     TEST_ASSERT(foundC == U_SENTINEL);
    679     foundIndex = utext_getNativeIndex(ut);
    680     TEST_ASSERT(foundIndex == 0);
    681     foundIndex = utext_getPreviousNativeIndex(ut);
    682     TEST_ASSERT(foundIndex == 0);
    683 
    684 
    685     // And again, with the macros
    686     utext_setNativeIndex(ut, len);
    687     for (i=cpCount-1; i>=0; i--) {
    688         expectedC     = cpMap[i].cp;
    689         expectedIndex = cpMap[i].nativeIdx;
    690         foundC        = UTEXT_PREVIOUS32(ut);
    691         foundIndex    = UTEXT_GETNATIVEINDEX(ut);
    692         TEST_ASSERT(expectedIndex == foundIndex);
    693         TEST_ASSERT(expectedC == foundC);
    694         if (gFailed) {
    695             return;
    696         }
    697     }
    698 
    699     //
    700     //  Backwards iteration, above, should have left our iterator
    701     //   position at zero, and continued backwards iterationshould fail.
    702     //
    703     foundIndex = UTEXT_GETNATIVEINDEX(ut);
    704     TEST_ASSERT(foundIndex == 0);
    705 
    706     foundC = UTEXT_PREVIOUS32(ut);
    707     TEST_ASSERT(foundC == U_SENTINEL);
    708     foundIndex = UTEXT_GETNATIVEINDEX(ut);
    709     TEST_ASSERT(foundIndex == 0);
    710     if (gFailed) {
    711         return;
    712     }
    713 
    714     //
    715     //  next32From(), prevous32From(), Iterate in a somewhat random order.
    716     //
    717     int  cpIndex = 0;
    718     for (i=0; i<cpCount; i++) {
    719         cpIndex = (cpIndex + 9973) % cpCount;
    720         index         = cpMap[cpIndex].nativeIdx;
    721         expectedC     = cpMap[cpIndex].cp;
    722         foundC        = utext_next32From(ut, index);
    723         TEST_ASSERT(expectedC == foundC);
    724         if (gFailed) {
    725             return;
    726         }
    727     }
    728 
    729     cpIndex = 0;
    730     for (i=0; i<cpCount; i++) {
    731         cpIndex = (cpIndex + 9973) % cpCount;
    732         index         = cpMap[cpIndex+1].nativeIdx;
    733         expectedC     = cpMap[cpIndex].cp;
    734         foundC        = utext_previous32From(ut, index);
    735         TEST_ASSERT(expectedC == foundC);
    736         if (gFailed) {
    737             return;
    738         }
    739     }
    740 
    741 
    742     //
    743     // moveIndex(int32_t delta);
    744     //
    745 
    746     // Walk through frontwards, incrementing by one
    747     utext_setNativeIndex(ut, 0);
    748     for (i=1; i<=cpCount; i++) {
    749         utext_moveIndex32(ut, 1);
    750         index = utext_getNativeIndex(ut);
    751         expectedIndex = cpMap[i].nativeIdx;
    752         TEST_ASSERT(expectedIndex == index);
    753         index = UTEXT_GETNATIVEINDEX(ut);
    754         TEST_ASSERT(expectedIndex == index);
    755     }
    756 
    757     // Walk through frontwards, incrementing by two
    758     utext_setNativeIndex(ut, 0);
    759     for (i=2; i<cpCount; i+=2) {
    760         utext_moveIndex32(ut, 2);
    761         index = utext_getNativeIndex(ut);
    762         expectedIndex = cpMap[i].nativeIdx;
    763         TEST_ASSERT(expectedIndex == index);
    764         index = UTEXT_GETNATIVEINDEX(ut);
    765         TEST_ASSERT(expectedIndex == index);
    766     }
    767 
    768     // walk through the string backwards, decrementing by one.
    769     i = cpMap[cpCount].nativeIdx;
    770     utext_setNativeIndex(ut, i);
    771     for (i=cpCount; i>=0; i--) {
    772         expectedIndex = cpMap[i].nativeIdx;
    773         index = utext_getNativeIndex(ut);
    774         TEST_ASSERT(expectedIndex == index);
    775         index = UTEXT_GETNATIVEINDEX(ut);
    776         TEST_ASSERT(expectedIndex == index);
    777         utext_moveIndex32(ut, -1);
    778     }
    779 
    780 
    781     // walk through backwards, decrementing by three
    782     i = cpMap[cpCount].nativeIdx;
    783     utext_setNativeIndex(ut, i);
    784     for (i=cpCount; i>=0; i-=3) {
    785         expectedIndex = cpMap[i].nativeIdx;
    786         index = utext_getNativeIndex(ut);
    787         TEST_ASSERT(expectedIndex == index);
    788         index = UTEXT_GETNATIVEINDEX(ut);
    789         TEST_ASSERT(expectedIndex == index);
    790         utext_moveIndex32(ut, -3);
    791     }
    792 
    793 
    794     //
    795     // Extract
    796     //
    797     int bufSize = us.length() + 10;
    798     UChar *buf = new UChar[bufSize];
    799     status = U_ZERO_ERROR;
    800     expectedLen = us.length();
    801     len = utext_extract(ut, 0, utlen, buf, bufSize, &status);
    802     TEST_SUCCESS(status);
    803     TEST_ASSERT(len == expectedLen);
    804     int compareResult = us.compare(buf, -1);
    805     TEST_ASSERT(compareResult == 0);
    806 
    807     status = U_ZERO_ERROR;
    808     len = utext_extract(ut, 0, utlen, NULL, 0, &status);
    809     if (utlen == 0) {
    810         TEST_ASSERT(status == U_STRING_NOT_TERMINATED_WARNING);
    811     } else {
    812         TEST_ASSERT(status == U_BUFFER_OVERFLOW_ERROR);
    813     }
    814     TEST_ASSERT(len == expectedLen);
    815 
    816     status = U_ZERO_ERROR;
    817     u_memset(buf, 0x5555, bufSize);
    818     len = utext_extract(ut, 0, utlen, buf, 1, &status);
    819     if (us.length() == 0) {
    820         TEST_SUCCESS(status);
    821         TEST_ASSERT(buf[0] == 0);
    822     } else {
    823         // Buf len == 1, extracting a single 16 bit value.
    824         // If the data char is supplementary, it doesn't matter whether the buffer remains unchanged,
    825         //   or whether the lead surrogate of the pair is extracted.
    826         //   It's a buffer overflow error in either case.
    827         TEST_ASSERT(buf[0] == us.charAt(0) ||
    828                     (buf[0] == 0x5555 && U_IS_SUPPLEMENTARY(us.char32At(0))));
    829         TEST_ASSERT(buf[1] == 0x5555);
    830         if (us.length() == 1) {
    831             TEST_ASSERT(status == U_STRING_NOT_TERMINATED_WARNING);
    832         } else {
    833             TEST_ASSERT(status == U_BUFFER_OVERFLOW_ERROR);
    834         }
    835     }
    836 
    837     delete []buf;
    838 }
    839 
    840 //
    841 //  ErrorTest()    Check various error and edge cases.
    842 //
    843 void UTextTest::ErrorTest()
    844 {
    845     // Close of an unitialized UText.  Shouldn't blow up.
    846     {
    847         UText  ut;
    848         memset(&ut, 0, sizeof(UText));
    849         utext_close(&ut);
    850         utext_close(NULL);
    851     }
    852 
    853     // Double-close of a UText.  Shouldn't blow up.  UText should still be usable.
    854     {
    855         UErrorCode status = U_ZERO_ERROR;
    856         UText ut = UTEXT_INITIALIZER;
    857         UnicodeString s("Hello, World");
    858         UText *ut2 = utext_openUnicodeString(&ut, &s, &status);
    859         TEST_SUCCESS(status);
    860         TEST_ASSERT(ut2 == &ut);
    861 
    862         UText *ut3 = utext_close(&ut);
    863         TEST_ASSERT(ut3 == &ut);
    864 
    865         UText *ut4 = utext_close(&ut);
    866         TEST_ASSERT(ut4 == &ut);
    867 
    868         utext_openUnicodeString(&ut, &s, &status);
    869         TEST_SUCCESS(status);
    870         utext_close(&ut);
    871     }
    872 
    873     // Re-use of a UText, chaining through each of the types of UText
    874     //   (If it doesn't blow up, and doesn't leak, it's probably working fine)
    875     {
    876         UErrorCode status = U_ZERO_ERROR;
    877         UText ut = UTEXT_INITIALIZER;
    878         UText  *utp;
    879         UnicodeString s1("Hello, World");
    880         UChar s2[] = {(UChar)0x41, (UChar)0x42, (UChar)0};
    881         const char  *s3 = "\x66\x67\x68";
    882 
    883         utp = utext_openUnicodeString(&ut, &s1, &status);
    884         TEST_SUCCESS(status);
    885         TEST_ASSERT(utp == &ut);
    886 
    887         utp = utext_openConstUnicodeString(&ut, &s1, &status);
    888         TEST_SUCCESS(status);
    889         TEST_ASSERT(utp == &ut);
    890 
    891         utp = utext_openUTF8(&ut, s3, -1, &status);
    892         TEST_SUCCESS(status);
    893         TEST_ASSERT(utp == &ut);
    894 
    895         utp = utext_openUChars(&ut, s2, -1, &status);
    896         TEST_SUCCESS(status);
    897         TEST_ASSERT(utp == &ut);
    898 
    899         utp = utext_close(&ut);
    900         TEST_ASSERT(utp == &ut);
    901 
    902         utp = utext_openUnicodeString(&ut, &s1, &status);
    903         TEST_SUCCESS(status);
    904         TEST_ASSERT(utp == &ut);
    905     }
    906 
    907     // Invalid parameters on open
    908     //
    909     {
    910         UErrorCode status = U_ZERO_ERROR;
    911         UText ut = UTEXT_INITIALIZER;
    912 
    913         utext_openUChars(&ut, NULL, 5, &status);
    914         TEST_ASSERT(status == U_ILLEGAL_ARGUMENT_ERROR);
    915 
    916         status = U_ZERO_ERROR;
    917         utext_openUChars(&ut, NULL, -1, &status);
    918         TEST_ASSERT(status == U_ILLEGAL_ARGUMENT_ERROR);
    919 
    920         status = U_ZERO_ERROR;
    921         utext_openUTF8(&ut, NULL, 4, &status);
    922         TEST_ASSERT(status == U_ILLEGAL_ARGUMENT_ERROR);
    923 
    924         status = U_ZERO_ERROR;
    925         utext_openUTF8(&ut, NULL, -1, &status);
    926         TEST_ASSERT(status == U_ILLEGAL_ARGUMENT_ERROR);
    927     }
    928 
    929     //
    930     //  UTF-8 with malformed sequences.
    931     //    These should come through as the Unicode replacement char, \ufffd
    932     //
    933     {
    934         UErrorCode status = U_ZERO_ERROR;
    935         UText *ut = NULL;
    936         const char *badUTF8 = "\x41\x81\x42\xf0\x81\x81\x43";
    937         UChar32  c;
    938 
    939         ut = utext_openUTF8(NULL, badUTF8, -1, &status);
    940         TEST_SUCCESS(status);
    941         c = utext_char32At(ut, 1);
    942         TEST_ASSERT(c == 0xfffd);
    943         c = utext_char32At(ut, 3);
    944         TEST_ASSERT(c == 0xfffd);
    945         c = utext_char32At(ut, 5);
    946         TEST_ASSERT(c == 0xfffd);
    947         c = utext_char32At(ut, 6);
    948         TEST_ASSERT(c == 0x43);
    949 
    950         UChar buf[10];
    951         int n = utext_extract(ut, 0, 9, buf, 10, &status);
    952         TEST_SUCCESS(status);
    953         TEST_ASSERT(n==7);
    954         TEST_ASSERT(buf[0] == 0x41);
    955         TEST_ASSERT(buf[1] == 0xfffd);
    956         TEST_ASSERT(buf[2] == 0x42);
    957         TEST_ASSERT(buf[3] == 0xfffd);
    958         TEST_ASSERT(buf[4] == 0xfffd);
    959         TEST_ASSERT(buf[5] == 0xfffd);
    960         TEST_ASSERT(buf[6] == 0x43);
    961         utext_close(ut);
    962     }
    963 
    964 
    965     //
    966     //  isLengthExpensive - does it make the exptected transitions after
    967     //                      getting the length of a nul terminated string?
    968     //
    969     {
    970         UErrorCode status = U_ZERO_ERROR;
    971         UnicodeString sa("Hello, this is a string");
    972         UBool  isExpensive;
    973 
    974         UChar sb[100];
    975         memset(sb, 0x20, sizeof(sb));
    976         sb[99] = 0;
    977 
    978         UText *uta = utext_openUnicodeString(NULL, &sa, &status);
    979         TEST_SUCCESS(status);
    980         isExpensive = utext_isLengthExpensive(uta);
    981         TEST_ASSERT(isExpensive == FALSE);
    982         utext_close(uta);
    983 
    984         UText *utb = utext_openUChars(NULL, sb, -1, &status);
    985         TEST_SUCCESS(status);
    986         isExpensive = utext_isLengthExpensive(utb);
    987         TEST_ASSERT(isExpensive == TRUE);
    988         int64_t  len = utext_nativeLength(utb);
    989         TEST_ASSERT(len == 99);
    990         isExpensive = utext_isLengthExpensive(utb);
    991         TEST_ASSERT(isExpensive == FALSE);
    992         utext_close(utb);
    993     }
    994 
    995     //
    996     // Index to positions not on code point boundaries.
    997     //
    998     {
    999         const char *u8str =         "\xc8\x81\xe1\x82\x83\xf1\x84\x85\x86";
   1000         int32_t startMap[] =        {   0,  0,  2,  2,  2,  5,  5,  5,  5,  9,  9};
   1001         int32_t nextMap[]  =        {   2,  2,  5,  5,  5,  9,  9,  9,  9,  9,  9};
   1002         int32_t prevMap[]  =        {   0,  0,  0,  0,  0,  2,  2,  2,  2,  5,  5};
   1003         UChar32  c32Map[] =    {0x201, 0x201, 0x1083, 0x1083, 0x1083, 0x044146, 0x044146, 0x044146, 0x044146, -1, -1};
   1004         UChar32  pr32Map[] =   {    -1,   -1,  0x201,  0x201,  0x201,   0x1083,   0x1083,   0x1083,   0x1083, 0x044146, 0x044146};
   1005 
   1006         // extractLen is the size, in UChars, of what will be extracted between index and index+1.
   1007         //  is zero when both index positions lie within the same code point.
   1008         int32_t  exLen[] =          {   0,  1,   0,  0,  1,  0,  0,  0,  2,  0,  0};
   1009 
   1010 
   1011         UErrorCode status = U_ZERO_ERROR;
   1012         UText *ut = utext_openUTF8(NULL, u8str, -1, &status);
   1013         TEST_SUCCESS(status);
   1014 
   1015         // Check setIndex
   1016         int32_t i;
   1017         int32_t startMapLimit = UPRV_LENGTHOF(startMap);
   1018         for (i=0; i<startMapLimit; i++) {
   1019             utext_setNativeIndex(ut, i);
   1020             int64_t cpIndex = utext_getNativeIndex(ut);
   1021             TEST_ASSERT(cpIndex == startMap[i]);
   1022             cpIndex = UTEXT_GETNATIVEINDEX(ut);
   1023             TEST_ASSERT(cpIndex == startMap[i]);
   1024         }
   1025 
   1026         // Check char32At
   1027         for (i=0; i<startMapLimit; i++) {
   1028             UChar32 c32 = utext_char32At(ut, i);
   1029             TEST_ASSERT(c32 == c32Map[i]);
   1030             int64_t cpIndex = utext_getNativeIndex(ut);
   1031             TEST_ASSERT(cpIndex == startMap[i]);
   1032         }
   1033 
   1034         // Check utext_next32From
   1035         for (i=0; i<startMapLimit; i++) {
   1036             UChar32 c32 = utext_next32From(ut, i);
   1037             TEST_ASSERT(c32 == c32Map[i]);
   1038             int64_t cpIndex = utext_getNativeIndex(ut);
   1039             TEST_ASSERT(cpIndex == nextMap[i]);
   1040         }
   1041 
   1042         // check utext_previous32From
   1043         for (i=0; i<startMapLimit; i++) {
   1044             gTestNum++;
   1045             UChar32 c32 = utext_previous32From(ut, i);
   1046             TEST_ASSERT(c32 == pr32Map[i]);
   1047             int64_t cpIndex = utext_getNativeIndex(ut);
   1048             TEST_ASSERT(cpIndex == prevMap[i]);
   1049         }
   1050 
   1051         // check Extract
   1052         //   Extract from i to i+1, which may be zero or one code points,
   1053         //     depending on whether the indices straddle a cp boundary.
   1054         for (i=0; i<startMapLimit; i++) {
   1055             UChar buf[3];
   1056             status = U_ZERO_ERROR;
   1057             int32_t  extractedLen = utext_extract(ut, i, i+1, buf, 3, &status);
   1058             TEST_SUCCESS(status);
   1059             TEST_ASSERT(extractedLen == exLen[i]);
   1060             if (extractedLen > 0) {
   1061                 UChar32  c32;
   1062                 /* extractedLen-extractedLen == 0 is used to get around a compiler warning. */
   1063                 U16_GET(buf, 0, extractedLen-extractedLen, extractedLen, c32);
   1064                 TEST_ASSERT(c32 == c32Map[i]);
   1065             }
   1066         }
   1067 
   1068         utext_close(ut);
   1069     }
   1070 
   1071 
   1072     {    //  Similar test, with utf16 instead of utf8
   1073          //  TODO:  merge the common parts of these tests.
   1074 
   1075         UnicodeString u16str("\\u1000\\U00011000\\u2000\\U00022000", -1, US_INV);
   1076         int32_t startMap[]  ={ 0,     1,   1,    3,     4,  4,     6,  6};
   1077         int32_t nextMap[]  = { 1,     3,   3,    4,     6,  6,     6,  6};
   1078         int32_t prevMap[]  = { 0,     0,   0,    1,     3,  3,     4,  4};
   1079         UChar32  c32Map[] =  {0x1000, 0x11000, 0x11000, 0x2000,  0x22000, 0x22000, -1, -1};
   1080         UChar32  pr32Map[] = {    -1, 0x1000,  0x1000,  0x11000, 0x2000,  0x2000,   0x22000,   0x22000};
   1081         int32_t  exLen[] =   {   1,  0,   2,  1,  0,  2,  0,  0,};
   1082 
   1083         u16str = u16str.unescape();
   1084         UErrorCode status = U_ZERO_ERROR;
   1085         UText *ut = utext_openUnicodeString(NULL, &u16str, &status);
   1086         TEST_SUCCESS(status);
   1087 
   1088         int32_t startMapLimit = UPRV_LENGTHOF(startMap);
   1089         int i;
   1090         for (i=0; i<startMapLimit; i++) {
   1091             utext_setNativeIndex(ut, i);
   1092             int64_t cpIndex = utext_getNativeIndex(ut);
   1093             TEST_ASSERT(cpIndex == startMap[i]);
   1094         }
   1095 
   1096         // Check char32At
   1097         for (i=0; i<startMapLimit; i++) {
   1098             UChar32 c32 = utext_char32At(ut, i);
   1099             TEST_ASSERT(c32 == c32Map[i]);
   1100             int64_t cpIndex = utext_getNativeIndex(ut);
   1101             TEST_ASSERT(cpIndex == startMap[i]);
   1102         }
   1103 
   1104         // Check utext_next32From
   1105         for (i=0; i<startMapLimit; i++) {
   1106             UChar32 c32 = utext_next32From(ut, i);
   1107             TEST_ASSERT(c32 == c32Map[i]);
   1108             int64_t cpIndex = utext_getNativeIndex(ut);
   1109             TEST_ASSERT(cpIndex == nextMap[i]);
   1110         }
   1111 
   1112         // check utext_previous32From
   1113         for (i=0; i<startMapLimit; i++) {
   1114             UChar32 c32 = utext_previous32From(ut, i);
   1115             TEST_ASSERT(c32 == pr32Map[i]);
   1116             int64_t cpIndex = utext_getNativeIndex(ut);
   1117             TEST_ASSERT(cpIndex == prevMap[i]);
   1118         }
   1119 
   1120         // check Extract
   1121         //   Extract from i to i+1, which may be zero or one code points,
   1122         //     depending on whether the indices straddle a cp boundary.
   1123         for (i=0; i<startMapLimit; i++) {
   1124             UChar buf[3];
   1125             status = U_ZERO_ERROR;
   1126             int32_t  extractedLen = utext_extract(ut, i, i+1, buf, 3, &status);
   1127             TEST_SUCCESS(status);
   1128             TEST_ASSERT(extractedLen == exLen[i]);
   1129             if (extractedLen > 0) {
   1130                 UChar32  c32;
   1131                 /* extractedLen-extractedLen == 0 is used to get around a compiler warning. */
   1132                 U16_GET(buf, 0, extractedLen-extractedLen, extractedLen, c32);
   1133                 TEST_ASSERT(c32 == c32Map[i]);
   1134             }
   1135         }
   1136 
   1137         utext_close(ut);
   1138     }
   1139 
   1140     {    //  Similar test, with UText over Replaceable
   1141          //  TODO:  merge the common parts of these tests.
   1142 
   1143         UnicodeString u16str("\\u1000\\U00011000\\u2000\\U00022000", -1, US_INV);
   1144         int32_t startMap[]  ={ 0,     1,   1,    3,     4,  4,     6,  6};
   1145         int32_t nextMap[]  = { 1,     3,   3,    4,     6,  6,     6,  6};
   1146         int32_t prevMap[]  = { 0,     0,   0,    1,     3,  3,     4,  4};
   1147         UChar32  c32Map[] =  {0x1000, 0x11000, 0x11000, 0x2000,  0x22000, 0x22000, -1, -1};
   1148         UChar32  pr32Map[] = {    -1, 0x1000,  0x1000,  0x11000, 0x2000,  0x2000,   0x22000,   0x22000};
   1149         int32_t  exLen[] =   {   1,  0,   2,  1,  0,  2,  0,  0,};
   1150 
   1151         u16str = u16str.unescape();
   1152         UErrorCode status = U_ZERO_ERROR;
   1153         UText *ut = utext_openReplaceable(NULL, &u16str, &status);
   1154         TEST_SUCCESS(status);
   1155 
   1156         int32_t startMapLimit = UPRV_LENGTHOF(startMap);
   1157         int i;
   1158         for (i=0; i<startMapLimit; i++) {
   1159             utext_setNativeIndex(ut, i);
   1160             int64_t cpIndex = utext_getNativeIndex(ut);
   1161             TEST_ASSERT(cpIndex == startMap[i]);
   1162         }
   1163 
   1164         // Check char32At
   1165         for (i=0; i<startMapLimit; i++) {
   1166             UChar32 c32 = utext_char32At(ut, i);
   1167             TEST_ASSERT(c32 == c32Map[i]);
   1168             int64_t cpIndex = utext_getNativeIndex(ut);
   1169             TEST_ASSERT(cpIndex == startMap[i]);
   1170         }
   1171 
   1172         // Check utext_next32From
   1173         for (i=0; i<startMapLimit; i++) {
   1174             UChar32 c32 = utext_next32From(ut, i);
   1175             TEST_ASSERT(c32 == c32Map[i]);
   1176             int64_t cpIndex = utext_getNativeIndex(ut);
   1177             TEST_ASSERT(cpIndex == nextMap[i]);
   1178         }
   1179 
   1180         // check utext_previous32From
   1181         for (i=0; i<startMapLimit; i++) {
   1182             UChar32 c32 = utext_previous32From(ut, i);
   1183             TEST_ASSERT(c32 == pr32Map[i]);
   1184             int64_t cpIndex = utext_getNativeIndex(ut);
   1185             TEST_ASSERT(cpIndex == prevMap[i]);
   1186         }
   1187 
   1188         // check Extract
   1189         //   Extract from i to i+1, which may be zero or one code points,
   1190         //     depending on whether the indices straddle a cp boundary.
   1191         for (i=0; i<startMapLimit; i++) {
   1192             UChar buf[3];
   1193             status = U_ZERO_ERROR;
   1194             int32_t  extractedLen = utext_extract(ut, i, i+1, buf, 3, &status);
   1195             TEST_SUCCESS(status);
   1196             TEST_ASSERT(extractedLen == exLen[i]);
   1197             if (extractedLen > 0) {
   1198                 UChar32  c32;
   1199                 /* extractedLen-extractedLen == 0 is used to get around a compiler warning. */
   1200                 U16_GET(buf, 0, extractedLen-extractedLen, extractedLen, c32);
   1201                 TEST_ASSERT(c32 == c32Map[i]);
   1202             }
   1203         }
   1204 
   1205         utext_close(ut);
   1206     }
   1207 }
   1208 
   1209 
   1210 void UTextTest::FreezeTest() {
   1211     // Check isWritable() and freeze() behavior.
   1212     //
   1213 
   1214     UnicodeString  ustr("Hello, World.");
   1215     const char u8str[] = {char(0x31), (char)0x32, (char)0x33, 0};
   1216     const UChar u16str[] = {(UChar)0x31, (UChar)0x32, (UChar)0x44, 0};
   1217 
   1218     UErrorCode status = U_ZERO_ERROR;
   1219     UText  *ut        = NULL;
   1220     UText  *ut2       = NULL;
   1221 
   1222     ut = utext_openUTF8(ut, u8str, -1, &status);
   1223     TEST_SUCCESS(status);
   1224     UBool writable = utext_isWritable(ut);
   1225     TEST_ASSERT(writable == FALSE);
   1226     utext_copy(ut, 1, 2, 0, TRUE, &status);
   1227     TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
   1228 
   1229     status = U_ZERO_ERROR;
   1230     ut = utext_openUChars(ut, u16str, -1, &status);
   1231     TEST_SUCCESS(status);
   1232     writable = utext_isWritable(ut);
   1233     TEST_ASSERT(writable == FALSE);
   1234     utext_copy(ut, 1, 2, 0, TRUE, &status);
   1235     TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
   1236 
   1237     status = U_ZERO_ERROR;
   1238     ut = utext_openUnicodeString(ut, &ustr, &status);
   1239     TEST_SUCCESS(status);
   1240     writable = utext_isWritable(ut);
   1241     TEST_ASSERT(writable == TRUE);
   1242     utext_freeze(ut);
   1243     writable = utext_isWritable(ut);
   1244     TEST_ASSERT(writable == FALSE);
   1245     utext_copy(ut, 1, 2, 0, TRUE, &status);
   1246     TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
   1247 
   1248     status = U_ZERO_ERROR;
   1249     ut = utext_openUnicodeString(ut, &ustr, &status);
   1250     TEST_SUCCESS(status);
   1251     ut2 = utext_clone(ut2, ut, FALSE, FALSE, &status);  // clone with readonly = false
   1252     TEST_SUCCESS(status);
   1253     writable = utext_isWritable(ut2);
   1254     TEST_ASSERT(writable == TRUE);
   1255     ut2 = utext_clone(ut2, ut, FALSE, TRUE, &status);  // clone with readonly = true
   1256     TEST_SUCCESS(status);
   1257     writable = utext_isWritable(ut2);
   1258     TEST_ASSERT(writable == FALSE);
   1259     utext_copy(ut2, 1, 2, 0, TRUE, &status);
   1260     TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
   1261 
   1262     status = U_ZERO_ERROR;
   1263     ut = utext_openConstUnicodeString(ut, (const UnicodeString *)&ustr, &status);
   1264     TEST_SUCCESS(status);
   1265     writable = utext_isWritable(ut);
   1266     TEST_ASSERT(writable == FALSE);
   1267     utext_copy(ut, 1, 2, 0, TRUE, &status);
   1268     TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
   1269 
   1270     // Deep Clone of a frozen UText should re-enable writing in the copy.
   1271     status = U_ZERO_ERROR;
   1272     ut = utext_openUnicodeString(ut, &ustr, &status);
   1273     TEST_SUCCESS(status);
   1274     utext_freeze(ut);
   1275     ut2 = utext_clone(ut2, ut, TRUE, FALSE, &status);   // deep clone
   1276     TEST_SUCCESS(status);
   1277     writable = utext_isWritable(ut2);
   1278     TEST_ASSERT(writable == TRUE);
   1279 
   1280 
   1281     // Deep clone of a frozen UText, where the base type is intrinsically non-writable,
   1282     //  should NOT enable writing in the copy.
   1283     status = U_ZERO_ERROR;
   1284     ut = utext_openUChars(ut, u16str, -1, &status);
   1285     TEST_SUCCESS(status);
   1286     utext_freeze(ut);
   1287     ut2 = utext_clone(ut2, ut, TRUE, FALSE, &status);   // deep clone
   1288     TEST_SUCCESS(status);
   1289     writable = utext_isWritable(ut2);
   1290     TEST_ASSERT(writable == FALSE);
   1291 
   1292     // cleanup
   1293     utext_close(ut);
   1294     utext_close(ut2);
   1295 }
   1296 
   1297 
   1298 //
   1299 //  Fragmented UText
   1300 //      A UText type that works with a chunk size of 1.
   1301 //      Intended to test for edge cases.
   1302 //      Input comes from a UnicodeString.
   1303 //
   1304 //       ut.b    the character.  Put into both halves.
   1305 //
   1306 
   1307 U_CDECL_BEGIN
   1308 static UBool U_CALLCONV
   1309 fragTextAccess(UText *ut, int64_t index, UBool forward) {
   1310     const UnicodeString *us = (const UnicodeString *)ut->context;
   1311     UChar  c;
   1312     int32_t length = us->length();
   1313     if (forward && index>=0 && index<length) {
   1314         c = us->charAt((int32_t)index);
   1315         ut->b = c | c<<16;
   1316         ut->chunkOffset = 0;
   1317         ut->chunkLength = 1;
   1318         ut->chunkNativeStart = index;
   1319         ut->chunkNativeLimit = index+1;
   1320         return true;
   1321     }
   1322     if (!forward && index>0 && index <=length) {
   1323         c = us->charAt((int32_t)index-1);
   1324         ut->b = c | c<<16;
   1325         ut->chunkOffset = 1;
   1326         ut->chunkLength = 1;
   1327         ut->chunkNativeStart = index-1;
   1328         ut->chunkNativeLimit = index;
   1329         return true;
   1330     }
   1331     ut->b = 0;
   1332     ut->chunkOffset = 0;
   1333     ut->chunkLength = 0;
   1334     if (index <= 0) {
   1335         ut->chunkNativeStart = 0;
   1336         ut->chunkNativeLimit = 0;
   1337     } else {
   1338         ut->chunkNativeStart = length;
   1339         ut->chunkNativeLimit = length;
   1340     }
   1341     return false;
   1342 }
   1343 
   1344 // Function table to be used with this fragmented text provider.
   1345 //   Initialized in the open function.
   1346 static UTextFuncs  fragmentFuncs;
   1347 
   1348 // Clone function for fragmented text provider.
   1349 //   Didn't really want to provide this, but it's easier to provide it than to keep it
   1350 //   out of the tests.
   1351 //
   1352 UText *
   1353 cloneFragmentedUnicodeString(UText *dest, const UText *src, UBool deep, UErrorCode *status) {
   1354     if (U_FAILURE(*status)) {
   1355         return NULL;
   1356     }
   1357     if (deep) {
   1358         *status = U_UNSUPPORTED_ERROR;
   1359         return NULL;
   1360     }
   1361     dest = utext_openUnicodeString(dest, (UnicodeString *)src->context, status);
   1362     utext_setNativeIndex(dest, utext_getNativeIndex(src));
   1363     return dest;
   1364 }
   1365 
   1366 U_CDECL_END
   1367 
   1368 // Open function for the fragmented text provider.
   1369 UText *
   1370 openFragmentedUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status) {
   1371     ut = utext_openUnicodeString(ut, s, status);
   1372     if (U_FAILURE(*status)) {
   1373         return ut;
   1374     }
   1375 
   1376     // Copy of the function table from the stock UnicodeString UText,
   1377     //   and replace the entry for the access function.
   1378     memcpy(&fragmentFuncs, ut->pFuncs, sizeof(fragmentFuncs));
   1379     fragmentFuncs.access = fragTextAccess;
   1380     fragmentFuncs.clone  = cloneFragmentedUnicodeString;
   1381     ut->pFuncs = &fragmentFuncs;
   1382 
   1383     ut->chunkContents = (UChar *)&ut->b;
   1384     ut->pFuncs->access(ut, 0, TRUE);
   1385     return ut;
   1386 }
   1387 
   1388 // Regression test for Ticket 5560
   1389 //   Clone fails to update chunkContentPointer in the cloned copy.
   1390 //   This is only an issue for UText types that work in a local buffer,
   1391 //      (UTF-8 wrapper, for example)
   1392 //
   1393 //   The test:
   1394 //     1.  Create an inital UText
   1395 //     2.  Deep clone it.  Contents should match original.
   1396 //     3.  Reset original to something different.
   1397 //     4.  Check that clone contents did not change.
   1398 //
   1399 void UTextTest::Ticket5560() {
   1400     /* The following two strings are in UTF-8 even on EBCDIC platforms. */
   1401     static const char s1[] = {0x41,0x42,0x43,0x44,0x45,0x46,0}; /* "ABCDEF" */
   1402     static const char s2[] = {0x31,0x32,0x33,0x34,0x35,0x36,0}; /* "123456" */
   1403 	UErrorCode status = U_ZERO_ERROR;
   1404 
   1405 	UText ut1 = UTEXT_INITIALIZER;
   1406 	UText ut2 = UTEXT_INITIALIZER;
   1407 
   1408 	utext_openUTF8(&ut1, s1, -1, &status);
   1409 	UChar c = utext_next32(&ut1);
   1410 	TEST_ASSERT(c == 0x41);  // c == 'A'
   1411 
   1412 	utext_clone(&ut2, &ut1, TRUE, FALSE, &status);
   1413 	TEST_SUCCESS(status);
   1414     c = utext_next32(&ut2);
   1415 	TEST_ASSERT(c == 0x42);  // c == 'B'
   1416     c = utext_next32(&ut1);
   1417 	TEST_ASSERT(c == 0x42);  // c == 'B'
   1418 
   1419 	utext_openUTF8(&ut1, s2, -1, &status);
   1420 	c = utext_next32(&ut1);
   1421 	TEST_ASSERT(c == 0x31);  // c == '1'
   1422     c = utext_next32(&ut2);
   1423 	TEST_ASSERT(c == 0x43);  // c == 'C'
   1424 
   1425     utext_close(&ut1);
   1426     utext_close(&ut2);
   1427 }
   1428 
   1429 
   1430 // Test for Ticket 6847
   1431 //
   1432 void UTextTest::Ticket6847() {
   1433     const int STRLEN = 90;
   1434     UChar s[STRLEN+1];
   1435     u_memset(s, 0x41, STRLEN);
   1436     s[STRLEN] = 0;
   1437 
   1438     UErrorCode status = U_ZERO_ERROR;
   1439     UText *ut = utext_openUChars(NULL, s, -1, &status);
   1440 
   1441     utext_setNativeIndex(ut, 0);
   1442     int32_t count = 0;
   1443     UChar32 c = 0;
   1444     int64_t nativeIndex = UTEXT_GETNATIVEINDEX(ut);
   1445     TEST_ASSERT(nativeIndex == 0);
   1446     while ((c = utext_next32(ut)) != U_SENTINEL) {
   1447         TEST_ASSERT(c == 0x41);
   1448         TEST_ASSERT(count < STRLEN);
   1449         if (count >= STRLEN) {
   1450             break;
   1451         }
   1452         count++;
   1453         nativeIndex = UTEXT_GETNATIVEINDEX(ut);
   1454         TEST_ASSERT(nativeIndex == count);
   1455     }
   1456     TEST_ASSERT(count == STRLEN);
   1457     nativeIndex = UTEXT_GETNATIVEINDEX(ut);
   1458     TEST_ASSERT(nativeIndex == STRLEN);
   1459     utext_close(ut);
   1460 }
   1461 
   1462 
   1463 void UTextTest::Ticket10562() {
   1464     // Note: failures show as a heap error when the test is run under valgrind.
   1465     UErrorCode status = U_ZERO_ERROR;
   1466 
   1467     const char *utf8_string = "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41";
   1468     UText *utf8Text = utext_openUTF8(NULL, utf8_string, -1, &status);
   1469     TEST_SUCCESS(status);
   1470     UText *deepClone = utext_clone(NULL, utf8Text, TRUE, FALSE, &status);
   1471     TEST_SUCCESS(status);
   1472     UText *shallowClone = utext_clone(NULL, deepClone, FALSE, FALSE, &status);
   1473     TEST_SUCCESS(status);
   1474     utext_close(shallowClone);
   1475     utext_close(deepClone);
   1476     utext_close(utf8Text);
   1477 
   1478     status = U_ZERO_ERROR;
   1479     UnicodeString usString("Hello, World.");
   1480     UText *usText = utext_openUnicodeString(NULL, &usString, &status);
   1481     TEST_SUCCESS(status);
   1482     UText *usDeepClone = utext_clone(NULL, usText, TRUE, FALSE, &status);
   1483     TEST_SUCCESS(status);
   1484     UText *usShallowClone = utext_clone(NULL, usDeepClone, FALSE, FALSE, &status);
   1485     TEST_SUCCESS(status);
   1486     utext_close(usShallowClone);
   1487     utext_close(usDeepClone);
   1488     utext_close(usText);
   1489 }
   1490 
   1491 
   1492 void UTextTest::Ticket10983() {
   1493     // Note: failure shows as a seg fault when the defect is present.
   1494 
   1495     UErrorCode status = U_ZERO_ERROR;
   1496     UnicodeString s("Hello, World");
   1497     UText *ut = utext_openConstUnicodeString(NULL, &s, &status);
   1498     TEST_SUCCESS(status);
   1499 
   1500     status = U_INVALID_STATE_ERROR;
   1501     UText *cloned = utext_clone(NULL, ut, TRUE, TRUE, &status);
   1502     TEST_ASSERT(cloned == NULL);
   1503     TEST_ASSERT(status == U_INVALID_STATE_ERROR);
   1504 
   1505     utext_close(ut);
   1506 }
   1507 
   1508 // Ticket 12130 - extract on a UText wrapping a null terminated UChar * string
   1509 //                leaves the iteration position set incorrectly when the
   1510 //                actual string length is not yet known.
   1511 //
   1512 //                The test text needs to be long enough that UText defers getting the length.
   1513 
   1514 void UTextTest::Ticket12130() {
   1515     UErrorCode status = U_ZERO_ERROR;
   1516 
   1517     const char *text8 =
   1518         "Fundamentally, computers just deal with numbers. They store letters and other characters "
   1519         "by assigning a number for each one. Before Unicode was invented, there were hundreds "
   1520         "of different encoding systems for assigning these numbers. No single encoding could "
   1521         "contain enough characters: for example, the European Union alone requires several "
   1522         "different encodings to cover all its languages. Even for a single language like "
   1523         "English no single encoding was adequate for all the letters, punctuation, and technical "
   1524         "symbols in common use.";
   1525 
   1526     UnicodeString str(text8);
   1527     const UChar *ustr = str.getTerminatedBuffer();
   1528     UText ut = UTEXT_INITIALIZER;
   1529     utext_openUChars(&ut, ustr, -1, &status);
   1530     UChar extractBuffer[50];
   1531 
   1532     for (int32_t startIdx = 0; startIdx<str.length(); ++startIdx) {
   1533         int32_t endIdx = startIdx + 20;
   1534 
   1535         u_memset(extractBuffer, 0, UPRV_LENGTHOF(extractBuffer));
   1536         utext_extract(&ut, startIdx, endIdx, extractBuffer, UPRV_LENGTHOF(extractBuffer), &status);
   1537         if (U_FAILURE(status)) {
   1538             errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
   1539             return;
   1540         }
   1541         int64_t ni  = utext_getNativeIndex(&ut);
   1542         int64_t expectedni = startIdx + 20;
   1543         if (expectedni > str.length()) {
   1544             expectedni = str.length();
   1545         }
   1546         if (expectedni != ni) {
   1547             errln("%s:%d utext_getNativeIndex() expected %d, got %d", __FILE__, __LINE__, expectedni, ni);
   1548         }
   1549         if (0 != str.tempSubString(startIdx, 20).compare(extractBuffer)) {
   1550             errln("%s:%d utext_extract() failed. expected \"%s\", got \"%s\"",
   1551                     __FILE__, __LINE__, CStr(str.tempSubString(startIdx, 20))(), CStr(UnicodeString(extractBuffer))());
   1552         }
   1553     }
   1554     utext_close(&ut);
   1555 
   1556     // Similar utext extract, this time with the string length provided to the UText in advance,
   1557     // and a buffer of larger than required capacity.
   1558 
   1559     utext_openUChars(&ut, ustr, str.length(), &status);
   1560     for (int32_t startIdx = 0; startIdx<str.length(); ++startIdx) {
   1561         int32_t endIdx = startIdx + 20;
   1562         u_memset(extractBuffer, 0, UPRV_LENGTHOF(extractBuffer));
   1563         utext_extract(&ut, startIdx, endIdx, extractBuffer, UPRV_LENGTHOF(extractBuffer), &status);
   1564         if (U_FAILURE(status)) {
   1565             errln("%s:%d %s", __FILE__, __LINE__, u_errorName(status));
   1566             return;
   1567         }
   1568         int64_t ni  = utext_getNativeIndex(&ut);
   1569         int64_t expectedni = startIdx + 20;
   1570         if (expectedni > str.length()) {
   1571             expectedni = str.length();
   1572         }
   1573         if (expectedni != ni) {
   1574             errln("%s:%d utext_getNativeIndex() expected %d, got %d", __FILE__, __LINE__, expectedni, ni);
   1575         }
   1576         if (0 != str.tempSubString(startIdx, 20).compare(extractBuffer)) {
   1577             errln("%s:%d utext_extract() failed. expected \"%s\", got \"%s\"",
   1578                     __FILE__, __LINE__, CStr(str.tempSubString(startIdx, 20))(), CStr(UnicodeString(extractBuffer))());
   1579         }
   1580     }
   1581     utext_close(&ut);
   1582 }
   1583 
   1584 // Ticket 13344 The macro form of UTEXT_SETNATIVEINDEX failed when target was a trail surrogate
   1585 //              of a supplementary character.
   1586 
   1587 void UTextTest::Ticket13344() {
   1588     UErrorCode status = U_ZERO_ERROR;
   1589     const char16_t *str = u"abc\U0010abcd xyz";
   1590     LocalUTextPointer ut(utext_openUChars(NULL, str, -1, &status));
   1591 
   1592     assertSuccess("UTextTest::Ticket13344-status", status);
   1593     UTEXT_SETNATIVEINDEX(ut.getAlias(), 3);
   1594     assertEquals("UTextTest::Ticket13344-lead", (int64_t)3, utext_getNativeIndex(ut.getAlias()));
   1595     UTEXT_SETNATIVEINDEX(ut.getAlias(), 4);
   1596     assertEquals("UTextTest::Ticket13344-trail", (int64_t)3, utext_getNativeIndex(ut.getAlias()));
   1597     UTEXT_SETNATIVEINDEX(ut.getAlias(), 5);
   1598     assertEquals("UTextTest::Ticket13344-bmp", (int64_t)5, utext_getNativeIndex(ut.getAlias()));
   1599 
   1600     utext_setNativeIndex(ut.getAlias(), 3);
   1601     assertEquals("UTextTest::Ticket13344-lead-2", (int64_t)3, utext_getNativeIndex(ut.getAlias()));
   1602     utext_setNativeIndex(ut.getAlias(), 4);
   1603     assertEquals("UTextTest::Ticket13344-trail-2", (int64_t)3, utext_getNativeIndex(ut.getAlias()));
   1604     utext_setNativeIndex(ut.getAlias(), 5);
   1605     assertEquals("UTextTest::Ticket13344-bmp-2", (int64_t)5, utext_getNativeIndex(ut.getAlias()));
   1606 }
   1607 
   1608