• 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 "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 
68 // new DateTimeFormat(locale)
HWTEST_F_L0(BuiltinsDateTimeFormatTest,DateTimeFormatConstructor)69 HWTEST_F_L0(BuiltinsDateTimeFormatTest, DateTimeFormatConstructor)
70 {
71     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
72     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
73     JSHandle<JSFunction> newTarget(env->GetDateTimeFormatFunction());
74 
75     JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en-US"));
76     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
77     ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
78     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
79     ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
80     // option tag is default value
81     ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
82 
83     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
84     JSTaggedValue result = BuiltinsDateTimeFormat::DateTimeFormatConstructor(ecmaRuntimeCallInfo);
85     TestHelper::TearDownFrame(thread, prev);
86     EXPECT_TRUE(result.IsJSDateTimeFormat());
87 }
88 
BuiltinsDateTimeOptionsSet(JSThread * thread)89 static JSTaggedValue BuiltinsDateTimeOptionsSet(JSThread *thread)
90 {
91     auto globalConst = thread->GlobalConstants();
92     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
93     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
94 
95     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
96     JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
97 
98     JSHandle<JSTaggedValue> weekDay = globalConst->GetHandledWeekdayString();
99     JSHandle<JSTaggedValue> dayPeriod = globalConst->GetHandledDayPeriodString();
100     JSHandle<JSTaggedValue> hourCycle = globalConst->GetHandledHourCycleString();
101     JSHandle<JSTaggedValue> timeZone = globalConst->GetHandledTimeZoneString();
102     JSHandle<JSTaggedValue> numicValue(factory->NewFromASCII("numeric")); // test numeric
103     JSHandle<JSTaggedValue> weekDayValue(factory->NewFromASCII("short")); // test short
104     JSHandle<JSTaggedValue> dayPeriodValue(factory->NewFromASCII("long")); // test long
105     JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h24")); // test h24
106     JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("UTC")); // test UTC
107 
108     JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(6); // 6 : 6 length
109     keyArray->Set(thread, 0, globalConst->GetHandledYearString()); // 0 : 0 first position
110     keyArray->Set(thread, 1, globalConst->GetHandledMonthString()); // 1 : 1 second position
111     keyArray->Set(thread, 2, globalConst->GetHandledDayString()); // 2 : 2 third position
112     keyArray->Set(thread, 3, globalConst->GetHandledHourString()); // 3 : 3 fourth position
113     keyArray->Set(thread, 4, globalConst->GetHandledMinuteString()); // 4 : 4 fifth position
114     keyArray->Set(thread, 5, globalConst->GetHandledSecondString()); // 5 : 5 sixth position
115 
116     uint32_t arrayLen = keyArray->GetLength();
117     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
118     for (uint32_t i = 0; i < arrayLen; i++) {
119         key.Update(keyArray->Get(thread, i));
120         JSObject::SetProperty(thread, optionsObj, key, numicValue);
121     }
122     JSObject::SetProperty(thread, optionsObj, weekDay, weekDayValue);
123     JSObject::SetProperty(thread, optionsObj, dayPeriod, dayPeriodValue);
124     JSObject::SetProperty(thread, optionsObj, hourCycle, hourCycleValue);
125     JSObject::SetProperty(thread, optionsObj, timeZone, timeZoneValue);
126     return optionsObj.GetTaggedValue();
127 }
128 
JSDateTimeFormatCreateWithLocaleTest(JSThread * thread,JSHandle<JSTaggedValue> & locale)129 static JSTaggedValue JSDateTimeFormatCreateWithLocaleTest(JSThread *thread, JSHandle<JSTaggedValue> &locale)
130 {
131     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
132     JSHandle<JSFunction> newTarget(env->GetDateTimeFormatFunction());
133     JSHandle<JSObject> optionsObj(thread, BuiltinsDateTimeOptionsSet(thread));
134 
135     JSHandle<JSTaggedValue> localesString = locale;
136     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
137     ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
138     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
139     ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
140     ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
141 
142     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
143     JSTaggedValue result = BuiltinsDateTimeFormat::DateTimeFormatConstructor(ecmaRuntimeCallInfo);
144     EXPECT_TRUE(result.IsJSDateTimeFormat());
145     TestHelper::TearDownFrame(thread, prev);
146     return result;
147 }
148 
BuiltinsDateCreate(const double year,const double month,const double date)149 static double BuiltinsDateCreate(const double year, const double month, const double date)
150 {
151     const double day = JSDate::MakeDay(year, month, date);
152     const double time = JSDate::MakeTime(0, 0, 0, 0); // 24:00:00
153     double days = JSDate::MakeDate(day, time);
154     return days;
155 }
156 
157 // Format.Tostring(en-US)
HWTEST_F_L0(BuiltinsDateTimeFormatTest,Format_001)158 HWTEST_F_L0(BuiltinsDateTimeFormatTest, Format_001)
159 {
160     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
161     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-US"));
162     JSHandle<JSDateTimeFormat> jsDateTimeFormat =
163        JSHandle<JSDateTimeFormat>(thread, JSDateTimeFormatCreateWithLocaleTest(thread, locale));
164 
165     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
166     ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
167     ecmaRuntimeCallInfo1->SetThis(jsDateTimeFormat.GetTaggedValue());
168     ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue::Undefined());
169 
170     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
171     JSTaggedValue result1 = BuiltinsDateTimeFormat::Format(ecmaRuntimeCallInfo1);
172     TestHelper::TearDownFrame(thread, prev);
173     // jsDate supports zero to eleven, the month should be added with one
174     JSHandle<JSFunction> jsFunction(thread, result1);
175     JSArray *jsArray =
176         JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
177     JSHandle<JSObject> jsObject(thread, jsArray);
178 
179     double days = BuiltinsDateCreate(2020, 10, 1);
180     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(static_cast<double>(days)));
181     PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(jsFunction), true, true, true);
182     JSHandle<JSTaggedValue> joinKey(factory->NewFromASCII("join"));
183     JSArray::DefineOwnProperty(thread, jsObject, joinKey, desc);
184 
185     auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
186     ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
187     ecmaRuntimeCallInfo2->SetThis(jsObject.GetTaggedValue());
188     ecmaRuntimeCallInfo2->SetCallArg(0, value.GetTaggedValue());
189 
190     prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
191     JSTaggedValue result2 = BuiltinsArray::ToString(ecmaRuntimeCallInfo2);
192     TestHelper::TearDownFrame(thread, prev);
193     JSHandle<EcmaString> resultStr(thread, result2);
194     EXPECT_STREQ("Sun, 11/1/2020, 24:00:00", EcmaStringAccessor(resultStr).ToCString().c_str());
195 }
196 
197 // Format.Tostring(pt-BR)
HWTEST_F_L0(BuiltinsDateTimeFormatTest,Format_002)198 HWTEST_F_L0(BuiltinsDateTimeFormatTest, Format_002)
199 {
200     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
201     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("pt-BR"));
202     JSHandle<JSDateTimeFormat> jsDateTimeFormat =
203        JSHandle<JSDateTimeFormat>(thread, JSDateTimeFormatCreateWithLocaleTest(thread, locale));
204 
205     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
206     ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
207     ecmaRuntimeCallInfo1->SetThis(jsDateTimeFormat.GetTaggedValue());
208     ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue::Undefined());
209 
210     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
211     JSTaggedValue result1 = BuiltinsDateTimeFormat::Format(ecmaRuntimeCallInfo1);
212     TestHelper::TearDownFrame(thread, prev);
213 
214     JSHandle<JSFunction> jsFunction(thread, result1);
215     JSArray *jsArray =
216         JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
217     JSHandle<JSObject> jsObject(thread, jsArray);
218 
219     double days = BuiltinsDateCreate(2020, 5, 11);
220     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(static_cast<double>(days)));
221     PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(jsFunction), true, true, true);
222     JSHandle<JSTaggedValue> joinKey(factory->NewFromASCII("join"));
223     JSArray::DefineOwnProperty(thread, jsObject, joinKey, desc);
224 
225     auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
226     ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
227     ecmaRuntimeCallInfo2->SetThis(jsObject.GetTaggedValue());
228     ecmaRuntimeCallInfo2->SetCallArg(0, value.GetTaggedValue());
229 
230     prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
231     JSTaggedValue result2 = BuiltinsArray::ToString(ecmaRuntimeCallInfo2);
232     TestHelper::TearDownFrame(thread, prev);
233     JSHandle<EcmaString> resultStr(thread, result2);
234     CString resStr = EcmaStringAccessor(resultStr).ToCString();
235     // the index of string "qui" is zero.
236     EXPECT_TRUE(resStr.find("qui") == 0);
237     // the index of string "11/06/2020 24:00:00" is not zero.
238     EXPECT_TRUE(resStr.find("11/06/2020 24:00:00") != 0);
239 }
240 
HWTEST_F_L0(BuiltinsDateTimeFormatTest,FormatToParts)241 HWTEST_F_L0(BuiltinsDateTimeFormatTest, FormatToParts)
242 {
243     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
244     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-US"));
245     JSHandle<JSDateTimeFormat> jsDateTimeFormat =
246        JSHandle<JSDateTimeFormat>(thread, JSDateTimeFormatCreateWithLocaleTest(thread, locale));
247 
248     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
249     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
250     ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
251     ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
252 
253     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
254     JSTaggedValue result = BuiltinsDateTimeFormat::FormatToParts(ecmaRuntimeCallInfo);
255     TestHelper::TearDownFrame(thread, prev);
256 
257     JSHandle<JSArray> resultHandle(thread, result);
258     JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
259     EXPECT_EQ(elements->GetLength(), 16U); // sixteen formatters
260 }
261 
262 // FormatRange(zh)
HWTEST_F_L0(BuiltinsDateTimeFormatTest,FormatRange_001)263 HWTEST_F_L0(BuiltinsDateTimeFormatTest, FormatRange_001)
264 {
265     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
266     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("zh"));
267     JSHandle<JSDateTimeFormat> jsDateTimeFormat =
268        JSHandle<JSDateTimeFormat>(thread, JSDateTimeFormatCreateWithLocaleTest(thread, locale));
269 
270     double days1 = BuiltinsDateCreate(2020, 10, 1);
271     double days2 = BuiltinsDateCreate(2021, 6, 1);
272     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
273     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
274     ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
275     ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(days1)));
276     ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(days2)));
277 
278     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
279     JSTaggedValue result = BuiltinsDateTimeFormat::FormatRange(ecmaRuntimeCallInfo);
280     TestHelper::TearDownFrame(thread, prev);
281 
282     JSHandle<EcmaString> handleStr(thread, result);
283     JSHandle<EcmaString> resultStr = factory->NewFromUtf8("2020/11/1周日 24:00:00 – 2021/7/1周四 24:00:00");
284     EXPECT_EQ(EcmaStringAccessor::Compare(instance, handleStr, resultStr), 0);
285 }
286 
287 // FormatRange(en)
HWTEST_F_L0(BuiltinsDateTimeFormatTest,FormatRange_002)288 HWTEST_F_L0(BuiltinsDateTimeFormatTest, FormatRange_002)
289 {
290     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
291     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-US"));
292     JSHandle<JSDateTimeFormat> jsDateTimeFormat =
293        JSHandle<JSDateTimeFormat>(thread, JSDateTimeFormatCreateWithLocaleTest(thread, locale));
294 
295     double days1 = BuiltinsDateCreate(2020, 12, 1);
296     double days2 = BuiltinsDateCreate(2021, 2, 1);
297     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
298     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
299     ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
300     ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(days1)));
301     ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(days2)));
302 
303     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
304     JSTaggedValue result = BuiltinsDateTimeFormat::FormatRange(ecmaRuntimeCallInfo);
305     TestHelper::TearDownFrame(thread, prev);
306 
307     JSHandle<EcmaString> handleStr(thread, result);
308     JSHandle<EcmaString> resultStr = factory->NewFromUtf8("Fri, 1/1/2021, 24:00:00 – Mon, 3/1/2021, 24:00:00");
309     EXPECT_EQ(EcmaStringAccessor::Compare(instance, handleStr, resultStr), 0);
310 }
311 
HWTEST_F_L0(BuiltinsDateTimeFormatTest,FormatRangeToParts)312 HWTEST_F_L0(BuiltinsDateTimeFormatTest, FormatRangeToParts)
313 {
314     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
315     JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-US"));
316     JSHandle<JSDateTimeFormat> jsDateTimeFormat =
317        JSHandle<JSDateTimeFormat>(thread, JSDateTimeFormatCreateWithLocaleTest(thread, locale));
318 
319     double days1 = BuiltinsDateCreate(2020, 12, 1);
320     double days2 = BuiltinsDateCreate(2021, 2, 1);
321     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
322     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
323     ecmaRuntimeCallInfo->SetThis(jsDateTimeFormat.GetTaggedValue());
324     ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(days1)));
325     ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<double>(days2)));
326 
327     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
328     JSTaggedValue result = BuiltinsDateTimeFormat::FormatRangeToParts(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(), 39U); // The number of characters of "Fri1/1/202124:00:00–Mon3/1/202124:00:00"
334 }
335 }  // namespace panda::test
336 
337