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