• 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 "builtin_test_util.h"
17 #include "ecmascript/builtins/builtins_date_time_format.h"
18 
19 #include <ctime>
20 #include <algorithm>
21 #include "ecmascript/builtins/builtins_array.h"
22 #include "ecmascript/global_env.h"
23 #include "ecmascript/js_date.h"
24 #include "ecmascript/js_date_time_format.h"
25 #include "ecmascript/tests/test_helper.h"
26 
27 using namespace panda::ecmascript;
28 using namespace panda::ecmascript::builtins;
29 
30 namespace panda::test {
31 using BuiltinsArray = ecmascript::builtins::BuiltinsArray;
32 class BuiltinsDateTimeFormatTest : public BaseTestWithScope<true> {
33 };
34 
HWTEST_F_L0(BuiltinsDateTimeFormatTest,ResolvedOptions)35 HWTEST_F_L0(BuiltinsDateTimeFormatTest, ResolvedOptions)
36 {
37     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
38     auto globalConst = thread->GlobalConstants();
39     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-ID"));
40     JSHandle<JSDateTimeFormat> jsDateTimeFormat =
41        JSHandle<JSDateTimeFormat>(thread, BuiltTestUtil::JSDateTimeFormatCreateWithLocaleTest(thread, locale));
42 
43     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
44     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
45     ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
46 
47     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
48     JSTaggedValue result = BuiltinsDateTimeFormat::ResolvedOptions(ecmaRuntimeCallInfo);
49     TestHelper::TearDownFrame(thread, prev);
50 
51     JSHandle<JSTaggedValue> resultObj =
52         JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result.GetRawData())));
53     // judge whether the properties of the object are the same as those of jsdatetimeformat tag
54     JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
55     JSHandle<JSTaggedValue> localeValue(factory->NewFromASCII("de"));
56     EXPECT_EQ(JSTaggedValue::SameValue(
57         JSObject::GetProperty(thread, resultObj, localeKey).GetValue(), localeValue), true);
58     JSHandle<JSTaggedValue> timeZone = globalConst->GetHandledTimeZoneString();
59     JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC"));
60     EXPECT_EQ(JSTaggedValue::SameValue(
61         JSObject::GetProperty(thread, resultObj, timeZone).GetValue(), timeZoneValue), true);
62 }
63 
64 // SupportedLocalesOf("best fit")
HWTEST_F_L0(BuiltinsDateTimeFormatTest,SupportedLocalesOf_001)65 HWTEST_F_L0(BuiltinsDateTimeFormatTest, SupportedLocalesOf_001)
66 {
67     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
68     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-ID"));
69 
70     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
71     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
72     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
73     ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
74     // set the tag is default value
75     ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
76 
77     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
78     JSTaggedValue resultArr = BuiltinsDateTimeFormat::SupportedLocalesOf(ecmaRuntimeCallInfo);
79     TestHelper::TearDownFrame(thread, prev);
80 
81     JSHandle<JSArray> resultHandle(thread, resultArr);
82     JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
83     EXPECT_EQ(elements->GetLength(), 1U);
84 
85     JSHandle<EcmaString> resultStr(thread, elements->Get(0));
86     EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(resultStr).ToCString().c_str());
87 }
88 
89 // SupportedLocalesOf("look up")
HWTEST_F_L0(BuiltinsDateTimeFormatTest,SupportedLocalesOf_002)90 HWTEST_F_L0(BuiltinsDateTimeFormatTest, SupportedLocalesOf_002)
91 {
92     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
93     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
94 
95     JSHandle<JSTaggedValue> localeMatcherKey = thread->GlobalConstants()->GetHandledLocaleMatcherString();
96     JSHandle<JSTaggedValue> localeMatcherValue(factory->NewFromASCII("lookup"));
97     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-DE"));
98 
99     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
100     JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
101     JSObject::SetProperty(thread, optionsObj, localeMatcherKey, localeMatcherValue);
102 
103     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
104     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
105     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
106     ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
107     ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
108 
109     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
110     JSTaggedValue resultArr = BuiltinsDateTimeFormat::SupportedLocalesOf(ecmaRuntimeCallInfo);
111     TestHelper::TearDownFrame(thread, prev);
112 
113     JSHandle<JSArray> resultHandle(thread, resultArr);
114     JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
115     EXPECT_EQ(elements->GetLength(), 1U);
116 
117     JSHandle<EcmaString> resultStr(thread, elements->Get(0));
118     EXPECT_STREQ("id-u-co-pinyin-de", EcmaStringAccessor(resultStr).ToCString().c_str());
119 }
120 
JSDateTime(JSThread * thread,JSTaggedValue & formatResult)121 static JSTaggedValue JSDateTime(JSThread *thread, JSTaggedValue &formatResult)
122 {
123     double days = 1665187200000;
124     JSHandle<JSFunction> jsFunction(thread, formatResult);
125     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(static_cast<double>(days)));
126     auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
127     ecmaRuntimeCallInfo2->SetFunction(jsFunction.GetTaggedValue());
128     ecmaRuntimeCallInfo2->SetThis(JSTaggedValue::Undefined());
129     ecmaRuntimeCallInfo2->SetCallArg(0, value.GetTaggedValue());
130 
131     [[maybe_unused]] auto prev2 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
132     JSTaggedValue result2 = JSFunction::Call(ecmaRuntimeCallInfo2);
133     TestHelper::TearDownFrame(thread, prev2);
134     return result2;
135 }
136 
JSDateTimeFormatConstructor(JSThread * thread,JSHandle<JSObject> & optionsObj,JSHandle<JSTaggedValue> & localesString)137 static JSTaggedValue JSDateTimeFormatConstructor(JSThread *thread, JSHandle<JSObject> &optionsObj,
138     JSHandle<JSTaggedValue> &localesString)
139 {
140     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
141     JSHandle<JSFunction> newTarget(env->GetDateTimeFormatFunction());
142 
143     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
144     ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
145     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
146     ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
147     ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
148 
149     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
150     JSTaggedValue result = BuiltinsDateTimeFormat::DateTimeFormatConstructor(ecmaRuntimeCallInfo);
151     EXPECT_TRUE(result.IsJSDateTimeFormat());
152     TestHelper::TearDownFrame(thread, prev);
153     return result;
154 }
155 
JSDateTimeFormatForObject(JSThread * thread,JSTaggedValue & constructorResult)156 static JSTaggedValue JSDateTimeFormatForObject(JSThread *thread, JSTaggedValue &constructorResult)
157 {
158     JSHandle<JSDateTimeFormat> jsDateTimeFormat = JSHandle<JSDateTimeFormat>(thread, constructorResult);
159     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
160     ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
161     ecmaRuntimeCallInfo1->SetThis(jsDateTimeFormat.GetTaggedValue());
162     ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue::Undefined());
163     [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
164     JSTaggedValue result1 = BuiltinsDateTimeFormat::Format(ecmaRuntimeCallInfo1);
165     TestHelper::TearDownFrame(thread, prev1);
166     return result1;
167 }
168 
JSDateTimeFormatForObj_001(JSThread * thread)169 static JSTaggedValue JSDateTimeFormatForObj_001(JSThread *thread)
170 {
171     auto globalConst = thread->GlobalConstants();
172     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
173     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
174     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
175     JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
176 
177     JSHandle<JSTaggedValue> timeZoneName = globalConst->GetHandledTimeZoneNameString();
178     JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en-US"));
179     JSHandle<JSTaggedValue> digitValue(factory->NewFromASCII("2-digit"));
180     JSHandle<JSTaggedValue> timeZoneNameValue(factory->NewFromASCII("short"));
181 
182     JSHandle<TaggedArray> keyArray = BuiltTestUtil::DateTimeGlobalSet(thread);
183     uint32_t arrayLen = keyArray->GetLength();
184     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
185     for (uint32_t i = 0; i < arrayLen; i++) {
186         key.Update(keyArray->Get(thread, i));
187         JSObject::SetProperty(thread, optionsObj, key, digitValue);
188     }
189     JSObject::SetProperty(thread, optionsObj, timeZoneName, timeZoneNameValue);
190     return optionsObj.GetTaggedValue();
191 }
192 
TimeOffset()193 static int TimeOffset()
194 {
195     // Get Sys time
196     time_t rt = time(nullptr);
197     // Convert Sys time to GMT time
198     tm gtm = *gmtime(&rt);
199     // Convert GMT time to Sys time
200     time_t gt = mktime(&gtm);
201     tm gtm2 = *localtime(&gt);
202     // Calculate time difference
203     int offset = ((rt - gt) + (gtm2.tm_isdst ? 3600 : 0)) / 60;
204     return offset;
205 }
206 
207 // DateTimeFormat_001
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_001)208 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_001)
209 {
210     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
211     JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en-US"));
212     auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_001(thread));
213     auto constructorResult = JSDateTimeFormatConstructor(thread, jsObj, localesString);
214     auto formatResult = JSDateTimeFormatForObject(thread, constructorResult);
215     auto dtResult = JSDateTime(thread, formatResult);
216     JSHandle<EcmaString> resultStr(thread, dtResult);
217 
218     constexpr int shanghai = 480;
219     constexpr int americaRegina = -360;
220     constexpr int americaNewYork = -300;
221     constexpr int sysDefaultTimezone = -180; // america_argentina_Buenos_Aires
222     constexpr int utc = 0;
223     auto cstr = EcmaStringAccessor(resultStr).ToCString();
224     if (TimeOffset() == utc) {
225         if (cstr.find("GMT") != std::string::npos) {
226             EXPECT_STREQ("10/08/22, 12:00:00 AM GMT", cstr.c_str());
227         }
228         if (cstr.find("UTC") != std::string::npos) {
229             EXPECT_STREQ("10/08/22, 12:00:00 AM UTC", cstr.c_str());
230         }
231     }
232     if (TimeOffset() == shanghai) {
233         if (cstr.find("CST") != std::string::npos) {
234             EXPECT_STREQ("10/08/22, 08:00:00 AM CST", cstr.c_str());
235         }
236         if (cstr.find("GMT+8") != std::string::npos) {
237             EXPECT_STREQ("10/08/22, 08:00:00 AM GMT+8", cstr.c_str());
238         }
239     }
240     if (TimeOffset() == americaRegina) {
241         if (cstr.find("CST") != std::string::npos) {
242             EXPECT_STREQ("10/07/22, 06:00:00 PM CST", cstr.c_str());
243         }
244     }
245     if (TimeOffset() == americaNewYork) {
246         if (cstr.find("EST") != std::string::npos) {
247             EXPECT_STREQ("10/07/22, 06:00:00 PM EST", cstr.c_str());
248         }
249     }
250     if (TimeOffset() == sysDefaultTimezone) {
251         if (cstr.find("GMT-3") != std::string::npos) {
252             EXPECT_STREQ("10/07/22, 09:00:00 PM GMT-3", cstr.c_str());
253         }
254     }
255 }
256 
JSDateTimeFormatForObj_002(JSThread * thread)257 static JSTaggedValue JSDateTimeFormatForObj_002(JSThread *thread)
258 {
259     auto globalConst = thread->GlobalConstants();
260     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
261     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
262     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
263     JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
264 
265     JSHandle<JSTaggedValue> timeZoneName = globalConst->GetHandledTimeZoneNameString();
266     JSHandle<JSTaggedValue> timeZone = globalConst->GetHandledTimeZoneString();
267     JSHandle<JSTaggedValue> numicValue(factory->NewFromASCII("numeric"));
268     JSHandle<JSTaggedValue> digitValue(factory->NewFromASCII("2-digit"));
269     JSHandle<JSTaggedValue> longValue(factory->NewFromASCII("long"));
270     JSHandle<JSTaggedValue> timeZoneNameValue(factory->NewFromASCII("short"));
271     JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC"));
272 
273     JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(6); // 6 : 6 length
274     keyArray->Set(thread, 0, globalConst->GetHandledYearString()); // 0 : 0 first position
275     keyArray->Set(thread, 1, globalConst->GetHandledMonthString()); // 1 : 1 second position
276     keyArray->Set(thread, 2, globalConst->GetHandledDayString()); // 2 : 2 third position
277     keyArray->Set(thread, 3, globalConst->GetHandledHourString()); // 3 : 3 fourth position
278     keyArray->Set(thread, 4, globalConst->GetHandledMinuteString()); // 4 : 4 fifth position
279     keyArray->Set(thread, 5, globalConst->GetHandledSecondString()); // 5 : 5 sixth position
280     uint32_t arrayLen = keyArray->GetLength();
281     uint32_t arrIndex[] = {0, 2};
282     uint32_t arrIndex2 = 1;
283     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
284     for (uint32_t i = 0; i < arrayLen; i++) {
285         key.Update(keyArray->Get(thread, i));
286         bool exists = std::count(std::begin(arrIndex), std::end(arrIndex), i) > 0;
287         if (exists) {
288             JSObject::SetProperty(thread, optionsObj, key, numicValue);
289         } else if (i == arrIndex2) {
290             JSObject::SetProperty(thread, optionsObj, key, longValue);
291         } else {
292             JSObject::SetProperty(thread, optionsObj, key, digitValue);
293         }
294     }
295     JSObject::SetProperty(thread, optionsObj, timeZoneName, timeZoneNameValue);
296     JSObject::SetProperty(thread, optionsObj, timeZone, timeZoneValue);
297     return optionsObj.GetTaggedValue();
298 }
299 
300 // DateTimeFormat_002
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_002)301 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_002)
302 {
303     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
304     JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("zh-CN"));
305     auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_002(thread));
306     auto constructorResult = JSDateTimeFormatConstructor(thread, jsObj, localesString);
307     auto formatResult = JSDateTimeFormatForObject(thread, constructorResult);
308     auto dtResult = JSDateTime(thread, formatResult);
309     JSHandle<EcmaString> resultStr(thread, dtResult);
310     EXPECT_STREQ("2022年10月8日 UTC 上午12:00:00", EcmaStringAccessor(resultStr).ToCString().c_str());
311 }
312 
313 // DateTimeFormat_003
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_003)314 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_003)
315 {
316     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
317     JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("zh-CN"));
318 
319     auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_002(thread));
320     auto constructorResult = JSDateTimeFormatConstructor(thread, jsObj, localesString);
321     JSHandle<JSDateTimeFormat> jsDateTimeFormat = JSHandle<JSDateTimeFormat>(thread, constructorResult);
322     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
323     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
324     ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
325     ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
326 
327     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
328     JSTaggedValue result = BuiltinsDateTimeFormat::FormatToParts(ecmaRuntimeCallInfo);
329     TestHelper::TearDownFrame(thread, prev);
330 
331     JSHandle<JSArray> resultHandle(thread, result);
332     JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
333     EXPECT_EQ(elements->GetLength(), 16U);
334 }
335 
336 // DateTimeFormat_004
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormat_004)337 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormat_004)
338 {
339     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
340     JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("zh-CN"));
341     auto jsObj = JSHandle<JSObject>(thread, JSDateTimeFormatForObj_002(thread));
342     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
343     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
344     JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
345     JSHandle<JSTaggedValue> fullValue(factory->NewFromASCII("full"));
346     JSHandle<JSTaggedValue> falseValue(thread, JSTaggedValue(false));
347     JSHandle<JSTaggedValue> dateStyleValue(factory->NewFromASCII("dateStyle"));
348     JSHandle<JSTaggedValue> timeStyleeValue(factory->NewFromASCII("timeStyle"));
349     JSHandle<JSTaggedValue> hour12Value(factory->NewFromASCII("hour12"));
350     JSHandle<JSTaggedValue> timeZone(factory->NewFromASCII("timeZone"));
351     JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC"));
352     JSObject::SetProperty(thread, optionsObj, dateStyleValue, fullValue);
353     JSObject::SetProperty(thread, optionsObj, timeStyleeValue, fullValue);
354     JSObject::SetProperty(thread, optionsObj, hour12Value, falseValue);
355     JSObject::SetProperty(thread, optionsObj, timeZone, timeZoneValue);
356     auto constructorResult = JSDateTimeFormatConstructor(thread, optionsObj, localesString);
357     JSHandle<EcmaString> resultStr =
358         JSDateTimeFormat::FormatDateTime(thread, JSHandle<JSDateTimeFormat>(thread, constructorResult), 0.0);
359     EXPECT_STREQ("1970年1月1日星期四 协调世界时 00:00:00", EcmaStringAccessor(resultStr).ToCString().c_str());
360 }
361 } // namespace panda::test