1 // © 2016 and later: Unicode, Inc. and others. 
   2 // License & terms of use: http://www.unicode.org/copyright.html 
   3 /******************************************************************** 
   5  * Copyright (c) 2001-2010, International Business Machines Corporation and 
   6  * others. All Rights Reserved. 
   7  ********************************************************************/ 
   8 /************************************************************************ 
   9 *   This test program is intended for testing Replaceable class. 
  11 *   Date        Name        Description 
  12 *   11/28/2001  hshih       Ported back from Java. 
  14 ************************************************************************/ 
  16 #include "unicode/utypes.h" 
  18 #if !UCONFIG_NO_TRANSLITERATION 
  24 #include "unicode/rep.h" 
  27 //--------------------------------------------- 
  29 //--------------------------------------------- 
  32      * This is a test class that simulates styled text. 
  33      * It associates a style number (0..65535) with each character, 
  34      * and maintains that style in the normal fashion: 
  35      * When setting text from raw string or characters,<br> 
  36      * Set the styles to the style of the first character replaced.<br> 
  37      * If no characters are replaced, use the style of the previous character.<br> 
  38      * If at start, use the following character<br> 
  39      * Otherwise use NO_STYLE. 
  41 class TestReplaceable 
: public Replaceable 
{ 
  45     static const UChar NO_STYLE
; 
  47     static const UChar NO_STYLE_MARK
; 
  50      * The address of this static class variable serves as this class's ID 
  51      * for ICU "poor man's RTTI". 
  53     static const char fgClassID
; 
  56     TestReplaceable (const UnicodeString
& text
,  
  57                      const UnicodeString
& newStyles
) { 
  60         for (int i 
= 0; i 
< text
.length(); ++i
) { 
  61             if (i 
< newStyles
.length()) { 
  62                 s
.append(newStyles
.charAt(i
)); 
  64                 if (text
.charAt(i
) == NO_STYLE_MARK
) { 
  67                     s
.append((UChar
)(i 
+ 0x0031)); 
  74     virtual Replaceable 
*clone() const { 
  75         return new TestReplaceable(chars
, styles
); 
  78     ~TestReplaceable(void) {} 
  80     UnicodeString 
getStyles() { 
  84     UnicodeString 
toString() { 
  85         UnicodeString s 
= chars
; 
  92     void extractBetween(int32_t start
, int32_t limit
, UnicodeString
& result
) const { 
  93         chars
.extractBetween(start
, limit
, result
); 
  97      * ICU "poor man's RTTI", returns a UClassID for this class. 
 101     static inline UClassID 
getStaticClassID() { return (UClassID
)&fgClassID
; } 
 104      * ICU "poor man's RTTI", returns a UClassID for the actual class. 
 108     virtual inline UClassID 
getDynamicClassID() const { return getStaticClassID(); } 
 111     virtual int32_t getLength() const { 
 112         return chars
.length(); 
 115     virtual UChar 
getCharAt(int32_t offset
) const{ 
 116         return chars
.charAt(offset
); 
 119     virtual UChar32 
getChar32At(int32_t offset
) const{ 
 120         return chars
.char32At(offset
); 
 123     void fixStyles(int32_t start
, int32_t limit
, int32_t newLen
) { 
 124         UChar newStyle 
= NO_STYLE
; 
 125         if (start 
!= limit 
&& styles
.charAt(start
) != NO_STYLE
) { 
 126             newStyle 
= styles
.charAt(start
); 
 127         } else if (start 
> 0 && getCharAt(start
-1) != NO_STYLE_MARK
) { 
 128             newStyle 
= styles
.charAt(start
-1); 
 129         } else if (limit 
< styles
.length()) { 
 130             newStyle 
= styles
.charAt(limit
); 
 132         // dumb implementation for now. 
 134         for (int i 
= 0; i 
< newLen
; ++i
) { 
 135             // this doesn't really handle an embedded NO_STYLE_MARK 
 136             // in the middle of a long run of characters right -- but 
 137             // that case shouldn't happen anyway 
 138             if (getCharAt(start
+i
) == NO_STYLE_MARK
) { 
 144         styles
.replaceBetween(start
, limit
, s
); 
 147     virtual void handleReplaceBetween(int32_t start
, int32_t limit
, const UnicodeString
& text
) { 
 149         this->extractBetween(start
, limit
, s
); 
 150         if (s 
== text
) return; // NO ACTION! 
 151         this->chars
.replaceBetween(start
, limit
, text
); 
 152         fixStyles(start
, limit
, text
.length()); 
 156     virtual void copy(int32_t start
, int32_t limit
, int32_t dest
) { 
 157         chars
.copy(start
, limit
, dest
); 
 158         styles
.copy(start
, limit
, dest
); 
 162 const char TestReplaceable::fgClassID
=0; 
 164 const UChar 
TestReplaceable::NO_STYLE  
= 0x005F; 
 166 const UChar 
TestReplaceable::NO_STYLE_MARK 
= 0xFFFF; 
 169 ReplaceableTest::runIndexedTest(int32_t index
, UBool exec
, 
 170                                       const char* &name
, char* /*par*/) { 
 172         TESTCASE(0,TestReplaceableClass
); 
 173         default: name 
= ""; break; 
 178  * Dummy Replaceable implementation for better API/code coverage. 
 180 class NoopReplaceable 
: public Replaceable 
{ 
 182     virtual int32_t getLength() const { 
 186     virtual UChar 
getCharAt(int32_t /*offset*/) const{ 
 190     virtual UChar32 
getChar32At(int32_t /*offset*/) const{ 
 194     void extractBetween(int32_t /*start*/, int32_t /*limit*/, UnicodeString
& result
) const { 
 198     virtual void handleReplaceBetween(int32_t /*start*/, int32_t /*limit*/, const UnicodeString 
&/*text*/) { 
 202     virtual void copy(int32_t /*start*/, int32_t /*limit*/, int32_t /*dest*/) { 
 206     static inline UClassID 
getStaticClassID() { return (UClassID
)&fgClassID
; } 
 207     virtual inline UClassID 
getDynamicClassID() const { return getStaticClassID(); } 
 210     static const char fgClassID
; 
 213 const char NoopReplaceable::fgClassID
=0; 
 215 void ReplaceableTest::TestReplaceableClass(void) { 
 216     UChar rawTestArray
[][6] = { 
 217         {0x0041, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // ABCD 
 218         {0x0061, 0x0062, 0x0063, 0x0064, 0x00DF, 0x0000}, // abcd\u00DF 
 219         {0x0061, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // aBCD 
 220         {0x0041, 0x0300, 0x0045, 0x0300, 0x0000, 0x0000}, // A\u0300E\u0300 
 221         {0x00C0, 0x00C8, 0x0000, 0x0000, 0x0000, 0x0000}, // \u00C0\u00C8 
 222         {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */ 
 223         {0x0077, 0x0078, 0x0079, 0x007A, 0x0000, 0x0000}, /* "wxyz" */ 
 224         {0x0077, 0x0078, 0x0079, 0x007A, 0x0075, 0x0000}, /* "wxyzu" */ 
 225         {0x0078, 0x0079, 0x007A, 0x0000, 0x0000, 0x0000}, /* "xyz" */ 
 226         {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */ 
 227         {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */ 
 228         {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */ 
 230     check("Lower", rawTestArray
[0], "1234"); 
 231     check("Upper", rawTestArray
[1], "123455"); // must map 00DF to SS 
 232     check("Title", rawTestArray
[2], "1234"); 
 233     check("NFC",   rawTestArray
[3], "13"); 
 234     check("NFD",   rawTestArray
[4], "1122"); 
 235     check("*(x) > A $1 B", rawTestArray
[5], "11223"); 
 236     check("*(x)(y) > A $2 B $1 C $2 D", rawTestArray
[6], "113322334"); 
 237     check("*(x)(y)(z) > A $3 B $2 C $1 D", rawTestArray
[7], "114433225"); 
 238     // Disabled for 2.4.  TODO Revisit in 2.6 or later. 
 239     //check("*x > a", rawTestArray[8], "223"); // expect "123"? 
 240     //check("*x > a", rawTestArray[9], "113"); // expect "123"? 
 241     //check("*x > a", rawTestArray[10], "_33"); // expect "_23"? 
 242     //check("*(x) > A $1 B", rawTestArray[11], "__223"); 
 244     // improve API/code coverage 
 245     NoopReplaceable noop
; 
 247     if((p
=noop
.clone())!=NULL
) { 
 248         errln("Replaceable::clone() does not return NULL"); 
 252     if(!noop
.hasMetaData()) { 
 253         errln("Replaceable::hasMetaData() does not return TRUE"); 
 256     // try to call the compiler-provided 
 257     // UMemory/UObject/Replaceable assignment operators 
 258     NoopReplaceable noop2
; 
 260     if((p
=noop2
.clone())!=NULL
) { 
 261         errln("noop2.Replaceable::clone() does not return NULL"); 
 265     // try to call the compiler-provided 
 266     // UMemory/UObject/Replaceable copy constructors 
 267     NoopReplaceable 
noop3(noop
); 
 268     if((p
=noop3
.clone())!=NULL
) { 
 269         errln("noop3.Replaceable::clone() does not return NULL"); 
 274 void ReplaceableTest::check(const UnicodeString
& transliteratorName
,  
 275                             const UnicodeString
& test
,  
 276                             const UnicodeString
& shouldProduceStyles
)  
 278     UErrorCode status 
= U_ZERO_ERROR
; 
 279     TestReplaceable 
*tr 
= new TestReplaceable(test
, ""); 
 280     UnicodeString expectedStyles 
= shouldProduceStyles
; 
 281     UnicodeString original 
= tr
->toString(); 
 284     if (transliteratorName
.charAt(0) == 0x2A /*'*'*/) { 
 285         UnicodeString 
rules(transliteratorName
); 
 288         t 
= Transliterator::createFromRules("test", rules
, UTRANS_FORWARD
, 
 292         TestReplaceable 
*tr2 
= (TestReplaceable 
*)tr
->clone(); 
 298         t 
= Transliterator::createInstance(transliteratorName
, UTRANS_FORWARD
, status
); 
 300     if (U_FAILURE(status
)) { 
 301         dataerrln("FAIL: failed to create the " + transliteratorName 
+ " transliterator"); 
 305     t
->transliterate(*tr
); 
 306     UnicodeString newStyles 
= tr
->getStyles(); 
 307     if (newStyles 
!= expectedStyles
) { 
 308         errln("FAIL Styles: " + transliteratorName 
+ "{" + original 
+ "} => " 
 309             + tr
->toString() + "; should be {" + expectedStyles 
+ "}!"); 
 312         log(transliteratorName
); 
 316         logln(tr
->toString()); 
 322 #endif /* #if !UCONFIG_NO_TRANSLITERATION */