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