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