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