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