]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/apicoll.cpp
ICU-511.34.tar.gz
[apple/icu.git] / icuSources / test / intltest / apicoll.cpp
index ff8404f897e0c1e7c6114ff81cf6b69af4974fc9..2b35d2b21fe368e39ba839026c023622397b52fd 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * Copyright (c) 1997-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 //===============================================================================
@@ -31,6 +31,7 @@
 
 #if !UCONFIG_NO_COLLATION
 
+#include "unicode/localpointer.h"
 #include "unicode/coll.h"
 #include "unicode/tblcoll.h"
 #include "unicode/coleitr.h"
@@ -45,6 +46,8 @@
 #include "cmemory.h"
 #include <stdlib.h>
 
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
 void
 CollationAPITest::doAssert(UBool condition, const char *message)
 {
@@ -94,37 +97,42 @@ CollationAPITest::TestProperty(/* char* par */)
     UErrorCode success = U_ZERO_ERROR;
     Collator *col = 0;
     /*
-      All the collations have the same version in an ICU
-      version.
-      ICU 2.0 currVersionArray = {0x18, 0xC0, 0x02, 0x02};
-      ICU 2.1 currVersionArray = {0x19, 0x00, 0x03, 0x03};
-      ICU 2.2 currVersionArray = {0x21, 0x40, 0x04, 0x04};
-      ICU 2.4 currVersionArray = {0x21, 0x40, 0x04, 0x04};
-      ICU 2.6 currVersionArray = {0x21, 0x40, 0x03, 0x03};
-      ICU 2.8 currVersionArray = {0x29, 0x80, 0x00, 0x04};
-      ICU 3.4 currVersionArray = {0x31, 0xC0, 0x00, 0x04};
-    */
-    UVersionInfo currVersionArray = {0x31, 0xC0, 0x00, 0x05};
+     * Expected version of the English collator.
+     * Currently, the major/minor version numbers change when the builder code
+     * changes,
+     * number 2 is from the tailoring data version and
+     * number 3 is the UCA version.
+     * This changes with every UCA version change, and the expected value
+     * needs to be adjusted.
+     * Same in cintltst/capitst.c.
+     */
+    UVersionInfo currVersionArray = {0x31, 0xC0, 0x05, 0x2A};  // from ICU 4.4/UCA 5.2
     UVersionInfo versionArray;
-    int i = 0;
 
     logln("The property tests begin : ");
     logln("Test ctors : ");
     col = Collator::createInstance(Locale::getEnglish(), success);
+    if (U_FAILURE(success)){
+        errcheckln(success, "Default Collator creation failed. - %s", u_errorName(success));
+        return;
+    }
 
-    if (U_FAILURE(success))
-    {
-        errln("Default Collator creation failed.");
+    StringEnumeration* kwEnum = col->getKeywordValuesForLocale("", Locale::getEnglish(),true,success);
+    if (U_FAILURE(success)){
+        errcheckln(success, "Get Keyword Values for Locale failed. - %s", u_errorName(success));
         return;
     }
+    delete kwEnum;
 
     col->getVersion(versionArray);
-    for (i=0; i<4; ++i) {
-      if (versionArray[i] != currVersionArray[i]) {
-        errln("Testing ucol_getVersion() - unexpected result: %d.%d.%d.%d",
+    // Check for a version greater than some value rather than equality
+    // so that we need not update the expected version each time.
+    if (uprv_memcmp(versionArray, currVersionArray, 4)<0) {
+      errln("Testing Collator::getVersion() - unexpected result: %02x.%02x.%02x.%02x",
+            versionArray[0], versionArray[1], versionArray[2], versionArray[3]);
+    } else {
+      logln("Collator::getVersion() result: %02x.%02x.%02x.%02x",
             versionArray[0], versionArray[1], versionArray[2], versionArray[3]);
-        break;
-      }
     }
 
     doAssert((col->compare("ab", "abc") == Collator::LESS), "ab < abc comparison failed");
@@ -132,7 +140,19 @@ CollationAPITest::TestProperty(/* char* par */)
     doAssert((col->compare("blackbird", "black-bird") == Collator::GREATER), "black-bird > blackbird comparison failed");
     doAssert((col->compare("black bird", "black-bird") == Collator::LESS), "black bird > black-bird comparison failed");
     doAssert((col->compare("Hello", "hello") == Collator::GREATER), "Hello > hello comparison failed");
+    doAssert((col->compare("","",success) == UCOL_EQUAL), "Comparison between empty strings failed");
 
+    doAssert((col->compareUTF8("\x61\x62\xc3\xa4", "\x61\x62\xc3\x9f", success) == UCOL_LESS), "ab a-umlaut < ab sharp-s UTF-8 comparison failed");
+    success = U_ZERO_ERROR;
+    {
+        UnicodeString abau=UNICODE_STRING_SIMPLE("\\x61\\x62\\xe4").unescape();
+        UnicodeString abss=UNICODE_STRING_SIMPLE("\\x61\\x62\\xdf").unescape();
+        UCharIterator abauIter, abssIter;
+        uiter_setReplaceable(&abauIter, &abau);
+        uiter_setReplaceable(&abssIter, &abss);
+        doAssert((col->compare(abauIter, abssIter, success) == UCOL_LESS), "ab a-umlaut < ab sharp-s UCharIterator comparison failed");
+        success = U_ZERO_ERROR;
+    }
 
     /*start of update [Bertrand A. D. 02/10/98]*/
     doAssert((col->compare("ab", "abc", 2) == Collator::EQUAL), "ab = abc with length 2 comparison failed");
@@ -221,17 +241,22 @@ CollationAPITest::TestProperty(/* char* par */)
 
     doAssert(((RuleBasedCollator *)col)->getRules() == ((RuleBasedCollator *)junk)->getRules(),
                "The default collation should be returned.");
-    Collator *frCol = Collator::createInstance(Locale::getFrance(), success);
+    Collator *frCol = Collator::createInstance(Locale::getCanadaFrench(), success);
     if (U_FAILURE(success))
     {
-        errln("Creating French collator failed.");
-        delete col; delete junk;
+        errln("Creating fr_CA collator failed.");
+        delete col;
+        delete junk;
         return;
     }
 
-    doAssert((*frCol != *junk), "The junk is the same as the French collator.");
+    // If the default locale isn't French, the French and non-French collators
+    // should be different
+    if (frCol->getLocale(ULOC_ACTUAL_LOCALE, success) != Locale::getCanadaFrench()) {
+        doAssert((*frCol != *junk), "The junk is the same as the fr_CA collator.");
+    }
     Collator *aFrCol = frCol->clone();
-    doAssert((*frCol == *aFrCol), "The cloning of a French collator failed.");
+    doAssert((*frCol == *aFrCol), "The cloning of a fr_CA collator failed.");
     logln("Collator property test ended.");
 
     delete col;
@@ -270,7 +295,7 @@ CollationAPITest::TestRuleBasedColl()
 
     col1 = new RuleBasedCollator(ruleset1, status);
     if (U_FAILURE(status)) {
-        errln("RuleBased Collator creation failed.\n");
+        errcheckln(status, "RuleBased Collator creation failed. - %s", u_errorName(status));
         return;
     }
     else {
@@ -351,7 +376,7 @@ CollationAPITest::TestRules()
 
     coll = (RuleBasedCollator *)Collator::createInstance(Locale::getEnglish(), status);
     if (U_FAILURE(status)) {
-        errln("English Collator creation failed.\n");
+        errcheckln(status, "English Collator creation failed. - %s", u_errorName(status));
         return;
     }
     else {
@@ -359,8 +384,8 @@ CollationAPITest::TestRules()
     }
 
     coll->getRules(UCOL_TAILORING_ONLY, rules);
-    if (rules.length() != 0x0a) {
-      errln("English tailored rules failed - length is 0x%x expected 0x%x", rules.length(), 0x0e);
+    if (rules.length() != 0x00) {
+      errln("English tailored rules failed - length is 0x%x expected 0x%x", rules.length(), 0x00);
     }
 
     coll->getRules(UCOL_FULL_RULES, rules);
@@ -378,7 +403,7 @@ CollationAPITest::TestDecomposition() {
     *vi_VN = Collator::createInstance("vi_VN", status);
 
   if (U_FAILURE(status)) {
-    errln("ERROR: collation creation failed.\n");
+    errcheckln(status, "ERROR: collation creation failed. - %s", u_errorName(status));
     return;
   }
 
@@ -419,7 +444,7 @@ CollationAPITest::TestSafeClone() {
     someCollators[1] = Collator::createInstance("ko", err);
     someCollators[2] = Collator::createInstance("ja_JP", err);
     if(U_FAILURE(err)) {
-      errln("Couldn't instantiate collators. Error: %s", u_errorName(err));
+      errcheckln(err, "Couldn't instantiate collators. Error: %s", u_errorName(err));
       delete someCollators[0];
       delete someCollators[1];
       delete someCollators[2];
@@ -456,7 +481,7 @@ CollationAPITest::TestHashCode(/* char* par */)
     col1 = Collator::createInstance(Locale::getEnglish(), success);
     if (U_FAILURE(success))
     {
-        errln("Default collation creation failed.");
+        errcheckln(success, "Default collation creation failed. - %s", u_errorName(success));
         return;
     }
 
@@ -515,7 +540,7 @@ CollationAPITest::TestCollationKey(/* char* par */)
     col = Collator::createInstance(Locale::getEnglish(), success);
     if (U_FAILURE(success))
     {
-        errln("Default collation creation failed.");
+        errcheckln(success, "Default collation creation failed. - %s", u_errorName(success));
         return;
     }
     col->setStrength(Collator::TERTIARY);
@@ -534,7 +559,7 @@ CollationAPITest::TestCollationKey(/* char* par */)
     // bogus key returned here
     key1Status = U_ILLEGAL_ARGUMENT_ERROR;
     col->getCollationKey(NULL, 0, sortk1, key1Status);
-    doAssert(sortk1.getByteArray(length) == NULL && length == 0,
+    doAssert(sortk1.isBogus() && (sortk1.getByteArray(length), length) == 0,
         "Error code should return bogus collation key");
 
     key1Status = U_ZERO_ERROR;
@@ -571,16 +596,6 @@ CollationAPITest::TestCollationKey(/* char* par */)
     const uint8_t* byteArray1 = sortk1.getByteArray(cnt1);
     const uint8_t* byteArray2 = sortk2.getByteArray(cnt2);
 
-    /*
-    this is a bad test since it is dependent on the version of uca data,
-    which changes
-    will remove it.
-    const char sortk2_compat[] = {
-        // this is a 1.8 sortkey
-        0x17, 0x19, 0x1B, 0x1D, 0x17, 0x01, 0x08, 0x01, 0x08, 0x00
-    };
-    */
-
     const uint8_t* byteArray3 = 0;
     byteArray3 = sortk1.getByteArray(cnt3);
 
@@ -590,10 +605,6 @@ CollationAPITest::TestCollationKey(/* char* par */)
     CollationKey sortk4(byteArray1, cnt1), sortk5(byteArray2, cnt2);
     CollationKey sortk6(byteArray3, cnt3), sortk7(byteArray4, cnt4);
 
-    /*
-    doAssert(memcmp(byteArray2, sortk2_compat, strlen(sortk2_compat)) == 0,
-             "Binary format for 'abcda' sortkey different!");
-    */
     doAssert(sortk1.compareTo(sortk4) == Collator::EQUAL, "CollationKey::toByteArray(sortk1) Failed.");
     doAssert(sortk2.compareTo(sortk5) == Collator::EQUAL, "CollationKey::toByteArray(sortk2) Failed.");
     doAssert(sortk4.compareTo(sortk5) == Collator::GREATER, "sortk4 >>> sortk5 Failed");
@@ -638,7 +649,7 @@ CollationAPITest::TestElemIter(/* char* par */)
     col = Collator::createInstance(Locale::getEnglish(), success);
     if (U_FAILURE(success))
     {
-        errln("Default collation creation failed.");
+        errcheckln(success, "Default collation creation failed. - %s", u_errorName(success));
         return;
     }
 
@@ -831,7 +842,7 @@ CollationAPITest::TestOperators(/* char* par */)
     UnicodeString ruleset2("< a, A < b, B < c, C < d, D, e, E");
     RuleBasedCollator *col1 = new RuleBasedCollator(ruleset1, success);
     if (U_FAILURE(success)) {
-        errln("RuleBasedCollator creation failed.");
+        errcheckln(success, "RuleBasedCollator creation failed. - %s", u_errorName(success));
         return;
     }
     success = U_ZERO_ERROR;
@@ -963,7 +974,7 @@ CollationAPITest::TestCompare(/* char* par */)
     UErrorCode success = U_ZERO_ERROR;
     col = Collator::createInstance(Locale::getEnglish(), success);
     if (U_FAILURE(success)) {
-        errln("Default collation creation failed.");
+        errcheckln(success, "Default collation creation failed. - %s", u_errorName(success));
         return;
     }
     UnicodeString test1("Abcda"), test2("abcda");
@@ -1017,15 +1028,61 @@ CollationAPITest::TestCompare(/* char* par */)
 void
 CollationAPITest::TestGetAll(/* char* par */)
 {
-    int32_t count;
-    const Locale* list = Collator::getAvailableLocales(count);
-    for (int32_t i = 0; i < count; ++i) {
-        UnicodeString locName, dispName;
-        log("Locale name: ");
-        log(list[i].getName());
-        log(" , the display name is : ");
-        logln(list[i].getDisplayName(dispName));
+    int32_t count1, count2;
+    UErrorCode status = U_ZERO_ERROR;
+
+    logln("Trying Collator::getAvailableLocales(int&)");
+
+    const Locale* list = Collator::getAvailableLocales(count1);
+    for (int32_t i = 0; i < count1; ++i) {
+        UnicodeString dispName;
+        logln(UnicodeString("Locale name: ")
+            + UnicodeString(list[i].getName())
+            + UnicodeString(" , the display name is : ")
+            + UnicodeString(list[i].getDisplayName(dispName)));
+    }
+
+    if (count1 == 0 || list == NULL) {
+        dataerrln("getAvailableLocales(int&) returned an empty list");
+    }
+
+    logln("Trying Collator::getAvailableLocales()");
+    StringEnumeration* localeEnum = Collator::getAvailableLocales();
+    const UnicodeString* locStr;
+    const char *locCStr;
+    count2 = 0;
+
+    if (localeEnum == NULL) {
+        dataerrln("getAvailableLocales() returned NULL");
+        return;
+    }
+
+    while ((locStr = localeEnum->snext(status)) != NULL)
+    {
+        logln(UnicodeString("Locale name is: ") + *locStr);
+        count2++;
+    }
+    if (count1 != count2) {
+        errln("getAvailableLocales(int&) returned %d and getAvailableLocales() returned %d", count1, count2);
+    }
+
+    logln("Trying Collator::getAvailableLocales() clone");
+    count1 = 0;
+    StringEnumeration* localeEnum2 = localeEnum->clone();
+    localeEnum2->reset(status);
+    while ((locCStr = localeEnum2->next(NULL, status)) != NULL)
+    {
+        logln(UnicodeString("Locale name is: ") + UnicodeString(locCStr));
+        count1++;
+    }
+    if (count1 != count2) {
+        errln("getAvailableLocales(3rd time) returned %d and getAvailableLocales(2nd time) returned %d", count1, count2);
     }
+    if (localeEnum->count(status) != count1) {
+        errln("localeEnum->count() returned %d and getAvailableLocales() returned %d", localeEnum->count(status), count1);
+    }
+    delete localeEnum;
+    delete localeEnum2;
 }
 
 void CollationAPITest::TestSortKey()
@@ -1039,7 +1096,7 @@ void CollationAPITest::TestSortKey()
     */
     Collator *col = Collator::createInstance(Locale::getEnglish(), status);
     if (U_FAILURE(status)) {
-        errln("ERROR: Default collation creation failed.: %s\n", u_errorName(status));
+        errcheckln(status, "ERROR: Default collation creation failed.: %s\n", u_errorName(status));
         return;
     }
 
@@ -1051,47 +1108,6 @@ void CollationAPITest::TestSortKey()
     /* Need to use identical strength */
     col->setAttribute(UCOL_STRENGTH, UCOL_IDENTICAL, status);
 
-    uint8_t key2compat[] = {
-        /* 3.6 key, from UCA 5.0 */
-        0x29, 0x2b, 0x2d, 0x2f, 0x29, 0x01, 
-        0x09, 0x01, 0x09, 0x01, 0x28, 0x01, 
-        0x92, 0x93, 0x94, 0x95, 0x92, 0x00
-        
-        /* 3.4 key, from UCA 4.1 */
-        /*
-        0x28, 0x2a, 0x2c, 0x2e, 0x28, 0x01, 
-        0x09, 0x01, 0x09, 0x01, 0x27, 0x01, 
-        0x92, 0x93, 0x94, 0x95, 0x92, 0x00
-        */
-        /* 2.6.1 key */
-        /*
-        0x26, 0x28, 0x2A, 0x2C, 0x26, 0x01, 
-        0x09, 0x01, 0x09, 0x01, 0x25, 0x01, 
-        0x92, 0x93, 0x94, 0x95, 0x92, 0x00 
-        */
-        /* 2.2 key */
-        /*
-        0x1D, 0x1F, 0x21, 0x23, 0x1D, 0x01,
-        0x09, 0x01, 0x09, 0x01, 0x1C, 0x01,
-        0x92, 0x93, 0x94, 0x95, 0x92, 0x00
-        */
-        /* 2.0 key */
-        /*
-        0x19, 0x1B, 0x1D, 0x1F, 0x19,
-        0x01, 0x09, 0x01, 0x09, 0x01,
-        0x18, 0x01,
-        0x92, 0x93, 0x94, 0x95, 0x92,
-        0x00
-        */
-        /* 1.8.1 key.*/
-        /*
-        0x19, 0x1B, 0x1D, 0x1F, 0x19,
-        0x01, 0x0A, 0x01, 0x0A, 0x01,
-        0x92, 0x93, 0x94, 0x95, 0x92,
-        0x00 
-        */
-    };
-
     UChar test1[6] = {0x41, 0x62, 0x63, 0x64, 0x61, 0},
           test2[6] = {0x61, 0x62, 0x63, 0x64, 0x61, 0},
           test3[6] = {0x61, 0x62, 0x63, 0x64, 0x61, 0};
@@ -1118,10 +1134,11 @@ void CollationAPITest::TestSortKey()
     doAssert(key2.compareTo(key3) == Collator::EQUAL,
         "Result should be \"abcda\" ==  \"abcda\"");
 
+    // Clone the key2 sortkey for later.
     int32_t keylength = 0;
-    doAssert(strcmp((const char *)(key2.getByteArray(keylength)),
-                    (const char *)key2compat) == 0,
-        "Binary format for 'abcda' sortkey different!");
+    const uint8_t *key2primary_alias = key2.getByteArray(keylength);
+    LocalArray<uint8_t> key2primary(new uint8_t[keylength]);
+    memcpy(key2primary.getAlias(), key2primary_alias, keylength);
 
     col->getSortKey(test1, sortkey1, 64);
     col->getSortKey(test2, sortkey2, 64);
@@ -1181,8 +1198,8 @@ void CollationAPITest::TestSortKey()
         "Result should be \"abcda\" ==  \"abcda\"");
 
     tempkey = key2.getByteArray(keylength);
-    doAssert(memcmp(tempkey, key2compat, keylength - 1) == 0,
-             "Binary format for 'abcda' sortkey different!");
+    doAssert(memcmp(tempkey, key2primary.getAlias(), keylength - 1) == 0,
+             "Binary format for 'abcda' sortkey different for secondary strength!");
 
     col->getSortKey(test1, sortkey1, 64);
     col->getSortKey(test2, sortkey2, 64);
@@ -1230,6 +1247,55 @@ void CollationAPITest::TestSortKey()
     delete col;
 }
 
+void CollationAPITest::TestSortKeyOverflow() {
+    IcuTestErrorCode errorCode(*this, "TestSortKeyOverflow()");
+    LocalPointer<Collator> col(Collator::createInstance(Locale::getEnglish(), errorCode));
+    if (errorCode.logDataIfFailureAndReset("Collator::createInstance(English) failed")) {
+        return;
+    }
+    col->setAttribute(UCOL_STRENGTH, UCOL_PRIMARY, errorCode);
+    UChar i_and_phi[] = { 0x438, 0x3c6 };  // Cyrillic small i & Greek small phi.
+    // The sort key should be 6 bytes:
+    // 2 bytes for the Cyrillic i, 1 byte for the primary-compression terminator,
+    // 2 bytes for the Greek phi, and 1 byte for the NUL terminator.
+    uint8_t sortKey[12];
+    int32_t length = col->getSortKey(i_and_phi, 2, sortKey, LENGTHOF(sortKey));
+    uint8_t sortKey2[12];
+    for (int32_t capacity = 0; capacity < length; ++capacity) {
+        uprv_memset(sortKey2, 2, LENGTHOF(sortKey2));
+        int32_t length2 = col->getSortKey(i_and_phi, 2, sortKey2, capacity);
+        if (length2 != length || 0 != uprv_memcmp(sortKey, sortKey2, capacity)) {
+            errln("getSortKey(i_and_phi, capacity=%d) failed to write proper prefix", capacity);
+        } else if (sortKey2[capacity] != 2 || sortKey2[capacity + 1] != 2) {
+            errln("getSortKey(i_and_phi, capacity=%d) wrote beyond capacity", capacity);
+        }
+    }
+
+    // Now try to break getCollationKey().
+    // Internally, it always starts with a large stack buffer.
+    // Since we cannot control the initial capacity, we throw an increasing number
+    // of characters at it, with the problematic part at the end.
+    const int32_t longCapacity = 2000;
+    // Each 'a' in the prefix should result in one primary sort key byte.
+    // For i_and_phi we expect 6 bytes, then the NUL terminator.
+    const int32_t maxPrefixLength = longCapacity - 6 - 1;
+    LocalArray<uint8_t> longSortKey(new uint8_t[longCapacity]);
+    UnicodeString s(FALSE, i_and_phi, 2);
+    for (int32_t prefixLength = 0; prefixLength < maxPrefixLength; ++prefixLength) {
+        length = col->getSortKey(s, longSortKey.getAlias(), longCapacity);
+        CollationKey collKey;
+        col->getCollationKey(s, collKey, errorCode);
+        int32_t collKeyLength;
+        const uint8_t *collSortKey = collKey.getByteArray(collKeyLength);
+        if (collKeyLength != length || 0 != uprv_memcmp(longSortKey.getAlias(), collSortKey, length)) {
+            errln("getCollationKey(prefix[%d]+i_and_phi) failed to write proper sort key", prefixLength);
+        }
+
+        // Insert an 'a' to match ++prefixLength.
+        s.insert(prefixLength, (UChar)0x61);
+    }
+}
+
 void CollationAPITest::TestMaxExpansion()
 {
     UErrorCode          status = U_ZERO_ERROR;
@@ -1241,7 +1307,7 @@ void CollationAPITest::TestMaxExpansion()
     UnicodeString rule("&a < ab < c/aba < d < z < ch");
     RuleBasedCollator coll(rule, status);
     if(U_FAILURE(status)) {
-      errln("Collator creation failed with error %s", u_errorName(status));
+      errcheckln(status, "Collator creation failed with error %s", u_errorName(status));
       return;
     }
     UnicodeString str(ch);
@@ -1269,23 +1335,23 @@ void CollationAPITest::TestMaxExpansion()
 
         size = coll.getMaxExpansion(order);
         if (U_FAILURE(status) || size < count) {
-            errln("Failure at codepoint %d, maximum expansion count < %d\n",
-                  ch, count);
+            errln("Failure at codepoint U+%04X, maximum expansion count %d < %d",
+                  ch, size, count);
         }
     }
 
     /* testing for exact max expansion */
+    int32_t size;
     ch = 0;
     while (ch < 0x61) {
         uint32_t order;
-        int32_t  size;
         str.setCharAt(0, ch);
         iter->setText(str, status);
         order = iter->previous(status);
         size  = coll.getMaxExpansion(order);
         if (U_FAILURE(status) || size != 1) {
-            errln("Failure at codepoint %d, maximum expansion count < %d\n",
-                ch, 1);
+            errln("Failure at codepoint U+%04X, maximum expansion count %d < %d",
+                  ch, size, 1);
         }
         ch ++;
     }
@@ -1294,29 +1360,29 @@ void CollationAPITest::TestMaxExpansion()
     str.setTo(ch);
     iter->setText(str, status);
     temporder = iter->previous(status);
-
-    if (U_FAILURE(status) || coll.getMaxExpansion(temporder) != 3) {
-        errln("Failure at codepoint %d, maximum expansion count != %d\n",
-              ch, 3);
+    size = coll.getMaxExpansion(temporder);
+    if (U_FAILURE(status) || size != 3) {
+        errln("Failure at codepoint U+%04X, CE %08x, maximum expansion count %d != %d",
+              ch, temporder, size, 3);
     }
 
     ch = 0x64;
     str.setTo(ch);
     iter->setText(str, status);
     temporder = iter->previous(status);
-
-    if (U_FAILURE(status) || coll.getMaxExpansion(temporder) != 1) {
-        errln("Failure at codepoint %d, maximum expansion count != %d\n",
-                ch, 3);
+    size = coll.getMaxExpansion(temporder);
+    if (U_FAILURE(status) || size != 1) {
+        errln("Failure at codepoint U+%04X, CE %08x, maximum expansion count %d != %d",
+              ch, temporder, size, 1);
     }
 
     str.setTo(unassigned);
     iter->setText(str, status);
     sorder = iter->previous(status);
-
-    if (U_FAILURE(status) || coll.getMaxExpansion(sorder) != 2) {
-        errln("Failure at supplementary codepoints, maximum expansion count < %d\n",
-              2);
+    size = coll.getMaxExpansion(sorder);
+    if (U_FAILURE(status) || size != 2) {
+        errln("Failure at supplementary codepoints, maximum expansion count %d < %d",
+              size, 2);
     }
 
     /* testing jamo */
@@ -1324,9 +1390,10 @@ void CollationAPITest::TestMaxExpansion()
     str.setTo(ch);
     iter->setText(str, status);
     temporder = iter->previous(status);
-    if (U_FAILURE(status) || coll.getMaxExpansion(temporder) > 3) {
-        errln("Failure at codepoint %d, maximum expansion count > %d\n",
-              ch, 3);
+    size = coll.getMaxExpansion(temporder);
+    if (U_FAILURE(status) || size > 3) {
+        errln("Failure at codepoint U+%04X, maximum expansion count %d > %d",
+              ch, size, 3);
     }
 
     delete iter;
@@ -1337,9 +1404,10 @@ void CollationAPITest::TestMaxExpansion()
     RuleBasedCollator jamocoll(rule, status);
     iter = jamocoll.createCollationElementIterator(str);
     temporder = iter->previous(status);
-    if (U_FAILURE(status) || iter->getMaxExpansion(temporder) != 6) {
-        errln("Failure at codepoint %d, maximum expansion count > %d\n",
-              ch, 5);
+    size = iter->getMaxExpansion(temporder);
+    if (U_FAILURE(status) || size != 6) {
+        errln("Failure at codepoint U+%04X, maximum expansion count %d > %d",
+              ch, size, 5);
     }
 
     delete iter;
@@ -1350,7 +1418,7 @@ void CollationAPITest::TestDisplayName()
     UErrorCode error = U_ZERO_ERROR;
     Collator *coll = Collator::createInstance("en_US", error);
     if (U_FAILURE(error)) {
-        errln("Failure creating english collator");
+        errcheckln(error, "Failure creating english collator - %s", u_errorName(error));
         return;
     }
     UnicodeString name;
@@ -1375,7 +1443,7 @@ void CollationAPITest::TestAttribute()
     Collator *coll = Collator::createInstance(error);
 
     if (U_FAILURE(error)) {
-        errln("Creation of default collator failed");
+        errcheckln(error, "Creation of default collator failed - %s", u_errorName(error));
         return;
     }
 
@@ -1480,7 +1548,7 @@ void CollationAPITest::TestVariableTopSetting() {
   Collator *coll = Collator::createInstance(status);
   if(U_FAILURE(status)) {
     delete coll;
-    errln("Collator creation failed with error %s", u_errorName(status));
+    errcheckln(status, "Collator creation failed with error %s", u_errorName(status));
     return;
   }
 
@@ -1620,14 +1688,14 @@ void CollationAPITest::TestBounds(void) {
     Collator *coll = Collator::createInstance(Locale("sh"), status);
     if(U_FAILURE(status)) {
       delete coll;
-      errln("Collator creation failed with %s", u_errorName(status));
+      errcheckln(status, "Collator creation failed with %s", u_errorName(status));
       return;
     }
 
     uint8_t sortkey[512], lower[512], upper[512];
     UChar buffer[512];
 
-    const char *test[] = {
+    static const char * const test[] = {
         "John Smith",
         "JOHN SMITH",
         "john SMITH",
@@ -1638,7 +1706,7 @@ void CollationAPITest::TestBounds(void) {
         "John Smithsonian"
     };
 
-    static struct teststruct tests[] = {
+    struct teststruct tests[] = {
         {"\\u010CAKI MIHALJ", {0}},
         {"\\u010CAKI MIHALJ", {0}},
         {"\\u010CAKI PIRO\\u0160KA", {0}},
@@ -1781,7 +1849,7 @@ void CollationAPITest::TestGetTailoredSet()
       }
       delete set;
     } else {
-      errln("Couldn't open collator with rules %s\n", setTest[i].rules);
+      errcheckln(status, "Couldn't open collator with rules %s - %s", setTest[i].rules, u_errorName(status));
     }
     delete coll;
   }
@@ -1798,7 +1866,7 @@ void CollationAPITest::TestUClassID()
         = (RuleBasedCollator *)Collator::createInstance(status);
     if(U_FAILURE(status)) {
       delete coll;
-      errln("Collator creation failed with %s", u_errorName(status));
+      errcheckln(status, "Collator creation failed with %s", u_errorName(status));
       return;
     }
     id = *((char *)coll->getDynamicClassID());
@@ -1834,32 +1902,7 @@ class TestCollator  : public Collator
 public:
     virtual Collator* clone(void) const;
 
-    // dang, markus says we can't use 'using' in ICU.  I hate doing this for
-    // deprecated methods...
-
-    // using Collator::compare;
-
-    virtual EComparisonResult compare(const UnicodeString& source, 
-                                      const UnicodeString& target) const
-    {
-        return Collator::compare(source, target);
-    }
-
-    virtual EComparisonResult compare(const UnicodeString& source,
-                                      const UnicodeString& target,
-                                      int32_t length) const
-    {
-        return Collator::compare(source, target, length);
-    }
-
-    virtual EComparisonResult compare(const UChar* source, 
-                                      int32_t sourceLength, 
-                                      const UChar* target, 
-                                      int32_t targetLength) const
-    {
-        return Collator::compare(source, sourceLength, target, targetLength);
-    }
-
+    using Collator::compare;
 
     virtual UCollationResult compare(const UnicodeString& source, 
                                       const UnicodeString& target,
@@ -1881,8 +1924,7 @@ public:
                                           CollationKey& key,
                                           UErrorCode& status) const;
     virtual int32_t hashCode(void) const;
-    virtual const Locale getLocale(ULocDataLocaleType type, 
-                                   UErrorCode& status) const;
+    virtual Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
     virtual ECollationStrength getStrength(void) const;
     virtual void setStrength(ECollationStrength newStrength);
     virtual UClassID getDynamicClassID(void) const;
@@ -1890,35 +1932,38 @@ public:
     virtual void setAttribute(UColAttribute attr, UColAttributeValue value, 
                               UErrorCode &status);
     virtual UColAttributeValue getAttribute(UColAttribute attr, 
-                                            UErrorCode &status);
+                                            UErrorCode &status) const;
     virtual uint32_t setVariableTop(const UChar *varTop, int32_t len, 
                                     UErrorCode &status);
-    virtual uint32_t setVariableTop(const UnicodeString varTop, 
+    virtual uint32_t setVariableTop(const UnicodeString &varTop, 
                                     UErrorCode &status);
-    virtual void setVariableTop(const uint32_t varTop, UErrorCode &status);
+    virtual void setVariableTop(uint32_t varTop, UErrorCode &status);
     virtual uint32_t getVariableTop(UErrorCode &status) const;
-    virtual Collator* safeClone(void);
     virtual int32_t getSortKey(const UnicodeString& source,
                             uint8_t* result,
                             int32_t resultLength) const;
     virtual int32_t getSortKey(const UChar*source, int32_t sourceLength,
                              uint8_t*result, int32_t resultLength) const;
     virtual UnicodeSet *getTailoredSet(UErrorCode &status) const;
-    virtual UBool operator!=(const Collator& other) const;
-    virtual void setLocales(const Locale& requestedLocale, const Locale& validLocale);
+    virtual UBool operator==(const Collator& other) const;
+    // Collator::operator!= calls !Collator::operator== which works for all subclasses.
+    virtual void setLocales(const Locale& requestedLocale, const Locale& validLocale, const Locale& actualLocale);
     TestCollator() : Collator() {};
     TestCollator(UCollationStrength collationStrength, 
            UNormalizationMode decompositionMode) : Collator(collationStrength, decompositionMode) {};
 };
 
-inline UBool TestCollator::operator!=(const Collator& other) const {
-    return Collator::operator!=(other);
-}
+inline UBool TestCollator::operator==(const Collator& other) const {
+    // TestCollator has no fields, so we test for identity.
+    return this == &other;
 
-#define returnEComparisonResult(data) \
-    if (data < 0) return Collator::LESS;\
-    if (data > 0) return Collator::GREATER;\
-    return Collator::EQUAL;
+    // Normally, subclasses should do something like the following:
+    //    if (this == &other) { return TRUE; }
+    //    if (!Collator::operator==(other)) { return FALSE; }  // not the same class
+    //
+    //    const TestCollator &o = (const TestCollator&)other;
+    //    (compare this vs. o's subclass fields)
+}
 
 Collator* TestCollator::clone() const
 {
@@ -2004,8 +2049,7 @@ int32_t TestCollator::hashCode() const
     return 0;
 }
 
-const Locale TestCollator::getLocale(ULocDataLocaleType type, 
-                                     UErrorCode& status) const
+Locale TestCollator::getLocale(ULocDataLocaleType type, UErrorCode& status) const
 {
     // api not used, this is to make the compiler happy
     if (U_FAILURE(status)) {
@@ -2047,7 +2091,7 @@ void TestCollator::setAttribute(UColAttribute attr, UColAttributeValue value,
 }
 
 UColAttributeValue TestCollator::getAttribute(UColAttribute attr, 
-                                              UErrorCode &status)
+                                              UErrorCode &status) const
 {
     // api not used, this is to make the compiler happy
     if (U_FAILURE(status) || attr == UCOL_ATTRIBUTE_COUNT) {
@@ -2066,7 +2110,7 @@ uint32_t TestCollator::setVariableTop(const UChar *varTop, int32_t len,
     return 0;
 }
 
-uint32_t TestCollator::setVariableTop(const UnicodeString varTop, 
+uint32_t TestCollator::setVariableTop(const UnicodeString &varTop, 
                                   UErrorCode &status)
 {
     // api not used, this is to make the compiler happy
@@ -2076,7 +2120,7 @@ uint32_t TestCollator::setVariableTop(const UnicodeString varTop,
     return 0;
 }
 
-void TestCollator::setVariableTop(const uint32_t varTop, UErrorCode &status)
+void TestCollator::setVariableTop(uint32_t varTop, UErrorCode &status)
 {
     // api not used, this is to make the compiler happy
     if (U_SUCCESS(status) && varTop == 0) {
@@ -2094,19 +2138,14 @@ uint32_t TestCollator::getVariableTop(UErrorCode &status) const
     return (uint32_t)(0xFFFFFFFFu);
 }
 
-Collator* TestCollator::safeClone(void)
-{
-    return new TestCollator();
-}
-
 UnicodeSet * TestCollator::getTailoredSet(UErrorCode &status) const
 {
     return Collator::getTailoredSet(status);
 }
 
-void TestCollator::setLocales(const Locale& requestedLocale, const Locale& validLocale) 
+void TestCollator::setLocales(const Locale& requestedLocale, const Locale& validLocale, const Locale& actualLocale
 {
-    Collator::setLocales(requestedLocale, validLocale);
+    Collator::setLocales(requestedLocale, validLocale, actualLocale);
 }
 
 
@@ -2114,7 +2153,7 @@ void CollationAPITest::TestSubclass()
 {
     TestCollator col1;
     TestCollator col2;
-    doAssert(col1 != col2, "2 instance of TestCollator should be different");
+    doAssert(col1 != col2, "2 instances of TestCollator should be different");
     if (col1.hashCode() != col2.hashCode()) {
         errln("Every TestCollator has the same hashcode");
     }
@@ -2145,7 +2184,7 @@ void CollationAPITest::TestSubclass()
     // use base class implementation
     Locale loc1 = Locale::getGermany();
     Locale loc2 = Locale::getFrance();
-    col1.setLocales(loc1, loc2); // default implementation has no effect
+    col1.setLocales(loc1, loc2, loc2); // default implementation has no effect
 
     UnicodeString displayName;
     col1.getDisplayName(loc1, loc2, displayName); // de_DE collator in fr_FR locale
@@ -2174,7 +2213,9 @@ void CollationAPITest::TestNULLCharTailoring()
     UnicodeString second((UChar)0);
     RuleBasedCollator *coll = new RuleBasedCollator(UnicodeString(buf, len), status);
     if(U_FAILURE(status)) {
-        errln("Failed to open collator");
+        delete coll;
+        errcheckln(status, "Failed to open collator - %s", u_errorName(status));
+        return;
     }
     UCollationResult res = coll->compare(first, second, status);
     if(res != UCOL_LESS) {
@@ -2187,6 +2228,12 @@ void CollationAPITest::TestClone() {
     logln("\ninit c0");
     UErrorCode status = U_ZERO_ERROR;
     RuleBasedCollator* c0 = (RuleBasedCollator*)Collator::createInstance(status);
+
+    if (U_FAILURE(status)) {
+        errcheckln(status, "Collator::CreateInstance(status) failed with %s", u_errorName(status));
+        return;
+    }
+
     c0->setStrength(Collator::TERTIARY);
     dump("c0", c0, status);
 
@@ -2236,33 +2283,33 @@ void CollationAPITest::TestClone() {
 void CollationAPITest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par */)
 {
     if (exec) logln("TestSuite CollationAPITest: ");
-    switch (index) {
-        case 0: name = "TestProperty";  if (exec)   TestProperty(/* par */); break;
-        case 1: name = "TestOperators"; if (exec)   TestOperators(/* par */); break;
-        case 2: name = "TestDuplicate"; if (exec)   TestDuplicate(/* par */); break;
-        case 3: name = "TestCompare";   if (exec)   TestCompare(/* par */); break;
-        case 4: name = "TestHashCode";  if (exec)   TestHashCode(/* par */); break;
-        case 5: name = "TestCollationKey";  if (exec)   TestCollationKey(/* par */); break;
-        case 6: name = "TestElemIter";  if (exec)   TestElemIter(/* par */); break;
-        case 7: name = "TestGetAll";    if (exec)   TestGetAll(/* par */); break;
-        case 8: name = "TestRuleBasedColl"; if (exec)   TestRuleBasedColl(/* par */); break;
-        case 9: name = "TestDecomposition"; if (exec)   TestDecomposition(/* par */); break;
-        case 10: name = "TestSafeClone"; if (exec)   TestSafeClone(/* par */); break;
-        case 11: name = "TestSortKey";   if (exec)   TestSortKey(); break;
-        case 12: name = "TestMaxExpansion";   if (exec)   TestMaxExpansion(); break;
-        case 13: name = "TestDisplayName";   if (exec)   TestDisplayName(); break;
-        case 14: name = "TestAttribute";   if (exec)   TestAttribute(); break;
-        case 15: name = "TestVariableTopSetting"; if (exec) TestVariableTopSetting(); break;
-        case 16: name = "TestRules"; if (exec) TestRules(); break;
-        case 17: name = "TestGetLocale"; if (exec) TestGetLocale(); break;
-        case 18: name = "TestBounds"; if (exec) TestBounds(); break;
-        case 19: name = "TestGetTailoredSet"; if (exec) TestGetTailoredSet(); break;
-        case 20: name = "TestUClassID"; if (exec) TestUClassID(); break;
-        case 21: name = "TestSubclass"; if (exec) TestSubclass(); break;
-        case 22: name = "TestNULLCharTailoring"; if (exec) TestNULLCharTailoring(); break;
-        case 23: name = "TestClone"; if (exec) TestClone(); break;
-        default: name = ""; break;
-    }
+    TESTCASE_AUTO_BEGIN;
+    TESTCASE_AUTO(TestProperty);
+    TESTCASE_AUTO(TestOperators);
+    TESTCASE_AUTO(TestDuplicate);
+    TESTCASE_AUTO(TestCompare);
+    TESTCASE_AUTO(TestHashCode);
+    TESTCASE_AUTO(TestCollationKey);
+    TESTCASE_AUTO(TestElemIter);
+    TESTCASE_AUTO(TestGetAll);
+    TESTCASE_AUTO(TestRuleBasedColl);
+    TESTCASE_AUTO(TestDecomposition);
+    TESTCASE_AUTO(TestSafeClone);
+    TESTCASE_AUTO(TestSortKey);
+    TESTCASE_AUTO(TestSortKeyOverflow);
+    TESTCASE_AUTO(TestMaxExpansion);
+    TESTCASE_AUTO(TestDisplayName);
+    TESTCASE_AUTO(TestAttribute);
+    TESTCASE_AUTO(TestVariableTopSetting);
+    TESTCASE_AUTO(TestRules);
+    TESTCASE_AUTO(TestGetLocale);
+    TESTCASE_AUTO(TestBounds);
+    TESTCASE_AUTO(TestGetTailoredSet);
+    TESTCASE_AUTO(TestUClassID);
+    TESTCASE_AUTO(TestSubclass);
+    TESTCASE_AUTO(TestNULLCharTailoring);
+    TESTCASE_AUTO(TestClone);
+    TESTCASE_AUTO_END;
 }
 
 #endif /* #if !UCONFIG_NO_COLLATION */