/******************************************************************** * COPYRIGHT: * Copyright (c) 2001-2010, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /************************************************************************ * This test program is intended for testing Replaceable class. * * Date Name Description * 11/28/2001 hshih Ported back from Java. * ************************************************************************/ #include "unicode/utypes.h" #if !UCONFIG_NO_TRANSLITERATION #include "ittrans.h" #include <string.h> #include <stdio.h> #include <stdlib.h> #include "unicode/rep.h" #include "reptest.h" //--------------------------------------------- // runIndexedTest //--------------------------------------------- /** * This is a test class that simulates styled text. * It associates a style number (0..65535) with each character, * and maintains that style in the normal fashion: * When setting text from raw string or characters,<br> * Set the styles to the style of the first character replaced.<br> * If no characters are replaced, use the style of the previous character.<br> * If at start, use the following character<br> * Otherwise use NO_STYLE. */ class TestReplaceable : public Replaceable { UnicodeString chars; UnicodeString styles; static const UChar NO_STYLE; static const UChar NO_STYLE_MARK; /** * The address of this static class variable serves as this class's ID * for ICU "poor man's RTTI". */ static const char fgClassID; public: TestReplaceable (const UnicodeString& text, const UnicodeString& newStyles) { chars = text; UnicodeString s; for (int i = 0; i < text.length(); ++i) { if (i < newStyles.length()) { s.append(newStyles.charAt(i)); } else { if (text.charAt(i) == NO_STYLE_MARK) { s.append(NO_STYLE); } else { s.append((UChar)(i + 0x0031)); } } } this->styles = s; } virtual Replaceable *clone() const { return new TestReplaceable(chars, styles); } ~TestReplaceable(void) {} UnicodeString getStyles() { return styles; } UnicodeString toString() { UnicodeString s = chars; s.append("{"); s.append(styles); s.append("}"); return s; } void extractBetween(int32_t start, int32_t limit, UnicodeString& result) const { chars.extractBetween(start, limit, result); } /** * ICU "poor man's RTTI", returns a UClassID for this class. * * @draft ICU 2.2 */ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } /** * ICU "poor man's RTTI", returns a UClassID for the actual class. * * @draft ICU 2.2 */ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } protected: virtual int32_t getLength() const { return chars.length(); } virtual UChar getCharAt(int32_t offset) const{ return chars.charAt(offset); } virtual UChar32 getChar32At(int32_t offset) const{ return chars.char32At(offset); } void fixStyles(int32_t start, int32_t limit, int32_t newLen) { UChar newStyle = NO_STYLE; if (start != limit && styles.charAt(start) != NO_STYLE) { newStyle = styles.charAt(start); } else if (start > 0 && getCharAt(start-1) != NO_STYLE_MARK) { newStyle = styles.charAt(start-1); } else if (limit < styles.length()) { newStyle = styles.charAt(limit); } // dumb implementation for now. UnicodeString s; for (int i = 0; i < newLen; ++i) { // this doesn't really handle an embedded NO_STYLE_MARK // in the middle of a long run of characters right -- but // that case shouldn't happen anyway if (getCharAt(start+i) == NO_STYLE_MARK) { s.append(NO_STYLE); } else { s.append(newStyle); } } styles.replaceBetween(start, limit, s); } virtual void handleReplaceBetween(int32_t start, int32_t limit, const UnicodeString& text) { UnicodeString s; this->extractBetween(start, limit, s); if (s == text) return; // NO ACTION! this->chars.replaceBetween(start, limit, text); fixStyles(start, limit, text.length()); } virtual void copy(int32_t start, int32_t limit, int32_t dest) { chars.copy(start, limit, dest); styles.copy(start, limit, dest); } }; const char TestReplaceable::fgClassID=0; const UChar TestReplaceable::NO_STYLE = 0x005F; const UChar TestReplaceable::NO_STYLE_MARK = 0xFFFF; void ReplaceableTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) { switch (index) { TESTCASE(0,TestReplaceableClass); default: name = ""; break; } } /* * Dummy Replaceable implementation for better API/code coverage. */ class NoopReplaceable : public Replaceable { public: virtual int32_t getLength() const { return 0; } virtual UChar getCharAt(int32_t /*offset*/) const{ return 0xffff; } virtual UChar32 getChar32At(int32_t /*offset*/) const{ return 0xffff; } void extractBetween(int32_t /*start*/, int32_t /*limit*/, UnicodeString& result) const { result.remove(); } virtual void handleReplaceBetween(int32_t /*start*/, int32_t /*limit*/, const UnicodeString &/*text*/) { /* do nothing */ } virtual void copy(int32_t /*start*/, int32_t /*limit*/, int32_t /*dest*/) { /* do nothing */ } static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } private: static const char fgClassID; }; const char NoopReplaceable::fgClassID=0; void ReplaceableTest::TestReplaceableClass(void) { UChar rawTestArray[][6] = { {0x0041, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // ABCD {0x0061, 0x0062, 0x0063, 0x0064, 0x00DF, 0x0000}, // abcd\u00DF {0x0061, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // aBCD {0x0041, 0x0300, 0x0045, 0x0300, 0x0000, 0x0000}, // A\u0300E\u0300 {0x00C0, 0x00C8, 0x0000, 0x0000, 0x0000, 0x0000}, // \u00C0\u00C8 {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */ {0x0077, 0x0078, 0x0079, 0x007A, 0x0000, 0x0000}, /* "wxyz" */ {0x0077, 0x0078, 0x0079, 0x007A, 0x0075, 0x0000}, /* "wxyzu" */ {0x0078, 0x0079, 0x007A, 0x0000, 0x0000, 0x0000}, /* "xyz" */ {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */ {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */ {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */ }; check("Lower", rawTestArray[0], "1234"); check("Upper", rawTestArray[1], "123455"); // must map 00DF to SS check("Title", rawTestArray[2], "1234"); check("NFC", rawTestArray[3], "13"); check("NFD", rawTestArray[4], "1122"); check("*(x) > A $1 B", rawTestArray[5], "11223"); check("*(x)(y) > A $2 B $1 C $2 D", rawTestArray[6], "113322334"); check("*(x)(y)(z) > A $3 B $2 C $1 D", rawTestArray[7], "114433225"); // Disabled for 2.4. TODO Revisit in 2.6 or later. //check("*x > a", rawTestArray[8], "223"); // expect "123"? //check("*x > a", rawTestArray[9], "113"); // expect "123"? //check("*x > a", rawTestArray[10], "_33"); // expect "_23"? //check("*(x) > A $1 B", rawTestArray[11], "__223"); // improve API/code coverage NoopReplaceable noop; Replaceable *p; if((p=noop.clone())!=NULL) { errln("Replaceable::clone() does not return NULL"); delete p; } if(!noop.hasMetaData()) { errln("Replaceable::hasMetaData() does not return TRUE"); } // try to call the compiler-provided // UMemory/UObject/Replaceable assignment operators NoopReplaceable noop2; noop2=noop; if((p=noop2.clone())!=NULL) { errln("noop2.Replaceable::clone() does not return NULL"); delete p; } // try to call the compiler-provided // UMemory/UObject/Replaceable copy constructors NoopReplaceable noop3(noop); if((p=noop3.clone())!=NULL) { errln("noop3.Replaceable::clone() does not return NULL"); delete p; } } void ReplaceableTest::check(const UnicodeString& transliteratorName, const UnicodeString& test, const UnicodeString& shouldProduceStyles) { UErrorCode status = U_ZERO_ERROR; TestReplaceable *tr = new TestReplaceable(test, ""); UnicodeString expectedStyles = shouldProduceStyles; UnicodeString original = tr->toString(); Transliterator* t; if (transliteratorName.charAt(0) == 0x2A /*'*'*/) { UnicodeString rules(transliteratorName); rules.remove(0,1); UParseError pe; t = Transliterator::createFromRules("test", rules, UTRANS_FORWARD, pe, status); // test clone() TestReplaceable *tr2 = (TestReplaceable *)tr->clone(); if(tr2 != NULL) { delete tr; tr = tr2; } } else { t = Transliterator::createInstance(transliteratorName, UTRANS_FORWARD, status); } if (U_FAILURE(status)) { dataerrln("FAIL: failed to create the " + transliteratorName + " transliterator"); delete tr; return; } t->transliterate(*tr); UnicodeString newStyles = tr->getStyles(); if (newStyles != expectedStyles) { errln("FAIL Styles: " + transliteratorName + "{" + original + "} => " + tr->toString() + "; should be {" + expectedStyles + "}!"); } else { log("OK: "); log(transliteratorName); log("("); log(original); log(") => "); logln(tr->toString()); } delete tr; delete t; } #endif /* #if !UCONFIG_NO_TRANSLITERATION */