1/****************************************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2010, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 * Modification History:
6 *
7 *   Date          Name        Description
8 *   05/22/2000    Madhu       Added tests for testing new API for utf16 support and more
9 ****************************************************************************************/
10
11#include <string.h>
12#include <typeinfo>  // for 'typeid' to work
13
14#include "unicode/chariter.h"
15#include "unicode/ustring.h"
16#include "unicode/unistr.h"
17#include "unicode/schriter.h"
18#include "unicode/uchriter.h"
19#include "unicode/uiter.h"
20#include "unicode/putil.h"
21#include "citrtest.h"
22
23
24class  SCharacterIterator : public CharacterIterator {
25public:
26    SCharacterIterator(const UnicodeString& textStr){
27        text = textStr;
28        pos=0;
29        textLength = textStr.length();
30        begin = 0;
31        end=textLength;
32
33    }
34
35    virtual ~SCharacterIterator(){};
36
37
38    void setText(const UnicodeString& newText){
39        text = newText;
40    }
41
42    virtual void getText(UnicodeString& result) {
43        text.extract(0,text.length(),result);
44    }
45    static UClassID getStaticClassID(void){
46        return (UClassID)(&fgClassID);
47    }
48    virtual UClassID getDynamicClassID(void) const{
49        return getStaticClassID();
50    }
51
52    virtual UBool operator==(const ForwardCharacterIterator& /*that*/) const{
53        return TRUE;
54    }
55
56    virtual CharacterIterator* clone(void) const {
57        return NULL;
58    }
59    virtual int32_t hashCode(void) const{
60        return DONE;
61    }
62    virtual UChar nextPostInc(void){ return text.charAt(pos++);}
63    virtual UChar32 next32PostInc(void){return text.char32At(pos++);}
64    virtual UBool hasNext() { return TRUE;};
65    virtual UChar first(){return DONE;};
66    virtual UChar32 first32(){return DONE;};
67    virtual UChar last(){return DONE;};
68    virtual UChar32 last32(){return DONE;};
69    virtual UChar setIndex(int32_t /*pos*/){return DONE;};
70    virtual UChar32 setIndex32(int32_t /*pos*/){return DONE;};
71    virtual UChar current() const{return DONE;};
72    virtual UChar32 current32() const{return DONE;};
73    virtual UChar next(){return DONE;};
74    virtual UChar32 next32(){return DONE;};
75    virtual UChar previous(){return DONE;};
76    virtual UChar32 previous32(){return DONE;};
77    virtual int32_t move(int32_t delta,CharacterIterator::EOrigin origin){
78        switch(origin) {
79        case kStart:
80            pos = begin + delta;
81            break;
82        case kCurrent:
83            pos += delta;
84            break;
85        case kEnd:
86            pos = end + delta;
87            break;
88        default:
89            break;
90        }
91
92        if(pos < begin) {
93            pos = begin;
94        } else if(pos > end) {
95            pos = end;
96        }
97
98        return pos;
99    };
100    virtual int32_t move32(int32_t delta, CharacterIterator::EOrigin origin){
101        switch(origin) {
102        case kStart:
103            pos = begin;
104            if(delta > 0) {
105                UTF_FWD_N(text, pos, end, delta);
106            }
107            break;
108        case kCurrent:
109            if(delta > 0) {
110                UTF_FWD_N(text, pos, end, delta);
111            } else {
112                UTF_BACK_N(text, begin, pos, -delta);
113            }
114            break;
115        case kEnd:
116            pos = end;
117            if(delta < 0) {
118                UTF_BACK_N(text, begin, pos, -delta);
119            }
120            break;
121        default:
122            break;
123        }
124
125        return pos;
126    };
127    virtual UBool hasPrevious() {return TRUE;};
128
129  SCharacterIterator&  operator=(const SCharacterIterator&    that){
130     text = that.text;
131     return *this;
132  }
133
134
135private:
136    UnicodeString text;
137    static const char fgClassID;
138};
139const char SCharacterIterator::fgClassID=0;
140
141#define LENGTHOF(array) ((int32_t)(sizeof(array)/sizeof((array)[0])))
142
143CharIterTest::CharIterTest()
144{
145}
146void CharIterTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
147{
148    if (exec) logln("TestSuite CharIterTest: ");
149    switch (index) {
150        case 0: name = "TestConstructionAndEquality"; if (exec) TestConstructionAndEquality(); break;
151        case 1: name = "TestConstructionAndEqualityUChariter"; if (exec) TestConstructionAndEqualityUChariter(); break;
152        case 2: name = "TestIteration"; if (exec) TestIteration(); break;
153        case 3: name = "TestIterationUChar32"; if (exec) TestIterationUChar32(); break;
154        case 4: name = "TestUCharIterator"; if (exec) TestUCharIterator(); break;
155        case 5: name = "TestCoverage"; if(exec) TestCoverage(); break;
156        case 6: name = "TestCharIteratorSubClasses"; if (exec) TestCharIteratorSubClasses(); break;
157        default: name = ""; break; //needed to end loop
158    }
159}
160
161void CharIterTest::TestCoverage(){
162    UnicodeString  testText("Now is the time for all good men to come to the aid of their country.");
163    UnicodeString testText2("\\ud800\\udc01deadbeef");
164    testText2 = testText2.unescape();
165    SCharacterIterator* test = new SCharacterIterator(testText);
166    if(test->firstPostInc()!= 0x004E){
167        errln("Failed: firstPostInc() failed");
168    }
169    if(test->getIndex()!=1){
170        errln("Failed: getIndex().");
171    }
172    if(test->getLength()!=testText.length()){
173        errln("Failed: getLength()");
174    }
175    test->setToStart();
176    if(test->getIndex()!=0){
177        errln("Failed: setToStart().");
178    }
179    test->setToEnd();
180    if(test->getIndex()!=testText.length()){
181        errln("Failed: setToEnd().");
182    }
183    if(test->startIndex() != 0){
184        errln("Failed: startIndex()");
185    }
186    test->setText(testText2);
187    if(test->first32PostInc()!= testText2.char32At(0)){
188        errln("Failed: first32PostInc() failed");
189    }
190
191    delete test;
192
193}
194void CharIterTest::TestConstructionAndEquality() {
195    UnicodeString  testText("Now is the time for all good men to come to the aid of their country.");
196    UnicodeString  testText2("Don't bother using this string.");
197    UnicodeString result1, result2, result3;
198
199    CharacterIterator* test1 = new StringCharacterIterator(testText);
200    CharacterIterator* test1b= new StringCharacterIterator(testText, -1);
201    CharacterIterator* test1c= new StringCharacterIterator(testText, 100);
202    CharacterIterator* test1d= new StringCharacterIterator(testText, -2, 100, 5);
203    CharacterIterator* test1e= new StringCharacterIterator(testText, 100, 20, 5);
204    CharacterIterator* test2 = new StringCharacterIterator(testText, 5);
205    CharacterIterator* test3 = new StringCharacterIterator(testText, 2, 20, 5);
206    CharacterIterator* test4 = new StringCharacterIterator(testText2);
207    CharacterIterator* test5 = test1->clone();
208
209    if (test1d->startIndex() < 0)
210        errln("Construction failed: startIndex is negative");
211    if (test1d->endIndex() > testText.length())
212        errln("Construction failed: endIndex is greater than the text length");
213    if (test1d->getIndex() < test1d->startIndex() || test1d->endIndex() < test1d->getIndex())
214        errln("Construction failed: index is invalid");
215
216    if (*test1 == *test2 || *test1 == *test3 || *test1 == *test4)
217        errln("Construction or operator== failed: Unequal objects compared equal");
218    if (*test1 != *test5)
219        errln("clone() or equals() failed: Two clones tested unequal");
220
221    if (test1->hashCode() == test2->hashCode() || test1->hashCode() == test3->hashCode()
222                    || test1->hashCode() == test4->hashCode())
223        errln("hashCode() failed:  different objects have same hash code");
224
225    if (test1->hashCode() != test5->hashCode())
226        errln("hashCode() failed:  identical objects have different hash codes");
227
228    if(test1->getLength() != testText.length()){
229        errln("getLength of CharacterIterator failed");
230    }
231    test1->getText(result1);
232    test1b->getText(result2);
233    test1c->getText(result3);
234    if(result1 != result2 ||  result1 != result3)
235        errln("construction failed or getText() failed");
236
237
238    test1->setIndex(5);
239    if (*test1 != *test2 || *test1 == *test5)
240        errln("setIndex() failed");
241
242    *((StringCharacterIterator*)test1) = *((StringCharacterIterator*)test3);
243    if (*test1 != *test3 || *test1 == *test5)
244        errln("operator= failed");
245
246    delete test2;
247    delete test3;
248    delete test4;
249    delete test5;
250    delete test1b;
251    delete test1c;
252    delete test1d;
253    delete test1e;
254
255
256    StringCharacterIterator* testChar1=new StringCharacterIterator(testText);
257    StringCharacterIterator* testChar2=new StringCharacterIterator(testText2);
258    StringCharacterIterator* testChar3=(StringCharacterIterator*)test1->clone();
259
260    testChar1->getText(result1);
261    testChar2->getText(result2);
262    testChar3->getText(result3);
263    if(result1 != result3 || result1 == result2)
264        errln("getText() failed");
265    testChar3->setText(testText2);
266    testChar3->getText(result3);
267    if(result1 == result3 || result2 != result3)
268        errln("setText() or getText() failed");
269    testChar3->setText(testText);
270    testChar3->getText(result3);
271    if(result1 != result3 || result1 == result2)
272        errln("setText() or getText() round-trip failed");
273
274    delete testChar1;
275    delete testChar2;
276    delete testChar3;
277    delete test1;
278
279}
280void CharIterTest::TestConstructionAndEqualityUChariter() {
281    U_STRING_DECL(testText, "Now is the time for all good men to come to the aid of their country.", 69);
282    U_STRING_DECL(testText2, "Don't bother using this string.", 31);
283
284    U_STRING_INIT(testText, "Now is the time for all good men to come to the aid of their country.", 69);
285    U_STRING_INIT(testText2, "Don't bother using this string.", 31);
286
287    UnicodeString result, result4, result5;
288
289    UCharCharacterIterator* test1 = new UCharCharacterIterator(testText, u_strlen(testText));
290    UCharCharacterIterator* test2 = new UCharCharacterIterator(testText, u_strlen(testText), 5);
291    UCharCharacterIterator* test3 = new UCharCharacterIterator(testText, u_strlen(testText), 2, 20, 5);
292    UCharCharacterIterator* test4 = new UCharCharacterIterator(testText2, u_strlen(testText2));
293    UCharCharacterIterator* test5 = (UCharCharacterIterator*)test1->clone();
294    UCharCharacterIterator* test6 = new UCharCharacterIterator(*test1);
295
296    // j785: length=-1 will use u_strlen()
297    UCharCharacterIterator* test7a = new UCharCharacterIterator(testText, -1);
298    UCharCharacterIterator* test7b = new UCharCharacterIterator(testText, -1);
299    UCharCharacterIterator* test7c = new UCharCharacterIterator(testText, -1, 2, 20, 5);
300
301    // Bad parameters.
302    UCharCharacterIterator* test8a = new UCharCharacterIterator(testText, -1, -1, 20, 5);
303    UCharCharacterIterator* test8b = new UCharCharacterIterator(testText, -1, 2, 100, 5);
304    UCharCharacterIterator* test8c = new UCharCharacterIterator(testText, -1, 2, 20, 100);
305
306    if (test8a->startIndex() < 0)
307        errln("Construction failed: startIndex is negative");
308    if (test8b->endIndex() != u_strlen(testText))
309        errln("Construction failed: endIndex is different from the text length");
310    if (test8c->getIndex() < test8c->startIndex() || test8c->endIndex() < test8c->getIndex())
311        errln("Construction failed: index is invalid");
312
313    if (*test1 == *test2 || *test1 == *test3 || *test1 == *test4 )
314        errln("Construction or operator== failed: Unequal objects compared equal");
315    if (*test1 != *test5 )
316        errln("clone() or equals() failed: Two clones tested unequal");
317
318    if (*test6 != *test1 )
319        errln("copy construction or equals() failed: Two copies tested unequal");
320
321    if (test1->hashCode() == test2->hashCode() || test1->hashCode() == test3->hashCode()
322                    || test1->hashCode() == test4->hashCode())
323        errln("hashCode() failed:  different objects have same hash code");
324
325    if (test1->hashCode() != test5->hashCode())
326        errln("hashCode() failed:  identical objects have different hash codes");
327
328    test7a->getText(result);
329    test7b->getText(result4);
330    test7c->getText(result5);
331
332    if(result != UnicodeString(testText) || result4 != result || result5 != result)
333        errln("error in construction");
334
335    test1->getText(result);
336    test4->getText(result4);
337    test5->getText(result5);
338    if(result != result5 || result == result4)
339        errln("getText() failed");
340    test5->setText(testText2, u_strlen(testText2));
341    test5->getText(result5);
342    if(result == result5 || result4 != result5)
343        errln("setText() or getText() failed");
344    test5->setText(testText, u_strlen(testText));
345    test5->getText(result5);
346    if(result != result5 || result == result4)
347        errln("setText() or getText() round-trip failed");
348
349
350    test1->setIndex(5);
351    if (*test1 != *test2 || *test1 == *test5)
352        errln("setIndex() failed");
353    test8b->setIndex32(5);
354    if (test8b->getIndex()!=5)
355        errln("setIndex32() failed");
356
357    *test1 = *test3;
358    if (*test1 != *test3 || *test1 == *test5)
359        errln("operator= failed");
360
361    delete test1;
362    delete test2;
363    delete test3;
364    delete test4;
365    delete test5;
366    delete test6;
367    delete test7a;
368    delete test7b;
369    delete test7c;
370    delete test8a;
371    delete test8b;
372    delete test8c;
373}
374
375
376void CharIterTest::TestIteration() {
377    UnicodeString text("Now is the time for all good men to come to the aid of their country.");
378
379    UChar c;
380    int32_t i;
381    {
382        StringCharacterIterator   iter(text, 5);
383
384        UnicodeString iterText;
385        iter.getText(iterText);
386        if (iterText != text)
387          errln("iter.getText() failed");
388
389        if (iter.current() != text[(int32_t)5])
390            errln("Iterator didn't start out in the right place.");
391
392        c = iter.first();
393        i = 0;
394
395        if (iter.startIndex() != 0 || iter.endIndex() != text.length())
396            errln("startIndex() or endIndex() failed");
397
398        logln("Testing forward iteration...");
399        do {
400            if (c == CharacterIterator::DONE && i != text.length())
401                errln("Iterator reached end prematurely");
402            else if (c != text[i])
403                errln((UnicodeString)"Character mismatch at position " + i +
404                                    ", iterator has " + UCharToUnicodeString(c) +
405                                    ", string has " + UCharToUnicodeString(text[i]));
406
407            if (iter.current() != c)
408                errln("current() isn't working right");
409            if (iter.getIndex() != i)
410                errln("getIndex() isn't working right");
411
412            if (c != CharacterIterator::DONE) {
413                c = iter.next();
414                i++;
415            }
416        } while (c != CharacterIterator::DONE);
417        c=iter.next();
418        if(c!= CharacterIterator::DONE)
419            errln("next() didn't return DONE at the end");
420        c=iter.setIndex(text.length()+1);
421        if(c!= CharacterIterator::DONE)
422            errln("setIndex(len+1) didn't return DONE");
423
424        c = iter.last();
425        i = text.length() - 1;
426
427        logln("Testing backward iteration...");
428        do {
429            if (c == CharacterIterator::DONE && i >= 0)
430                errln("Iterator reached end prematurely");
431            else if (c != text[i])
432                errln((UnicodeString)"Character mismatch at position " + i +
433                                    ", iterator has " + UCharToUnicodeString(c) +
434                                    ", string has " + UCharToUnicodeString(text[i]));
435
436            if (iter.current() != c)
437                errln("current() isn't working right");
438            if (iter.getIndex() != i)
439                errln("getIndex() isn't working right");
440            if(iter.setIndex(i) != c)
441                errln("setIndex() isn't working right");
442
443            if (c != CharacterIterator::DONE) {
444                c = iter.previous();
445                i--;
446            }
447        } while (c != CharacterIterator::DONE);
448
449        c=iter.previous();
450        if(c!= CharacterIterator::DONE)
451            errln("previous didn't return DONE at the beginning");
452
453
454        //testing firstPostInc, nextPostInc, setTostart
455        i = 0;
456        c=iter.firstPostInc();
457        if(c != text[i])
458            errln((UnicodeString)"firstPostInc failed.  Expected->" +
459                         UCharToUnicodeString(text[i]) + " Got->" + UCharToUnicodeString(c));
460        if(iter.getIndex() != i+1)
461            errln((UnicodeString)"getIndex() after firstPostInc() failed");
462
463        iter.setToStart();
464        i=0;
465        if (iter.startIndex() != 0)
466            errln("setToStart failed");
467
468        logln("Testing forward iteration...");
469        do {
470            if (c != CharacterIterator::DONE)
471                c = iter.nextPostInc();
472
473            if(c != text[i])
474                errln((UnicodeString)"Character mismatch at position " + i +
475                                    (UnicodeString)", iterator has " + UCharToUnicodeString(c) +
476                                    (UnicodeString)", string has " + UCharToUnicodeString(text[i]));
477
478            i++;
479            if(iter.getIndex() != i)
480                errln("getIndex() aftr nextPostInc() isn't working right");
481            if(iter.current() != text[i])
482                errln("current() after nextPostInc() isn't working right");
483        } while (iter.hasNext());
484        c=iter.nextPostInc();
485        if(c!= CharacterIterator::DONE)
486            errln("nextPostInc() didn't return DONE at the beginning");
487    }
488
489    {
490        StringCharacterIterator iter(text, 5, 15, 10);
491        if (iter.startIndex() != 5 || iter.endIndex() != 15)
492            errln("creation of a restricted-range iterator failed");
493
494        if (iter.getIndex() != 10 || iter.current() != text[(int32_t)10])
495            errln("starting the iterator in the middle didn't work");
496
497        c = iter.first();
498        i = 5;
499
500        logln("Testing forward iteration over a range...");
501        do {
502            if (c == CharacterIterator::DONE && i != 15)
503                errln("Iterator reached end prematurely");
504            else if (c != text[i])
505                errln((UnicodeString)"Character mismatch at position " + i +
506                                    ", iterator has " + UCharToUnicodeString(c) +
507                                    ", string has " + UCharToUnicodeString(text[i]));
508
509            if (iter.current() != c)
510                errln("current() isn't working right");
511            if (iter.getIndex() != i)
512                errln("getIndex() isn't working right");
513            if(iter.setIndex(i) != c)
514                errln("setIndex() isn't working right");
515
516            if (c != CharacterIterator::DONE) {
517                c = iter.next();
518                i++;
519            }
520        } while (c != CharacterIterator::DONE);
521
522        c = iter.last();
523        i = 14;
524
525        logln("Testing backward iteration over a range...");
526        do {
527            if (c == CharacterIterator::DONE && i >= 5)
528                errln("Iterator reached end prematurely");
529            else if (c != text[i])
530                errln((UnicodeString)"Character mismatch at position " + i +
531                                    ", iterator has " + UCharToUnicodeString(c) +
532                                    ", string has " + UCharToUnicodeString(text[i]));
533
534            if (iter.current() != c)
535                errln("current() isn't working right");
536            if (iter.getIndex() != i)
537                errln("getIndex() isn't working right");
538
539            if (c != CharacterIterator::DONE) {
540                c = iter.previous();
541                i--;
542            }
543        } while (c != CharacterIterator::DONE);
544
545
546    }
547}
548
549//Tests for new API for utf-16 support
550void CharIterTest::TestIterationUChar32() {
551    UChar textChars[]={ 0x0061, 0x0062, 0xd841, 0xdc02, 0x20ac, 0xd7ff, 0xd842, 0xdc06, 0xd801, 0xdc00, 0x0061, 0x0000};
552    UnicodeString text(textChars);
553    UChar32 c;
554    int32_t i;
555    {
556        StringCharacterIterator   iter(text, 1);
557
558        UnicodeString iterText;
559        iter.getText(iterText);
560        if (iterText != text)
561          errln("iter.getText() failed");
562
563        if (iter.current32() != text[(int32_t)1])
564            errln("Iterator didn't start out in the right place.");
565
566        c=iter.setToStart();
567        i=0;
568        i=iter.move32(1, CharacterIterator::kStart);
569        c=iter.current32();
570        if(c != text.char32At(1) || i!=1)
571            errln("move32(1, kStart) didn't work correctly expected %X got %X", c, text.char32At(1) );
572
573        i=iter.move32(2, CharacterIterator::kCurrent);
574        c=iter.current32();
575        if(c != text.char32At(4) || i!=4)
576            errln("move32(2, kCurrent) didn't work correctly expected %X got %X i=%ld", c, text.char32At(4), i);
577
578        i=iter.move32(-2, CharacterIterator::kCurrent);
579        c=iter.current32();
580        if(c != text.char32At(1) || i!=1)
581            errln("move32(-2, kCurrent) didn't work correctly expected %X got %X i=%d", c, text.char32At(1), i);
582
583
584        i=iter.move32(-2, CharacterIterator::kEnd);
585        c=iter.current32();
586        if(c != text.char32At((text.length()-3)) || i!=(text.length()-3))
587            errln("move32(-2, kEnd) didn't work correctly expected %X got %X i=%d", c, text.char32At((text.length()-3)), i);
588
589
590        c = iter.first32();
591        i = 0;
592
593        if (iter.startIndex() != 0 || iter.endIndex() != text.length())
594            errln("startIndex() or endIndex() failed");
595
596        logln("Testing forward iteration...");
597        do {
598            /* logln("c=%d i=%d char32At=%d", c, i, text.char32At(i)); */
599            if (c == CharacterIterator::DONE && i != text.length())
600                errln("Iterator reached end prematurely");
601            else if(iter.hasNext() == FALSE && i != text.length())
602                errln("Iterator reached end prematurely.  Failed at hasNext");
603            else if (c != text.char32At(i))
604                errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
605
606            if (iter.current32() != c)
607                errln("current32() isn't working right");
608            if(iter.setIndex32(i) != c)
609                errln("setIndex32() isn't working right");
610            if (c != CharacterIterator::DONE) {
611                c = iter.next32();
612                i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i+2 : i+1;
613            }
614        } while (c != CharacterIterator::DONE);
615        if(iter.hasNext() == TRUE)
616           errln("hasNext() returned true at the end of the string");
617
618
619
620        c=iter.setToEnd();
621        if(iter.getIndex() != text.length() || iter.hasNext() != FALSE)
622            errln("setToEnd failed");
623
624        c=iter.next32();
625        if(c!= CharacterIterator::DONE)
626            errln("next32 didn't return DONE at the end");
627        c=iter.setIndex32(text.length()+1);
628        if(c!= CharacterIterator::DONE)
629            errln("setIndex32(len+1) didn't return DONE");
630
631
632        c = iter.last32();
633        i = text.length()-1;
634        logln("Testing backward iteration...");
635        do {
636            if (c == CharacterIterator::DONE && i >= 0)
637                errln((UnicodeString)"Iterator reached start prematurely for i=" + i);
638            else if(iter.hasPrevious() == FALSE && i>0)
639                errln((UnicodeString)"Iterator reached start prematurely for i=" + i);
640            else if (c != text.char32At(i))
641                errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
642
643            if (iter.current32() != c)
644                errln("current32() isn't working right");
645            if(iter.setIndex32(i) != c)
646                errln("setIndex32() isn't working right");
647            if (iter.getIndex() != i)
648                errln("getIndex() isn't working right");
649            if (c != CharacterIterator::DONE) {
650                c = iter.previous32();
651                i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i-2 : i-1;
652            }
653        } while (c != CharacterIterator::DONE);
654        if(iter.hasPrevious() == TRUE)
655            errln("hasPrevious returned true after reaching the start");
656
657        c=iter.previous32();
658        if(c!= CharacterIterator::DONE)
659            errln("previous32 didn't return DONE at the beginning");
660
661
662
663
664        //testing first32PostInc, next32PostInc, setTostart
665        i = 0;
666        c=iter.first32PostInc();
667        if(c != text.char32At(i))
668            errln("first32PostInc failed.  Expected->%X Got->%X", text.char32At(i), c);
669        if(iter.getIndex() != UTF16_CHAR_LENGTH(c) + i)
670            errln((UnicodeString)"getIndex() after first32PostInc() failed");
671
672        iter.setToStart();
673        i=0;
674        if (iter.startIndex() != 0)
675            errln("setToStart failed");
676
677        logln("Testing forward iteration...");
678        do {
679            if (c != CharacterIterator::DONE)
680                c = iter.next32PostInc();
681
682            if(c != text.char32At(i))
683                errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
684
685            i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i+2 : i+1;
686            if(iter.getIndex() != i)
687                errln("getIndex() aftr next32PostInc() isn't working right");
688            if(iter.current32() != text.char32At(i))
689                errln("current() after next32PostInc() isn't working right");
690        } while (iter.hasNext());
691        c=iter.next32PostInc();
692        if(c!= CharacterIterator::DONE)
693            errln("next32PostInc() didn't return DONE at the beginning");
694
695
696    }
697
698    {
699        StringCharacterIterator iter(text, 1, 11, 10);
700        if (iter.startIndex() != 1 || iter.endIndex() != 11)
701            errln("creation of a restricted-range iterator failed");
702
703        if (iter.getIndex() != 10 || iter.current32() != text.char32At(10))
704            errln("starting the iterator in the middle didn't work");
705
706        c = iter.first32();
707
708        i = 1;
709
710        logln("Testing forward iteration over a range...");
711        do {
712            if (c == CharacterIterator::DONE && i != 11)
713                errln("Iterator reached end prematurely");
714            else if(iter.hasNext() == FALSE)
715                errln("Iterator reached end prematurely");
716            else if (c != text.char32At(i))
717                errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
718
719            if (iter.current32() != c)
720                errln("current32() isn't working right");
721            if(iter.setIndex32(i) != c)
722                errln("setIndex32() isn't working right");
723
724            if (c != CharacterIterator::DONE) {
725                c = iter.next32();
726                i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i+2 : i+1;
727            }
728        } while (c != CharacterIterator::DONE);
729        c=iter.next32();
730        if(c != CharacterIterator::DONE)
731            errln("error in next32()");
732
733
734
735        c=iter.last32();
736        i = 10;
737        logln("Testing backward iteration over a range...");
738        do {
739            if (c == CharacterIterator::DONE && i >= 5)
740                errln("Iterator reached start prematurely");
741            else if(iter.hasPrevious() == FALSE && i > 5)
742                errln("Iterator reached start prematurely");
743            else if (c != text.char32At(i))
744                errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
745            if (iter.current32() != c)
746                errln("current32() isn't working right");
747            if (iter.getIndex() != i)
748                errln("getIndex() isn't working right");
749            if(iter.setIndex32(i) != c)
750                errln("setIndex32() isn't working right");
751
752            if (c != CharacterIterator::DONE) {
753                c = iter.previous32();
754                i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i-2 : i-1;
755            }
756
757        } while (c != CharacterIterator::DONE);
758        c=iter.previous32();
759        if(c!= CharacterIterator::DONE)
760            errln("error on previous32");
761
762
763    }
764}
765
766void CharIterTest::TestUCharIterator(UCharIterator *iter, CharacterIterator &ci,
767                                     const char *moves, const char *which) {
768    int32_t m;
769    UChar32 c, c2;
770    UBool h, h2;
771
772    for(m=0;; ++m) {
773        // move both iter and s[index]
774        switch(moves[m]) {
775        case '0':
776            h=iter->hasNext(iter);
777            h2=ci.hasNext();
778            c=iter->current(iter);
779            c2=ci.current();
780            break;
781        case '|':
782            h=iter->hasNext(iter);
783            h2=ci.hasNext();
784            c=uiter_current32(iter);
785            c2=ci.current32();
786            break;
787
788        case '+':
789            h=iter->hasNext(iter);
790            h2=ci.hasNext();
791            c=iter->next(iter);
792            c2=ci.nextPostInc();
793            break;
794        case '>':
795            h=iter->hasNext(iter);
796            h2=ci.hasNext();
797            c=uiter_next32(iter);
798            c2=ci.next32PostInc();
799            break;
800
801        case '-':
802            h=iter->hasPrevious(iter);
803            h2=ci.hasPrevious();
804            c=iter->previous(iter);
805            c2=ci.previous();
806            break;
807        case '<':
808            h=iter->hasPrevious(iter);
809            h2=ci.hasPrevious();
810            c=uiter_previous32(iter);
811            c2=ci.previous32();
812            break;
813
814        case '2':
815            h=h2=FALSE;
816            c=(UChar32)iter->move(iter, 2, UITER_CURRENT);
817            c2=(UChar32)ci.move(2, CharacterIterator::kCurrent);
818            break;
819
820        case '8':
821            h=h2=FALSE;
822            c=(UChar32)iter->move(iter, -2, UITER_CURRENT);
823            c2=(UChar32)ci.move(-2, CharacterIterator::kCurrent);
824            break;
825
826        case 0:
827            return;
828        default:
829            errln("error: unexpected move character '%c' in \"%s\"", moves[m], moves);
830            return;
831        }
832
833        // compare results
834        if(c2==0xffff) {
835            c2=(UChar32)-1;
836        }
837        if(c!=c2 || h!=h2 || ci.getIndex()!=iter->getIndex(iter, UITER_CURRENT)) {
838            errln("error: UCharIterator(%s) misbehaving at \"%s\"[%d]='%c'", which, moves, m, moves[m]);
839        }
840    }
841}
842
843void CharIterTest::TestUCharIterator() {
844    // test string of length 8
845    UnicodeString s=UnicodeString("a \\U00010001b\\U0010fffdz", "").unescape();
846    const char *const moves=
847        "0+++++++++" // 10 moves per line
848        "----0-----"
849        ">>|>>>>>>>"
850        "<<|<<<<<<<"
851        "22+>8>-8+2";
852
853    StringCharacterIterator sci(s), compareCI(s);
854
855    UCharIterator sIter, cIter, rIter;
856
857    uiter_setString(&sIter, s.getBuffer(), s.length());
858    uiter_setCharacterIterator(&cIter, &sci);
859    uiter_setReplaceable(&rIter, &s);
860
861    TestUCharIterator(&sIter, compareCI, moves, "uiter_setString");
862    compareCI.setIndex(0);
863    TestUCharIterator(&cIter, compareCI, moves, "uiter_setCharacterIterator");
864    compareCI.setIndex(0);
865    TestUCharIterator(&rIter, compareCI, moves, "uiter_setReplaceable");
866
867    // test move & getIndex some more
868    sIter.start=2;
869    sIter.index=3;
870    sIter.limit=5;
871    if( sIter.getIndex(&sIter, UITER_ZERO)!=0 ||
872        sIter.getIndex(&sIter, UITER_START)!=2 ||
873        sIter.getIndex(&sIter, UITER_CURRENT)!=3 ||
874        sIter.getIndex(&sIter, UITER_LIMIT)!=5 ||
875        sIter.getIndex(&sIter, UITER_LENGTH)!=s.length()
876    ) {
877        errln("error: UCharIterator(string).getIndex returns wrong index");
878    }
879
880    if( sIter.move(&sIter, 4, UITER_ZERO)!=4 ||
881        sIter.move(&sIter, 1, UITER_START)!=3 ||
882        sIter.move(&sIter, 3, UITER_CURRENT)!=5 ||
883        sIter.move(&sIter, -1, UITER_LIMIT)!=4 ||
884        sIter.move(&sIter, -5, UITER_LENGTH)!=3 ||
885        sIter.move(&sIter, 0, UITER_CURRENT)!=sIter.getIndex(&sIter, UITER_CURRENT) ||
886        sIter.getIndex(&sIter, UITER_CURRENT)!=3
887    ) {
888        errln("error: UCharIterator(string).move sets/returns wrong index");
889    }
890
891    sci=StringCharacterIterator(s, 2, 5, 3);
892    uiter_setCharacterIterator(&cIter, &sci);
893    if( cIter.getIndex(&cIter, UITER_ZERO)!=0 ||
894        cIter.getIndex(&cIter, UITER_START)!=2 ||
895        cIter.getIndex(&cIter, UITER_CURRENT)!=3 ||
896        cIter.getIndex(&cIter, UITER_LIMIT)!=5 ||
897        cIter.getIndex(&cIter, UITER_LENGTH)!=s.length()
898    ) {
899        errln("error: UCharIterator(character iterator).getIndex returns wrong index");
900    }
901
902    if( cIter.move(&cIter, 4, UITER_ZERO)!=4 ||
903        cIter.move(&cIter, 1, UITER_START)!=3 ||
904        cIter.move(&cIter, 3, UITER_CURRENT)!=5 ||
905        cIter.move(&cIter, -1, UITER_LIMIT)!=4 ||
906        cIter.move(&cIter, -5, UITER_LENGTH)!=3 ||
907        cIter.move(&cIter, 0, UITER_CURRENT)!=cIter.getIndex(&cIter, UITER_CURRENT) ||
908        cIter.getIndex(&cIter, UITER_CURRENT)!=3
909    ) {
910        errln("error: UCharIterator(character iterator).move sets/returns wrong index");
911    }
912
913
914    if(cIter.getIndex(&cIter, (enum UCharIteratorOrigin)-1) != -1)
915    {
916        errln("error: UCharIterator(char iter).getIndex did not return error value");
917    }
918
919    if(cIter.move(&cIter, 0, (enum UCharIteratorOrigin)-1) != -1)
920    {
921        errln("error: UCharIterator(char iter).move did not return error value");
922    }
923
924
925    if(rIter.getIndex(&rIter, (enum UCharIteratorOrigin)-1) != -1)
926    {
927        errln("error: UCharIterator(repl iter).getIndex did not return error value");
928    }
929
930    if(rIter.move(&rIter, 0, (enum UCharIteratorOrigin)-1) != -1)
931    {
932        errln("error: UCharIterator(repl iter).move did not return error value");
933    }
934
935
936    if(sIter.getIndex(&sIter, (enum UCharIteratorOrigin)-1) != -1)
937    {
938        errln("error: UCharIterator(string iter).getIndex did not return error value");
939    }
940
941    if(sIter.move(&sIter, 0, (enum UCharIteratorOrigin)-1) != -1)
942    {
943        errln("error: UCharIterator(string iter).move did not return error value");
944    }
945
946    /* Testing function coverage on bad input */
947    UErrorCode status = U_ZERO_ERROR;
948    uiter_setString(&sIter, NULL, 1);
949    uiter_setState(&sIter, 1, &status);
950    if (status != U_UNSUPPORTED_ERROR) {
951        errln("error: uiter_setState returned %s instead of U_UNSUPPORTED_ERROR", u_errorName(status));
952    }
953    status = U_ZERO_ERROR;
954    uiter_setState(NULL, 1, &status);
955    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
956        errln("error: uiter_setState returned %s instead of U_ILLEGAL_ARGUMENT_ERROR", u_errorName(status));
957    }
958    if (uiter_getState(&sIter) != UITER_NO_STATE) {
959        errln("error: uiter_getState did not return UITER_NO_STATE on bad input");
960    }
961}
962
963// subclass test, and completing API coverage -------------------------------
964
965class SubCharIter : public CharacterIterator {
966public:
967    // public default constructor, to get coverage of CharacterIterator()
968    SubCharIter() : CharacterIterator() {
969        textLength=end=LENGTHOF(s);
970        s[0]=0x61;      // 'a'
971        s[1]=0xd900;    // U+50400
972        s[2]=0xdd00;
973        s[3]=0x2029;    // PS
974    }
975
976    // useful stuff, mostly dummy but testing coverage and subclassability
977    virtual UChar nextPostInc() {
978        if(pos<LENGTHOF(s)) {
979            return s[pos++];
980        } else {
981            return DONE;
982        }
983    }
984
985    virtual UChar32 next32PostInc() {
986        if(pos<LENGTHOF(s)) {
987            UChar32 c;
988            U16_NEXT(s, pos, LENGTHOF(s), c);
989            return c;
990        } else {
991            return DONE;
992        }
993    }
994
995    virtual UBool hasNext() {
996        return pos<LENGTHOF(s);
997    }
998
999    virtual UChar first() {
1000        pos=0;
1001        return s[0];
1002    }
1003
1004    virtual UChar32 first32() {
1005        UChar32 c;
1006        pos=0;
1007        U16_NEXT(s, pos, LENGTHOF(s), c);
1008        pos=0;
1009        return c;
1010    }
1011
1012    virtual UChar setIndex(int32_t position) {
1013        if(0<=position && position<=LENGTHOF(s)) {
1014            pos=position;
1015            if(pos<LENGTHOF(s)) {
1016                return s[pos];
1017            }
1018        }
1019        return DONE;
1020    }
1021
1022    virtual UChar32 setIndex32(int32_t position) {
1023        if(0<=position && position<=LENGTHOF(s)) {
1024            pos=position;
1025            if(pos<LENGTHOF(s)) {
1026                UChar32 c;
1027                U16_GET(s, 0, pos, LENGTHOF(s), c);
1028                return c;
1029            }
1030        }
1031        return DONE;
1032    }
1033
1034    virtual UChar current() const {
1035        if(pos<LENGTHOF(s)) {
1036            return s[pos];
1037        } else {
1038            return DONE;
1039        }
1040    }
1041
1042    virtual UChar32 current32() const {
1043        if(pos<LENGTHOF(s)) {
1044            UChar32 c;
1045            U16_GET(s, 0, pos, LENGTHOF(s), c);
1046            return c;
1047        } else {
1048            return DONE;
1049        }
1050    }
1051
1052    virtual UChar next() {
1053        if(pos<LENGTHOF(s) && ++pos<LENGTHOF(s)) {
1054            return s[pos];
1055        } else {
1056            return DONE;
1057        }
1058    }
1059
1060    virtual UChar32 next32() {
1061        if(pos<LENGTHOF(s)) {
1062            U16_FWD_1(s, pos, LENGTHOF(s));
1063        }
1064        if(pos<LENGTHOF(s)) {
1065            UChar32 c;
1066            int32_t i=pos;
1067            U16_NEXT(s, i, LENGTHOF(s), c);
1068            return c;
1069        } else {
1070            return DONE;
1071        }
1072    }
1073
1074    virtual UBool hasPrevious() {
1075        return pos>0;
1076    }
1077
1078    virtual void getText(UnicodeString &result) {
1079        result.setTo(s, LENGTHOF(s));
1080    }
1081
1082    // dummy implementations of other pure virtual base class functions
1083    virtual UBool operator==(const ForwardCharacterIterator &that) const {
1084        return
1085            this==&that ||
1086            (typeid(*this)==typeid(that) && pos==((SubCharIter &)that).pos);
1087    }
1088
1089    virtual int32_t hashCode() const {
1090        return 2;
1091    }
1092
1093    virtual CharacterIterator *clone() const {
1094        return NULL;
1095    }
1096
1097    virtual UChar last() {
1098        return 0;
1099    }
1100
1101    virtual UChar32 last32() {
1102        return 0;
1103    }
1104
1105    virtual UChar previous() {
1106        return 0;
1107    }
1108
1109    virtual UChar32 previous32() {
1110        return 0;
1111    }
1112
1113    virtual int32_t move(int32_t /*delta*/, EOrigin /*origin*/) {
1114        return 0;
1115    }
1116
1117    virtual int32_t move32(int32_t /*delta*/, EOrigin /*origin*/) {
1118        return 0;
1119    }
1120
1121    // RTTI
1122    static UClassID getStaticClassID() {
1123        return (UClassID)(&fgClassID);
1124    }
1125
1126    virtual UClassID getDynamicClassID() const {
1127        return getStaticClassID();
1128    }
1129
1130private:
1131    // dummy string data
1132    UChar s[4];
1133
1134    static const char fgClassID;
1135};
1136
1137const char SubCharIter::fgClassID = 0;
1138
1139class SubStringCharIter : public StringCharacterIterator {
1140public:
1141    SubStringCharIter() {
1142        setText(UNICODE_STRING("abc", 3));
1143    }
1144};
1145
1146class SubUCharCharIter : public UCharCharacterIterator {
1147public:
1148    SubUCharCharIter() {
1149        setText(u, 3);
1150    }
1151
1152private:
1153    static const UChar u[3];
1154};
1155
1156const UChar SubUCharCharIter::u[3]={ 0x61, 0x62, 0x63 };
1157
1158void CharIterTest::TestCharIteratorSubClasses() {
1159    SubCharIter *p;
1160
1161    // coverage - call functions that are not otherwise tested
1162    // first[32]PostInc() are default implementations that are overridden
1163    // in ICU's own CharacterIterator subclasses
1164    p=new SubCharIter;
1165    if(p->firstPostInc()!=0x61) {
1166        errln("SubCharIter.firstPosInc() failed\n");
1167    }
1168    delete p;
1169
1170    p=new SubCharIter[2];
1171    if(p[1].first32PostInc()!=0x61) {
1172        errln("SubCharIter.first32PosInc() failed\n");
1173    }
1174    delete [] p;
1175
1176    // coverage: StringCharacterIterator default constructor
1177    SubStringCharIter sci;
1178    if(sci.firstPostInc()!=0x61) {
1179        errln("SubStringCharIter.firstPostInc() failed\n");
1180    }
1181
1182    // coverage: UCharCharacterIterator default constructor
1183    SubUCharCharIter uci;
1184    if(uci.firstPostInc()!=0x61) {
1185        errln("SubUCharCharIter.firstPostInc() failed\n");
1186    }
1187}
1188