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
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_002)33 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_002)
34 {
35 auto vm = thread->GetEcmaVM();
36 auto factory = vm->GetFactory();
37 auto env = vm->GetGlobalEnv();
38 auto globalConst = thread->GlobalConstants();
39
40 icu::Locale icuLocale("zh", "Hans", "Cn");
41 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
42 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
43 JSHandle<JSTaggedValue> hourCycleKey = globalConst->GetHandledHourCycleString();
44 JSHandle<JSTaggedValue> hourCycleValue(factory->NewFromASCII("h12"));
45 JSHandle<JSTaggedValue> timeZoneKey = globalConst->GetHandledTimeZoneString();
46 JSHandle<JSTaggedValue> timeZoneValue(factory->NewFromASCII("ETC/GMT-8"));
47 JSObject::SetProperty(thread, options, timeZoneKey, timeZoneValue);
48 JSObject::SetProperty(thread, options, hourCycleKey, hourCycleValue);
49 options = JSDateTimeFormat::ToDateTimeOptions(
50 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
51 JSHandle<JSDateTimeFormat> dtf = EcmaTestCommon::CreateDateTimeFormatTest(thread, icuLocale, options);
52
53 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
54 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
55
56 // Format to include all options by "DefaultsOption::ALL".
57 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
58 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr1).c_str(), "2022/5/25 上午11:09:34");
59 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
60 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr2).c_str(), "2022/5/30 下午10:30:12");
61 }
62
FormatCommonSet(JSThread * thread,JSHandle<JSObject> & options,icu::Locale & icuLocale,std::map<std::string,std::string> & dateOptionsMap)63 static JSHandle<JSDateTimeFormat> FormatCommonSet(JSThread *thread, JSHandle<JSObject>& options, icu::Locale& icuLocale,
64 std::map<std::string, std::string>& dateOptionsMap)
65 {
66 std::map<std::string, std::string> timeOptionsMap {
67 { "dayPeriod", "long" },
68 { "hour", "2-digit" },
69 { "minute", "2-digit" },
70 { "second", "2-digit" },
71 { "fractionalSecond", "3" }
72 };
73 EcmaTestCommon::SetDateOptionsTest(thread, options, dateOptionsMap);
74 EcmaTestCommon::SetTimeOptionsTest(thread, options, timeOptionsMap);
75 options = JSDateTimeFormat::ToDateTimeOptions(
76 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
77 JSHandle<JSDateTimeFormat> dtf = EcmaTestCommon::CreateDateTimeFormatTest(thread, icuLocale, options);
78 return dtf;
79 }
80
FormatDateTimeCommon(JSThread * thread,icu::Locale & icuLocale)81 static JSHandle<JSDateTimeFormat> FormatDateTimeCommon(JSThread *thread, icu::Locale& icuLocale)
82 {
83 std::string cycle("h12");
84 std::string zone("ETC/GMT-8");
85 auto options = EcmaTestCommon::SetHourCycleKeyValue(thread, cycle, zone);
86
87 // Set custom date time format.
88 std::map<std::string, std::string> dateOptionsMap {
89 { "weekday", "long" },
90 { "year", "2-digit" },
91 { "month", "2-digit" },
92 { "day", "2-digit" }
93 };
94 auto dtf = FormatCommonSet(thread, options, icuLocale, dateOptionsMap);
95 return dtf;
96 }
97
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_003)98 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_003)
99 {
100 icu::Locale icuLocale("zh", "Hans", "Cn");
101
102 auto dtf = FormatDateTimeCommon(thread, icuLocale);
103 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
104 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
105
106 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
107 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr1).c_str(),
108 "22年05月25日星期三 上午11:09:34.000");
109 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
110 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr2).c_str(), "22年05月30日星期一 晚上10:30:12.999");
111 }
112
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTime_004)113 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTime_004)
114 {
115 icu::Locale icuLocale("en", "Latn", "US");
116 auto dtf = FormatDateTimeCommon(thread, icuLocale);
117
118 double timeStamp1 = 1653448174000; // test "2022-05-25 11:09:34.000"
119 double timeStamp2 = 1653921012999; // test "2022-05-30 22:30:12.999"
120
121 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp1);
122 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr1).c_str(),
123 "Wednesday, 05/25/22, 11:09:34.000 in the morning");
124 JSHandle<EcmaString> dateTimeEcamStr2 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp2);
125 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr2).c_str(),
126 "Monday, 05/30/22, 10:30:12.999 at night");
127 }
128
GetDateTimePartStringTest(JSThread * thread,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> part)129 std::string GetDateTimePartStringTest(JSThread *thread, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> part)
130 {
131 JSHandle<JSObject> partObj = JSHandle<JSObject>::Cast(part);
132 JSHandle<JSTaggedValue> partValue = JSObject::GetProperty(thread, partObj, key).GetValue();
133 JSHandle<EcmaString> partEcmaStr = JSHandle<EcmaString>::Cast(partValue);
134 std::string partStr = LocaleHelper::ConvertToStdString(thread, partEcmaStr);
135 return partStr;
136 }
137
138 /**
139 * @tc.name: FormatDateTimeToParts
140 * @tc.desc: Convert floating-point timestamp to fixed format time date through time date format.
141 * The "FormatDateTimeToParts" method converts the output result into an array containing various time and
142 * date attributes.
143 * @tc.type: FUNC
144 * @tc.require:
145 */
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTimeToParts_001)146 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTimeToParts_001)
147 {
148 auto globalConst = thread->GlobalConstants();
149
150 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
151 JSHandle<JSTaggedValue> valueKey = globalConst->GetHandledValueString();
152
153 icu::Locale icuLocale("zh", "Hans", "Cn");
154 std::string cycle("h12");
155 std::string zone("ETC/GMT-8");
156 auto options = EcmaTestCommon::SetHourCycleKeyValue(thread, cycle, zone);
157 JSHandle<JSDateTimeFormat> dtf = EcmaTestCommon::CreateDateTimeFormatTest(thread, icuLocale, options);
158
159 double timeStamp = 1653448174123; // test "2022-05-25 11:09:34.123"
160 // Use default date time format and format date and time to parts.
161 JSHandle<EcmaString> dateTimeEcamStr1 = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp);
162 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr1).c_str(), "2022/5/25");
163 JSHandle<JSArray> dateTimeArray1 = JSDateTimeFormat::FormatDateTimeToParts(thread, dtf, timeStamp);
164 auto year = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 0).GetValue();
165 auto literal1 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 1).GetValue();
166 auto month = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 2).GetValue();
167 auto literal2 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 3).GetValue();
168 auto day = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray1), 4).GetValue();
169 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, year).c_str(), "year");
170 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, year).c_str(), "2022");
171 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal1).c_str(), "literal");
172 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal1).c_str(), "/");
173 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, month).c_str(), "month");
174 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, month).c_str(), "5");
175 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal2).c_str(), "literal");
176 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal2).c_str(), "/");
177 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, day).c_str(), "day");
178 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, day).c_str(), "25");
179 }
180
CheckOther(JSThread * thread,JSHandle<JSArray> & dateTimeArray,JSHandle<JSTaggedValue> & typeKey,JSHandle<JSTaggedValue> & valueKey)181 void CheckOther(JSThread *thread, JSHandle<JSArray>& dateTimeArray, JSHandle<JSTaggedValue>& typeKey,
182 JSHandle<JSTaggedValue>& valueKey)
183 {
184 auto month = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 2).GetValue();
185 auto literal2 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 3).GetValue();
186 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, month).c_str(), "month");
187 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, month).c_str(), "05");
188 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal2).c_str(), "literal");
189 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal2).c_str(), "月");
190
191 auto day = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 4).GetValue();
192 auto literal3 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 5).GetValue();
193 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, day).c_str(), "day");
194 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, day).c_str(), "25");
195 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal3).c_str(), "literal");
196 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal3).c_str(), "日");
197
198 auto weekday = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 6).GetValue();
199 auto literal4 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 7).GetValue();
200 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, weekday).c_str(), "weekday");
201 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, weekday).c_str(), "星期三");
202 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal4).c_str(), "literal");
203 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal4).c_str(), " ");
204
205 auto dayPeriod = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 8).GetValue();
206 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, dayPeriod).c_str(), "dayPeriod");
207 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, dayPeriod).c_str(), "上午");
208
209 auto hour = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 9).GetValue();
210 auto literal5 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 10).GetValue();
211 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, hour).c_str(), "hour");
212 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, hour).c_str(), "11");
213 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal5).c_str(), "literal");
214 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal5).c_str(), ":");
215 auto minute = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 11).GetValue();
216 auto literal6 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 12).GetValue();
217 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, minute).c_str(), "minute");
218 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, minute).c_str(), "09");
219 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal6).c_str(), "literal");
220 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal6).c_str(), ":");
221 auto second = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 13).GetValue();
222 auto literal7 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 14).GetValue();
223 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, second).c_str(), "second");
224 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, second).c_str(), "34");
225 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal7).c_str(), "literal");
226 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal7).c_str(), ".");
227 auto fracSec = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 15).GetValue();
228 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, fracSec).c_str(), "fractionalSecond");
229 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, fracSec).c_str(), "123");
230 }
231
HWTEST_F_L0(JSDateTimeFormatTest,FormatDateTimeToParts_002)232 HWTEST_F_L0(JSDateTimeFormatTest, FormatDateTimeToParts_002)
233 {
234 auto globalConst = thread->GlobalConstants();
235
236 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
237 JSHandle<JSTaggedValue> valueKey = globalConst->GetHandledValueString();
238 icu::Locale icuLocale("zh", "Hans", "Cn");
239 std::string cycle("h12");
240 std::string zone("ETC/GMT-8");
241 auto options = EcmaTestCommon::SetHourCycleKeyValue(thread, cycle, zone);
242
243 double timeStamp = 1653448174123; // test "2022-05-25 11:09:34.123"
244 // Set custom date time format and format date and time to parts.
245 std::map<std::string, std::string> dateOptionsMap {
246 { "weekday", "long" },
247 { "year", "2-digit" },
248 { "month", "2-digit" },
249 { "day", "2-digit" }
250 };
251 std::map<std::string, std::string> timeOptionsMap {
252 { "dayPeriod", "long" },
253 { "hour", "2-digit" },
254 { "minute", "2-digit" },
255 { "second", "2-digit" },
256 { "fractionalSecond", "3" }
257 };
258 EcmaTestCommon::SetDateOptionsTest(thread, options, dateOptionsMap);
259 EcmaTestCommon::SetTimeOptionsTest(thread, options, timeOptionsMap);
260 options = JSDateTimeFormat::ToDateTimeOptions(
261 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
262 JSHandle<JSDateTimeFormat> dtf = EcmaTestCommon::CreateDateTimeFormatTest(thread, icuLocale, options);
263 JSHandle<EcmaString> dateTimeEcamStr = JSDateTimeFormat::FormatDateTime(thread, dtf, timeStamp);
264 EXPECT_STREQ(LocaleHelper::ConvertToStdString(thread, dateTimeEcamStr).c_str(),
265 "22年05月25日星期三 上午11:09:34.123");
266
267 JSHandle<JSArray> dateTimeArray = JSDateTimeFormat::FormatDateTimeToParts(thread, dtf, timeStamp);
268 auto year = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 0).GetValue();
269 auto literal1 = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(dateTimeArray), 1).GetValue();
270 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, year).c_str(), "year");
271 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, year).c_str(), "22");
272 EXPECT_STREQ(GetDateTimePartStringTest(thread, typeKey, literal1).c_str(), "literal");
273 EXPECT_STREQ(GetDateTimePartStringTest(thread, valueKey, literal1).c_str(), "年");
274 CheckOther(thread, dateTimeArray, typeKey, valueKey);
275 }
276 /**
277 * @tc.name: GainAvailableLocales
278 * @tc.desc: Get the available localized label array. If the global time date localized label is not set, return an
279 * array containing all available labels. Otherwise, return an array containing self-defined labels.
280 * @tc.type: FUNC
281 * @tc.require:
282 */
HWTEST_F_L0(JSDateTimeFormatTest,GainAvailableLocales)283 HWTEST_F_L0(JSDateTimeFormatTest, GainAvailableLocales)
284 {
285 auto vm = thread->GetEcmaVM();
286 auto factory = vm->GetFactory();
287 auto env = vm->GetGlobalEnv();
288
289 // The date and time format locales is not initialized,
290 // then get all available locales and save them in a 'TaggedArray'.
291 JSHandle<JSTaggedValue> dateTimeFormatLocales = env->GetDateTimeFormatLocales();
292 EXPECT_EQ(dateTimeFormatLocales.GetTaggedValue(), JSTaggedValue::Undefined());
293
294 const char *key = "calendar";
295 const char *path = nullptr;
296 std::vector<std::string> availableStringLocales = intl::LocaleHelper::GetAvailableLocales(thread, key, path);
297 JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
298 env->SetDateTimeFormatLocales(thread, availableLocales);
299 JSHandle<TaggedArray> gainLocales1 = JSDateTimeFormat::GainAvailableLocales(thread);
300 EXPECT_EQ(JSHandle<JSTaggedValue>::Cast(gainLocales1).GetTaggedValue().GetRawData(),
301 JSHandle<JSTaggedValue>::Cast(availableLocales).GetTaggedValue().GetRawData());
302
303 // The date and time format locales has already been initialized,
304 // then get custom locale and save it in a 'TaggedArray'.
305 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
306 JSHandle<JSTaggedValue> localeCtor = env->GetLocaleFunction();
307 JSHandle<JSTaggedValue> dtfCtor = env->GetDateTimeFormatFunction();
308
309 JSHandle<JSLocale> locales =
310 JSHandle<JSLocale>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(localeCtor), localeCtor));
311 icu::Locale icuLocale("zh", "Hans", "Cn", "calendar=chinese");
312 factory->NewJSIntlIcuData(locales, icuLocale, JSLocale::FreeIcuLocale);
313 JSHandle<JSObject> options = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
314 options = JSDateTimeFormat::ToDateTimeOptions(
315 thread, JSHandle<JSTaggedValue>::Cast(options), RequiredOption::ANY, DefaultsOption::ALL);
316 JSHandle<JSDateTimeFormat> dtf =
317 JSHandle<JSDateTimeFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(dtfCtor), dtfCtor));
318 dtf = JSDateTimeFormat::InitializeDateTimeFormat(
319 thread, dtf, JSHandle<JSTaggedValue>::Cast(locales), JSHandle<JSTaggedValue>::Cast(options));
320
321 JSHandle<JSTaggedValue> localeTagVal(thread, dtf->GetLocale(thread));
322 JSHandle<TaggedArray> localesTagArr = factory->NewTaggedArray(1);
323 localesTagArr->Set(thread, 0, localeTagVal);
324 env->SetDateTimeFormatLocales(thread, localesTagArr);
325 JSHandle<TaggedArray> gainLocales2 = JSDateTimeFormat::GainAvailableLocales(thread);
326 EXPECT_EQ(gainLocales2->GetLength(), 1U);
327 EXPECT_STREQ(EcmaStringAccessor(gainLocales2->Get(thread, 0)).ToCString(thread).c_str(),
328 "zh-Hans-CN-u-ca-chinese");
329 }
330 } // namespace panda::test