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_date_time_format.h"
17
18 #include <ctime>
19 #include <algorithm>
20 #include "ecmascript/builtins/builtins_array.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/js_date.h"
23 #include "ecmascript/js_date_time_format.h"
24 #include "ecmascript/tests/test_helper.h"
25
26 using namespace panda::ecmascript;
27 using namespace panda::ecmascript::builtins;
28
29 namespace panda::test {
30 using BuiltinsArray = ecmascript::builtins::BuiltinsArray;
31 class BuiltinsDateTimeFormatTest : public testing::Test {
32 public:
SetUpTestCase()33 static void SetUpTestCase()
34 {
35 GTEST_LOG_(INFO) << "SetUpTestCase";
36 }
37
TearDownTestCase()38 static void TearDownTestCase()
39 {
40 GTEST_LOG_(INFO) << "TearDownCase";
41 }
42
SetUp()43 void SetUp() override
44 {
45 JSRuntimeOptions options;
46 #if PANDA_TARGET_LINUX
47 // for consistency requirement, use ohos_icu4j/data as icu-data-path
48 options.SetIcuDataPath(ICU_PATH);
49 #endif
50 options.SetEnableForceGC(true);
51 instance = JSNApi::CreateEcmaVM(options);
52 instance->SetEnableForceGC(true);
53 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
54 thread = instance->GetJSThread();
55 scope = new EcmaHandleScope(thread);
56 }
57
TearDown()58 void TearDown() override
59 {
60 TestHelper::DestroyEcmaVMWithScope(instance, scope);
61 }
62
63 EcmaVM *instance {nullptr};
64 EcmaHandleScope *scope {nullptr};
65 JSThread *thread {nullptr};
66 };
67
BuiltinsDateTimeOptionsSet(JSThread * thread)68 static JSTaggedValue BuiltinsDateTimeOptionsSet(JSThread *thread)
69 {
70 auto globalConst = thread->GlobalConstants();
71 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
72 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
73
74 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
75 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
76
77 JSHandle<JSTaggedValue> weekDay = globalConst->GetHandledWeekdayString();
78 JSHandle<JSTaggedValue> dayPeriod = globalConst->GetHandledDayPeriodString();
79 JSHandle<JSTaggedValue> hourCycle = globalConst->GetHandledHourCycleString();
80 JSHandle<JSTaggedValue> timeZone = globalConst->GetHandledTimeZoneString();
81 JSHandle<JSTaggedValue> numicValue(factory->NewFromASCII("numeric")); // test numeric
82 JSHandle<JSTaggedValue> weekDayValue(factory->NewFromASCII("short")); // test short
83 JSHandle<JSTaggedValue> dayPeriodValue(factory->NewFromASCII("long")); // test long
84 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h24")); // test h24
85 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC")); // test UTC
86
87 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(6); // 6 : 6 length
88 keyArray->Set(thread, 0, globalConst->GetHandledYearString()); // 0 : 0 first position
89 keyArray->Set(thread, 1, globalConst->GetHandledMonthString()); // 1 : 1 second position
90 keyArray->Set(thread, 2, globalConst->GetHandledDayString()); // 2 : 2 third position
91 keyArray->Set(thread, 3, globalConst->GetHandledHourString()); // 3 : 3 fourth position
92 keyArray->Set(thread, 4, globalConst->GetHandledMinuteString()); // 4 : 4 fifth position
93 keyArray->Set(thread, 5, globalConst->GetHandledSecondString()); // 5 : 5 sixth position
94
95 uint32_t arrayLen = keyArray->GetLength();
96 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
97 for (uint32_t i = 0; i < arrayLen; i++) {
98 key.Update(keyArray->Get(thread, i));
99 JSObject::SetProperty(thread, optionsObj, key, numicValue);
100 }
101 JSObject::SetProperty(thread, optionsObj, weekDay, weekDayValue);
102 JSObject::SetProperty(thread, optionsObj, dayPeriod, dayPeriodValue);
103 JSObject::SetProperty(thread, optionsObj, hourCycle, hourCycleValue);
104 JSObject::SetProperty(thread, optionsObj, timeZone, timeZoneValue);
105 return optionsObj.GetTaggedValue();
106 }
107
JSDateTimeFormatCreateWithLocaleTest(JSThread * thread,JSHandle<JSTaggedValue> & locale)108 static JSTaggedValue JSDateTimeFormatCreateWithLocaleTest(JSThread *thread, JSHandle<JSTaggedValue> &locale)
109 {
110 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
111 JSHandle<JSFunction> newTarget(env->GetDateTimeFormatFunction());
112 JSHandle<JSObject> optionsObj(thread, BuiltinsDateTimeOptionsSet(thread));
113
114 JSHandle<JSTaggedValue> localesString = locale;
115 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
116 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
117 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
118 ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
119 ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
120
121 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
122 JSTaggedValue result = BuiltinsDateTimeFormat::DateTimeFormatConstructor(ecmaRuntimeCallInfo);
123 EXPECT_TRUE(result.IsJSDateTimeFormat());
124 TestHelper::TearDownFrame(thread, prev);
125 return result;
126 }
127
HWTEST_F_L0(BuiltinsDateTimeFormatTest,ResolvedOptions)128 HWTEST_F_L0(BuiltinsDateTimeFormatTest, ResolvedOptions)
129 {
130 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
131 auto globalConst = thread->GlobalConstants();
132 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-ID"));
133 JSHandle<JSDateTimeFormat> jsDateTimeFormat =
134 JSHandle<JSDateTimeFormat>(thread, JSDateTimeFormatCreateWithLocaleTest(thread, locale));
135
136 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
137 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
138 ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
139
140 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
141 JSTaggedValue result = BuiltinsDateTimeFormat::ResolvedOptions(ecmaRuntimeCallInfo);
142 TestHelper::TearDownFrame(thread, prev);
143
144 JSHandle<JSTaggedValue> resultObj =
145 JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result.GetRawData())));
146 // judge whether the properties of the object are the same as those of jsdatetimeformat tag
147 JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
148 JSHandle<JSTaggedValue> localeValue(factory->NewFromASCII("de"));
149 EXPECT_EQ(JSTaggedValue::SameValue(
150 JSObject::GetProperty(thread, resultObj, localeKey).GetValue(), localeValue), true);
151 JSHandle<JSTaggedValue> timeZone = globalConst->GetHandledTimeZoneString();
152 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC"));
153 EXPECT_EQ(JSTaggedValue::SameValue(
154 JSObject::GetProperty(thread, resultObj, timeZone).GetValue(), timeZoneValue), true);
155 }
156
157 // SupportedLocalesOf("best fit")
HWTEST_F_L0(BuiltinsDateTimeFormatTest,SupportedLocalesOf_001)158 HWTEST_F_L0(BuiltinsDateTimeFormatTest, SupportedLocalesOf_001)
159 {
160 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
161 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-ID"));
162
163 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
164 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
165 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
166 ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
167 // set the tag is default value
168 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
169
170 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
171 JSTaggedValue resultArr = BuiltinsDateTimeFormat::SupportedLocalesOf(ecmaRuntimeCallInfo);
172 TestHelper::TearDownFrame(thread, prev);
173
174 JSHandle<JSArray> resultHandle(thread, resultArr);
175 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
176 EXPECT_EQ(elements->GetLength(), 1U);
177
178 JSHandle<EcmaString> resultStr(thread, elements->Get(0));
179 EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(resultStr).ToCString().c_str());
180 }
181
182 // SupportedLocalesOf("look up")
HWTEST_F_L0(BuiltinsDateTimeFormatTest,SupportedLocalesOf_002)183 HWTEST_F_L0(BuiltinsDateTimeFormatTest, SupportedLocalesOf_002)
184 {
185 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
186 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
187
188 JSHandle<JSTaggedValue> localeMatcherKey = thread->GlobalConstants()->GetHandledLocaleMatcherString();
189 JSHandle<JSTaggedValue> localeMatcherValue(factory->NewFromASCII("lookup"));
190 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-DE"));
191
192 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
193 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
194 JSObject::SetProperty(thread, optionsObj, localeMatcherKey, localeMatcherValue);
195
196 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
197 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
198 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
199 ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
200 ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
201
202 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
203 JSTaggedValue resultArr = BuiltinsDateTimeFormat::SupportedLocalesOf(ecmaRuntimeCallInfo);
204 TestHelper::TearDownFrame(thread, prev);
205
206 JSHandle<JSArray> resultHandle(thread, resultArr);
207 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
208 EXPECT_EQ(elements->GetLength(), 1U);
209
210 JSHandle<EcmaString> resultStr(thread, elements->Get(0));
211 EXPECT_STREQ("id-u-co-pinyin-de", EcmaStringAccessor(resultStr).ToCString().c_str());
212 }
213
JSDateTime(JSThread * thread,JSTaggedValue & formatResult)214 static JSTaggedValue JSDateTime(JSThread *thread, JSTaggedValue &formatResult)
215 {
216 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
217 double days = 1665187200000;
218 // jsDate supports zero to eleven, the month should be added with one
219 JSHandle<JSFunction> jsFunction(thread, formatResult);
220 JSArray *jsArray =
221 JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
222 JSHandle<JSObject> jsObject(thread, jsArray);
223 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(static_cast<double>(days)));
224 PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(jsFunction), true, true, true);
225 JSHandle<JSTaggedValue> joinKey(factory->NewFromASCII("join"));
226 JSArray::DefineOwnProperty(thread, jsObject, joinKey, desc);
227 auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
228 ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
229 ecmaRuntimeCallInfo2->SetThis(jsObject.GetTaggedValue());
230 ecmaRuntimeCallInfo2->SetCallArg(0, value.GetTaggedValue());
231
232 [[maybe_unused]] auto prev2 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
233 JSTaggedValue result2 = BuiltinsArray::ToString(ecmaRuntimeCallInfo2);
234 TestHelper::TearDownFrame(thread, prev2);
235 return result2;
236 }
237
JSDateTimeFormatConstructor(JSThread * thread,JSHandle<JSObject> & optionsObj,JSHandle<JSTaggedValue> & localesString)238 static JSTaggedValue JSDateTimeFormatConstructor(JSThread *thread, JSHandle<JSObject> &optionsObj,
239 JSHandle<JSTaggedValue> &localesString)
240 {
241 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
242 JSHandle<JSFunction> newTarget(env->GetDateTimeFormatFunction());
243
244 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
245 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
246 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
247 ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
248 ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
249
250 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
251 JSTaggedValue result = BuiltinsDateTimeFormat::DateTimeFormatConstructor(ecmaRuntimeCallInfo);
252 EXPECT_TRUE(result.IsJSDateTimeFormat());
253 TestHelper::TearDownFrame(thread, prev);
254 return result;
255 }
256
JSDateTimeFormatForObject(JSThread * thread,JSTaggedValue & constructorResult)257 static JSTaggedValue JSDateTimeFormatForObject(JSThread *thread, JSTaggedValue &constructorResult)
258 {
259 JSHandle<JSDateTimeFormat> jsDateTimeFormat = JSHandle<JSDateTimeFormat>(thread, constructorResult);
260 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
261 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
262 ecmaRuntimeCallInfo1->SetThis(jsDateTimeFormat.GetTaggedValue());
263 ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue::Undefined());
264 [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
265 JSTaggedValue result1 = BuiltinsDateTimeFormat::Format(ecmaRuntimeCallInfo1);
266 TestHelper::TearDownFrame(thread, prev1);
267 return result1;
268 }
269
JSDateTimeFormatForObj_001(JSThread * thread)270 static JSTaggedValue JSDateTimeFormatForObj_001(JSThread *thread)
271 {
272 auto globalConst = thread->GlobalConstants();
273 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
274 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
275 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
276 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
277
278 JSHandle<JSTaggedValue> timeZoneName = globalConst->GetHandledTimeZoneNameString();
279 JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en-US"));
280 JSHandle<JSTaggedValue> digitValue(factory->NewFromASCII("2-digit"));
281 JSHandle<JSTaggedValue> timeZoneNameValue(factory->NewFromASCII("short"));
282
283 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(6); // 6 : 6 length
284 keyArray->Set(thread, 0, globalConst->GetHandledYearString()); // 0 : 0 first position
285 keyArray->Set(thread, 1, globalConst->GetHandledMonthString()); // 1 : 1 second position
286 keyArray->Set(thread, 2, globalConst->GetHandledDayString()); // 2 : 2 third position
287 keyArray->Set(thread, 3, globalConst->GetHandledHourString()); // 3 : 3 fourth position
288 keyArray->Set(thread, 4, globalConst->GetHandledMinuteString()); // 4 : 4 fifth position
289 keyArray->Set(thread, 5, globalConst->GetHandledSecondString()); // 5 : 5 sixth position
290 uint32_t arrayLen = keyArray->GetLength();
291 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
292 for (uint32_t i = 0; i < arrayLen; i++) {
293 key.Update(keyArray->Get(thread, i));
294 JSObject::SetProperty(thread, optionsObj, key, digitValue);
295 }
296 JSObject::SetProperty(thread, optionsObj, timeZoneName, timeZoneNameValue);
297 return optionsObj.GetTaggedValue();
298 }
299
TimeOffset()300 static int TimeOffset()
301 {
302 // Get Sys time
303 time_t rt = time(nullptr);
304 // Convert Sys time to GMT time
305 tm gtm = *gmtime(&rt);
306 // Convert GMT time to Sys time
307 time_t gt = mktime(>m);
308 tm gtm2 = *localtime(>);
309 // Calculate time difference
310 int offset = ((rt - gt) + (gtm2.tm_isdst ? 3600 : 0)) / 60;
311 return offset;
312 }
313
314 // DateTimeFormat_001
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_001)315 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_001)
316 {
317 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
318 JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en-US"));
319 auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_001(thread));
320 auto constructorResult = JSDateTimeFormatConstructor(thread, jsObj, localesString);
321 auto formatResult = JSDateTimeFormatForObject(thread, constructorResult);
322 auto dtResult = JSDateTime(thread, formatResult);
323 JSHandle<EcmaString> resultStr(thread, dtResult);
324
325 constexpr int shanghai = 480;
326 constexpr int americaRegina = -360;
327 constexpr int americaNewYork = -300;
328 constexpr int sysDefaultTimezone = -180; // america_argentina_Buenos_Aires
329 constexpr int utc = 0;
330 auto cstr = EcmaStringAccessor(resultStr).ToCString();
331 if (TimeOffset() == utc) {
332 if (cstr.find("GMT") != std::string::npos) {
333 EXPECT_STREQ("10/08/22, 12:00:00 AM GMT", cstr.c_str());
334 }
335 if (cstr.find("UTC") != std::string::npos) {
336 EXPECT_STREQ("10/08/22, 12:00:00 AM UTC", cstr.c_str());
337 }
338 }
339 if (TimeOffset() == shanghai) {
340 if (cstr.find("CST") != std::string::npos) {
341 EXPECT_STREQ("10/08/22, 08:00:00 AM CST", cstr.c_str());
342 }
343 if (cstr.find("GMT+8") != std::string::npos) {
344 EXPECT_STREQ("10/08/22, 08:00:00 AM GMT+8", cstr.c_str());
345 }
346 }
347 if (TimeOffset() == americaRegina) {
348 if (cstr.find("CST") != std::string::npos) {
349 EXPECT_STREQ("10/07/22, 06:00:00 PM CST", cstr.c_str());
350 }
351 }
352 if (TimeOffset() == americaNewYork) {
353 if (cstr.find("EST") != std::string::npos) {
354 EXPECT_STREQ("10/07/22, 06:00:00 PM EST", cstr.c_str());
355 }
356 }
357 if (TimeOffset() == sysDefaultTimezone) {
358 if (cstr.find("GMT-3") != std::string::npos) {
359 EXPECT_STREQ("10/07/22, 09:00:00 PM GMT-3", cstr.c_str());
360 }
361 }
362 }
363
JSDateTimeFormatForObj_002(JSThread * thread)364 static JSTaggedValue JSDateTimeFormatForObj_002(JSThread *thread)
365 {
366 auto globalConst = thread->GlobalConstants();
367 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
368 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
369 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
370 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
371
372 JSHandle<JSTaggedValue> timeZoneName = globalConst->GetHandledTimeZoneNameString();
373 JSHandle<JSTaggedValue> timeZone = globalConst->GetHandledTimeZoneString();
374 JSHandle<JSTaggedValue> numicValue(factory->NewFromASCII("numeric"));
375 JSHandle<JSTaggedValue> digitValue(factory->NewFromASCII("2-digit"));
376 JSHandle<JSTaggedValue> longValue(factory->NewFromASCII("long"));
377 JSHandle<JSTaggedValue> timeZoneNameValue(factory->NewFromASCII("short"));
378 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC"));
379
380 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(6); // 6 : 6 length
381 keyArray->Set(thread, 0, globalConst->GetHandledYearString()); // 0 : 0 first position
382 keyArray->Set(thread, 1, globalConst->GetHandledMonthString()); // 1 : 1 second position
383 keyArray->Set(thread, 2, globalConst->GetHandledDayString()); // 2 : 2 third position
384 keyArray->Set(thread, 3, globalConst->GetHandledHourString()); // 3 : 3 fourth position
385 keyArray->Set(thread, 4, globalConst->GetHandledMinuteString()); // 4 : 4 fifth position
386 keyArray->Set(thread, 5, globalConst->GetHandledSecondString()); // 5 : 5 sixth position
387 uint32_t arrayLen = keyArray->GetLength();
388 uint32_t arrIndex[] = {0, 2};
389 uint32_t arrIndex2 = 1;
390 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
391 for (uint32_t i = 0; i < arrayLen; i++) {
392 key.Update(keyArray->Get(thread, i));
393 bool exists = std::count(std::begin(arrIndex), std::end(arrIndex), i) > 0;
394 if (exists) {
395 JSObject::SetProperty(thread, optionsObj, key, numicValue);
396 } else if (i == arrIndex2) {
397 JSObject::SetProperty(thread, optionsObj, key, longValue);
398 } else {
399 JSObject::SetProperty(thread, optionsObj, key, digitValue);
400 }
401 }
402 JSObject::SetProperty(thread, optionsObj, timeZoneName, timeZoneNameValue);
403 JSObject::SetProperty(thread, optionsObj, timeZone, timeZoneValue);
404 return optionsObj.GetTaggedValue();
405 }
406
407 // DateTimeFormat_002
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_002)408 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_002)
409 {
410 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
411 JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("zh-CN"));
412 auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_002(thread));
413 auto constructorResult = JSDateTimeFormatConstructor(thread, jsObj, localesString);
414 auto formatResult = JSDateTimeFormatForObject(thread, constructorResult);
415 auto dtResult = JSDateTime(thread, formatResult);
416 JSHandle<EcmaString> resultStr(thread, dtResult);
417 EXPECT_STREQ("2022年10月8日 UTC 上午12:00:00", EcmaStringAccessor(resultStr).ToCString().c_str());
418 }
419
420 // DateTimeFormat_003
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_003)421 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_003)
422 {
423 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
424 JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("zh-CN"));
425
426 auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_002(thread));
427 auto constructorResult = JSDateTimeFormatConstructor(thread, jsObj, localesString);
428 JSHandle<JSDateTimeFormat> jsDateTimeFormat = JSHandle<JSDateTimeFormat>(thread, constructorResult);
429 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
430 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
431 ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
432 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
433
434 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
435 JSTaggedValue result = BuiltinsDateTimeFormat::FormatToParts(ecmaRuntimeCallInfo);
436 TestHelper::TearDownFrame(thread, prev);
437
438 JSHandle<JSArray> resultHandle(thread, result);
439 JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
440 EXPECT_EQ(elements->GetLength(), 16U);
441 }
442
443 // DateTimeFormat_004
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_004)444 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_004)
445 {
446 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
447 JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("zh-CN"));
448 auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_002(thread));
449 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
450 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
451 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
452 JSHandle<JSTaggedValue> fullValue(factory->NewFromASCII("full"));
453 JSHandle<JSTaggedValue> falseValue(thread, JSTaggedValue(false));
454 JSHandle<JSTaggedValue> dateStyleValue(factory->NewFromASCII("dateStyle"));
455 JSHandle<JSTaggedValue> timeStyleeValue(factory->NewFromASCII("timeStyle"));
456 JSHandle<JSTaggedValue> hour12Value(factory->NewFromASCII("hour12"));
457 JSHandle<JSTaggedValue> timeZone(factory->NewFromASCII("timeZone"));
458 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC"));
459 JSObject::SetProperty(thread, optionsObj, dateStyleValue, fullValue);
460 JSObject::SetProperty(thread, optionsObj, timeStyleeValue, fullValue);
461 JSObject::SetProperty(thread, optionsObj, hour12Value, falseValue);
462 JSObject::SetProperty(thread, optionsObj, timeZone, timeZoneValue);
463 auto constructorResult = JSDateTimeFormatConstructor(thread, optionsObj, localesString);
464 JSHandle<EcmaString> resultStr =
465 JSDateTimeFormat::FormatDateTime(thread, JSHandle<JSDateTimeFormat>(thread, constructorResult), 0.0);
466 EXPECT_STREQ("1970年1月1日星期四 协调世界时 00:00:00", EcmaStringAccessor(resultStr).ToCString().c_str());
467 }
468 } // namespace panda::test