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_relative_time_format.h"
17
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_relative_time_format.h"
20 #include "ecmascript/tests/test_helper.h"
21
22 using namespace panda::ecmascript;
23 using namespace panda::ecmascript::builtins;
24
25 namespace panda::test {
26 class BuiltinsRelativeTimeFormatTest : public testing::Test {
27 public:
SetUpTestCase()28 static void SetUpTestCase()
29 {
30 GTEST_LOG_(INFO) << "SetUpTestCase";
31 }
32
TearDownTestCase()33 static void TearDownTestCase()
34 {
35 GTEST_LOG_(INFO) << "TearDownCase";
36 }
37
SetUp()38 void SetUp() override
39 {
40 JSRuntimeOptions options;
41 #if PANDA_TARGET_LINUX
42 // for consistency requirement, use ohos_icu4j/data as icu-data-path
43 options.SetIcuDataPath(ICU_PATH);
44 #endif
45 options.SetEnableForceGC(true);
46 instance = JSNApi::CreateEcmaVM(options);
47 instance->SetEnableForceGC(true);
48 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
49 thread = instance->GetJSThread();
50 scope = new EcmaHandleScope(thread);
51 }
52
TearDown()53 void TearDown() override
54 {
55 TestHelper::DestroyEcmaVMWithScope(instance, scope);
56 }
57
58 EcmaVM *instance {nullptr};
59 EcmaHandleScope *scope {nullptr};
60 JSThread *thread {nullptr};
61 };
62
63 // new RelativeTimeFormat(newTarget is undefined)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,RelativeTimeFormatConstructor)64 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, RelativeTimeFormatConstructor)
65 {
66 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
68 JSHandle<JSFunction> newTarget(env->GetRelativeTimeFormatFunction());
69
70 JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en"));
71 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
72 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
73 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
74 ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
75 // option tag is default value
76 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
77
78 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
79 JSTaggedValue result = BuiltinsRelativeTimeFormat::RelativeTimeFormatConstructor(ecmaRuntimeCallInfo);
80 TestHelper::TearDownFrame(thread, prev);
81
82 EXPECT_TRUE(result.IsJSRelativeTimeFormat());
83 }
84
JSRelativeTimeFormatCreateWithLocaleTest(JSThread * thread,JSHandle<JSTaggedValue> & locale,JSHandle<JSTaggedValue> & numericValue)85 static JSTaggedValue JSRelativeTimeFormatCreateWithLocaleTest(JSThread *thread, JSHandle<JSTaggedValue> &locale,
86 JSHandle<JSTaggedValue> &numericValue)
87 {
88 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
89 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
90 JSHandle<JSFunction> newTarget(env->GetRelativeTimeFormatFunction());
91 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
92 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
93
94 JSHandle<JSTaggedValue> typeKey = thread->GlobalConstants()->GetHandledNumericString();
95 JSObject::SetProperty(thread, optionsObj, typeKey, numericValue);
96
97 JSHandle<JSTaggedValue> localesString = locale;
98 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
99 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
100 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
101 ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
102 ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
103
104 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
105 JSTaggedValue result = BuiltinsRelativeTimeFormat::RelativeTimeFormatConstructor(ecmaRuntimeCallInfo);
106 EXPECT_TRUE(result.IsJSRelativeTimeFormat());
107 TestHelper::TearDownFrame(thread, prev);
108 return result;
109 }
110
111 // format(1, auto)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,Format_001)112 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_001)
113 {
114 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
115 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
116 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto")); // the default value
117 JSHandle<JSRelativeTimeFormat> jsPluralRules =
118 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
119 thread, locale, numericValue));
120 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
121 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(1));
122 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
123 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
124 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
125 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
126 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
127
128 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
129 JSTaggedValue result = BuiltinsRelativeTimeFormat::Format(ecmaRuntimeCallInfo);
130 TestHelper::TearDownFrame(thread, prev);
131
132 JSHandle<EcmaString> handleEcmaStr(thread, result);
133 EXPECT_STREQ("tomorrow", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
134 }
135
136 // format(0, auto)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,Format_002)137 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_002)
138 {
139 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
140 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
141 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto"));
142 JSHandle<JSRelativeTimeFormat> jsPluralRules =
143 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
144 thread, locale, numericValue));
145 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
146 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(0));
147 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
148 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
149 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
150 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
151 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
152
153 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
154 JSTaggedValue result = BuiltinsRelativeTimeFormat::Format(ecmaRuntimeCallInfo);
155 TestHelper::TearDownFrame(thread, prev);
156
157 JSHandle<EcmaString> handleEcmaStr(thread, result);
158 EXPECT_STREQ("today", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
159 }
160
161 // format(-1, auto)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,Format_003)162 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_003)
163 {
164 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
165 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
166 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto")); // the default value
167 JSHandle<JSRelativeTimeFormat> jsPluralRules =
168 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
169 thread, locale, numericValue));
170 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
171 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(-1));
172 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
173 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
174 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
175 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
176 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
177
178 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
179 JSTaggedValue result = BuiltinsRelativeTimeFormat::Format(ecmaRuntimeCallInfo);
180 TestHelper::TearDownFrame(thread, prev);
181
182 JSHandle<EcmaString> handleEcmaStr(thread, result);
183 EXPECT_STREQ("yesterday", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
184 }
185
186 // format(-1, always)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,Format_004)187 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_004)
188 {
189 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
190 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
191 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("always")); // the default value
192 JSHandle<JSRelativeTimeFormat> jsPluralRules =
193 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
194 thread, locale, numericValue));
195 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
196 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(-1));
197 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
198 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
199 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
200 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
201 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
202
203 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
204 JSTaggedValue result = BuiltinsRelativeTimeFormat::Format(ecmaRuntimeCallInfo);
205 TestHelper::TearDownFrame(thread, prev);
206
207 JSHandle<EcmaString> handleEcmaStr(thread, result);
208 EXPECT_STREQ("1 day ago", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
209 }
210
211 // format(1, always)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,Format_005)212 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_005)
213 {
214 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
215 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
216 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("always")); // the default value
217 JSHandle<JSRelativeTimeFormat> jsPluralRules =
218 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
219 thread, locale, numericValue));
220 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
221 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(1));
222 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
223 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
224 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
225 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
226 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
227
228 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
229 JSTaggedValue result = BuiltinsRelativeTimeFormat::Format(ecmaRuntimeCallInfo);
230 TestHelper::TearDownFrame(thread, prev);
231
232 JSHandle<EcmaString> handleEcmaStr(thread, result);
233 EXPECT_STREQ("in 1 day", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
234 }
235
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,FormatToParts)236 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, FormatToParts)
237 {
238 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
239 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
240 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
241 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("always"));
242 JSHandle<JSRelativeTimeFormat> jsPluralRules =
243 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
244 thread, locale, numericValue));
245 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("seconds"));
246 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(10));
247
248 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
249 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
250 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
251 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
252 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
253
254 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
255 JSTaggedValue result = BuiltinsRelativeTimeFormat::FormatToParts(ecmaRuntimeCallInfo);
256 TestHelper::TearDownFrame(thread, prev);
257
258 JSHandle<JSArray> resultArr(thread, result);
259 EXPECT_EQ(JSObject::GetProperty(thread, JSHandle<JSObject>(resultArr), lengthKey).GetValue()->GetInt(), 3);
260 }
261
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest,ResolvedOptions)262 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, ResolvedOptions)
263 {
264 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
265 auto globalConst = thread->GlobalConstants();
266 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE"));
267 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto"));
268 JSHandle<JSRelativeTimeFormat> jsPluralRules =
269 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
270 thread, locale, numericValue));
271
272 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
273 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
274 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
275
276 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
277 JSTaggedValue result = BuiltinsRelativeTimeFormat::ResolvedOptions(ecmaRuntimeCallInfo);
278 TestHelper::TearDownFrame(thread, prev);
279
280 JSHandle<JSTaggedValue> resultObj =
281 JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result.GetRawData())));
282 // judge whether the properties of the object are the same as those of jsrelativetimeformat tag
283 JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
284 EXPECT_EQ(JSTaggedValue::SameValue(
285 JSObject::GetProperty(thread, resultObj, localeKey).GetValue(), locale), true);
286 JSHandle<JSTaggedValue> styleKey = globalConst->GetHandledStyleString();
287 JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("long"));
288 EXPECT_EQ(JSTaggedValue::SameValue(
289 JSObject::GetProperty(thread, resultObj, styleKey).GetValue(), styleValue), true);
290 JSHandle<JSTaggedValue> numberingSystemKey = globalConst->GetHandledNumberingSystemString();
291 JSHandle<JSTaggedValue> numberingSystemValue(factory->NewFromASCII("latn"));
292 EXPECT_EQ(JSTaggedValue::SameValue(
293 JSObject::GetProperty(thread, resultObj, numberingSystemKey).GetValue(), numberingSystemValue), true);
294 }
295 } // namespace panda::test
296