• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) 2001-2010, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 /************************************************************************
9 *   This test program is intended for testing Replaceable class.
10 *
11 *   Date        Name        Description
12 *   11/28/2001  hshih       Ported back from Java.
13 *
14 ************************************************************************/
15 
16 #include "unicode/utypes.h"
17 
18 #if !UCONFIG_NO_TRANSLITERATION
19 
20 #include "ittrans.h"
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "unicode/rep.h"
25 #include "reptest.h"
26 
27 //---------------------------------------------
28 // runIndexedTest
29 //---------------------------------------------
30 
31     /**
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.
40      */
41 class TestReplaceable : public Replaceable {
42     UnicodeString chars;
43     UnicodeString styles;
44 
45     static const UChar NO_STYLE;
46 
47     static const UChar NO_STYLE_MARK;
48 
49     /**
50      * The address of this static class variable serves as this class's ID
51      * for ICU "poor man's RTTI".
52      */
53     static const char fgClassID;
54 
55 public:
TestReplaceable(const UnicodeString & text,const UnicodeString & newStyles)56     TestReplaceable (const UnicodeString& text,
57                      const UnicodeString& newStyles) {
58         chars = text;
59         UnicodeString s;
60         for (int i = 0; i < text.length(); ++i) {
61             if (i < newStyles.length()) {
62                 s.append(newStyles.charAt(i));
63             } else {
64                 if (text.charAt(i) == NO_STYLE_MARK) {
65                     s.append(NO_STYLE);
66                 } else {
67                     s.append((UChar)(i + 0x0031));
68                 }
69             }
70         }
71         this->styles = s;
72     }
73 
clone() const74     virtual TestReplaceable *clone() const {
75         return new TestReplaceable(chars, styles);
76     }
77 
~TestReplaceable(void)78     ~TestReplaceable(void) {}
79 
getStyles()80     UnicodeString getStyles() {
81         return styles;
82     }
83 
toString()84     UnicodeString toString() {
85         UnicodeString s = chars;
86         s.append("{");
87         s.append(styles);
88         s.append("}");
89         return s;
90     }
91 
extractBetween(int32_t start,int32_t limit,UnicodeString & result) const92     void extractBetween(int32_t start, int32_t limit, UnicodeString& result) const {
93         chars.extractBetween(start, limit, result);
94     }
95 
96     /**
97      * ICU "poor man's RTTI", returns a UClassID for this class.
98      *
99      * @draft ICU 2.2
100      */
getStaticClassID()101     static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
102 
103     /**
104      * ICU "poor man's RTTI", returns a UClassID for the actual class.
105      *
106      * @draft ICU 2.2
107      */
getDynamicClassID() const108     virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
109 
110 protected:
getLength() const111     virtual int32_t getLength() const {
112         return chars.length();
113     }
114 
getCharAt(int32_t offset) const115     virtual UChar getCharAt(int32_t offset) const{
116         return chars.charAt(offset);
117     }
118 
getChar32At(int32_t offset) const119     virtual UChar32 getChar32At(int32_t offset) const{
120         return chars.char32At(offset);
121     }
122 
fixStyles(int32_t start,int32_t limit,int32_t newLen)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);
131         }
132         // dumb implementation for now.
133         UnicodeString s;
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) {
139                 s.append(NO_STYLE);
140             } else {
141                 s.append(newStyle);
142             }
143         }
144         styles.replaceBetween(start, limit, s);
145     }
146 
handleReplaceBetween(int32_t start,int32_t limit,const UnicodeString & text)147     virtual void handleReplaceBetween(int32_t start, int32_t limit, const UnicodeString& text) {
148         UnicodeString s;
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());
153     }
154 
155 
copy(int32_t start,int32_t limit,int32_t dest)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);
159     }
160 };
161 
162 const char TestReplaceable::fgClassID=0;
163 
164 const UChar TestReplaceable::NO_STYLE  = 0x005F;
165 
166 const UChar TestReplaceable::NO_STYLE_MARK = 0xFFFF;
167 
168 void
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)169 ReplaceableTest::runIndexedTest(int32_t index, UBool exec,
170                                       const char* &name, char* /*par*/) {
171     switch (index) {
172         TESTCASE(0,TestReplaceableClass);
173         default: name = ""; break;
174     }
175 }
176 
177 /*
178  * Dummy Replaceable implementation for better API/code coverage.
179  */
180 class NoopReplaceable : public Replaceable {
181 public:
getLength() const182     virtual int32_t getLength() const {
183         return 0;
184     }
185 
getCharAt(int32_t) const186     virtual UChar getCharAt(int32_t /*offset*/) const{
187         return 0xffff;
188     }
189 
getChar32At(int32_t) const190     virtual UChar32 getChar32At(int32_t /*offset*/) const{
191         return 0xffff;
192     }
193 
extractBetween(int32_t,int32_t,UnicodeString & result) const194     void extractBetween(int32_t /*start*/, int32_t /*limit*/, UnicodeString& result) const {
195         result.remove();
196     }
197 
handleReplaceBetween(int32_t,int32_t,const UnicodeString &)198     virtual void handleReplaceBetween(int32_t /*start*/, int32_t /*limit*/, const UnicodeString &/*text*/) {
199         /* do nothing */
200     }
201 
copy(int32_t,int32_t,int32_t)202     virtual void copy(int32_t /*start*/, int32_t /*limit*/, int32_t /*dest*/) {
203         /* do nothing */
204     }
205 
getStaticClassID()206     static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
getDynamicClassID() const207     virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
208 
209 private:
210     static const char fgClassID;
211 };
212 
213 const char NoopReplaceable::fgClassID=0;
214 
TestReplaceableClass(void)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" */
229     };
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");
243 
244     // improve API/code coverage
245     NoopReplaceable noop;
246     Replaceable *p;
247     if((p=noop.clone())!=NULL) {
248         errln("Replaceable::clone() does not return NULL");
249         delete p;
250     }
251 
252     if(!noop.hasMetaData()) {
253         errln("Replaceable::hasMetaData() does not return TRUE");
254     }
255 
256     // try to call the compiler-provided
257     // UMemory/UObject/Replaceable assignment operators
258     NoopReplaceable noop2;
259     noop2=noop;
260     if((p=noop2.clone())!=NULL) {
261         errln("noop2.Replaceable::clone() does not return NULL");
262         delete p;
263     }
264 
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");
270         delete p;
271     }
272 }
273 
check(const UnicodeString & transliteratorName,const UnicodeString & test,const UnicodeString & shouldProduceStyles)274 void ReplaceableTest::check(const UnicodeString& transliteratorName,
275                             const UnicodeString& test,
276                             const UnicodeString& shouldProduceStyles)
277 {
278     UErrorCode status = U_ZERO_ERROR;
279     TestReplaceable *tr = new TestReplaceable(test, "");
280     UnicodeString expectedStyles = shouldProduceStyles;
281     UnicodeString original = tr->toString();
282 
283     Transliterator* t;
284     if (transliteratorName.charAt(0) == 0x2A /*'*'*/) {
285         UnicodeString rules(transliteratorName);
286         rules.remove(0,1);
287         UParseError pe;
288         t = Transliterator::createFromRules("test", rules, UTRANS_FORWARD,
289                                             pe, status);
290 
291         // test clone()
292         TestReplaceable *tr2 = tr->clone();
293         if(tr2 != NULL) {
294             delete tr;
295             tr = tr2;
296         }
297     } else {
298         t = Transliterator::createInstance(transliteratorName, UTRANS_FORWARD, status);
299     }
300     if (U_FAILURE(status)) {
301         dataerrln("FAIL: failed to create the " + transliteratorName + " transliterator");
302         delete tr;
303         return;
304     }
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 + "}!");
310     } else {
311         log("OK: ");
312         log(transliteratorName);
313         log("(");
314         log(original);
315         log(") => ");
316         logln(tr->toString());
317     }
318     delete tr;
319     delete t;
320 }
321 
322 #endif /* #if !UCONFIG_NO_TRANSLITERATION */
323