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 BaseTestWithScope<true> {
27 };
28
29 // new RelativeTimeFormat(newTarget is undefined)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, RelativeTimeFormatConstructor)30 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, RelativeTimeFormatConstructor)
31 {
32 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
33 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
34 JSHandle<JSFunction> newTarget(env->GetRelativeTimeFormatFunction());
35
36 JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en"));
37 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
38 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
39 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
40 ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
41 // option tag is default value
42 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
43
44 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
45 JSTaggedValue result = BuiltinsRelativeTimeFormat::RelativeTimeFormatConstructor(ecmaRuntimeCallInfo);
46 TestHelper::TearDownFrame(thread, prev);
47
48 EXPECT_TRUE(result.IsJSRelativeTimeFormat());
49 }
50
JSRelativeTimeFormatCreateWithLocaleTest(JSThread *thread, JSHandle<JSTaggedValue> &locale, JSHandle<JSTaggedValue> &numericValue)51 static JSTaggedValue JSRelativeTimeFormatCreateWithLocaleTest(JSThread *thread, JSHandle<JSTaggedValue> &locale,
52 JSHandle<JSTaggedValue> &numericValue)
53 {
54 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
55 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
56 JSHandle<JSFunction> newTarget(env->GetRelativeTimeFormatFunction());
57 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
58 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
59
60 JSHandle<JSTaggedValue> typeKey = thread->GlobalConstants()->GetHandledNumericString();
61 JSObject::SetProperty(thread, optionsObj, typeKey, numericValue);
62
63 JSHandle<JSTaggedValue> localesString = locale;
64 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
65 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
66 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
67 ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
68 ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
69
70 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
71 JSTaggedValue result = BuiltinsRelativeTimeFormat::RelativeTimeFormatConstructor(ecmaRuntimeCallInfo);
72 EXPECT_TRUE(result.IsJSRelativeTimeFormat());
73 TestHelper::TearDownFrame(thread, prev);
74 return result;
75 }
76
FormatCommon(JSThread *thread, JSHandle<JSRelativeTimeFormat> &jsPluralRules, JSHandle<JSTaggedValue> &numberValue, JSHandle<JSTaggedValue> &unitValue)77 JSTaggedValue FormatCommon(JSThread *thread, JSHandle<JSRelativeTimeFormat> &jsPluralRules,
78 JSHandle<JSTaggedValue> &numberValue, JSHandle<JSTaggedValue> &unitValue)
79 {
80 auto ecmaRuntimeCallInfo =
81 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8: arg max len
82 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
83 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
84 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
85 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
86
87 auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
88 JSTaggedValue result = BuiltinsRelativeTimeFormat::Format(ecmaRuntimeCallInfo);
89 TestHelper::TearDownFrame(thread, prev);
90 return result;
91 }
92
93 // format(1, auto)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_001)94 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_001)
95 {
96 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
97 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
98 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto")); // the default value
99 JSHandle<JSRelativeTimeFormat> jsPluralRules =
100 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
101 thread, locale, numericValue));
102 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
103 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(1));
104 auto result = FormatCommon(thread, jsPluralRules, numberValue, unitValue);
105
106 JSHandle<EcmaString> handleEcmaStr(thread, result);
107 EXPECT_STREQ("tomorrow", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
108 }
109
110 // format(0, auto)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_002)111 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_002)
112 {
113 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
114 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
115 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto"));
116 JSHandle<JSRelativeTimeFormat> jsPluralRules =
117 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
118 thread, locale, numericValue));
119 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
120 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(0));
121 auto result = FormatCommon(thread, jsPluralRules, numberValue, unitValue);
122
123 JSHandle<EcmaString> handleEcmaStr(thread, result);
124 EXPECT_STREQ("today", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
125 }
126
127 // format(-1, auto)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_003)128 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_003)
129 {
130 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
131 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
132 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto")); // the default value
133 JSHandle<JSRelativeTimeFormat> jsPluralRules =
134 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
135 thread, locale, numericValue));
136 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
137 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(-1));
138
139 auto result = FormatCommon(thread, jsPluralRules, numberValue, unitValue);
140
141 JSHandle<EcmaString> handleEcmaStr(thread, result);
142 EXPECT_STREQ("yesterday", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
143 }
144
145 // format(-1, always)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_004)146 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_004)
147 {
148 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
149 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
150 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("always")); // the default value
151 JSHandle<JSRelativeTimeFormat> jsPluralRules =
152 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
153 thread, locale, numericValue));
154 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
155 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(-1));
156
157 auto result = FormatCommon(thread, jsPluralRules, numberValue, unitValue);
158
159 JSHandle<EcmaString> handleEcmaStr(thread, result);
160 EXPECT_STREQ("1 day ago", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
161 }
162
163 // format(1, always)
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_005)164 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, Format_005)
165 {
166 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
167 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
168 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("always")); // the default value
169 JSHandle<JSRelativeTimeFormat> jsPluralRules =
170 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
171 thread, locale, numericValue));
172 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("day"));
173 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(1));
174 auto result = FormatCommon(thread, jsPluralRules, numberValue, unitValue);
175
176 JSHandle<EcmaString> handleEcmaStr(thread, result);
177 EXPECT_STREQ("in 1 day", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
178 }
179
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, FormatToParts)180 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, FormatToParts)
181 {
182 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
183 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
184 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
185 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("always"));
186 JSHandle<JSRelativeTimeFormat> jsPluralRules =
187 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
188 thread, locale, numericValue));
189 JSHandle<JSTaggedValue> unitValue(factory->NewFromASCII("seconds"));
190 JSHandle<JSTaggedValue> numberValue(thread, JSTaggedValue(10));
191
192 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
193 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
194 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
195 ecmaRuntimeCallInfo->SetCallArg(0, numberValue.GetTaggedValue());
196 ecmaRuntimeCallInfo->SetCallArg(1, unitValue.GetTaggedValue());
197
198 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
199 JSTaggedValue result = BuiltinsRelativeTimeFormat::FormatToParts(ecmaRuntimeCallInfo);
200 TestHelper::TearDownFrame(thread, prev);
201
202 JSHandle<JSArray> resultArr(thread, result);
203 EXPECT_EQ(JSObject::GetProperty(thread, JSHandle<JSObject>(resultArr), lengthKey).GetValue()->GetInt(), 3);
204 }
205
HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, ResolvedOptions)206 HWTEST_F_L0(BuiltinsRelativeTimeFormatTest, ResolvedOptions)
207 {
208 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
209 auto globalConst = thread->GlobalConstants();
210 JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE"));
211 JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("auto"));
212 JSHandle<JSRelativeTimeFormat> jsPluralRules =
213 JSHandle<JSRelativeTimeFormat>(thread, JSRelativeTimeFormatCreateWithLocaleTest(
214 thread, locale, numericValue));
215
216 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
217 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
218 ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
219
220 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
221 JSTaggedValue result = BuiltinsRelativeTimeFormat::ResolvedOptions(ecmaRuntimeCallInfo);
222 TestHelper::TearDownFrame(thread, prev);
223
224 JSHandle<JSTaggedValue> resultObj =
225 JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result.GetRawData())));
226 // judge whether the properties of the object are the same as those of jsrelativetimeformat tag
227 JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
228 EXPECT_EQ(JSTaggedValue::SameValue(
229 JSObject::GetProperty(thread, resultObj, localeKey).GetValue(), locale), true);
230 JSHandle<JSTaggedValue> styleKey = globalConst->GetHandledStyleString();
231 JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("long"));
232 EXPECT_EQ(JSTaggedValue::SameValue(
233 JSObject::GetProperty(thread, resultObj, styleKey).GetValue(), styleValue), true);
234 JSHandle<JSTaggedValue> numberingSystemKey = globalConst->GetHandledNumberingSystemString();
235 JSHandle<JSTaggedValue> numberingSystemValue(factory->NewFromASCII("latn"));
236 EXPECT_EQ(JSTaggedValue::SameValue(
237 JSObject::GetProperty(thread, resultObj, numberingSystemKey).GetValue(), numberingSystemValue), true);
238 }
239 } // namespace panda::test
240