Home | History | Annotate | Download | only in intltest
      1 // Copyright (C) 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:
     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 
     74     virtual Replaceable *clone() const {
     75         return new TestReplaceable(chars, styles);
     76     }
     77 
     78     ~TestReplaceable(void) {}
     79 
     80     UnicodeString getStyles() {
     81         return styles;
     82     }
     83 
     84     UnicodeString toString() {
     85         UnicodeString s = chars;
     86         s.append("{");
     87         s.append(styles);
     88         s.append("}");
     89         return s;
     90     }
     91 
     92     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      */
    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      */
    108     virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
    109 
    110 protected:
    111     virtual int32_t getLength() const {
    112         return chars.length();
    113     }
    114 
    115     virtual UChar getCharAt(int32_t offset) const{
    116         return chars.charAt(offset);
    117     }
    118 
    119     virtual UChar32 getChar32At(int32_t offset) const{
    120         return chars.char32At(offset);
    121     }
    122 
    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 
    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 
    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
    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:
    182     virtual int32_t getLength() const {
    183         return 0;
    184     }
    185 
    186     virtual UChar getCharAt(int32_t /*offset*/) const{
    187         return 0xffff;
    188     }
    189 
    190     virtual UChar32 getChar32At(int32_t /*offset*/) const{
    191         return 0xffff;
    192     }
    193 
    194     void extractBetween(int32_t /*start*/, int32_t /*limit*/, UnicodeString& result) const {
    195         result.remove();
    196     }
    197 
    198     virtual void handleReplaceBetween(int32_t /*start*/, int32_t /*limit*/, const UnicodeString &/*text*/) {
    199         /* do nothing */
    200     }
    201 
    202     virtual void copy(int32_t /*start*/, int32_t /*limit*/, int32_t /*dest*/) {
    203         /* do nothing */
    204     }
    205 
    206     static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
    207     virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
    208 
    209 private:
    210     static const char fgClassID;
    211 };
    212 
    213 const char NoopReplaceable::fgClassID=0;
    214 
    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 
    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 = (TestReplaceable *)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