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/js_locale.h"
17#include "ecmascript/js_collator.h"
18#include "ecmascript/js_number_format.h"
19#include "ecmascript/js_plural_rules.h"
20#include "ecmascript/global_env.h"
21#include "ecmascript/object_factory-inl.h"
22#include "ecmascript/tests/test_helper.h"
23
24using namespace panda::ecmascript;
25
26namespace panda::test {
27class JSLocaleTest : public BaseTestWithScope<true> {
28};
29
30void CreateLanguageIterator(std::vector<std::string>& languageTemp)
31{
32    languageTemp.push_back("zh-Hans-Cn");
33    languageTemp.push_back("ko-kore-kr");
34    languageTemp.push_back("fr-FR");
35    languageTemp.push_back("en-Latn-US");
36    languageTemp.push_back("ja-JP-u-ca-japanese");
37    languageTemp.push_back("ar-EG");
38}
39
40/**
41 * @tc.name: JSIntlIteratorTest
42 * @tc.desc: Construct an iterator of JSIntl and then traverse the iterator to compare whether the variable
43 *           at each position is equal to the setting.
44 * @tc.type: FUNC
45 * @tc.require:
46 */
47HWTEST_F_L0(JSLocaleTest, JSIntlIteratorTest)
48{
49    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
50    std::vector<std::string> languageVector;
51    CreateLanguageIterator(languageVector);
52    uint32_t arrayDataLength = languageVector.size();
53    JSHandle<TaggedArray> arrayData = factory->NewTaggedArray(arrayDataLength);
54
55    for (uint32_t i = 0; i < arrayDataLength; i++) {
56        JSHandle<JSTaggedValue> languageStr(factory->NewFromASCII(languageVector[i].c_str()));
57        arrayData->Set(thread, i, languageStr);
58    }
59    // construct a JSIntlIterator object
60    JSIntlIterator jsIntlIterator(arrayData, arrayDataLength);
61    EXPECT_TRUE(jsIntlIterator.hasNext());
62    // call "next" function to traverse the container
63    for (uint32_t i = 0; i < arrayDataLength; i++) {
64        EXPECT_TRUE(jsIntlIterator.next() != nullptr);
65        EXPECT_STREQ(jsIntlIterator[i].c_str(), languageVector[i].c_str());
66    }
67    EXPECT_FALSE(jsIntlIterator.hasNext());
68}
69
70/**
71 * @tc.name: IsPrivateSubTag
72 * @tc.desc: Check whether the string is private subtag through "IsPrivateSubTag" function.
73 * @tc.type: FUNC
74 * @tc.require:
75 */
76HWTEST_F_L0(JSLocaleTest, IsPrivateSubTag)
77{
78    std::string result = "en-GB-oed";
79    EXPECT_FALSE(JSLocale::IsPrivateSubTag(result, result.length()));
80
81    result = "i-ami";
82    EXPECT_TRUE(JSLocale::IsPrivateSubTag(result, result.length()));
83
84    result = "x-default";
85    EXPECT_TRUE(JSLocale::IsPrivateSubTag(result, result.length()));
86}
87
88/**
89 * @tc.name: GetIcuField
90 * @tc.desc: Call "NewJSIntlIcuData" function Set locale IcuField,check whether the locale IcuField through
91 *           "getBaseName" function is within expectations.
92 * @tc.type: FUNC
93 * @tc.require:
94 */
95HWTEST_F_L0(JSLocaleTest, GetIcuField)
96{
97    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
98    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
99    JSHandle<JSTaggedValue> ctor = env->GetLocaleFunction();
100    JSHandle<JSLocale> locale =
101        JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
102    // call "NewJSIntlIcuData" function Set IcuField
103    icu::Locale icuLocale("zh", "Hans", "Cn");
104    factory->NewJSIntlIcuData(locale, icuLocale, JSLocale::FreeIcuLocale);
105
106    // call "GetIcuLocale" function Get IcuField
107    icu::Locale *result = locale->GetIcuLocale();
108    EXPECT_STREQ(result->getBaseName(), "zh_Hans_CN");
109}
110
111/**
112 * @tc.name: IsValidTimeZoneName
113 * @tc.desc: Call "IsValidTimeZoneName" function check whether the TimeZone is valid.if TimeZone include "GMT-Time"
114 *           return true otherwise, return false.
115 * @tc.type: FUNC
116 * @tc.require:
117 */
118HWTEST_F_L0(JSLocaleTest, IsValidTimeZoneName)
119{
120    icu::UnicodeString stringID1("GMT-8:00");
121    icu::TimeZone *timeZone = icu::TimeZone::createTimeZone(stringID1);
122    EXPECT_TRUE(JSLocale::IsValidTimeZoneName(*timeZone));
123    delete timeZone;
124
125    icu::UnicodeString stringID2("Etc/Unknown");
126    timeZone = icu::TimeZone::createTimeZone(stringID2);
127    EXPECT_FALSE(JSLocale::IsValidTimeZoneName(*timeZone));
128    delete timeZone;
129}
130
131/**
132 * @tc.name: PutElement
133 * @tc.desc: Put elements in empty JSArray and return the JSArray.call "GetProperty" function to get the value and
134 *           check whether the value is consistent with the value of the put.
135 * @tc.type: FUNC
136 * @tc.require:
137 */
138HWTEST_F_L0(JSLocaleTest, PutElement)
139{
140    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
141    auto globalConst = thread->GlobalConstants();
142    JSHandle<JSArray> jsArray = factory->NewJSArray();
143    JSHandle<JSTaggedValue> typeString = globalConst->GetHandledTypeString();
144    JSHandle<JSTaggedValue> valueString = globalConst->GetHandledValueString();
145    JSHandle<JSTaggedValue> fieldTypeString = globalConst->GetHandledUnitString();
146    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(static_cast<int>(11)));
147
148    int index = 1;
149    JSHandle<JSObject> recordObj = JSLocale::PutElement(thread, index, jsArray, fieldTypeString, value);
150    EXPECT_EQ(JSTaggedValue::SameValue(
151              JSObject::GetProperty(thread, recordObj, typeString).GetValue(), fieldTypeString), true);
152    EXPECT_EQ(JSObject::GetProperty(thread, recordObj, valueString).GetValue()->GetInt(), 11);
153
154    JSHandle<JSTaggedValue> indexKey(factory->NewFromASCII("1"));
155    EXPECT_TRUE(JSObject::GetProperty(thread, JSHandle<JSObject>(jsArray), indexKey).GetValue()->IsECMAObject());
156}
157
158/**
159 * @tc.name: GetNumberingSystem
160 * @tc.desc: Call "GetNumberingSystem" function get the script from the ICU Locale.
161 * @tc.type: FUNC
162 * @tc.require:
163 */
164HWTEST_F_L0(JSLocaleTest, GetNumberingSystem)
165{
166    icu::Locale icuLocale1("en", "US");
167    std::string numberingSystem = JSLocale::GetNumberingSystem(icuLocale1);
168    EXPECT_STREQ("latn", numberingSystem.c_str());
169
170    icu::Locale icuLocale2("zh", "Hans", "CN", "collation=phonebk;numbers=hans");
171    numberingSystem = JSLocale::GetNumberingSystem(icuLocale2);
172    EXPECT_STREQ("hans", numberingSystem.c_str());
173}
174
175/**
176 * @tc.name: GetNumberFieldType
177 * @tc.desc: Call "GetNumberFieldType" function get Number Field type.
178 * @tc.type: FUNC
179 * @tc.require:
180 */
181HWTEST_F_L0(JSLocaleTest, GetNumberFieldType)
182{
183    auto globalConst = thread->GlobalConstants();
184    int32_t fieldId = 0; // UNUM_INTEGER_FIELD
185
186    JSTaggedValue x(0.0f / 0.0f); // Nan
187    JSHandle<JSTaggedValue> nanString = globalConst->GetHandledNanString();
188    JSHandle<JSTaggedValue> fieldTypeString = JSLocale::GetNumberFieldType(thread, x, fieldId);
189    EXPECT_EQ(JSTaggedValue::SameValue(fieldTypeString, nanString), true);
190
191    JSTaggedValue y(-10); // integer(sign bit)
192    JSHandle<JSTaggedValue> integerString = globalConst->GetHandledIntegerString();
193    fieldTypeString = JSLocale::GetNumberFieldType(thread, y, fieldId);
194    EXPECT_EQ(JSTaggedValue::SameValue(fieldTypeString, integerString), true);
195
196    fieldId = 10; // UNUM_SIGN_FIELD
197    JSHandle<JSTaggedValue> minusSignString = globalConst->GetHandledMinusSignString();
198    fieldTypeString = JSLocale::GetNumberFieldType(thread, y, fieldId);
199    EXPECT_EQ(JSTaggedValue::SameValue(fieldTypeString, minusSignString), true);
200
201    JSTaggedValue z(10); // no sign bit
202    JSHandle<JSTaggedValue> plusSignString = globalConst->GetHandledPlusSignString();
203    fieldTypeString = JSLocale::GetNumberFieldType(thread, z, fieldId);
204    EXPECT_EQ(JSTaggedValue::SameValue(fieldTypeString, plusSignString), true);
205}
206
207/**
208 * @tc.name: ApplyOptionsToTag
209 * @tc.desc: Call "ApplyOptionsToTag" function parse information in option into tag string.
210 * @tc.type: FUNC
211 * @tc.require:
212 */
213HWTEST_F_L0(JSLocaleTest, ApplyOptionsToTag)
214{
215    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
216    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
217    TagElements tagElements;
218    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
219    JSHandle<EcmaString> languageTag = intl::LocaleHelper::DefaultLocale(thread);
220
221    JSHandle<JSTaggedValue> languageKey = thread->GlobalConstants()->GetHandledLanguageString();
222    JSHandle<JSTaggedValue> regionKey = thread->GlobalConstants()->GetHandledRegionString();
223    JSHandle<JSTaggedValue> scriptKey = thread->GlobalConstants()->GetHandledScriptString();
224    JSHandle<JSTaggedValue> languageValue(factory->NewFromASCII("en"));
225    JSHandle<JSTaggedValue> regionValue(factory->NewFromASCII("US"));
226    JSHandle<JSTaggedValue> scriptValue(factory->NewFromASCII("Latn"));
227
228    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
229    JSObject::SetProperty(thread, optionsObj, languageKey, languageValue);
230    JSObject::SetProperty(thread, optionsObj, regionKey, regionValue);
231    JSObject::SetProperty(thread, optionsObj, scriptKey, scriptValue);
232    bool result = JSLocale::ApplyOptionsToTag(thread, languageTag, optionsObj, tagElements);
233    EXPECT_TRUE(result);
234    EXPECT_EQ(tagElements.language, languageValue);
235    EXPECT_EQ(tagElements.script, scriptValue);
236    EXPECT_EQ(tagElements.region, regionValue);
237    // fault script
238    JSHandle<JSTaggedValue> scriptValue1(factory->NewFromASCII(""));
239    JSObject::SetProperty(thread, optionsObj, scriptKey, scriptValue1);
240    result = JSLocale::ApplyOptionsToTag(thread, languageTag, optionsObj, tagElements);
241    EXPECT_FALSE(result);
242}
243
244/**
245 * @tc.name: ConstructLocaleList
246 * @tc.desc: Get LocaleList numbers through "ConstructLocaleList" function.
247 * @tc.type: FUNC
248 * @tc.require:
249 */
250HWTEST_F_L0(JSLocaleTest, ConstructLocaleList)
251{
252    std::vector<std::string> availableLocales = {"zh-Hans-CN", "de-ID", "en-US", "en-GB"};
253    JSHandle<TaggedArray> localeArr = JSLocale::ConstructLocaleList(thread, availableLocales);
254    EXPECT_EQ(localeArr->GetLength(), 4U); // 4 : 4 Number of locales
255}
256
257/**
258 * @tc.name: SetNumberFormatDigitOptions
259 * @tc.desc: Call "SetNumberFormatDigitOptions" function parse information in option into attributes
260 *           of the JSNumberFormat.
261 * @tc.type: FUNC
262 * @tc.require:
263 */
264HWTEST_F_L0(JSLocaleTest, SetNumberFormatDigitOptions_Significant)
265{
266    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
267    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
268    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
269    JSHandle<JSTaggedValue> numberFormatObj = env->GetNumberFormatFunction();
270
271    JSHandle<JSTaggedValue> mnidKey = thread->GlobalConstants()->GetHandledMinimumIntegerDigitsString();
272    JSHandle<JSTaggedValue> mnsdKey = thread->GlobalConstants()->GetHandledMinimumSignificantDigitsString();
273    JSHandle<JSTaggedValue> mxsdKey = thread->GlobalConstants()->GetHandledMaximumSignificantDigitsString();
274    JSHandle<JSTaggedValue> mnidValue(thread, JSTaggedValue(10));
275    JSHandle<JSTaggedValue> maxFraValue(thread, JSTaggedValue(11));
276    JSHandle<JSTaggedValue> minSignValue(thread, JSTaggedValue(12));
277
278    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
279    JSObject::SetProperty(thread, optionsObj, mnidKey, mnidValue);
280    JSObject::SetProperty(thread, optionsObj, mnsdKey, maxFraValue);
281    JSObject::SetProperty(thread, optionsObj, mxsdKey, minSignValue);
282    JSHandle<JSNumberFormat> jsNumberFormat = JSHandle<JSNumberFormat>::Cast(
283        factory->NewJSObjectByConstructor(JSHandle<JSFunction>(numberFormatObj), numberFormatObj));
284
285    JSLocale::SetNumberFormatDigitOptions(thread, jsNumberFormat, JSHandle<JSTaggedValue>(optionsObj),
286                                                   1, 1, NotationOption::COMPACT);
287    EXPECT_EQ(jsNumberFormat->GetMinimumSignificantDigits().GetInt(), 11);
288    EXPECT_EQ(jsNumberFormat->GetMaximumSignificantDigits().GetInt(), 12);
289    EXPECT_EQ(jsNumberFormat->GetMinimumIntegerDigits().GetInt(), 10);
290    EXPECT_EQ(jsNumberFormat->GetRoundingType(), RoundingType::SIGNIFICANTDIGITS);
291}
292
293HWTEST_F_L0(JSLocaleTest, SetNumberFormatDigitOptions_Fraction)
294{
295    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
296    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
297    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
298    JSHandle<JSTaggedValue> pluralRulesObj = env->GetPluralRulesFunction();
299
300    JSHandle<JSTaggedValue> mnidKey = thread->GlobalConstants()->GetHandledMinimumIntegerDigitsString();
301    JSHandle<JSTaggedValue> mnidValue(thread, JSTaggedValue(10));
302
303    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
304    JSObject::SetProperty(thread, optionsObj, mnidKey, mnidValue);
305    JSHandle<JSPluralRules> jsPluralRules = JSHandle<JSPluralRules>::Cast(
306        factory->NewJSObjectByConstructor(JSHandle<JSFunction>(pluralRulesObj), pluralRulesObj));
307
308    JSLocale::SetNumberFormatDigitOptions(thread, jsPluralRules, JSHandle<JSTaggedValue>(optionsObj),
309                                                  10, 13, NotationOption::EXCEPTION);
310    EXPECT_EQ(jsPluralRules->GetMinimumFractionDigits().GetInt(), 10);
311    EXPECT_EQ(jsPluralRules->GetMaximumFractionDigits().GetInt(), 13);
312    EXPECT_EQ(jsPluralRules->GetMinimumIntegerDigits().GetInt(), 10);
313    EXPECT_EQ(jsPluralRules->GetRoundingType(), RoundingType::FRACTIONDIGITS);
314}
315
316/**
317 * @tc.name: CheckLocales
318 * @tc.desc: Call "CheckLocales" function check wether language is correct from locale libraries obtained
319 *           from different ways.
320 * @tc.type: FUNC
321 * @tc.require:
322 */
323HWTEST_F_L0(JSLocaleTest, CheckLocales)
324{
325    bool res = false;
326    const char *path = JSCollator::uIcuDataColl.c_str();
327    // default language
328    bool result = JSLocale::CheckLocales("en", nullptr, path, res);
329    EXPECT_TRUE(result);
330    // fault language
331    result = JSLocale::CheckLocales("e", nullptr, path, res);
332    EXPECT_FALSE(result);
333    // find language in calendar
334    result = JSLocale::CheckLocales("en-US", "calendar", nullptr, res);
335    EXPECT_TRUE(result);
336    // find language in NumberElements
337    result = JSLocale::CheckLocales("en-US", "NumberElements", nullptr, res);
338    EXPECT_TRUE(result);
339}
340
341/**
342 * @tc.name: UnicodeExtensionValue
343 * @tc.desc: Call "UnicodeExtensionValue" function get subtag after key in Extension.
344 * @tc.type: FUNC
345 * @tc.require:
346 */
347HWTEST_F_L0(JSLocaleTest, UnicodeExtensionValue)
348{
349    // extension has one "-"
350    std::string result = JSLocale::UnicodeExtensionValue("-ca=chinese", "ca");
351    EXPECT_STREQ(result.c_str(), "undefined");
352    // extension has one "-" and key value is full
353    result = JSLocale::UnicodeExtensionValue("-ca", "ca");
354    EXPECT_STREQ(result.c_str(), "");
355    // extension has two "-"
356    result = JSLocale::UnicodeExtensionValue("-ca-chinese", "ca");
357    EXPECT_STREQ(result.c_str(), "chinese");
358
359    result = JSLocale::UnicodeExtensionValue("-ca-chinese-co-compat", "co");
360    EXPECT_STREQ(result.c_str(), "compat");
361
362    result = JSLocale::UnicodeExtensionValue("-ca-kn-true", "kn");
363    EXPECT_STREQ(result.c_str(), "true");
364}
365
366/**
367 * @tc.name: IsWellCalendar
368 * @tc.desc: Call "IsWellCalendar" function judge whether the calendar is well from locale.
369 * @tc.type: FUNC
370 * @tc.require:
371 */
372HWTEST_F_L0(JSLocaleTest, IsWellCalendar)
373{
374    EXPECT_TRUE(JSLocale::IsWellCalendar("ar-EG", "islamic"));
375    EXPECT_TRUE(JSLocale::IsWellCalendar("ar-EG", "coptic"));
376    EXPECT_TRUE(JSLocale::IsWellCalendar("zh-CN", "chinese"));
377    EXPECT_TRUE(JSLocale::IsWellCalendar("en-US", "gregory"));
378
379    EXPECT_FALSE(JSLocale::IsWellCalendar("zh-CN", "English"));
380}
381
382/**
383 * @tc.name: IsWellCollation
384 * @tc.desc: Call "IsWellCollation" function judge whether the collation is well from locale.
385 * @tc.type: FUNC
386 * @tc.require:
387 */
388HWTEST_F_L0(JSLocaleTest, IsWellCollation)
389{
390    EXPECT_TRUE(JSLocale::IsWellCollation("ar-EG", "compat"));
391
392    EXPECT_FALSE(JSLocale::IsWellCollation("ar-EG", "stroke"));
393    EXPECT_FALSE(JSLocale::IsWellCollation("ar-EG", "pinyin"));
394    EXPECT_FALSE(JSLocale::IsWellCollation("ar-EG", "phonebk"));
395    EXPECT_FALSE(JSLocale::IsWellCollation("ar-EG", "search"));
396    EXPECT_FALSE(JSLocale::IsWellCollation("ar-EG", "standard"));
397}
398
399/**
400 * @tc.name: IsWellNumberingSystem
401 * @tc.desc: Call "IsWellNumberingSystem" function judge whether the script is well.
402 * @tc.type: FUNC
403 * @tc.require:
404 */
405HWTEST_F_L0(JSLocaleTest, IsWellNumberingSystem)
406{
407    EXPECT_FALSE(JSLocale::IsWellNumberingSystem("finance"));
408    EXPECT_FALSE(JSLocale::IsWellNumberingSystem("native"));
409    EXPECT_FALSE(JSLocale::IsWellNumberingSystem("traditio"));
410
411    EXPECT_TRUE(JSLocale::IsWellNumberingSystem("hans"));
412    EXPECT_TRUE(JSLocale::IsWellNumberingSystem("deva"));
413    EXPECT_TRUE(JSLocale::IsWellNumberingSystem("greklow"));
414}
415
416/**
417 * @tc.name: DefaultNumberOption
418 * @tc.desc: Call "DefaultNumberOption" function get default number from value.
419 * @tc.type: FUNC
420 * @tc.require:
421 */
422HWTEST_F_L0(JSLocaleTest, DefaultNumberOption)
423{
424    JSHandle<JSTaggedValue> value1(thread, JSTaggedValue(static_cast<double>(4.99)));
425    int result = JSLocale::DefaultNumberOption(thread, value1, 1, 5, 1);
426    EXPECT_EQ(result, 4);
427    JSHandle<JSTaggedValue> value2(thread, JSTaggedValue::Undefined());
428    result = JSLocale::DefaultNumberOption(thread, value2, 1, 5, 1);
429    EXPECT_EQ(result, 1);
430}
431
432JSHandle<JSObject> GetOptionCommon(JSThread *thread, JSHandle<JSTaggedValue>& languageProperty,
433    JSHandle<JSTaggedValue>& languageValue)
434{
435    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
436    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
437    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
438    // Set key value
439    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
440    JSObject::SetProperty(thread, optionsObj, languageProperty, languageValue);
441    return optionsObj;
442}
443/**
444 * @tc.name: GetOptionOfString
445 * @tc.desc: Call "GetOptionOfString" function get the string from Option value.
446 * @tc.type: FUNC
447 * @tc.require:
448 */
449HWTEST_F_L0(JSLocaleTest, GetOptionOfString)
450{
451    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
452    JSHandle<JSTaggedValue> languageProperty = thread->GlobalConstants()->GetHandledLanguageString();
453    JSHandle<JSTaggedValue> regionProperty = thread->GlobalConstants()->GetHandledRegionString();
454    JSHandle<JSTaggedValue> regionValue(factory->NewFromASCII("CN"));
455    JSHandle<JSTaggedValue> languageValue(factory->NewFromASCII("zh"));
456    // Set key value
457    JSHandle<JSObject> optionsObj = GetOptionCommon(thread, languageProperty, languageValue);
458    JSObject::SetProperty(thread, optionsObj, regionProperty, regionValue);
459    std::vector<std::string> stringValues = {"zh", "Hans", "CN"};
460    std::string optionValue;
461    // Get language
462    bool result = JSLocale::GetOptionOfString(thread, optionsObj, languageProperty, stringValues, &optionValue);
463    EXPECT_TRUE(result);
464    EXPECT_STREQ(optionValue.c_str(), "zh");
465    // Get region
466    result = JSLocale::GetOptionOfString(thread, optionsObj, regionProperty, stringValues, &optionValue);
467    EXPECT_TRUE(result);
468    EXPECT_STREQ(optionValue.c_str(), "CN");
469}
470
471/**
472 * @tc.name: GetOption
473 * @tc.desc: Call "GetOption" function get value of the key from Option.
474 * @tc.type: FUNC
475 * @tc.require:
476 */
477HWTEST_F_L0(JSLocaleTest, GetOption)
478{
479    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
480    JSHandle<JSTaggedValue> languageProperty = thread->GlobalConstants()->GetHandledLanguageString();
481    JSHandle<JSTaggedValue> regionProperty = thread->GlobalConstants()->GetHandledRegionString();
482    JSHandle<JSTaggedValue> regionValue(factory->NewFromASCII("CN"));
483    JSHandle<JSTaggedValue> languageValue(factory->NewFromASCII("zh"));
484    // Set key value
485    JSHandle<JSObject> optionsObj = GetOptionCommon(thread, languageProperty, languageValue);
486    JSHandle<TaggedArray> stringValues = factory->NewTaggedArray(3);
487    stringValues->Set(thread, 0, languageValue);
488    stringValues->Set(thread, 1, regionValue);
489    JSHandle<JSTaggedValue> arrayValue(stringValues);
490    JSHandle<JSTaggedValue> fallback(thread, JSTaggedValue::Undefined());
491
492    JSHandle<JSTaggedValue> optionValue =
493        JSLocale::GetOption(thread, optionsObj, languageProperty, OptionType::STRING, arrayValue, fallback);
494    EXPECT_EQ(JSTaggedValue::SameValue(optionValue, languageValue), true);
495
496    optionValue = JSLocale::GetOption(thread, optionsObj, regionProperty, OptionType::STRING, arrayValue, fallback);
497    EXPECT_EQ(JSTaggedValue::SameValue(optionValue, fallback), true);
498}
499
500/**
501 * @tc.name: GetOptionOfBool
502 * @tc.desc: Call "GetOptionOfBool" function get the bool value from Option.
503 * @tc.type: FUNC
504 * @tc.require:
505 */
506HWTEST_F_L0(JSLocaleTest, GetOptionOfBool)
507{
508    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
509    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
510    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
511
512    JSHandle<JSTaggedValue> numericProperty = thread->GlobalConstants()->GetHandledNumericString();
513    JSHandle<JSTaggedValue> numericValue(thread, JSTaggedValue::True());
514    // Set key value
515    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
516    JSObject::SetProperty(thread, optionsObj, numericProperty, numericValue);
517    bool res;
518    // Test correct keyValue
519    EXPECT_TRUE(JSLocale::GetOptionOfBool(thread, optionsObj, numericProperty, false, &res));
520    EXPECT_TRUE(res);
521
522    JSHandle<JSTaggedValue> numericValue1(thread, JSTaggedValue(0));
523    JSObject::SetProperty(thread, optionsObj, numericProperty, numericValue1);
524    // Test fault keyValue
525    EXPECT_TRUE(JSLocale::GetOptionOfBool(thread, optionsObj, numericProperty, false, &res));
526    EXPECT_FALSE(res);
527}
528
529ResolvedLocale ResolveLocaleCommon(JSThread *thread, JSHandle<TaggedArray> &availableLocales,
530                                   JSHandle<TaggedArray> &requestedLocales,
531                                   std::set<std::string> &relevantExtensionKeys, JSHandle<JSTaggedValue> &testLocale1)
532{
533    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
534    ResolvedLocale result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
535                                                    LocaleMatcherOption::BEST_FIT, relevantExtensionKeys);
536    EXPECT_STREQ("en-US", result.locale.c_str());  // default locale
537    // availableLocales and requestLocales is not empty
538    std::vector<std::string> availableStringLocales =
539        intl::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr);
540    availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
541    requestedLocales = factory->NewTaggedArray(1);
542    // test locale1
543    requestedLocales->Set(thread, 0, testLocale1);
544    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, LocaleMatcherOption::BEST_FIT,
545                                     relevantExtensionKeys);
546    return result;
547}
548
549/**
550 * @tc.name: ResolveLocale
551 * @tc.desc: Resolve Locale and return from available locale through "ResolveLocale" function.
552 * @tc.type: FUNC
553 * @tc.require:
554 */
555HWTEST_F_L0(JSLocaleTest, ResolveLocale_001)
556{
557    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
558    JSHandle<TaggedArray> availableLocales = factory->EmptyArray();
559    JSHandle<TaggedArray> requestedLocales = factory->EmptyArray();
560    std::set<std::string> relevantExtensionKeys = {"co", "ca"};
561    JSHandle<JSTaggedValue> testLocale1(factory->NewFromASCII("id-u-co-pinyin-ca-gregory-de-ID"));
562    JSHandle<JSTaggedValue> testLocale2(factory->NewFromASCII("en-Latn-US-u-co-phonebk-ca-ethioaa"));
563    // availableLocales and requestLocales is empty
564    auto result = ResolveLocaleCommon(thread, availableLocales, requestedLocales, relevantExtensionKeys, testLocale1);
565    EXPECT_STREQ("id-u-ca-gregory-co-pinyin-de-id", result.locale.c_str());
566    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
567                                                    LocaleMatcherOption::LOOKUP, relevantExtensionKeys);
568    EXPECT_STREQ("id-u-ca-gregory-co-pinyin-de-id", result.locale.c_str());
569    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
570                                                    LocaleMatcherOption::EXCEPTION, relevantExtensionKeys);
571    EXPECT_STREQ("id-u-ca-gregory-co-pinyin-de-id", result.locale.c_str());
572    // test locale2
573    requestedLocales->Set(thread, 0, testLocale2);
574    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
575                                     LocaleMatcherOption::BEST_FIT, relevantExtensionKeys);
576    EXPECT_STREQ("en-u-ca-ethioaa-co-phonebk", result.locale.c_str());
577    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
578                                     LocaleMatcherOption::LOOKUP, relevantExtensionKeys);
579    EXPECT_STREQ("en-u-ca-ethioaa-co-phonebk", result.locale.c_str());
580    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
581                                     LocaleMatcherOption::EXCEPTION, relevantExtensionKeys);
582    EXPECT_STREQ("en-u-ca-ethioaa-co-phonebk", result.locale.c_str());
583}
584
585HWTEST_F_L0(JSLocaleTest, ResolveLocale_002)
586{
587    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
588    JSHandle<TaggedArray> availableLocales = factory->EmptyArray();
589    JSHandle<TaggedArray> requestedLocales = factory->EmptyArray();
590    std::set<std::string> relevantExtensionKeys = {"hc", "lb", "kn", "kf"};
591    JSHandle<JSTaggedValue> testLocale1(factory->NewFromASCII("id-u-kn-false-kf-yes-de-ID"));
592    JSHandle<JSTaggedValue> testLocale2(factory->NewFromASCII("en-US-u-hc-h24-lb-strict"));
593    // availableLocales and requestLocales is empty
594    auto result = ResolveLocaleCommon(thread, availableLocales, requestedLocales, relevantExtensionKeys, testLocale1);
595    EXPECT_STREQ("id-u-de-id-kf-kn-false", result.locale.c_str());
596    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
597                                                    LocaleMatcherOption::LOOKUP, relevantExtensionKeys);
598    EXPECT_STREQ("id-u-de-id-kf-kn-false", result.locale.c_str());
599    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
600                                                    LocaleMatcherOption::EXCEPTION, relevantExtensionKeys);
601    EXPECT_STREQ("id-u-de-id-kf-kn-false", result.locale.c_str());
602    // test locale2
603    requestedLocales->Set(thread, 0, testLocale2);
604    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
605                                     LocaleMatcherOption::BEST_FIT, relevantExtensionKeys);
606    EXPECT_STREQ("en-US-u-hc-h24-lb-strict", result.locale.c_str());
607    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
608                                     LocaleMatcherOption::LOOKUP, relevantExtensionKeys);
609    EXPECT_STREQ("en-US-u-hc-h24-lb-strict", result.locale.c_str());
610    result = JSLocale::ResolveLocale(thread, availableLocales, requestedLocales,
611                                     LocaleMatcherOption::EXCEPTION, relevantExtensionKeys);
612    EXPECT_STREQ("en-US-u-hc-h24-lb-strict", result.locale.c_str());
613}
614}  // namespace panda::test
615