Home | History | Annotate | Download | only in intltest
      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