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_displaynames.h"
17
18 #include "ecmascript/intl/locale_helper.h"
19 #include "ecmascript/tests/test_helper.h"
20
21 using namespace panda;
22 using namespace panda::ecmascript;
23
24 namespace panda::test {
25 class JSDisplayNamesTest : public testing::Test {
26 public:
SetUpTestCase()27 static void SetUpTestCase()
28 {
29 GTEST_LOG_(INFO) << "SetUpTestCase";
30 }
31
TearDownTestCase()32 static void TearDownTestCase()
33 {
34 GTEST_LOG_(INFO) << "TearDownCase";
35 }
36
SetUp()37 void SetUp() override
38 {
39 JSRuntimeOptions options;
40 #if PANDA_TARGET_LINUX
41 // for consistency requirement, use ohos_icu4j/data/icudt67l.dat as icu-data-path
42 options.SetIcuDataPath(ICU_PATH);
43 #endif
44 options.SetEnableForceGC(true);
45 instance = JSNApi::CreateEcmaVM(options);
46 instance->SetEnableForceGC(true);
47 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
48 thread = instance->GetJSThread();
49 scope = new EcmaHandleScope(thread);
50 }
51
TearDown()52 void TearDown() override
53 {
54 TestHelper::DestroyEcmaVMWithScope(instance, scope);
55 }
56
57 EcmaVM *instance {nullptr};
58 EcmaHandleScope *scope {nullptr};
59 JSThread *thread {nullptr};
60 };
61
62 /**
63 * @tc.name: GetIcuLocaleDisplayNames
64 * @tc.desc: Call "SetIcuLocaleDisplayNames" function Set IcuLocale DisplayNames,check whether the IcuLocale
65 * DisplayNames through "GetIcuLocaleDisplayNames" function is within expectations then call "getLocale"
66 * function display locale and check the locale is within expectations.
67 * @tc.type: FUNC
68 * @tc.require:
69 */
HWTEST_F_L0(JSDisplayNamesTest,GetIcuLocaleDisplayNames)70 HWTEST_F_L0(JSDisplayNamesTest, GetIcuLocaleDisplayNames)
71 {
72 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
73 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
74
75 JSHandle<JSTaggedValue> ctor = env->GetDisplayNamesFunction();
76 JSHandle<JSDisplayNames> displayNames =
77 JSHandle<JSDisplayNames>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
78
79 icu::Locale icuLocale("en");
80 UDisplayContext display_context[] = {UDISPCTX_LENGTH_SHORT};
81 icu::LocaleDisplayNames* iculocaledisplaynames =
82 icu::LocaleDisplayNames::createInstance(icuLocale, display_context, 1);
83 EXPECT_TRUE(iculocaledisplaynames != nullptr);
84 JSDisplayNames::SetIcuLocaleDisplayNames(
85 thread, displayNames, iculocaledisplaynames, JSDisplayNames::FreeIcuLocaleDisplayNames);
86 icu::LocaleDisplayNames *resultIculocaledisplaynames = displayNames->GetIcuLocaleDisplayNames();
87 EXPECT_TRUE(iculocaledisplaynames == resultIculocaledisplaynames);
88 JSHandle<EcmaString> localeStr =
89 intl::LocaleHelper::ToLanguageTag(thread, resultIculocaledisplaynames->getLocale());
90 EXPECT_STREQ(EcmaStringAccessor(localeStr).ToCString().c_str(), "en");
91 }
92
93 /**
94 * @tc.name: GetAvailableLocales
95 * @tc.desc: Call function "GetAvailableLocales" to obtain the available locale from the ICU library and
96 * check whether the obtained locale is empty.
97 * @tc.type: FUNC
98 * @tc.require:
99 */
HWTEST_F_L0(JSDisplayNamesTest,GetAvailableLocales)100 HWTEST_F_L0(JSDisplayNamesTest, GetAvailableLocales)
101 {
102 JSHandle<TaggedArray> displayLocale = JSDisplayNames::GetAvailableLocales(thread);
103 uint32_t localeLen = displayLocale->GetLength();
104 EXPECT_NE(localeLen, 0U);
105
106 for (uint32_t i = 0; i < localeLen; i++) {
107 EXPECT_FALSE(displayLocale->Get(i).IsHole());
108 }
109 }
110
SetOptionProperties(JSThread * thread,JSHandle<JSObject> & optionsObj,std::map<std::string,std::string> & displayOptions)111 void SetOptionProperties(JSThread *thread, JSHandle<JSObject> &optionsObj,
112 std::map<std::string, std::string> &displayOptions)
113 {
114 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
115 auto globalConst = thread->GlobalConstants();
116 // display options keys
117 JSHandle<JSTaggedValue> styleKey = globalConst->GetHandledStyleString();
118 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
119 JSHandle<JSTaggedValue> fallBackKey = globalConst->GetHandledFallbackString();
120 // display options value
121 JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII(displayOptions["style"].c_str()));
122 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII(displayOptions["type"].c_str()));
123 JSHandle<JSTaggedValue> fallBackValue(factory->NewFromASCII(displayOptions["fallback"].c_str()));
124 JSObject::SetProperty(thread, optionsObj, styleKey, styleValue);
125 JSObject::SetProperty(thread, optionsObj, typeKey, typeValue);
126 JSObject::SetProperty(thread, optionsObj, fallBackKey, fallBackValue);
127 }
128
129 /**
130 * @tc.name: InitializeDisplayNames
131 * @tc.desc: Call function "InitializeDisplayNames" to initialize the jsdisplaynames class object and check whether the
132 * properties of the object is within expectations.
133 * @tc.type: FUNC
134 * @tc.require:
135 */
HWTEST_F_L0(JSDisplayNamesTest,InitializeDisplayNames)136 HWTEST_F_L0(JSDisplayNamesTest, InitializeDisplayNames)
137 {
138 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
139 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
140
141 JSHandle<JSTaggedValue> ctor = env->GetDisplayNamesFunction();
142 JSHandle<JSDisplayNames> displayNames =
143 JSHandle<JSDisplayNames>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
144 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
145 JSHandle<JSObject> displayOptions = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
146 JSHandle<JSTaggedValue> localeStr(factory->NewFromASCII("en-US"));
147 // options is empty
148 JSDisplayNames::InitializeDisplayNames(thread, displayNames, localeStr, JSHandle<JSTaggedValue>(displayOptions));
149 // Default attribute value and type is undefiend throw a expection
150 EXPECT_EQ(displayNames->GetStyle(), StyOption::LONG);
151 EXPECT_EQ(displayNames->GetType(), TypednsOption::EXCEPTION);
152 EXPECT_EQ(displayNames->GetFallback(), FallbackOption::EXCEPTION);
153 EXPECT_TRUE(thread->HasPendingException());
154 thread->ClearException();
155 // options of the key and value
156 std::map<std::string, std::string> displayOptionsProperty {
157 { "style", "short" },
158 { "type", "script" },
159 { "fallback", "none" },
160 };
161 SetOptionProperties(thread, displayOptions, displayOptionsProperty);
162 // options is not empty
163 JSDisplayNames::InitializeDisplayNames(thread, displayNames, localeStr, JSHandle<JSTaggedValue>(displayOptions));
164 JSHandle<EcmaString> setlocale(thread, displayNames->GetLocale());
165 EXPECT_EQ(displayNames->GetStyle(), StyOption::SHORT);
166 EXPECT_EQ(displayNames->GetType(), TypednsOption::SCRIPT);
167 EXPECT_EQ(displayNames->GetFallback(), FallbackOption::NONE);
168 EXPECT_STREQ(EcmaStringAccessor(setlocale).ToCString().c_str(), "en-US");
169 EXPECT_TRUE(displayNames->GetIcuLocaleDisplayNames() != nullptr);
170 }
171
172 /**
173 * @tc.name: CanonicalCodeForDisplayNames
174 * @tc.desc: Display the language region and script of the locale according to the display configuration of
175 * different regions.
176 * @tc.type: FUNC
177 * @tc.require:
178 */
HWTEST_F_L0(JSDisplayNamesTest,CanonicalCodeForDisplayNames)179 HWTEST_F_L0(JSDisplayNamesTest, CanonicalCodeForDisplayNames)
180 {
181 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
182 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
183
184 JSHandle<JSTaggedValue> ctor = env->GetDisplayNamesFunction();
185 JSHandle<JSDisplayNames> displayNames =
186 JSHandle<JSDisplayNames>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
187 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
188 JSHandle<JSObject> displayOptions = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
189 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("zh-Hant"));
190 // test UDISPCTX_LENGTH_SHORT
191 std::map<std::string, std::string> displayOptionsProperty {
192 { "style", "narrow" },
193 { "type", "script" },
194 { "fallback", "none" },
195 };
196 SetOptionProperties(thread, displayOptions, displayOptionsProperty);
197 JSHandle<JSDisplayNames> initDisplayNames =
198 JSDisplayNames::InitializeDisplayNames(thread, displayNames, locale, JSHandle<JSTaggedValue>(displayOptions));
199 // CanonicalCode for script
200 JSHandle<EcmaString> code = factory->NewFromASCII("Kana");
201 JSHandle<EcmaString> resultDisplay =
202 JSDisplayNames::CanonicalCodeForDisplayNames(thread, initDisplayNames, initDisplayNames->GetType(), code);
203 EXPECT_STREQ(EcmaStringAccessor(resultDisplay).ToCString().c_str(), "片假名");
204 // CanonicalCode for languege
205 code = factory->NewFromASCII("fr");
206 initDisplayNames->SetType(TypednsOption::LANGUAGE);
207 resultDisplay =
208 JSDisplayNames::CanonicalCodeForDisplayNames(thread, initDisplayNames, initDisplayNames->GetType(), code);
209 EXPECT_STREQ(EcmaStringAccessor(resultDisplay).ToCString().c_str(), "法文");
210 // CanonicalCode for region
211 code = factory->NewFromASCII("US");
212 initDisplayNames->SetType(TypednsOption::REGION);
213 resultDisplay =
214 JSDisplayNames::CanonicalCodeForDisplayNames(thread, initDisplayNames, initDisplayNames->GetType(), code);
215 EXPECT_STREQ(EcmaStringAccessor(resultDisplay).ToCString().c_str(), "美國");
216 }
217
218 /**
219 * @tc.name: ResolvedOptions
220 * @tc.desc: Call function "InitializeDisplayNames" to initialize the jsdisplaynames class object and Copy the
221 * properties of jsdisplaynames class to a new object.
222 * @tc.type: FUNC
223 * @tc.require:
224 */
HWTEST_F_L0(JSDisplayNamesTest,ResolvedOptions)225 HWTEST_F_L0(JSDisplayNamesTest, ResolvedOptions)
226 {
227 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
228 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
229 auto globalConst = thread->GlobalConstants();
230 JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
231 JSHandle<JSTaggedValue> styleKey = globalConst->GetHandledStyleString();
232 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
233 JSHandle<JSTaggedValue> fallBackKey = globalConst->GetHandledFallbackString();
234
235 JSHandle<JSTaggedValue> ctor = env->GetDisplayNamesFunction();
236 JSHandle<JSDisplayNames> displayNames =
237 JSHandle<JSDisplayNames>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
238 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
239 JSHandle<JSObject> displayOptions = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
240 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("zh-Hant"));
241
242 std::map<std::string, std::string> displayOptionsProperty {
243 { "style", "short" },
244 { "type", "region" },
245 { "fallback", "code" },
246 };
247 JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII(displayOptionsProperty["style"].c_str()));
248 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII(displayOptionsProperty["type"].c_str()));
249 JSHandle<JSTaggedValue> fallBackValue(factory->NewFromASCII(displayOptionsProperty["fallback"].c_str()));
250 SetOptionProperties(thread, displayOptions, displayOptionsProperty);
251 JSHandle<JSDisplayNames> initDisplayNames =
252 JSDisplayNames::InitializeDisplayNames(thread, displayNames, locale, JSHandle<JSTaggedValue>(displayOptions));
253
254 JSDisplayNames::ResolvedOptions(thread, initDisplayNames, displayOptions);
255 EXPECT_EQ(JSTaggedValue::SameValue(
256 JSObject::GetProperty(thread, displayOptions, styleKey).GetValue(), styleValue), true);
257 EXPECT_EQ(JSTaggedValue::SameValue(
258 JSObject::GetProperty(thread, displayOptions, localeKey).GetValue(), locale), true);
259 EXPECT_EQ(JSTaggedValue::SameValue(
260 JSObject::GetProperty(thread, displayOptions, fallBackKey).GetValue(), fallBackValue), true);
261 EXPECT_EQ(JSTaggedValue::SameValue(
262 JSObject::GetProperty(thread, displayOptions, typeKey).GetValue(), typeValue), true);
263 }
264 } // namespace panda::test
265