• 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/intl/locale_helper.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/js_date.h"
19 #include "ecmascript/js_date_time_format.h"
20 #include "ecmascript/js_locale.h"
21 #include "ecmascript/object_factory-inl.h"
22 #include "ecmascript/tests/ecma_test_common.h"
23 
24 using namespace panda;
25 using namespace panda::ecmascript;
26 using namespace panda::ecmascript::base;
27 using LocaleHelper = panda::ecmascript::intl::LocaleHelper;
28 
29 namespace panda::test {
30 class JSDateTimeFormatTest : public BaseTestWithScope<true> {
31 };
32 
33 /**
34  * @tc.name: GetIcuLocale & SetIcuLocale
35  * @tc.desc: Set and obtain localization labels compatible with ICU Libraries.
36  * @tc.type: FUNC
37  * @tc.require:
38  */
HWTEST_F_L0(JSDateTimeFormatTest,Set_Get_IcuLocale)39 HWTEST_F_L0(JSDateTimeFormatTest, Set_Get_IcuLocale)
40 {
41     auto vm = thread->GetEcmaVM();
42     auto factory = vm->GetFactory();
43     auto env = vm->GetGlobalEnv();
44     JSHandle<JSTaggedValue> ctor = env->GetDateTimeFormatFunction();
45     JSHandle<JSDateTimeFormat> dtf =
46         JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
47 
48     icu::Locale locale1("ko", "Kore", "KR");
49     JSDateTimeFormat::SetIcuLocale(thread, dtf, locale1, JSDateTimeFormat::FreeIcuLocale);
50     icu::Locale *resLocale1 = dtf->GetIcuLocale();
51     EXPECT_STREQ(resLocale1->getBaseName(), "ko_Kore_KR");
52 
53     icu::Locale locale2("zh", "Hans", "Cn");
54     JSDateTimeFormat::SetIcuLocale(thread, dtf, locale2, JSDateTimeFormat::FreeIcuLocale);
55     icu::Locale *resLocale2 = dtf->GetIcuLocale();
56     EXPECT_STREQ(resLocale2->getBaseName(), "zh_Hans_CN");
57 }
58 
59 /**
60  * @tc.name: SetIcuSimpleDateFormat & GetIcuSimpleDateFormat
61  * @tc.desc: Set and obtain a simple time and date format compatible with ICU Libraries.
62  * @tc.type: FUNC
63  * @tc.require:
64  */
HWTEST_F_L0(JSDateTimeFormatTest,Set_Get_IcuSimpleDateFormat)65 HWTEST_F_L0(JSDateTimeFormatTest, Set_Get_IcuSimpleDateFormat)
66 {
67     auto vm = thread->GetEcmaVM();
68     auto factory = vm->GetFactory();
69     auto env = vm->GetGlobalEnv();
70     const icu::UnicodeString timeZoneId("Asia/Shanghai");
71     icu::TimeZone *tz = icu::TimeZone::createTimeZone(timeZoneId);
72     icu::TimeZone::adoptDefault(tz);
73     JSHandle<JSTaggedValue> ctor = env->GetDateTimeFormatFunction();
74     JSHandle<JSDateTimeFormat> dtf =
75         JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
76     UErrorCode status = UErrorCode::U_ZERO_ERROR;
77     icu::UnicodeString dateTime1("2022.05.25 11:09:34");
78     icu::UnicodeString dateTime2("2022.May.25 11:09:34");
79     icu::UnicodeString dateTime3("2022.May.25 AD 11:09:34 AM");
80 
81     icu::UnicodeString pattern("yyyy.MM.dd HH:mm:ss");
82     icu::SimpleDateFormat sdf(pattern, status);
83     JSDateTimeFormat::SetIcuSimpleDateFormat(thread, dtf, sdf, JSDateTimeFormat::FreeSimpleDateFormat);
84     icu::SimpleDateFormat *resSdf = dtf->GetIcuSimpleDateFormat();
85     UDate timeStamp = resSdf->parse(dateTime1, status);
86     EXPECT_EQ(timeStamp, 1653448174000);
87     status = UErrorCode::U_ZERO_ERROR;
88     timeStamp = resSdf->parse(dateTime2, status);
89     EXPECT_EQ(timeStamp, 1653448174000);
90     status = UErrorCode::U_ZERO_ERROR;
91     timeStamp = resSdf->parse(dateTime3, status);
92     EXPECT_EQ(timeStamp, 0);
93 
94     status = UErrorCode::U_ZERO_ERROR;
95     icu::UnicodeString pattern2("yyyyy.MMMMM.dd GGG hh:mm::ss aaa");
96     icu::SimpleDateFormat sdf2(pattern2, status);
97     JSDateTimeFormat::SetIcuSimpleDateFormat(thread, dtf, sdf2, JSDateTimeFormat::FreeSimpleDateFormat);
98     icu::SimpleDateFormat *resSdf2 = dtf->GetIcuSimpleDateFormat();
99     timeStamp = resSdf2->parse(dateTime1, status);
100     EXPECT_EQ(timeStamp, 0);
101     status = UErrorCode::U_ZERO_ERROR;
102     timeStamp = resSdf2->parse(dateTime2, status);
103     EXPECT_EQ(timeStamp, 0);
104     status = UErrorCode::U_ZERO_ERROR;
105     timeStamp = resSdf2->parse(dateTime3, status);
106     EXPECT_EQ(timeStamp, 1653448174000);
107 }
108 
109 /**
110  * @tc.name: InitializeDateTimeFormat
111  * @tc.desc: Initialize the time and date format through localization label locales and options.
112  *           Options can include year, month, day, hour, minute, second, time zone and weekday, etc.
113  * @tc.type: FUNC
114  * @tc.require:
115  */
HWTEST_F_L0(JSDateTimeFormatTest,InitializeDateTimeFormat)116 HWTEST_F_L0(JSDateTimeFormatTest, InitializeDateTimeFormat)
117 {
118     auto vm = thread->GetEcmaVM();
119     auto factory = vm->GetFactory();
120     auto env = vm->GetGlobalEnv();
121     // Create locales.
122     JSHandle<JSTaggedValue> localeCtor = env->GetLocaleFunction();
123     JSHandle<JSLocale> locales =
124         JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(localeCtor), localeCtor));
125     icu::Locale icuLocale("zh", "Hans", "Cn", "calendar=chinese");
126     factory->NewJSIntlIcuData(locales, icuLocale, JSLocale::FreeIcuLocale);
127     // Create options.
128     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
129     JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
130     options = JSDateTimeFormat::ToDateTimeOptions(
131         thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
132     // Initialize DateTimeFormat.
133     JSHandle<JSTaggedValue> dtfCtor = env->GetDateTimeFormatFunction();
134     JSHandle<JSDateTimeFormat> dtf =
135         JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dtfCtor), dtfCtor));
136     dtf = JSDateTimeFormat::InitializeDateTimeFormat(
137         thread, dtf, JSHandle<JSTaggedValue>::Cast(locales), JSHandle<JSTaggedValue>::Cast(options));
138 
139     JSHandle<JSTaggedValue> localeTagVal(thread, dtf->GetLocale());
140     JSHandle<EcmaString> localeEcmaStr = JSHandle<EcmaString>::Cast(localeTagVal);
141     std::string localeStr = LocaleHelper::ConvertToStdString(localeEcmaStr);
142     EXPECT_STREQ(localeStr.c_str(), "zh-Hans-CN-u-ca-chinese");
143 }
144 
145 /**
146  * @tc.name: ToDateTimeOptions
147  * @tc.desc: Empty or incomplete option objects are supplemented according to the required option and default option.
148  * @tc.type: FUNC
149  * @tc.require:
150  */
HWTEST_F_L0(JSDateTimeFormatTest,ToDateTimeOptions_001)151 HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_001)
152 {
153     auto vm = thread->GetEcmaVM();
154     auto factory = vm->GetFactory();
155     auto env = vm->GetGlobalEnv();
156     auto globalConst = thread->GlobalConstants();
157 
158     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
159     JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
160     JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
161     JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
162     JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
163     JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
164     JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
165 
166     // When the option value is blank, it will be set according to the default option,
167     // including the year, month, day, hour, minute and second, and the values are all numeric.
168     JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
169     options = JSDateTimeFormat::ToDateTimeOptions(
170         thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ALL"
171     auto yearEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
172     EXPECT_STREQ(LocaleHelper::ConvertToStdString(yearEcmaStr).c_str(), "numeric");
173     auto monthEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
174     EXPECT_STREQ(LocaleHelper::ConvertToStdString(monthEcmaStr).c_str(), "numeric");
175     auto dayEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
176     EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayEcmaStr).c_str(), "numeric");
177     auto hourEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
178     EXPECT_STREQ(LocaleHelper::ConvertToStdString(hourEcmaStr).c_str(), "numeric");
179     auto minuteEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
180     EXPECT_STREQ(LocaleHelper::ConvertToStdString(minuteEcmaStr).c_str(), "numeric");
181     auto secondEcmaStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
182     EXPECT_STREQ(LocaleHelper::ConvertToStdString(secondEcmaStr).c_str(), "numeric");
183 }
184 
HWTEST_F_L0(JSDateTimeFormatTest,ToDateTimeOptions_002)185 HWTEST_F_L0(JSDateTimeFormatTest, ToDateTimeOptions_002)
186 {
187     auto vm = thread->GetEcmaVM();
188     auto factory = vm->GetFactory();
189     auto env = vm->GetGlobalEnv();
190     auto globalConst = thread->GlobalConstants();
191 
192     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
193     JSHandle<JSTaggedValue> weekdayKey = globalConst->GetHandledWeekdayString();
194     JSHandle<JSTaggedValue> yearKey = globalConst->GetHandledYearString();
195     JSHandle<JSTaggedValue> monthKey = globalConst->GetHandledMonthString();
196     JSHandle<JSTaggedValue> dayKey = globalConst->GetHandledDayString();
197     JSHandle<JSTaggedValue> dayPeriodKey = globalConst->GetHandledDayPeriodString();
198     JSHandle<JSTaggedValue> hourKey = globalConst->GetHandledHourString();
199     JSHandle<JSTaggedValue> minuteKey = globalConst->GetHandledMinuteString();
200     JSHandle<JSTaggedValue> secondKey = globalConst->GetHandledSecondString();
201     JSHandle<JSTaggedValue> fracSecKey = globalConst->GetHandledFractionalSecondDigitsString();
202 
203     // When the option value is not empty, it will be set according to the required options.
204     JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
205     std::map<std::string, std::string> dateOptionsMap {
206         { "weekday", "narrow" },
207         { "year", "2-digit" },
208         { "month", "2-digit" },
209         { "day", "2-digit" }
210     };
211     std::map<std::string, std::string> timeOptionsMap {
212         { "dayPeriod", "narrow" },
213         { "hour", "2-digit" },
214         { "minute", "2-digit" },
215         { "second", "2-digit" },
216         { "fractionalSecond", "1" }
217     };
218     EcmaTestCommon::SetDateOptionsTest(thread, options, dateOptionsMap);
219     EcmaTestCommon::SetTimeOptionsTest(thread, options, timeOptionsMap);
220     options = JSDateTimeFormat::ToDateTimeOptions(
221         thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL); // test "ANY"
222     auto weekdayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, weekdayKey).GetValue());
223     EXPECT_STREQ(LocaleHelper::ConvertToStdString(weekdayStr).c_str(), "narrow");
224     auto yearStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, yearKey).GetValue());
225     EXPECT_STREQ(LocaleHelper::ConvertToStdString(yearStr).c_str(), "2-digit");
226     auto monthStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, monthKey).GetValue());
227     EXPECT_STREQ(LocaleHelper::ConvertToStdString(monthStr).c_str(), "2-digit");
228     auto dayStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayKey).GetValue());
229     EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayStr).c_str(), "2-digit");
230 
231     auto dayPeriodStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, dayPeriodKey).GetValue());
232     EXPECT_STREQ(LocaleHelper::ConvertToStdString(dayPeriodStr).c_str(), "narrow");
233     auto hourStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, hourKey).GetValue());
234     EXPECT_STREQ(LocaleHelper::ConvertToStdString(hourStr).c_str(), "2-digit");
235     auto minuteStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, minuteKey).GetValue());
236     EXPECT_STREQ(LocaleHelper::ConvertToStdString(minuteStr).c_str(), "2-digit");
237     auto secondStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, secondKey).GetValue());
238     EXPECT_STREQ(LocaleHelper::ConvertToStdString(secondStr).c_str(), "2-digit");
239     auto fracSecStr = JSHandle<EcmaString>::Cast(JSObject::GetProperty(thread, options, fracSecKey).GetValue());
240     EXPECT_STREQ(LocaleHelper::ConvertToStdString(fracSecStr).c_str(), "1");
241 }
242 
243 
244 /**
245  * @tc.name: FormatDateTime
246  * @tc.desc: Convert floating-point timestamp to fixed format time date through time date format.
247  * @tc.type: FUNC
248  * @tc.require:
249  */
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_001)250 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_001)
251 {
252     icu::Locale icuLocale("zh", "Hans", "Cn");
253     std::string cycle("h12");
254     std::string zone("ETC/GMT-8");
255     auto options = EcmaTestCommon::SetHourCycleKeyValue(thread, cycle, zone);
256     JSHandle<JSDateTimeFormat> dtf = EcmaTestCommon::CreateDateTimeFormatTest(thread, icuLocale, options);
257 
258     double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
259     double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
260 
261     // When the option is blank, the default format is "yyyy/MM/dd", the year, month and day are all numeric,
262     // because the default option in initialization is "DefaultsOption::DATE".
263     JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
264     EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr1).c_str(), "2022/5/25");
265     JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
266     EXPECT_STREQ(LocaleHelper::ConvertToStdString(dateTimeEcamStr2).c_str(), "2022/5/30");
267 }
268 } // namespace panda::test
269