1/* 2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/intl/locale_helper.h" 17#include "ecmascript/ecma_string.h" 18#include "ecmascript/global_env.h" 19#include "ecmascript/js_collator.h" 20#include "ecmascript/js_object-inl.h" 21#include "ecmascript/tests/test_helper.h" 22 23using namespace panda::ecmascript; 24using namespace panda::ecmascript::base; 25using LocaleHelper = panda::ecmascript::intl::LocaleHelper; 26 27namespace panda::test { 28class LocaleHelperTest : public BaseTestWithScope<true> { 29}; 30 31/** 32 * @tc.name: UStringToString 33 * @tc.desc: Call "UStringToString" function Convert UnicodeString to string(Utf16). 34 * @tc.type: FUNC 35 * @tc.require: 36 */ 37HWTEST_F_L0(LocaleHelperTest, UStringToString) 38{ 39 icu::UnicodeString unicodeString1("GMT-12:00"); // times 40 JSHandle<EcmaString> ecmaString = LocaleHelper::UStringToString(thread, unicodeString1); 41 EXPECT_STREQ("GMT-12:00", EcmaStringAccessor(ecmaString).ToCString().c_str()); 42 43 icu::UnicodeString unicodeString2("周日16:00:00–周五23:00:00"); // date 44 ecmaString = LocaleHelper::UStringToString(thread, unicodeString2); 45 EXPECT_STREQ("周日16:00:00–周五23:00:00", EcmaStringAccessor(ecmaString).ToCString().c_str()); 46 47 icu::UnicodeString unicodeString3("$654K"); // money 48 ecmaString = LocaleHelper::UStringToString(thread, unicodeString3); 49 EXPECT_STREQ("$654K", EcmaStringAccessor(ecmaString).ToCString().c_str()); 50 51 icu::UnicodeString unicodeString4("1 minute ago"); // moment 52 ecmaString = LocaleHelper::UStringToString(thread, unicodeString4, 0, 2); 53 EXPECT_STREQ("1 ", EcmaStringAccessor(ecmaString).ToCString().c_str()); 54} 55 56/** 57 * @tc.name: CanonicalizeLocaleList 58 * @tc.desc: Create a list of locales and canonicalize the locales in the list through "CanonicalizeUnicodeLocaleId" 59 * function. 60 * @tc.type: FUNC 61 * @tc.require: 62 */ 63HWTEST_F_L0(LocaleHelperTest, CanonicalizeLocaleList) 64{ 65 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 66 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 67 JSHandle<JSTaggedValue> ctor = env->GetLocaleFunction(); 68 JSHandle<JSLocale> jsLocale = 69 JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor)); 70 // Set IcuLocale 71 icu::Locale icuLocale("fr", "Latn", "Fr"); 72 factory->NewJSIntlIcuData(jsLocale, icuLocale, JSLocale::FreeIcuLocale); 73 // test locale is jslocale 74 JSHandle<TaggedArray> localeArr = LocaleHelper::CanonicalizeLocaleList(thread, JSHandle<JSTaggedValue>(jsLocale)); 75 EXPECT_EQ(localeArr->GetLength(), 1U); 76 JSHandle<EcmaString> handleEcmaStr(thread, localeArr->Get(0)); 77 EXPECT_STREQ("fr-Latn-FR", EcmaStringAccessor(handleEcmaStr).ToCString().c_str()); 78 // test locale is object 79 JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>(); 80 JSHandle<JSTaggedValue> localeObj(thread, arr); 81 82 JSHandle<JSTaggedValue> localeStr1(factory->NewFromASCII("EN-us")); 83 PropertyDescriptor desc1(thread, localeStr1, true, true, true); 84 JSHandle<JSTaggedValue> key1(factory->NewFromASCII("1")); 85 JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(localeObj), key1, desc1); 86 87 JSHandle<JSTaggedValue> localeStr2(factory->NewFromASCII("en-GB")); 88 PropertyDescriptor desc2(thread, localeStr2, true, true, true); 89 JSHandle<JSTaggedValue> key2(factory->NewFromASCII("2")); 90 JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(localeObj), key2, desc2); 91 // check canonicalized string 92 localeArr = LocaleHelper::CanonicalizeLocaleList(thread, localeObj); 93 EXPECT_EQ(localeArr->GetLength(), 2U); 94 JSHandle<EcmaString> resultEcmaStr1(thread, localeArr->Get(0)); 95 EXPECT_STREQ("en-US", EcmaStringAccessor(resultEcmaStr1).ToCString().c_str()); 96 JSHandle<EcmaString> resultEcmaStr2(thread, localeArr->Get(1)); 97 EXPECT_STREQ("en-GB", EcmaStringAccessor(resultEcmaStr2).ToCString().c_str()); 98} 99 100/** 101 * @tc.name: CanonicalizeUnicodeLocaleId 102 * @tc.desc: Call "CanonicalizeUnicodeLocaleId" function canonicalize locale(Language-Tag),The English case of language, 103 * region and script is fixed.the language is lowercase.the beginning of region is uppercase, and the script 104 * is lowercase.if locale string is IsUtf16,return empty string. 105 * @tc.type: FUNC 106 * @tc.require: 107 */ 108HWTEST_F_L0(LocaleHelperTest, CanonicalizeUnicodeLocaleId) 109{ 110 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 111 112 JSHandle<EcmaString> locale = factory-> NewFromStdString("en-Us"); 113 JSHandle<EcmaString> canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale); 114 EXPECT_STREQ("en-US", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str()); 115 116 locale = factory-> NewFromStdString("kO-kore-kr"); 117 canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale); 118 EXPECT_STREQ("ko-Kore-KR", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str()); 119 120 locale = factory-> NewFromStdString("id-u-co-pinyin-de-ID"); 121 canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale); 122 EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(canonicalizeLocaleId).ToCString().c_str()); 123 // invalid locale 124 uint16_t localeArr[] = {0x122, 0x104, 0x45, 0x72, 0x97, 0x110, 0x115, 0x45, 0x67, 0x78}; // zh-Hans-CN 125 uint32_t localeArrLength = sizeof(localeArr) / sizeof(localeArr[0]); 126 locale = factory->NewFromUtf16(localeArr, localeArrLength); 127 128 canonicalizeLocaleId = LocaleHelper::CanonicalizeUnicodeLocaleId(thread, locale); 129 JSHandle<EcmaString> emptyString = factory->GetEmptyString(); 130 EXPECT_EQ(EcmaStringAccessor::Compare(instance, canonicalizeLocaleId, emptyString), 0); 131} 132 133/** 134 * @tc.name: ToLanguageTag 135 * @tc.desc: call "ToLanguageTag" function Convert ICU Locale into language tag. 136 * @tc.type: FUNC 137 * @tc.require: 138 */ 139HWTEST_F_L0(LocaleHelperTest, ToLanguageTag) 140{ 141 icu::Locale icuLocale1("en", "Latn", "US", "collation=phonebk;currency=euro"); 142 JSHandle<EcmaString> languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale1); 143 EXPECT_STREQ("en-Latn-US-u-co-phonebk-cu-euro", EcmaStringAccessor(languageTag).ToCString().c_str()); 144 145 icu::Locale icuLocale2("zh", "Hans", "CN", "collation=phonebk;kn=true"); 146 languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale2); 147 EXPECT_STREQ("zh-Hans-CN-u-co-phonebk-kn", EcmaStringAccessor(languageTag).ToCString().c_str()); 148 149 icu::Locale icuLocale3("ja", "Jpan", "JP", "collation=phonebk;co=yes"); 150 languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale3); 151 EXPECT_STREQ("ja-Jpan-JP-u-co", EcmaStringAccessor(languageTag).ToCString().c_str()); 152 153 icu::Locale icuLocale4("z", "CN"); // language is fault 154 languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale4); 155 EXPECT_STREQ("und-CN", EcmaStringAccessor(languageTag).ToCString().c_str()); 156 157 icu::Locale icuLocale5("zh", "c"); // script is fault 158 languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale5); 159 EXPECT_STREQ("zh-x-lvariant-c", EcmaStringAccessor(languageTag).ToCString().c_str()); 160 161 icu::Locale icuLocale6("en", "Latn", "E"); // region is fault 162 languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale6); 163 EXPECT_STREQ("en-Latn-x-lvariant-e", EcmaStringAccessor(languageTag).ToCString().c_str()); 164 165 icu::Locale icuLocale7("en", "Latn", "EG", "kf=yes"); // key value is fault 166 languageTag = LocaleHelper::ToLanguageTag(thread, icuLocale7); 167 EXPECT_STREQ("en-Latn-EG-u-kf", EcmaStringAccessor(languageTag).ToCString().c_str()); 168} 169 170/** 171 * @tc.name: IsStructurallyValidLanguageTag 172 * @tc.desc: Call "IsStructurallyValidLanguageTag" function check Language-Tag is valid structurally.If the tag contains 173 * the correct language, region, script and extension, return true otherwise, return false. 174 * @tc.type: FUNC 175 * @tc.require: 176 */ 177HWTEST_F_L0(LocaleHelperTest, IsStructurallyValidLanguageTag) 178{ 179 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 180 // number-language 181 JSHandle<EcmaString> handleEcmaStr = factory->NewFromStdString("123-de"); 182 EXPECT_FALSE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr)); 183 // only language(zh) 184 handleEcmaStr = factory-> NewFromStdString("zh"); 185 EXPECT_TRUE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr)); 186 // only language and script, region 187 handleEcmaStr = factory-> NewFromStdString("zh-Hans-Cn"); 188 EXPECT_TRUE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr)); 189 190 handleEcmaStr = factory-> NewFromStdString("ja-JP-u-ca-japanese"); 191 EXPECT_TRUE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr)); 192 193 handleEcmaStr = factory-> NewFromStdString("语言脚本地区"); 194 EXPECT_FALSE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr)); 195 196 handleEcmaStr = factory-> NewFromStdString("e-US"); 197 EXPECT_FALSE(LocaleHelper::IsStructurallyValidLanguageTag(handleEcmaStr)); 198} 199 200/** 201 * @tc.name: ConvertToStdString 202 * @tc.desc: Convert char* type to std string,check whether the returned string through "ConvertToStdString" 203 * function is within expectations. 204 * @tc.type: FUNC 205 * @tc.require: 206 */ 207HWTEST_F_L0(LocaleHelperTest, ConvertToStdString) 208{ 209 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 210 JSHandle<EcmaString> handleEcmaStr = factory-> NewFromStdString("一二三四"); 211 std::string stdString = LocaleHelper::ConvertToStdString(handleEcmaStr); 212 EXPECT_STREQ(stdString.c_str(), "一二三四"); 213 214 handleEcmaStr = factory-> NewFromStdString("#%!\0@$"); 215 stdString = LocaleHelper::ConvertToStdString(handleEcmaStr); 216 EXPECT_STREQ(stdString.c_str(), "#%!\0@$"); 217 218 handleEcmaStr = factory-> NewFromStdString("123456"); 219 stdString = LocaleHelper::ConvertToStdString(handleEcmaStr); 220 EXPECT_STREQ(stdString.c_str(), "123456"); 221 222 handleEcmaStr = factory-> NewFromStdString("zhde"); 223 stdString = LocaleHelper::ConvertToStdString(handleEcmaStr); 224 EXPECT_STREQ(stdString.c_str(), "zhde"); 225} 226 227/** 228 * @tc.name: HandleLocaleExtension 229 * @tc.desc: Find position of subtag "x" or "u" in Locale through "HandleLocaleExtension" function. 230 * @tc.type: FUNC 231 * @tc.require: 232 */ 233HWTEST_F_L0(LocaleHelperTest, HandleLocaleExtension) 234{ 235 std::string result = "en-Latn-US-u-ca-gregory-co-compat"; 236 size_t start = 0; 237 size_t extensionEnd = 0; 238 LocaleHelper::HandleLocaleExtension(start, extensionEnd, result, result.size()); 239 EXPECT_EQ(extensionEnd, 10U); // the position of "u" 240 // private extension("x") 241 result = "de-zh-x-co-phonebk-nu-kali"; 242 start = 0; 243 extensionEnd = 0; 244 LocaleHelper::HandleLocaleExtension(start, extensionEnd, result, result.size()); 245 EXPECT_EQ(extensionEnd, 5U); // the position of "x" 246} 247 248/** 249 * @tc.name: HandleLocale 250 * @tc.desc: Call "HandleLocale" function handle locale,if Locale has subtag "u" ignore it.If Locale has 251 * both subtag "x" and "u","x" is in front of "u","u" does not ignore,"x" is after "u","u" ignores. 252 * @tc.type: FUNC 253 * @tc.require: 254 */ 255HWTEST_F_L0(LocaleHelperTest, HandleLocale) 256{ 257 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 258 // no "u" or "x" 259 JSHandle<EcmaString> localeString = factory->NewFromASCII("en-Latn-US"); 260 LocaleHelper::ParsedLocale parsedResult = LocaleHelper::HandleLocale(localeString); 261 EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US"); 262 // only "x" 263 localeString = factory->NewFromASCII("zh-CN-x-ca-pinyin"); 264 parsedResult = LocaleHelper::HandleLocale(localeString); 265 EXPECT_STREQ(parsedResult.base.c_str(), "zh-CN-x-ca-pinyin"); 266 // only "u" 267 localeString = factory->NewFromASCII("ko-Kore-KR-u-co-phonebk"); 268 parsedResult = LocaleHelper::HandleLocale(localeString); 269 EXPECT_STREQ(parsedResult.base.c_str(), "ko-Kore-KR"); 270 // both "x" and "u" 271 localeString = factory->NewFromASCII("en-Latn-US-u-x-co-phonebk-kn-true"); 272 parsedResult = LocaleHelper::HandleLocale(localeString); 273 EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US-x-co-phonebk-kn-true"); 274 275 localeString = factory->NewFromASCII("en-Latn-US-x-u-ca-pinyin-co-compat"); 276 parsedResult = LocaleHelper::HandleLocale(localeString); 277 EXPECT_STREQ(parsedResult.base.c_str(), "en-Latn-US-x-u-ca-pinyin-co-compat"); 278} 279 280/** 281 * @tc.name: BestAvailableLocale 282 * @tc.desc: Match the best Locale and return from available locale through "BestAvailableLocale" function. 283 * @tc.type: FUNC 284 * @tc.require: 285 */ 286HWTEST_F_L0(LocaleHelperTest, BestAvailableLocale) 287{ 288 const char *path = JSCollator::uIcuDataColl.c_str(); 289 // available locales in uIcuDataColl 290 std::vector<std::string> icuDataAvailableLocales = 291 LocaleHelper::GetAvailableLocales(thread, nullptr, path); 292 // available locales(calendar) 293 std::vector<std::string> calendarAvailableLocales = 294 LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr); 295 // available locales(NumberElements) 296 std::vector<std::string> numberAvailableLocales = 297 LocaleHelper::GetAvailableLocales(thread, "NumberElements", nullptr); 298 // "ar-001" is found 299 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "ar-001").c_str(), "ar-001"); 300 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "ar-001").c_str(), "ar-001"); 301 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "ar-001").c_str(), "ar-001"); 302 // "agq-CM" is not found in uIcuDataColl 303 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "agq-CM").c_str(), ""); 304 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "agq-CM").c_str(), "agq-CM"); 305 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "agq-CM").c_str(), "agq-CM"); 306 // language(und)-region(CN) 307 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "und-CN").c_str(), ""); 308 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "und-CN").c_str(), ""); 309 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "und-CN").c_str(), ""); 310 // language(en)-region(001) 311 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "en-001").c_str(), "en-001"); 312 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "en-001").c_str(), "en-001"); 313 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "en-001").c_str(), "en-001"); 314 // language(en)-script(Hans)-region(US) 315 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(icuDataAvailableLocales, "en-Hans-US").c_str(), "en"); 316 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(calendarAvailableLocales, "en-Hans-US").c_str(), "en"); 317 EXPECT_STREQ(LocaleHelper::BestAvailableLocale(numberAvailableLocales, "en-Hans-US").c_str(), "en"); 318} 319} // namespace panda::test