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/builtins/builtins_list_format.h"
17
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_list_format.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/tests/test_helper.h"
22
23 using namespace panda::ecmascript;
24 using namespace panda::ecmascript::builtins;
25
26 namespace panda::test {
27 class BuiltinsListFormatTest : 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/icudt67l.dat 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 EcmaHandleScope *scope {nullptr};
61 JSThread *thread {nullptr};
62 };
63
JSListFormatCreateWithOptionTest(JSThread * thread,JSHandle<JSTaggedValue> & locale,JSHandle<JSTaggedValue> & typeValue)64 static JSTaggedValue JSListFormatCreateWithOptionTest(JSThread *thread, JSHandle<JSTaggedValue> &locale,
65 JSHandle<JSTaggedValue> &typeValue)
66 {
67 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
68 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
69 JSHandle<JSFunction> newTarget(env->GetListFormatFunction());
70 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
71 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
72
73 JSHandle<JSTaggedValue> typeKey = thread->GlobalConstants()->GetHandledTypeString();
74 JSObject::SetProperty(thread, optionsObj, typeKey, typeValue);
75
76 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
77 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
78 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
79 ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
80 ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
81
82 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
83 JSTaggedValue result = BuiltinsListFormat::ListFormatConstructor(ecmaRuntimeCallInfo);
84 TestHelper::TearDownFrame(thread, prev);
85
86 EXPECT_TRUE(result.IsJSListFormat());
87 return result;
88 }
89
HWTEST_F_L0(BuiltinsListFormatTest,FormatToParts_001)90 HWTEST_F_L0(BuiltinsListFormatTest, FormatToParts_001)
91 {
92 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
93 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE"));
94 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("conjunction"));
95 JSHandle<JSListFormat> jSListFormat =
96 JSHandle<JSListFormat>(thread, JSListFormatCreateWithOptionTest(thread, locale, typeValue));
97 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
98 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
99 ecmaRuntimeCallInfo->SetThis(jSListFormat.GetTaggedValue());
100 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
101
102 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
103 JSTaggedValue result = BuiltinsListFormat::FormatToParts(ecmaRuntimeCallInfo);
104 TestHelper::TearDownFrame(thread, prev);
105
106 JSHandle<JSArray> resultHandle(thread, result);
107 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
108 EXPECT_EQ(elements->GetLength(), 0U); // zero formatters
109 }
110
111 // FormatToParts(["Apple", "Orange", "Pineapple" ], type(conjunction))
HWTEST_F_L0(BuiltinsListFormatTest,FormatToParts_002)112 HWTEST_F_L0(BuiltinsListFormatTest, FormatToParts_002)
113 {
114 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
115 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-GB"));
116 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("conjunction")); // the default value
117 JSHandle<JSListFormat> jSListFormat =
118 JSHandle<JSListFormat>(thread, JSListFormatCreateWithOptionTest(thread, locale, typeValue));
119 JSHandle<JSTaggedValue> listValue1(factory->NewFromStdString("Apple"));
120 JSHandle<JSTaggedValue> listValue2(factory->NewFromStdString("Orange"));
121 JSHandle<JSTaggedValue> listValue3(factory->NewFromStdString("Pineapple"));
122
123 JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>();
124 EXPECT_TRUE(arr != nullptr);
125 JSHandle<JSObject> value(thread, arr);
126 JSHandle<JSTaggedValue> key0(thread, JSTaggedValue(0));
127 PropertyDescriptor desc0(thread, listValue1, true, true, true);
128 JSArray::DefineOwnProperty(thread, value, key0, desc0);
129 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(1));
130 PropertyDescriptor desc1(thread, listValue2, true, true, true);
131 JSArray::DefineOwnProperty(thread, value, key1, desc1);
132 JSHandle<JSTaggedValue> key2(thread, JSTaggedValue(2));
133 PropertyDescriptor desc2(thread, listValue3, true, true, true);
134 JSArray::DefineOwnProperty(thread, value, key2, desc2);
135
136 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
137 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
138 ecmaRuntimeCallInfo->SetThis(jSListFormat.GetTaggedValue());
139 ecmaRuntimeCallInfo->SetCallArg(0, value.GetTaggedValue());
140
141 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
142 JSTaggedValue result = BuiltinsListFormat::FormatToParts(ecmaRuntimeCallInfo);
143 TestHelper::TearDownFrame(thread, prev);
144
145 JSHandle<JSArray> resultHandle(thread, result);
146 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
147 EXPECT_EQ(elements->GetLength(), 6U);
148 }
149
HWTEST_F_L0(BuiltinsListFormatTest,FormatToParts_003)150 HWTEST_F_L0(BuiltinsListFormatTest, FormatToParts_003)
151 {
152 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
153 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
154 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-GB"));
155 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("conjunction")); // the default value
156 JSHandle<JSListFormat> jSListFormat =
157 JSHandle<JSListFormat>(thread, JSListFormatCreateWithOptionTest(thread, locale, typeValue));
158 JSHandle<JSTaggedValue> listValue1(factory->NewFromStdString("Apple"));
159 JSHandle<JSTaggedValue> listValue2(factory->NewFromStdString("Orange"));
160 JSHandle<JSTaggedValue> listValue3(factory->NewFromStdString("Pineapple"));
161
162 JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>();
163 EXPECT_TRUE(arr != nullptr);
164 JSHandle<JSObject> value(thread, arr);
165 JSHandle<JSTaggedValue> key0(thread, JSTaggedValue(0));
166 PropertyDescriptor desc0(thread, listValue1, true, true, true);
167 JSArray::DefineOwnProperty(thread, value, key0, desc0);
168 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(1));
169 PropertyDescriptor desc1(thread, listValue2, true, true, true);
170 JSArray::DefineOwnProperty(thread, value, key1, desc1);
171 JSHandle<JSTaggedValue> key2(thread, JSTaggedValue(2));
172 PropertyDescriptor desc2(thread, listValue3, true, true, true);
173 JSArray::DefineOwnProperty(thread, value, key2, desc2);
174
175 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
176 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
177 ecmaRuntimeCallInfo->SetThis(jSListFormat.GetTaggedValue());
178 ecmaRuntimeCallInfo->SetCallArg(0, value.GetTaggedValue());
179
180 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
181 JSTaggedValue result = BuiltinsListFormat::FormatToParts(ecmaRuntimeCallInfo);
182 TestHelper::TearDownFrame(thread, prev);
183 JSTaggedValue valueList(static_cast<JSTaggedType>(result.GetRawData()));
184
185 ASSERT_TRUE(valueList.IsECMAObject());
186 JSHandle<JSObject> valueHandle(thread, valueList);
187 EXPECT_EQ(JSArray::GetProperty(thread, JSHandle<JSTaggedValue>(valueHandle), lengthKey).GetValue()->GetInt(), 5);
188 }
189
190 // FormatToParts(["中文", "英文"], type(conjunction))
HWTEST_F_L0(BuiltinsListFormatTest,FormatToParts_004)191 HWTEST_F_L0(BuiltinsListFormatTest, FormatToParts_004)
192 {
193 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
194 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("zh-cn"));
195 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("conjunction"));
196 JSHandle<JSListFormat> jSListFormat =
197 JSHandle<JSListFormat>(thread, JSListFormatCreateWithOptionTest(thread, locale, typeValue));
198 JSHandle<JSTaggedValue> listValue1(factory->NewFromStdString("中文"));
199 JSHandle<JSTaggedValue> listValue2(factory->NewFromStdString("英文"));
200
201 JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>();
202 EXPECT_TRUE(arr != nullptr);
203 JSHandle<JSObject> value(thread, arr);
204 JSHandle<JSTaggedValue> key0(thread, JSTaggedValue(0));
205 PropertyDescriptor desc0(thread, listValue1, true, true, true);
206 JSArray::DefineOwnProperty(thread, value, key0, desc0);
207 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(1));
208 PropertyDescriptor desc1(thread, listValue2, true, true, true);
209 JSArray::DefineOwnProperty(thread, value, key1, desc1);
210
211 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
212 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
213 ecmaRuntimeCallInfo->SetThis(jSListFormat.GetTaggedValue());
214 ecmaRuntimeCallInfo->SetCallArg(0, value.GetTaggedValue());
215
216 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
217 JSTaggedValue result = BuiltinsListFormat::FormatToParts(ecmaRuntimeCallInfo);
218 TestHelper::TearDownFrame(thread, prev);
219
220 JSHandle<JSArray> resultHandle(thread, result);
221 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
222 EXPECT_EQ(elements->GetLength(), 3U);
223 }
224
225 // FormatToParts(["中文", "英文","韩文","葡萄牙语"], type(disjunction))
HWTEST_F_L0(BuiltinsListFormatTest,FormatToParts_005)226 HWTEST_F_L0(BuiltinsListFormatTest, FormatToParts_005)
227 {
228 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
229 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
230 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("zh-cn"));
231 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("disjunction"));
232 JSHandle<JSListFormat> jSListFormat =
233 JSHandle<JSListFormat>(thread, JSListFormatCreateWithOptionTest(thread, locale, typeValue));
234 JSHandle<JSTaggedValue> listValue1(factory->NewFromStdString("中文"));
235 JSHandle<JSTaggedValue> listValue2(factory->NewFromStdString("英文"));
236 JSHandle<JSTaggedValue> listValue3(factory->NewFromStdString("韩文"));
237 JSHandle<JSTaggedValue> listValue4(factory->NewFromStdString("葡萄牙语"));
238
239 JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>();
240 EXPECT_TRUE(arr != nullptr);
241 JSHandle<JSObject> value(thread, arr);
242 JSHandle<JSTaggedValue> key0(thread, JSTaggedValue(0));
243 PropertyDescriptor desc0(thread, listValue1, true, true, true);
244 JSArray::DefineOwnProperty(thread, value, key0, desc0);
245 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(1));
246 PropertyDescriptor desc1(thread, listValue2, true, true, true);
247 JSArray::DefineOwnProperty(thread, value, key1, desc1);
248 JSHandle<JSTaggedValue> key2(thread, JSTaggedValue(2));
249 PropertyDescriptor desc2(thread, listValue3, true, true, true);
250 JSArray::DefineOwnProperty(thread, value, key2, desc2);
251 JSHandle<JSTaggedValue> key3(thread, JSTaggedValue(3));
252 PropertyDescriptor desc3(thread, listValue4, true, true, true);
253 JSArray::DefineOwnProperty(thread, value, key3, desc3);
254
255 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
256 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
257 ecmaRuntimeCallInfo->SetThis(jSListFormat.GetTaggedValue());
258 ecmaRuntimeCallInfo->SetCallArg(0, value.GetTaggedValue());
259
260 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
261 JSTaggedValue result = BuiltinsListFormat::FormatToParts(ecmaRuntimeCallInfo);
262 TestHelper::TearDownFrame(thread, prev);
263 JSTaggedValue valueList(static_cast<JSTaggedType>(result.GetRawData()));
264
265 ASSERT_TRUE(valueList.IsECMAObject());
266 JSHandle<JSObject> valueHandle(thread, valueList);
267 EXPECT_EQ(JSArray::GetProperty(thread, JSHandle<JSTaggedValue>(valueHandle), lengthKey).GetValue()->GetInt(), 7);
268 }
269
270 // SupportedLocalesOf("best fit")
HWTEST_F_L0(BuiltinsListFormatTest,SupportedLocalesOf_001)271 HWTEST_F_L0(BuiltinsListFormatTest, SupportedLocalesOf_001)
272 {
273 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
274 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-ID"));
275
276 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
277 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
278 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
279 ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
280 // set the tag is default value
281 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
282
283 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
284 JSTaggedValue resultArr = BuiltinsListFormat::SupportedLocalesOf(ecmaRuntimeCallInfo);
285 TestHelper::TearDownFrame(thread, prev);
286
287 JSHandle<JSArray> resultHandle(thread, resultArr);
288 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
289 EXPECT_EQ(elements->GetLength(), 1U);
290 JSHandle<EcmaString> handleEcmaStr(thread, elements->Get(0));
291 EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
292 }
293
294 // SupportedLocalesOf("look up")
HWTEST_F_L0(BuiltinsListFormatTest,SupportedLocalesOf_002)295 HWTEST_F_L0(BuiltinsListFormatTest, SupportedLocalesOf_002)
296 {
297 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
298 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
299
300 JSHandle<JSTaggedValue> localeMatcherKey = thread->GlobalConstants()->GetHandledLocaleMatcherString();
301 JSHandle<JSTaggedValue> localeMatcherValue(factory->NewFromASCII("lookup"));
302 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-DE"));
303
304 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
305 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
306 JSObject::SetProperty(thread, optionsObj, localeMatcherKey, localeMatcherValue);
307
308 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
309 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
310 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
311 ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
312 ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
313
314 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
315 JSTaggedValue resultArr = BuiltinsListFormat::SupportedLocalesOf(ecmaRuntimeCallInfo);
316 TestHelper::TearDownFrame(thread, prev);
317
318 JSHandle<JSArray> resultHandle(thread, resultArr);
319 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
320 EXPECT_EQ(elements->GetLength(), 1U);
321
322 JSHandle<EcmaString> resultStr(thread, elements->Get(0));
323 EXPECT_STREQ("id-u-co-pinyin-de", EcmaStringAccessor(resultStr).ToCString().c_str());
324 }
325
HWTEST_F_L0(BuiltinsListFormatTest,ResolvedOptions)326 HWTEST_F_L0(BuiltinsListFormatTest, ResolvedOptions)
327 {
328 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
329 auto globalConst = thread->GlobalConstants();
330 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE"));
331 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("disjunction"));
332 JSHandle<JSListFormat> jSListFormat =
333 JSHandle<JSListFormat>(thread, JSListFormatCreateWithOptionTest(thread, locale, typeValue));
334
335 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
336 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
337 ecmaRuntimeCallInfo->SetThis(jSListFormat.GetTaggedValue());
338
339 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
340 JSTaggedValue result = BuiltinsListFormat::ResolvedOptions(ecmaRuntimeCallInfo);
341 TestHelper::TearDownFrame(thread, prev);
342
343 JSHandle<JSTaggedValue> resultObj =
344 JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result.GetRawData())));
345 // judge whether the properties of the object are the same as those of jslistformat tag
346 JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
347 JSHandle<JSTaggedValue> localeValue(factory->NewFromASCII("de-DE"));
348 EXPECT_EQ(JSTaggedValue::SameValue(
349 JSObject::GetProperty(thread, resultObj, localeKey).GetValue(), localeValue), true);
350 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
351 EXPECT_EQ(JSTaggedValue::SameValue(
352 JSObject::GetProperty(thread, resultObj, typeKey).GetValue(), typeValue), true);
353 }
354 } // namespace panda::test