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 TestReplaceable
*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
= 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 */