12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci/*
42e5b6d6dSopenharmony_ci *******************************************************************************
52e5b6d6dSopenharmony_ci * Copyright (C) 2003-2016, International Business Machines Corporation and
62e5b6d6dSopenharmony_ci * others. All Rights Reserved.
72e5b6d6dSopenharmony_ci *******************************************************************************
82e5b6d6dSopenharmony_ci */
92e5b6d6dSopenharmony_ci
102e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
112e5b6d6dSopenharmony_ci
122e5b6d6dSopenharmony_ci#if !UCONFIG_NO_COLLATION
132e5b6d6dSopenharmony_ci
142e5b6d6dSopenharmony_ci#include "svccoll.h"
152e5b6d6dSopenharmony_ci#include "unicode/coll.h"
162e5b6d6dSopenharmony_ci#include "unicode/strenum.h"
172e5b6d6dSopenharmony_ci#include "cmemory.h"
182e5b6d6dSopenharmony_ci#include "hash.h"
192e5b6d6dSopenharmony_ci#include "uassert.h"
202e5b6d6dSopenharmony_ci
212e5b6d6dSopenharmony_ci#include "cstring.h" // internal api used to compare locale strings
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_civoid CollationServiceTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par */)
242e5b6d6dSopenharmony_ci{
252e5b6d6dSopenharmony_ci    if (exec) logln("TestSuite CollationServiceTest: ");
262e5b6d6dSopenharmony_ci    switch (index) {
272e5b6d6dSopenharmony_ci        TESTCASE(0, TestRegister);
282e5b6d6dSopenharmony_ci        TESTCASE(1, TestRegisterFactory);
292e5b6d6dSopenharmony_ci        TESTCASE(2, TestSeparateTree);
302e5b6d6dSopenharmony_ci    default: name = ""; break;
312e5b6d6dSopenharmony_ci    }
322e5b6d6dSopenharmony_ci}
332e5b6d6dSopenharmony_ci
342e5b6d6dSopenharmony_civoid CollationServiceTest::TestRegister()
352e5b6d6dSopenharmony_ci{
362e5b6d6dSopenharmony_ci#if !UCONFIG_NO_SERVICE
372e5b6d6dSopenharmony_ci    // register a singleton
382e5b6d6dSopenharmony_ci    const Locale& FR = Locale::getFrance();
392e5b6d6dSopenharmony_ci    const Locale& US = Locale::getUS();
402e5b6d6dSopenharmony_ci    const Locale US_FOO("en", "US", "FOO");
412e5b6d6dSopenharmony_ci
422e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
432e5b6d6dSopenharmony_ci
442e5b6d6dSopenharmony_ci    Collator* frcol = Collator::createInstance(FR, status);
452e5b6d6dSopenharmony_ci    Collator* uscol = Collator::createInstance(US, status);
462e5b6d6dSopenharmony_ci    if(U_FAILURE(status)) {
472e5b6d6dSopenharmony_ci        errcheckln(status, "Failed to create collators with %s", u_errorName(status));
482e5b6d6dSopenharmony_ci        delete frcol;
492e5b6d6dSopenharmony_ci        delete uscol;
502e5b6d6dSopenharmony_ci        return;
512e5b6d6dSopenharmony_ci    }
522e5b6d6dSopenharmony_ci
532e5b6d6dSopenharmony_ci    { // try override en_US collator
542e5b6d6dSopenharmony_ci        Collator *clone = frcol->clone();
552e5b6d6dSopenharmony_ci        URegistryKey key = Collator::registerInstance(frcol, US, status);
562e5b6d6dSopenharmony_ci        // frcol has been adopted. We must not use it any more, nor rely on its attributes.
572e5b6d6dSopenharmony_ci        frcol = NULL;
582e5b6d6dSopenharmony_ci
592e5b6d6dSopenharmony_ci        Collator* ncol = Collator::createInstance(US_FOO, status);
602e5b6d6dSopenharmony_ci        if (*clone != *ncol) {
612e5b6d6dSopenharmony_ci            errln("register of french collator for en_US failed on request for en_US_FOO");
622e5b6d6dSopenharmony_ci        }
632e5b6d6dSopenharmony_ci        delete clone;
642e5b6d6dSopenharmony_ci
652e5b6d6dSopenharmony_ci        // The requested locale may be the same as the valid locale,
662e5b6d6dSopenharmony_ci        // or may not be supported at all. See ticket #10477.
672e5b6d6dSopenharmony_ci        Locale loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status);
682e5b6d6dSopenharmony_ci        if (U_SUCCESS(status) && loc != US_FOO && loc != US) {
692e5b6d6dSopenharmony_ci            errln(UnicodeString("requested locale for en_US_FOO is not en_US_FOO nor en_US but ") + loc.getName());
702e5b6d6dSopenharmony_ci        }
712e5b6d6dSopenharmony_ci        status = U_ZERO_ERROR;
722e5b6d6dSopenharmony_ci        loc = ncol->getLocale(ULOC_VALID_LOCALE, status);
732e5b6d6dSopenharmony_ci        if (loc != US) {
742e5b6d6dSopenharmony_ci            errln(UnicodeString("valid locale for en_US_FOO is not en_US but ") + loc.getName());
752e5b6d6dSopenharmony_ci        }
762e5b6d6dSopenharmony_ci        loc = ncol->getLocale(ULOC_ACTUAL_LOCALE, status);
772e5b6d6dSopenharmony_ci        if (loc != US) {
782e5b6d6dSopenharmony_ci            errln(UnicodeString("actual locale for en_US_FOO is not en_US but ") + loc.getName());
792e5b6d6dSopenharmony_ci        }
802e5b6d6dSopenharmony_ci        delete ncol; ncol = NULL;
812e5b6d6dSopenharmony_ci
822e5b6d6dSopenharmony_ci        if (!Collator::unregister(key, status)) {
832e5b6d6dSopenharmony_ci            errln("failed to unregister french collator");
842e5b6d6dSopenharmony_ci        }
852e5b6d6dSopenharmony_ci
862e5b6d6dSopenharmony_ci        ncol = Collator::createInstance(US, status);
872e5b6d6dSopenharmony_ci        if (*uscol != *ncol) {
882e5b6d6dSopenharmony_ci            errln("collator after unregister does not match original");
892e5b6d6dSopenharmony_ci        }
902e5b6d6dSopenharmony_ci        delete ncol; ncol = NULL;
912e5b6d6dSopenharmony_ci    }
922e5b6d6dSopenharmony_ci
932e5b6d6dSopenharmony_ci    // recreate frcol
942e5b6d6dSopenharmony_ci    frcol = Collator::createInstance(FR, status);
952e5b6d6dSopenharmony_ci
962e5b6d6dSopenharmony_ci    LocalUCollatorPointer frFR(ucol_open("fr_FR", &status));
972e5b6d6dSopenharmony_ci
982e5b6d6dSopenharmony_ci    { // try create collator for new locale
992e5b6d6dSopenharmony_ci        Locale fu_FU_FOO("fu", "FU", "FOO");
1002e5b6d6dSopenharmony_ci        Locale fu_FU("fu", "FU", "");
1012e5b6d6dSopenharmony_ci
1022e5b6d6dSopenharmony_ci        Collator* fucol = Collator::createInstance(fu_FU, status);
1032e5b6d6dSopenharmony_ci        Collator *clone = frcol->clone();
1042e5b6d6dSopenharmony_ci        URegistryKey key = Collator::registerInstance(frcol, fu_FU, status);
1052e5b6d6dSopenharmony_ci        frcol = NULL;  // frcol has been adopted.
1062e5b6d6dSopenharmony_ci        Collator* ncol = Collator::createInstance(fu_FU_FOO, status);
1072e5b6d6dSopenharmony_ci        if (*clone != *ncol) {
1082e5b6d6dSopenharmony_ci            errln("register of fr collator for fu_FU failed");
1092e5b6d6dSopenharmony_ci        }
1102e5b6d6dSopenharmony_ci        delete clone;
1112e5b6d6dSopenharmony_ci
1122e5b6d6dSopenharmony_ci        UnicodeString locName = fu_FU.getName();
1132e5b6d6dSopenharmony_ci        StringEnumeration* localeEnum = Collator::getAvailableLocales();
1142e5b6d6dSopenharmony_ci        UBool found = false;
1152e5b6d6dSopenharmony_ci        const UnicodeString* locStr, *ls2;
1162e5b6d6dSopenharmony_ci        for (locStr = localeEnum->snext(status);
1172e5b6d6dSopenharmony_ci        !found && locStr != NULL;
1182e5b6d6dSopenharmony_ci        locStr = localeEnum->snext(status)) {
1192e5b6d6dSopenharmony_ci            //
1202e5b6d6dSopenharmony_ci            if (locName == *locStr) {
1212e5b6d6dSopenharmony_ci                found = true;
1222e5b6d6dSopenharmony_ci            }
1232e5b6d6dSopenharmony_ci        }
1242e5b6d6dSopenharmony_ci
1252e5b6d6dSopenharmony_ci        StringEnumeration *le2 = NULL;
1262e5b6d6dSopenharmony_ci        localeEnum->reset(status);
1272e5b6d6dSopenharmony_ci        int32_t i, count;
1282e5b6d6dSopenharmony_ci        count = localeEnum->count(status);
1292e5b6d6dSopenharmony_ci        for(i = 0; i < count; ++i) {
1302e5b6d6dSopenharmony_ci            if(i == count / 2) {
1312e5b6d6dSopenharmony_ci                le2 = localeEnum->clone();
1322e5b6d6dSopenharmony_ci                if(le2 == NULL || count != le2->count(status)) {
1332e5b6d6dSopenharmony_ci                    errln("ServiceEnumeration.clone() failed");
1342e5b6d6dSopenharmony_ci                    break;
1352e5b6d6dSopenharmony_ci                }
1362e5b6d6dSopenharmony_ci            }
1372e5b6d6dSopenharmony_ci            if(i >= count / 2) {
1382e5b6d6dSopenharmony_ci                locStr = localeEnum->snext(status);
1392e5b6d6dSopenharmony_ci                ls2 = le2->snext(status);
1402e5b6d6dSopenharmony_ci                if(*locStr != *ls2) {
1412e5b6d6dSopenharmony_ci                    errln("ServiceEnumeration.clone() failed for item %d", i);
1422e5b6d6dSopenharmony_ci                }
1432e5b6d6dSopenharmony_ci            } else {
1442e5b6d6dSopenharmony_ci                localeEnum->snext(status);
1452e5b6d6dSopenharmony_ci            }
1462e5b6d6dSopenharmony_ci        }
1472e5b6d6dSopenharmony_ci
1482e5b6d6dSopenharmony_ci        delete localeEnum;
1492e5b6d6dSopenharmony_ci        delete le2;
1502e5b6d6dSopenharmony_ci
1512e5b6d6dSopenharmony_ci        if (!found) {
1522e5b6d6dSopenharmony_ci            errln("new locale fu_FU not reported as supported locale");
1532e5b6d6dSopenharmony_ci        }
1542e5b6d6dSopenharmony_ci
1552e5b6d6dSopenharmony_ci        UnicodeString displayName;
1562e5b6d6dSopenharmony_ci        Collator::getDisplayName(fu_FU, displayName);
1572e5b6d6dSopenharmony_ci        /* The locale display pattern for the locale ja, ko, and zh are different. */
1582e5b6d6dSopenharmony_ci        const UChar zh_fuFU_Array[] = { 0x0066, 0x0075, 0xff08, 0x0046, 0x0055, 0xff09, 0 };
1592e5b6d6dSopenharmony_ci        const UnicodeString zh_fuFU(zh_fuFU_Array);
1602e5b6d6dSopenharmony_ci        const Locale& defaultLocale = Locale::getDefault();
1612e5b6d6dSopenharmony_ci        if (displayName != "fu (FU)" &&
1622e5b6d6dSopenharmony_ci           ((defaultLocale == Locale::getKorean() && defaultLocale == Locale::getJapanese()) && displayName == "fu(FU)") &&
1632e5b6d6dSopenharmony_ci           ((defaultLocale == Locale::getChinese()) && displayName != zh_fuFU)) {
1642e5b6d6dSopenharmony_ci            errln(UnicodeString("found ") + displayName + " for fu_FU");
1652e5b6d6dSopenharmony_ci        }
1662e5b6d6dSopenharmony_ci
1672e5b6d6dSopenharmony_ci        Collator::getDisplayName(fu_FU, fu_FU, displayName);
1682e5b6d6dSopenharmony_ci        if (displayName != "fu (FU)" &&
1692e5b6d6dSopenharmony_ci           ((defaultLocale == Locale::getKorean() && defaultLocale == Locale::getJapanese()) && displayName == "fu(FU)") &&
1702e5b6d6dSopenharmony_ci           ((defaultLocale == Locale::getChinese()) && displayName != zh_fuFU)) {
1712e5b6d6dSopenharmony_ci            errln(UnicodeString("found ") + displayName + " for fu_FU");
1722e5b6d6dSopenharmony_ci        }
1732e5b6d6dSopenharmony_ci
1742e5b6d6dSopenharmony_ci        // test ucol_open
1752e5b6d6dSopenharmony_ci        LocalUCollatorPointer fufu(ucol_open("fu_FU_FOO", &status));
1762e5b6d6dSopenharmony_ci        if (fufu.isNull()) {
1772e5b6d6dSopenharmony_ci            errln("could not open fu_FU_FOO with ucol_open");
1782e5b6d6dSopenharmony_ci        } else {
1792e5b6d6dSopenharmony_ci            if (*Collator::fromUCollator(fufu.getAlias()) !=
1802e5b6d6dSopenharmony_ci                    *Collator::fromUCollator(frFR.getAlias())) {
1812e5b6d6dSopenharmony_ci                errln("collator fufu != collator frFR");
1822e5b6d6dSopenharmony_ci            }
1832e5b6d6dSopenharmony_ci        }
1842e5b6d6dSopenharmony_ci
1852e5b6d6dSopenharmony_ci        if (!Collator::unregister(key, status)) {
1862e5b6d6dSopenharmony_ci            errln("failed to unregister french collator");
1872e5b6d6dSopenharmony_ci        }
1882e5b6d6dSopenharmony_ci        // !!! note frcoll invalid again, but we're no longer using it
1892e5b6d6dSopenharmony_ci
1902e5b6d6dSopenharmony_ci        // other collators should still work ok
1912e5b6d6dSopenharmony_ci        Locale nloc = ncol->getLocale(ULOC_VALID_LOCALE, status);
1922e5b6d6dSopenharmony_ci        if (nloc != fu_FU) {
1932e5b6d6dSopenharmony_ci            errln(UnicodeString("asked for nloc valid locale after close and got") + nloc.getName());
1942e5b6d6dSopenharmony_ci        }
1952e5b6d6dSopenharmony_ci        delete ncol; ncol = NULL;
1962e5b6d6dSopenharmony_ci
1972e5b6d6dSopenharmony_ci        if (fufu.isValid()) {
1982e5b6d6dSopenharmony_ci            const char* nlocstr = ucol_getLocaleByType(fufu.getAlias(), ULOC_VALID_LOCALE, &status);
1992e5b6d6dSopenharmony_ci            if (uprv_strcmp(nlocstr, "fu_FU") != 0) {
2002e5b6d6dSopenharmony_ci                errln(UnicodeString("asked for uloc valid locale after close and got ") + nlocstr);
2012e5b6d6dSopenharmony_ci            }
2022e5b6d6dSopenharmony_ci        }
2032e5b6d6dSopenharmony_ci
2042e5b6d6dSopenharmony_ci        ncol = Collator::createInstance(fu_FU, status);
2052e5b6d6dSopenharmony_ci        if (*fucol != *ncol) {
2062e5b6d6dSopenharmony_ci            errln("collator after unregister does not match original fu_FU");
2072e5b6d6dSopenharmony_ci        }
2082e5b6d6dSopenharmony_ci        delete uscol; uscol = NULL;
2092e5b6d6dSopenharmony_ci        delete ncol; ncol = NULL;
2102e5b6d6dSopenharmony_ci        delete fucol; fucol = NULL;
2112e5b6d6dSopenharmony_ci    }
2122e5b6d6dSopenharmony_ci#endif
2132e5b6d6dSopenharmony_ci}
2142e5b6d6dSopenharmony_ci
2152e5b6d6dSopenharmony_ci// ------------------
2162e5b6d6dSopenharmony_ci
2172e5b6d6dSopenharmony_ci#if !UCONFIG_NO_SERVICE
2182e5b6d6dSopenharmony_cistruct CollatorInfo {
2192e5b6d6dSopenharmony_ci  Locale locale;
2202e5b6d6dSopenharmony_ci  Collator* collator;
2212e5b6d6dSopenharmony_ci  Hashtable* displayNames; // locale name -> string
2222e5b6d6dSopenharmony_ci
2232e5b6d6dSopenharmony_ci  CollatorInfo(const Locale& locale, Collator* collatorToAdopt, Hashtable* displayNamesToAdopt);
2242e5b6d6dSopenharmony_ci  ~CollatorInfo();
2252e5b6d6dSopenharmony_ci  UnicodeString& getDisplayName(const Locale& displayLocale, UnicodeString& name) const;
2262e5b6d6dSopenharmony_ci};
2272e5b6d6dSopenharmony_ci
2282e5b6d6dSopenharmony_ciCollatorInfo::CollatorInfo(const Locale& _locale, Collator* _collator, Hashtable* _displayNames)
2292e5b6d6dSopenharmony_ci  : locale(_locale)
2302e5b6d6dSopenharmony_ci  , collator(_collator)
2312e5b6d6dSopenharmony_ci  , displayNames(_displayNames)
2322e5b6d6dSopenharmony_ci{
2332e5b6d6dSopenharmony_ci  collator->setLocales(locale, locale, locale);
2342e5b6d6dSopenharmony_ci}
2352e5b6d6dSopenharmony_ci
2362e5b6d6dSopenharmony_ciCollatorInfo::~CollatorInfo() {
2372e5b6d6dSopenharmony_ci  delete collator;
2382e5b6d6dSopenharmony_ci  delete displayNames;
2392e5b6d6dSopenharmony_ci}
2402e5b6d6dSopenharmony_ci
2412e5b6d6dSopenharmony_ciUnicodeString&
2422e5b6d6dSopenharmony_ciCollatorInfo::getDisplayName(const Locale& displayLocale, UnicodeString& name) const {
2432e5b6d6dSopenharmony_ci  if (displayNames) {
2442e5b6d6dSopenharmony_ci    UnicodeString* val = (UnicodeString*)displayNames->get(displayLocale.getName());
2452e5b6d6dSopenharmony_ci    if (val) {
2462e5b6d6dSopenharmony_ci      name = *val;
2472e5b6d6dSopenharmony_ci      return name;
2482e5b6d6dSopenharmony_ci    }
2492e5b6d6dSopenharmony_ci  }
2502e5b6d6dSopenharmony_ci
2512e5b6d6dSopenharmony_ci  return locale.getDisplayName(displayLocale, name);
2522e5b6d6dSopenharmony_ci}
2532e5b6d6dSopenharmony_ci
2542e5b6d6dSopenharmony_ci// ---------------
2552e5b6d6dSopenharmony_ci
2562e5b6d6dSopenharmony_ciclass TestFactory : public CollatorFactory {
2572e5b6d6dSopenharmony_ci  CollatorInfo** info;
2582e5b6d6dSopenharmony_ci  int32_t count;
2592e5b6d6dSopenharmony_ci  UnicodeString* ids;
2602e5b6d6dSopenharmony_ci
2612e5b6d6dSopenharmony_ci  const CollatorInfo* getInfo(const Locale& loc) const {
2622e5b6d6dSopenharmony_ci    for (CollatorInfo** p = info; *p; ++p) {
2632e5b6d6dSopenharmony_ci      if (loc == (**p).locale) {
2642e5b6d6dSopenharmony_ci        return *p;
2652e5b6d6dSopenharmony_ci      }
2662e5b6d6dSopenharmony_ci    }
2672e5b6d6dSopenharmony_ci    return NULL;
2682e5b6d6dSopenharmony_ci  }
2692e5b6d6dSopenharmony_ci
2702e5b6d6dSopenharmony_cipublic:
2712e5b6d6dSopenharmony_ci  TestFactory(CollatorInfo** _info)
2722e5b6d6dSopenharmony_ci    : info(_info)
2732e5b6d6dSopenharmony_ci    , count(0)
2742e5b6d6dSopenharmony_ci    , ids(NULL)
2752e5b6d6dSopenharmony_ci  {
2762e5b6d6dSopenharmony_ci    CollatorInfo** p;
2772e5b6d6dSopenharmony_ci    for (p = info; *p; ++p) {}
2782e5b6d6dSopenharmony_ci    count = (int32_t)(p - info);
2792e5b6d6dSopenharmony_ci  }
2802e5b6d6dSopenharmony_ci
2812e5b6d6dSopenharmony_ci  ~TestFactory() {
2822e5b6d6dSopenharmony_ci    for (CollatorInfo** p = info; *p; ++p) {
2832e5b6d6dSopenharmony_ci      delete *p;
2842e5b6d6dSopenharmony_ci    }
2852e5b6d6dSopenharmony_ci    delete[] info;
2862e5b6d6dSopenharmony_ci    delete[] ids;
2872e5b6d6dSopenharmony_ci  }
2882e5b6d6dSopenharmony_ci
2892e5b6d6dSopenharmony_ci  virtual Collator* createCollator(const Locale& loc) override {
2902e5b6d6dSopenharmony_ci    const CollatorInfo* ci = getInfo(loc);
2912e5b6d6dSopenharmony_ci    if (ci) {
2922e5b6d6dSopenharmony_ci      return ci->collator->clone();
2932e5b6d6dSopenharmony_ci    }
2942e5b6d6dSopenharmony_ci    return NULL;
2952e5b6d6dSopenharmony_ci  }
2962e5b6d6dSopenharmony_ci
2972e5b6d6dSopenharmony_ci  virtual UnicodeString& getDisplayName(const Locale& objectLocale,
2982e5b6d6dSopenharmony_ci                                        const Locale& displayLocale,
2992e5b6d6dSopenharmony_ci                                        UnicodeString& result) override
3002e5b6d6dSopenharmony_ci  {
3012e5b6d6dSopenharmony_ci    const CollatorInfo* ci = getInfo(objectLocale);
3022e5b6d6dSopenharmony_ci    if (ci) {
3032e5b6d6dSopenharmony_ci      ci->getDisplayName(displayLocale, result);
3042e5b6d6dSopenharmony_ci    } else {
3052e5b6d6dSopenharmony_ci      result.setToBogus();
3062e5b6d6dSopenharmony_ci    }
3072e5b6d6dSopenharmony_ci    return result;
3082e5b6d6dSopenharmony_ci  }
3092e5b6d6dSopenharmony_ci
3102e5b6d6dSopenharmony_ci  const UnicodeString* getSupportedIDs(int32_t& _count, UErrorCode& status) override {
3112e5b6d6dSopenharmony_ci    if (U_SUCCESS(status)) {
3122e5b6d6dSopenharmony_ci      if (!ids) {
3132e5b6d6dSopenharmony_ci        ids = new UnicodeString[count];
3142e5b6d6dSopenharmony_ci        if (!ids) {
3152e5b6d6dSopenharmony_ci          status = U_MEMORY_ALLOCATION_ERROR;
3162e5b6d6dSopenharmony_ci          _count = 0;
3172e5b6d6dSopenharmony_ci          return NULL;
3182e5b6d6dSopenharmony_ci        }
3192e5b6d6dSopenharmony_ci
3202e5b6d6dSopenharmony_ci        for (int i = 0; i < count; ++i) {
3212e5b6d6dSopenharmony_ci          ids[i] = info[i]->locale.getName();
3222e5b6d6dSopenharmony_ci        }
3232e5b6d6dSopenharmony_ci      }
3242e5b6d6dSopenharmony_ci
3252e5b6d6dSopenharmony_ci      _count = count;
3262e5b6d6dSopenharmony_ci      return ids;
3272e5b6d6dSopenharmony_ci    }
3282e5b6d6dSopenharmony_ci    return NULL;
3292e5b6d6dSopenharmony_ci  }
3302e5b6d6dSopenharmony_ci
3312e5b6d6dSopenharmony_ci  virtual inline UClassID getDynamicClassID() const override {
3322e5b6d6dSopenharmony_ci    return (UClassID)&gClassID;
3332e5b6d6dSopenharmony_ci  }
3342e5b6d6dSopenharmony_ci
3352e5b6d6dSopenharmony_ci  static UClassID getStaticClassID() {
3362e5b6d6dSopenharmony_ci    return (UClassID)&gClassID;
3372e5b6d6dSopenharmony_ci  }
3382e5b6d6dSopenharmony_ci
3392e5b6d6dSopenharmony_ciprivate:
3402e5b6d6dSopenharmony_ci  static char gClassID;
3412e5b6d6dSopenharmony_ci};
3422e5b6d6dSopenharmony_ci
3432e5b6d6dSopenharmony_cichar TestFactory::gClassID = 0;
3442e5b6d6dSopenharmony_ci#endif
3452e5b6d6dSopenharmony_ci
3462e5b6d6dSopenharmony_civoid CollationServiceTest::TestRegisterFactory(void)
3472e5b6d6dSopenharmony_ci{
3482e5b6d6dSopenharmony_ci#if !UCONFIG_NO_SERVICE
3492e5b6d6dSopenharmony_ci    int32_t n1, n2, n3;
3502e5b6d6dSopenharmony_ci    Locale fu_FU("fu", "FU", "");
3512e5b6d6dSopenharmony_ci    Locale fu_FU_FOO("fu", "FU", "FOO");
3522e5b6d6dSopenharmony_ci
3532e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
3542e5b6d6dSopenharmony_ci
3552e5b6d6dSopenharmony_ci    Hashtable* fuFUNames = new Hashtable(false, status);
3562e5b6d6dSopenharmony_ci    if (!fuFUNames) {
3572e5b6d6dSopenharmony_ci        errln("memory allocation error");
3582e5b6d6dSopenharmony_ci        return;
3592e5b6d6dSopenharmony_ci    }
3602e5b6d6dSopenharmony_ci    fuFUNames->setValueDeleter(uprv_deleteUObject);
3612e5b6d6dSopenharmony_ci
3622e5b6d6dSopenharmony_ci    fuFUNames->put(fu_FU.getName(), new UnicodeString("ze leetle bunny Fu-Fu"), status);
3632e5b6d6dSopenharmony_ci    fuFUNames->put(fu_FU_FOO.getName(), new UnicodeString("zee leetel bunny Foo-Foo"), status);
3642e5b6d6dSopenharmony_ci    fuFUNames->put(Locale::getDefault().getName(), new UnicodeString("little bunny Foo Foo"), status);
3652e5b6d6dSopenharmony_ci
3662e5b6d6dSopenharmony_ci    Collator* frcol = Collator::createInstance(Locale::getFrance(), status);
3672e5b6d6dSopenharmony_ci    Collator* gecol = Collator::createInstance(Locale::getGermany(), status);
3682e5b6d6dSopenharmony_ci    Collator* jpcol = Collator::createInstance(Locale::getJapan(), status);
3692e5b6d6dSopenharmony_ci    if(U_FAILURE(status)) {
3702e5b6d6dSopenharmony_ci      errcheckln(status, "Failed to create collators with %s", u_errorName(status));
3712e5b6d6dSopenharmony_ci      delete frcol;
3722e5b6d6dSopenharmony_ci      delete gecol;
3732e5b6d6dSopenharmony_ci      delete jpcol;
3742e5b6d6dSopenharmony_ci      delete fuFUNames;
3752e5b6d6dSopenharmony_ci      return;
3762e5b6d6dSopenharmony_ci    }
3772e5b6d6dSopenharmony_ci
3782e5b6d6dSopenharmony_ci    CollatorInfo** info = new CollatorInfo*[4];
3792e5b6d6dSopenharmony_ci    if (!info) {
3802e5b6d6dSopenharmony_ci        errln("memory allocation error");
3812e5b6d6dSopenharmony_ci        return;
3822e5b6d6dSopenharmony_ci    }
3832e5b6d6dSopenharmony_ci
3842e5b6d6dSopenharmony_ci    info[0] = new CollatorInfo(Locale::getUS(), frcol, NULL);
3852e5b6d6dSopenharmony_ci    info[1] = new CollatorInfo(Locale::getFrance(), gecol, NULL);
3862e5b6d6dSopenharmony_ci    info[2] = new CollatorInfo(fu_FU, jpcol, fuFUNames);
3872e5b6d6dSopenharmony_ci    info[3] = NULL;
3882e5b6d6dSopenharmony_ci
3892e5b6d6dSopenharmony_ci    TestFactory* factory = new TestFactory(info);
3902e5b6d6dSopenharmony_ci    if (!factory) {
3912e5b6d6dSopenharmony_ci        errln("memory allocation error");
3922e5b6d6dSopenharmony_ci        return;
3932e5b6d6dSopenharmony_ci    }
3942e5b6d6dSopenharmony_ci
3952e5b6d6dSopenharmony_ci    Collator* uscol = Collator::createInstance(Locale::getUS(), status);
3962e5b6d6dSopenharmony_ci    Collator* fucol = Collator::createInstance(fu_FU, status);
3972e5b6d6dSopenharmony_ci
3982e5b6d6dSopenharmony_ci    {
3992e5b6d6dSopenharmony_ci        n1 = checkAvailable("before registerFactory");
4002e5b6d6dSopenharmony_ci
4012e5b6d6dSopenharmony_ci        URegistryKey key = Collator::registerFactory(factory, status);
4022e5b6d6dSopenharmony_ci
4032e5b6d6dSopenharmony_ci        n2 = checkAvailable("after registerFactory");
4042e5b6d6dSopenharmony_ci        assertTrue("count after > count before", n2 > n1);
4052e5b6d6dSopenharmony_ci
4062e5b6d6dSopenharmony_ci        Collator* ncol = Collator::createInstance(Locale::getUS(), status);
4072e5b6d6dSopenharmony_ci        if (*frcol != *ncol) {
4082e5b6d6dSopenharmony_ci            errln("frcoll for en_US failed");
4092e5b6d6dSopenharmony_ci        }
4102e5b6d6dSopenharmony_ci        delete ncol; ncol = NULL;
4112e5b6d6dSopenharmony_ci
4122e5b6d6dSopenharmony_ci        ncol = Collator::createInstance(fu_FU_FOO, status);
4132e5b6d6dSopenharmony_ci        if (*jpcol != *ncol) {
4142e5b6d6dSopenharmony_ci            errln("jpcol for fu_FU_FOO failed");
4152e5b6d6dSopenharmony_ci        }
4162e5b6d6dSopenharmony_ci
4172e5b6d6dSopenharmony_ci        // The requested locale may be the same as the valid locale,
4182e5b6d6dSopenharmony_ci        // or may not be supported at all. See ticket #10477.
4192e5b6d6dSopenharmony_ci        Locale loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status);
4202e5b6d6dSopenharmony_ci        if (U_SUCCESS(status) && loc != fu_FU_FOO && loc != fu_FU) {
4212e5b6d6dSopenharmony_ci            errln(UnicodeString("requested locale for fu_FU_FOO is not fu_FU_FOO nor fu_FU but ") + loc.getName());
4222e5b6d6dSopenharmony_ci        }
4232e5b6d6dSopenharmony_ci        status = U_ZERO_ERROR;
4242e5b6d6dSopenharmony_ci        loc = ncol->getLocale(ULOC_VALID_LOCALE, status);
4252e5b6d6dSopenharmony_ci        if (loc != fu_FU) {
4262e5b6d6dSopenharmony_ci            errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc.getName());
4272e5b6d6dSopenharmony_ci        }
4282e5b6d6dSopenharmony_ci        delete ncol; ncol = NULL;
4292e5b6d6dSopenharmony_ci
4302e5b6d6dSopenharmony_ci        UnicodeString locName = fu_FU.getName();
4312e5b6d6dSopenharmony_ci        StringEnumeration* localeEnum = Collator::getAvailableLocales();
4322e5b6d6dSopenharmony_ci        UBool found = false;
4332e5b6d6dSopenharmony_ci        const UnicodeString* locStr;
4342e5b6d6dSopenharmony_ci        for (locStr = localeEnum->snext(status);
4352e5b6d6dSopenharmony_ci            !found && locStr != NULL;
4362e5b6d6dSopenharmony_ci            locStr = localeEnum->snext(status))
4372e5b6d6dSopenharmony_ci        {
4382e5b6d6dSopenharmony_ci            if (locName == *locStr) {
4392e5b6d6dSopenharmony_ci                found = true;
4402e5b6d6dSopenharmony_ci            }
4412e5b6d6dSopenharmony_ci        }
4422e5b6d6dSopenharmony_ci        delete localeEnum;
4432e5b6d6dSopenharmony_ci
4442e5b6d6dSopenharmony_ci        if (!found) {
4452e5b6d6dSopenharmony_ci            errln("new locale fu_FU not reported as supported locale");
4462e5b6d6dSopenharmony_ci        }
4472e5b6d6dSopenharmony_ci
4482e5b6d6dSopenharmony_ci        UnicodeString name;
4492e5b6d6dSopenharmony_ci        Collator::getDisplayName(fu_FU, name);
4502e5b6d6dSopenharmony_ci        if (name != "little bunny Foo Foo") {
4512e5b6d6dSopenharmony_ci            errln(UnicodeString("found ") + name + " for fu_FU");
4522e5b6d6dSopenharmony_ci        }
4532e5b6d6dSopenharmony_ci
4542e5b6d6dSopenharmony_ci        Collator::getDisplayName(fu_FU, fu_FU_FOO, name);
4552e5b6d6dSopenharmony_ci        if (name != "zee leetel bunny Foo-Foo") {
4562e5b6d6dSopenharmony_ci            errln(UnicodeString("found ") + name + " for fu_FU in fu_FU_FOO");
4572e5b6d6dSopenharmony_ci        }
4582e5b6d6dSopenharmony_ci
4592e5b6d6dSopenharmony_ci        if (!Collator::unregister(key, status)) {
4602e5b6d6dSopenharmony_ci            errln("failed to unregister factory");
4612e5b6d6dSopenharmony_ci        }
4622e5b6d6dSopenharmony_ci        // ja, fr, ge collators no longer valid
4632e5b6d6dSopenharmony_ci
4642e5b6d6dSopenharmony_ci        ncol = Collator::createInstance(fu_FU, status);
4652e5b6d6dSopenharmony_ci        if (*fucol != *ncol) {
4662e5b6d6dSopenharmony_ci            errln("collator after unregister does not match original fu_FU");
4672e5b6d6dSopenharmony_ci        }
4682e5b6d6dSopenharmony_ci        delete ncol;
4692e5b6d6dSopenharmony_ci
4702e5b6d6dSopenharmony_ci        n3 = checkAvailable("after unregister");
4712e5b6d6dSopenharmony_ci        assertTrue("count after unregister == count before register", n3 == n1);
4722e5b6d6dSopenharmony_ci    }
4732e5b6d6dSopenharmony_ci
4742e5b6d6dSopenharmony_ci    delete fucol;
4752e5b6d6dSopenharmony_ci    delete uscol;
4762e5b6d6dSopenharmony_ci#endif
4772e5b6d6dSopenharmony_ci}
4782e5b6d6dSopenharmony_ci
4792e5b6d6dSopenharmony_ci/**
4802e5b6d6dSopenharmony_ci * Iterate through the given iterator, checking to see that all the strings
4812e5b6d6dSopenharmony_ci * in the expected array are present.
4822e5b6d6dSopenharmony_ci * @param expected array of strings we expect to see, or NULL
4832e5b6d6dSopenharmony_ci * @param expectedCount number of elements of expected, or 0
4842e5b6d6dSopenharmony_ci */
4852e5b6d6dSopenharmony_ciint32_t CollationServiceTest::checkStringEnumeration(const char* msg,
4862e5b6d6dSopenharmony_ci                                                     StringEnumeration& iter,
4872e5b6d6dSopenharmony_ci                                                     const char** expected,
4882e5b6d6dSopenharmony_ci                                                     int32_t expectedCount) {
4892e5b6d6dSopenharmony_ci    UErrorCode ec = U_ZERO_ERROR;
4902e5b6d6dSopenharmony_ci    U_ASSERT(expectedCount >= 0 && expectedCount < 31); // [sic] 31 not 32
4912e5b6d6dSopenharmony_ci    int32_t i = 0, idxAfterReset = 0, n = iter.count(ec);
4922e5b6d6dSopenharmony_ci    assertSuccess("count", ec);
4932e5b6d6dSopenharmony_ci    UnicodeString buf, buffAfterReset;
4942e5b6d6dSopenharmony_ci    int32_t seenMask = 0;
4952e5b6d6dSopenharmony_ci    for (;; ++i) {
4962e5b6d6dSopenharmony_ci        const UnicodeString* s = iter.snext(ec);
4972e5b6d6dSopenharmony_ci        if (!assertSuccess("snext", ec) || s == NULL)
4982e5b6d6dSopenharmony_ci            break;
4992e5b6d6dSopenharmony_ci        if (i != 0)
5002e5b6d6dSopenharmony_ci            buf.append(UNICODE_STRING_SIMPLE(", "));
5012e5b6d6dSopenharmony_ci        buf.append(*s);
5022e5b6d6dSopenharmony_ci        // check expected list
5032e5b6d6dSopenharmony_ci        for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) {
5042e5b6d6dSopenharmony_ci            if ((seenMask&bit)==0) {
5052e5b6d6dSopenharmony_ci                UnicodeString exp(expected[j], (char*)NULL);
5062e5b6d6dSopenharmony_ci                if (*s == exp) {
5072e5b6d6dSopenharmony_ci                    seenMask |= bit;
5082e5b6d6dSopenharmony_ci                    logln((UnicodeString)"Ok: \"" + exp + "\" seen");
5092e5b6d6dSopenharmony_ci                }
5102e5b6d6dSopenharmony_ci            }
5112e5b6d6dSopenharmony_ci        }
5122e5b6d6dSopenharmony_ci    }
5132e5b6d6dSopenharmony_ci    // can't get pesky operator+(const US&, foo) to cooperate; use toString
5142e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING
5152e5b6d6dSopenharmony_ci    logln(UnicodeString() + msg + " = [" + buf + "] (" + toString(i) + ")");
5162e5b6d6dSopenharmony_ci#else
5172e5b6d6dSopenharmony_ci    logln(UnicodeString() + msg + " = [" + buf + "] (??? NO_FORMATTING)");
5182e5b6d6dSopenharmony_ci#endif
5192e5b6d6dSopenharmony_ci    assertTrue("count verified", i==n);
5202e5b6d6dSopenharmony_ci    iter.reset(ec);
5212e5b6d6dSopenharmony_ci    for (;; ++idxAfterReset) {
5222e5b6d6dSopenharmony_ci        const UChar *s = iter.unext(NULL, ec);
5232e5b6d6dSopenharmony_ci        if (!assertSuccess("unext", ec) || s == NULL)
5242e5b6d6dSopenharmony_ci            break;
5252e5b6d6dSopenharmony_ci        if (idxAfterReset != 0)
5262e5b6d6dSopenharmony_ci            buffAfterReset.append(UNICODE_STRING_SIMPLE(", "));
5272e5b6d6dSopenharmony_ci        buffAfterReset.append(s);
5282e5b6d6dSopenharmony_ci    }
5292e5b6d6dSopenharmony_ci    assertTrue("idxAfterReset verified", idxAfterReset==n);
5302e5b6d6dSopenharmony_ci    assertTrue("buffAfterReset verified", buffAfterReset==buf);
5312e5b6d6dSopenharmony_ci    // did we see all expected strings?
5322e5b6d6dSopenharmony_ci    if (((1<<expectedCount)-1) != seenMask) {
5332e5b6d6dSopenharmony_ci        for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) {
5342e5b6d6dSopenharmony_ci            if ((seenMask&bit)==0) {
5352e5b6d6dSopenharmony_ci                errln((UnicodeString)"FAIL: \"" + expected[j] + "\" not seen");
5362e5b6d6dSopenharmony_ci            }
5372e5b6d6dSopenharmony_ci        }
5382e5b6d6dSopenharmony_ci    }
5392e5b6d6dSopenharmony_ci    return n;
5402e5b6d6dSopenharmony_ci}
5412e5b6d6dSopenharmony_ci
5422e5b6d6dSopenharmony_ci/**
5432e5b6d6dSopenharmony_ci * Check the integrity of the results of Collator::getAvailableLocales().
5442e5b6d6dSopenharmony_ci * Return the number of items returned.
5452e5b6d6dSopenharmony_ci */
5462e5b6d6dSopenharmony_ci#if !UCONFIG_NO_SERVICE
5472e5b6d6dSopenharmony_ciint32_t CollationServiceTest::checkAvailable(const char* msg) {
5482e5b6d6dSopenharmony_ci    StringEnumeration *iter = Collator::getAvailableLocales();
5492e5b6d6dSopenharmony_ci    if (!assertTrue("getAvailableLocales != NULL", iter!=NULL)) return -1;
5502e5b6d6dSopenharmony_ci    int32_t n = checkStringEnumeration(msg, *iter, NULL, 0);
5512e5b6d6dSopenharmony_ci    delete iter;
5522e5b6d6dSopenharmony_ci    return n;
5532e5b6d6dSopenharmony_ci}
5542e5b6d6dSopenharmony_ci#endif
5552e5b6d6dSopenharmony_ci
5562e5b6d6dSopenharmony_cistatic const char* KW[] = {
5572e5b6d6dSopenharmony_ci    "collation"
5582e5b6d6dSopenharmony_ci};
5592e5b6d6dSopenharmony_cistatic const int32_t KW_COUNT = UPRV_LENGTHOF(KW);
5602e5b6d6dSopenharmony_ci
5612e5b6d6dSopenharmony_cistatic const char* KWVAL[] = {
5622e5b6d6dSopenharmony_ci    "phonebook",
5632e5b6d6dSopenharmony_ci    "stroke",
5642e5b6d6dSopenharmony_ci    "emoji",
5652e5b6d6dSopenharmony_ci    "eor"
5662e5b6d6dSopenharmony_ci};
5672e5b6d6dSopenharmony_cistatic const int32_t KWVAL_COUNT = UPRV_LENGTHOF(KWVAL);
5682e5b6d6dSopenharmony_ci
5692e5b6d6dSopenharmony_civoid CollationServiceTest::TestSeparateTree() {
5702e5b6d6dSopenharmony_ci    UErrorCode ec = U_ZERO_ERROR;
5712e5b6d6dSopenharmony_ci    StringEnumeration *iter = Collator::getKeywords(ec);
5722e5b6d6dSopenharmony_ci    if (!assertTrue("getKeywords != NULL", iter!=NULL)) return;
5732e5b6d6dSopenharmony_ci    if (!assertSuccess("getKeywords", ec)) return;
5742e5b6d6dSopenharmony_ci    checkStringEnumeration("getKeywords", *iter, KW, KW_COUNT);
5752e5b6d6dSopenharmony_ci    delete iter;
5762e5b6d6dSopenharmony_ci
5772e5b6d6dSopenharmony_ci    iter = Collator::getKeywordValues(KW[0], ec);
5782e5b6d6dSopenharmony_ci    if (!assertTrue("getKeywordValues != NULL", iter!=NULL, false, true)) return;
5792e5b6d6dSopenharmony_ci    if (!assertSuccess("getKeywordValues", ec)) return;
5802e5b6d6dSopenharmony_ci    checkStringEnumeration("getKeywordValues", *iter, KWVAL, KWVAL_COUNT);
5812e5b6d6dSopenharmony_ci    delete iter;
5822e5b6d6dSopenharmony_ci
5832e5b6d6dSopenharmony_ci    UBool isAvailable;
5842e5b6d6dSopenharmony_ci    Locale equiv = Collator::getFunctionalEquivalent("collation",
5852e5b6d6dSopenharmony_ci                                                     Locale::createFromName("de"),
5862e5b6d6dSopenharmony_ci                                                     isAvailable, ec);
5872e5b6d6dSopenharmony_ci    assertSuccess("getFunctionalEquivalent", ec);
5882e5b6d6dSopenharmony_ci    assertEquals("getFunctionalEquivalent(de)", "", equiv.getName());
5892e5b6d6dSopenharmony_ci    assertTrue("getFunctionalEquivalent(de).isAvailable==true",
5902e5b6d6dSopenharmony_ci               isAvailable == true);
5912e5b6d6dSopenharmony_ci
5922e5b6d6dSopenharmony_ci    equiv = Collator::getFunctionalEquivalent("collation",
5932e5b6d6dSopenharmony_ci                                              Locale::createFromName("de_DE"),
5942e5b6d6dSopenharmony_ci                                              isAvailable, ec);
5952e5b6d6dSopenharmony_ci    assertSuccess("getFunctionalEquivalent", ec);
5962e5b6d6dSopenharmony_ci    assertEquals("getFunctionalEquivalent(de_DE)", "", equiv.getName());
5972e5b6d6dSopenharmony_ci    assertTrue("getFunctionalEquivalent(de_DE).isAvailable==false",
5982e5b6d6dSopenharmony_ci               isAvailable == false);
5992e5b6d6dSopenharmony_ci
6002e5b6d6dSopenharmony_ci    equiv = Collator::getFunctionalEquivalent("collation",
6012e5b6d6dSopenharmony_ci                                                     Locale::createFromName("sv"),
6022e5b6d6dSopenharmony_ci                                                     isAvailable, ec);
6032e5b6d6dSopenharmony_ci    assertSuccess("getFunctionalEquivalent", ec);
6042e5b6d6dSopenharmony_ci    assertEquals("getFunctionalEquivalent(sv)", "sv", equiv.getName());
6052e5b6d6dSopenharmony_ci    assertTrue("getFunctionalEquivalent(sv).isAvailable==true",
6062e5b6d6dSopenharmony_ci               isAvailable == true);
6072e5b6d6dSopenharmony_ci
6082e5b6d6dSopenharmony_ci    equiv = Collator::getFunctionalEquivalent("collation",
6092e5b6d6dSopenharmony_ci                                              Locale::createFromName("sv_SE"),
6102e5b6d6dSopenharmony_ci                                              isAvailable, ec);
6112e5b6d6dSopenharmony_ci    assertSuccess("getFunctionalEquivalent", ec);
6122e5b6d6dSopenharmony_ci    assertEquals("getFunctionalEquivalent(sv_SE)", "sv", equiv.getName());
6132e5b6d6dSopenharmony_ci    assertTrue("getFunctionalEquivalent(sv_SE).isAvailable==false",
6142e5b6d6dSopenharmony_ci               isAvailable == false);
6152e5b6d6dSopenharmony_ci}
6162e5b6d6dSopenharmony_ci
6172e5b6d6dSopenharmony_ci#endif
618