1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 2001-2010, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ********************************************************************/ 6 /************************************************************************ 7 * This test program is intended for testing Replaceable class. 8 * 9 * Date Name Description 10 * 11/28/2001 hshih Ported back from Java. 11 * 12 ************************************************************************/ 13 14 #include "unicode/utypes.h" 15 16 #if !UCONFIG_NO_TRANSLITERATION 17 18 #include "ittrans.h" 19 #include <string.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include "unicode/rep.h" 23 #include "reptest.h" 24 25 //--------------------------------------------- 26 // runIndexedTest 27 //--------------------------------------------- 28 29 /** 30 * This is a test class that simulates styled text. 31 * It associates a style number (0..65535) with each character, 32 * and maintains that style in the normal fashion: 33 * When setting text from raw string or characters,<br> 34 * Set the styles to the style of the first character replaced.<br> 35 * If no characters are replaced, use the style of the previous character.<br> 36 * If at start, use the following character<br> 37 * Otherwise use NO_STYLE. 38 */ 39 class TestReplaceable : public Replaceable { 40 UnicodeString chars; 41 UnicodeString styles; 42 43 static const UChar NO_STYLE; 44 45 static const UChar NO_STYLE_MARK; 46 47 /** 48 * The address of this static class variable serves as this class's ID 49 * for ICU "poor man's RTTI". 50 */ 51 static const char fgClassID; 52 53 public: 54 TestReplaceable (const UnicodeString& text, 55 const UnicodeString& newStyles) { 56 chars = text; 57 UnicodeString s; 58 for (int i = 0; i < text.length(); ++i) { 59 if (i < newStyles.length()) { 60 s.append(newStyles.charAt(i)); 61 } else { 62 if (text.charAt(i) == NO_STYLE_MARK) { 63 s.append(NO_STYLE); 64 } else { 65 s.append((UChar)(i + 0x0031)); 66 } 67 } 68 } 69 this->styles = s; 70 } 71 72 virtual Replaceable *clone() const { 73 return new TestReplaceable(chars, styles); 74 } 75 76 ~TestReplaceable(void) {} 77 78 UnicodeString getStyles() { 79 return styles; 80 } 81 82 UnicodeString toString() { 83 UnicodeString s = chars; 84 s.append("{"); 85 s.append(styles); 86 s.append("}"); 87 return s; 88 } 89 90 void extractBetween(int32_t start, int32_t limit, UnicodeString& result) const { 91 chars.extractBetween(start, limit, result); 92 } 93 94 /** 95 * ICU "poor man's RTTI", returns a UClassID for this class. 96 * 97 * @draft ICU 2.2 98 */ 99 static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } 100 101 /** 102 * ICU "poor man's RTTI", returns a UClassID for the actual class. 103 * 104 * @draft ICU 2.2 105 */ 106 virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } 107 108 protected: 109 virtual int32_t getLength() const { 110 return chars.length(); 111 } 112 113 virtual UChar getCharAt(int32_t offset) const{ 114 return chars.charAt(offset); 115 } 116 117 virtual UChar32 getChar32At(int32_t offset) const{ 118 return chars.char32At(offset); 119 } 120 121 void fixStyles(int32_t start, int32_t limit, int32_t newLen) { 122 UChar newStyle = NO_STYLE; 123 if (start != limit && styles.charAt(start) != NO_STYLE) { 124 newStyle = styles.charAt(start); 125 } else if (start > 0 && getCharAt(start-1) != NO_STYLE_MARK) { 126 newStyle = styles.charAt(start-1); 127 } else if (limit < styles.length()) { 128 newStyle = styles.charAt(limit); 129 } 130 // dumb implementation for now. 131 UnicodeString s; 132 for (int i = 0; i < newLen; ++i) { 133 // this doesn't really handle an embedded NO_STYLE_MARK 134 // in the middle of a long run of characters right -- but 135 // that case shouldn't happen anyway 136 if (getCharAt(start+i) == NO_STYLE_MARK) { 137 s.append(NO_STYLE); 138 } else { 139 s.append(newStyle); 140 } 141 } 142 styles.replaceBetween(start, limit, s); 143 } 144 145 virtual void handleReplaceBetween(int32_t start, int32_t limit, const UnicodeString& text) { 146 UnicodeString s; 147 this->extractBetween(start, limit, s); 148 if (s == text) return; // NO ACTION! 149 this->chars.replaceBetween(start, limit, text); 150 fixStyles(start, limit, text.length()); 151 } 152 153 154 virtual void copy(int32_t start, int32_t limit, int32_t dest) { 155 chars.copy(start, limit, dest); 156 styles.copy(start, limit, dest); 157 } 158 }; 159 160 const char TestReplaceable::fgClassID=0; 161 162 const UChar TestReplaceable::NO_STYLE = 0x005F; 163 164 const UChar TestReplaceable::NO_STYLE_MARK = 0xFFFF; 165 166 void 167 ReplaceableTest::runIndexedTest(int32_t index, UBool exec, 168 const char* &name, char* /*par*/) { 169 switch (index) { 170 TESTCASE(0,TestReplaceableClass); 171 default: name = ""; break; 172 } 173 } 174 175 /* 176 * Dummy Replaceable implementation for better API/code coverage. 177 */ 178 class NoopReplaceable : public Replaceable { 179 public: 180 virtual int32_t getLength() const { 181 return 0; 182 } 183 184 virtual UChar getCharAt(int32_t /*offset*/) const{ 185 return 0xffff; 186 } 187 188 virtual UChar32 getChar32At(int32_t /*offset*/) const{ 189 return 0xffff; 190 } 191 192 void extractBetween(int32_t /*start*/, int32_t /*limit*/, UnicodeString& result) const { 193 result.remove(); 194 } 195 196 virtual void handleReplaceBetween(int32_t /*start*/, int32_t /*limit*/, const UnicodeString &/*text*/) { 197 /* do nothing */ 198 } 199 200 virtual void copy(int32_t /*start*/, int32_t /*limit*/, int32_t /*dest*/) { 201 /* do nothing */ 202 } 203 204 static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } 205 virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } 206 207 private: 208 static const char fgClassID; 209 }; 210 211 const char NoopReplaceable::fgClassID=0; 212 213 void ReplaceableTest::TestReplaceableClass(void) { 214 UChar rawTestArray[][6] = { 215 {0x0041, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // ABCD 216 {0x0061, 0x0062, 0x0063, 0x0064, 0x00DF, 0x0000}, // abcd\u00DF 217 {0x0061, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // aBCD 218 {0x0041, 0x0300, 0x0045, 0x0300, 0x0000, 0x0000}, // A\u0300E\u0300 219 {0x00C0, 0x00C8, 0x0000, 0x0000, 0x0000, 0x0000}, // \u00C0\u00C8 220 {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */ 221 {0x0077, 0x0078, 0x0079, 0x007A, 0x0000, 0x0000}, /* "wxyz" */ 222 {0x0077, 0x0078, 0x0079, 0x007A, 0x0075, 0x0000}, /* "wxyzu" */ 223 {0x0078, 0x0079, 0x007A, 0x0000, 0x0000, 0x0000}, /* "xyz" */ 224 {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */ 225 {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */ 226 {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */ 227 }; 228 check("Lower", rawTestArray[0], "1234"); 229 check("Upper", rawTestArray[1], "123455"); // must map 00DF to SS 230 check("Title", rawTestArray[2], "1234"); 231 check("NFC", rawTestArray[3], "13"); 232 check("NFD", rawTestArray[4], "1122"); 233 check("*(x) > A $1 B", rawTestArray[5], "11223"); 234 check("*(x)(y) > A $2 B $1 C $2 D", rawTestArray[6], "113322334"); 235 check("*(x)(y)(z) > A $3 B $2 C $1 D", rawTestArray[7], "114433225"); 236 // Disabled for 2.4. TODO Revisit in 2.6 or later. 237 //check("*x > a", rawTestArray[8], "223"); // expect "123"? 238 //check("*x > a", rawTestArray[9], "113"); // expect "123"? 239 //check("*x > a", rawTestArray[10], "_33"); // expect "_23"? 240 //check("*(x) > A $1 B", rawTestArray[11], "__223"); 241 242 // improve API/code coverage 243 NoopReplaceable noop; 244 Replaceable *p; 245 if((p=noop.clone())!=NULL) { 246 errln("Replaceable::clone() does not return NULL"); 247 delete p; 248 } 249 250 if(!noop.hasMetaData()) { 251 errln("Replaceable::hasMetaData() does not return TRUE"); 252 } 253 254 // try to call the compiler-provided 255 // UMemory/UObject/Replaceable assignment operators 256 NoopReplaceable noop2; 257 noop2=noop; 258 if((p=noop2.clone())!=NULL) { 259 errln("noop2.Replaceable::clone() does not return NULL"); 260 delete p; 261 } 262 263 // try to call the compiler-provided 264 // UMemory/UObject/Replaceable copy constructors 265 NoopReplaceable noop3(noop); 266 if((p=noop3.clone())!=NULL) { 267 errln("noop3.Replaceable::clone() does not return NULL"); 268 delete p; 269 } 270 } 271 272 void ReplaceableTest::check(const UnicodeString& transliteratorName, 273 const UnicodeString& test, 274 const UnicodeString& shouldProduceStyles) 275 { 276 UErrorCode status = U_ZERO_ERROR; 277 TestReplaceable *tr = new TestReplaceable(test, ""); 278 UnicodeString expectedStyles = shouldProduceStyles; 279 UnicodeString original = tr->toString(); 280 281 Transliterator* t; 282 if (transliteratorName.charAt(0) == 0x2A /*'*'*/) { 283 UnicodeString rules(transliteratorName); 284 rules.remove(0,1); 285 UParseError pe; 286 t = Transliterator::createFromRules("test", rules, UTRANS_FORWARD, 287 pe, status); 288 289 // test clone() 290 TestReplaceable *tr2 = (TestReplaceable *)tr->clone(); 291 if(tr2 != NULL) { 292 delete tr; 293 tr = tr2; 294 } 295 } else { 296 t = Transliterator::createInstance(transliteratorName, UTRANS_FORWARD, status); 297 } 298 if (U_FAILURE(status)) { 299 dataerrln("FAIL: failed to create the " + transliteratorName + " transliterator"); 300 delete tr; 301 return; 302 } 303 t->transliterate(*tr); 304 UnicodeString newStyles = tr->getStyles(); 305 if (newStyles != expectedStyles) { 306 errln("FAIL Styles: " + transliteratorName + "{" + original + "} => " 307 + tr->toString() + "; should be {" + expectedStyles + "}!"); 308 } else { 309 log("OK: "); 310 log(transliteratorName); 311 log("("); 312 log(original); 313 log(") => "); 314 logln(tr->toString()); 315 } 316 delete tr; 317 delete t; 318 } 319 320 #endif /* #if !UCONFIG_NO_TRANSLITERATION */ 321