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