• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestReplaceable(const UnicodeString & text,const UnicodeString & newStyles)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 
clone() const72     virtual Replaceable *clone() const {
73         return new TestReplaceable(chars, styles);
74     }
75 
~TestReplaceable(void)76     ~TestReplaceable(void) {}
77 
getStyles()78     UnicodeString getStyles() {
79         return styles;
80     }
81 
toString()82     UnicodeString toString() {
83         UnicodeString s = chars;
84         s.append("{");
85         s.append(styles);
86         s.append("}");
87         return s;
88     }
89 
extractBetween(int32_t start,int32_t limit,UnicodeString & result) const90     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      */
getStaticClassID()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      */
getDynamicClassID() const106     virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
107 
108 protected:
getLength() const109     virtual int32_t getLength() const {
110         return chars.length();
111     }
112 
getCharAt(int32_t offset) const113     virtual UChar getCharAt(int32_t offset) const{
114         return chars.charAt(offset);
115     }
116 
getChar32At(int32_t offset) const117     virtual UChar32 getChar32At(int32_t offset) const{
118         return chars.char32At(offset);
119     }
120 
fixStyles(int32_t start,int32_t limit,int32_t newLen)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 
handleReplaceBetween(int32_t start,int32_t limit,const UnicodeString & text)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 
copy(int32_t start,int32_t limit,int32_t dest)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
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)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:
getLength() const180     virtual int32_t getLength() const {
181         return 0;
182     }
183 
getCharAt(int32_t) const184     virtual UChar getCharAt(int32_t /*offset*/) const{
185         return 0xffff;
186     }
187 
getChar32At(int32_t) const188     virtual UChar32 getChar32At(int32_t /*offset*/) const{
189         return 0xffff;
190     }
191 
extractBetween(int32_t,int32_t,UnicodeString & result) const192     void extractBetween(int32_t /*start*/, int32_t /*limit*/, UnicodeString& result) const {
193         result.remove();
194     }
195 
handleReplaceBetween(int32_t,int32_t,const UnicodeString &)196     virtual void handleReplaceBetween(int32_t /*start*/, int32_t /*limit*/, const UnicodeString &/*text*/) {
197         /* do nothing */
198     }
199 
copy(int32_t,int32_t,int32_t)200     virtual void copy(int32_t /*start*/, int32_t /*limit*/, int32_t /*dest*/) {
201         /* do nothing */
202     }
203 
getStaticClassID()204     static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
getDynamicClassID() const205     virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
206 
207 private:
208     static const char fgClassID;
209 };
210 
211 const char NoopReplaceable::fgClassID=0;
212 
TestReplaceableClass(void)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 
check(const UnicodeString & transliteratorName,const UnicodeString & test,const UnicodeString & shouldProduceStyles)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