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/containers/containers_private.h"
17 #include "ecmascript/ecma_string.h"
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_api/js_api_stack.h"
21 #include "ecmascript/js_api/js_api_stack_iterator.h"
22 #include "ecmascript/js_function.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_iterator.h"
25 #include "ecmascript/js_object-inl.h"
26 #include "ecmascript/js_tagged_value.h"
27 #include "ecmascript/object_factory.h"
28 #include "ecmascript/tests/test_helper.h"
29
30 using namespace panda;
31
32 using namespace panda::ecmascript;
33
34 using namespace panda::ecmascript::containers;
35
36 namespace panda::test {
37 class JSAPIStackTest : public testing::Test {
38 public:
SetUpTestCase()39 static void SetUpTestCase()
40 {
41 GTEST_LOG_(INFO) << "SetUpTestCase";
42 }
43
TearDownTestCase()44 static void TearDownTestCase()
45 {
46 GTEST_LOG_(INFO) << "TearDownCase";
47 }
48
SetUp()49 void SetUp() override
50 {
51 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
52 }
53
TearDown()54 void TearDown() override
55 {
56 TestHelper::DestroyEcmaVMWithScope(instance, scope);
57 }
58
59 EcmaVM *instance {nullptr};
60 ecmascript::EcmaHandleScope *scope {nullptr};
61 JSThread *thread {nullptr};
62
63 protected:
CreateStack()64 JSAPIStack *CreateStack()
65 {
66 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
68
69 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
70 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
71 JSHandle<JSTaggedValue> value =
72 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
73
74 auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
75 objCallInfo->SetFunction(JSTaggedValue::Undefined());
76 objCallInfo->SetThis(value.GetTaggedValue());
77 objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::Stack)));
78
79 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
80 JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo);
81 TestHelper::TearDownFrame(thread, prev);
82
83 JSHandle<JSTaggedValue> constructor(thread, result);
84 JSHandle<JSAPIStack> stack(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
85 stack->SetTop(-1);
86 return *stack;
87 }
88 };
89
HWTEST_F_L0(JSAPIStackTest,stackCreate)90 HWTEST_F_L0(JSAPIStackTest, stackCreate)
91 {
92 JSAPIStack *stack = CreateStack();
93 EXPECT_TRUE(stack != nullptr);
94 }
95
HWTEST_F_L0(JSAPIStackTest,PushAndPeek)96 HWTEST_F_L0(JSAPIStackTest, PushAndPeek)
97 {
98 constexpr uint32_t NODE_NUMBERS = 9;
99 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
100 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
101
102 JSHandle<JSAPIStack> toor(thread, CreateStack());
103
104 // test Peek empty
105 EXPECT_EQ(toor->Peek(), JSTaggedValue::Undefined());
106
107 std::string myValue("myvalue");
108 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
109 std::string ivalue = myValue + std::to_string(i);
110 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
111 JSTaggedValue result = JSAPIStack::Push(thread, toor, value);
112 EXPECT_EQ(result, value.GetTaggedValue());
113 EXPECT_EQ(toor->Peek(), value.GetTaggedValue());
114 }
115 EXPECT_EQ(static_cast<uint32_t>(toor->GetTop() + 1), NODE_NUMBERS);
116
117 toor->Dump();
118 }
119
HWTEST_F_L0(JSAPIStackTest,Pop)120 HWTEST_F_L0(JSAPIStackTest, Pop)
121 {
122 constexpr uint32_t NODE_NUMBERS = 9;
123 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
124 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
125
126 JSHandle<JSAPIStack> toor(thread, CreateStack());
127
128 // test Pop empty
129 EXPECT_EQ(toor->Pop(), JSTaggedValue::Undefined());
130
131 std::string myValue("myvalue");
132 for (uint32_t i = 1; i <= NODE_NUMBERS; i++) {
133 std::string ivalue = myValue + std::to_string(i);
134 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
135 JSTaggedValue result = JSAPIStack::Push(thread, toor, value);
136 EXPECT_EQ(result, value.GetTaggedValue());
137 EXPECT_EQ(toor->Peek(), value.GetTaggedValue());
138 }
139
140 for (uint32_t i = NODE_NUMBERS; i >= 1; i--) {
141 std::string ivalue = myValue + std::to_string(i);
142 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
143 JSTaggedValue gValue = toor->Pop();
144 EXPECT_EQ(gValue, value.GetTaggedValue());
145 }
146
147 toor->Dump();
148 }
149
HWTEST_F_L0(JSAPIStackTest,Empty)150 HWTEST_F_L0(JSAPIStackTest, Empty)
151 {
152 constexpr uint32_t NODE_NUMBERS = 9;
153 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
154 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
155
156 JSHandle<JSAPIStack> toor(thread, CreateStack());
157
158 std::string myValue("myvalue");
159 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
160 std::string ivalue = myValue + std::to_string(i);
161 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
162 JSTaggedValue result = JSAPIStack::Push(thread, toor, value);
163 EXPECT_EQ(result, value.GetTaggedValue());
164 EXPECT_EQ(toor->Peek(), value.GetTaggedValue());
165 EXPECT_EQ(toor->Empty(), false);
166 }
167
168 int num = 8;
169 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
170 std::string ivalue = myValue + std::to_string(i);
171 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
172 toor->Pop();
173 if (num == -1) {
174 EXPECT_EQ(toor->Empty(), true);
175 }
176 }
177
178 toor->Dump();
179 }
180
HWTEST_F_L0(JSAPIStackTest,Search)181 HWTEST_F_L0(JSAPIStackTest, Search)
182 {
183 constexpr uint32_t NODE_NUMBERS = 9;
184 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
185 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
186
187 JSHandle<JSAPIStack> toor(thread, CreateStack());
188
189 std::string myValue("myvalue");
190 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
191 std::string ivalue = myValue + std::to_string(i);
192 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
193 JSTaggedValue result = JSAPIStack::Push(thread, toor, value);
194 EXPECT_EQ(result, value.GetTaggedValue());
195 EXPECT_EQ(toor->Search(value), static_cast<int>(i));
196 }
197 value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
198 EXPECT_EQ(toor->Search(value), -1);
199
200 toor->Dump();
201 }
202
HWTEST_F_L0(JSAPIStackTest,GetOwnProperty)203 HWTEST_F_L0(JSAPIStackTest, GetOwnProperty)
204 {
205 constexpr uint32_t DEFAULT_LENGTH = 8;
206 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
207 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
208 JSHandle<JSAPIStack> toor(thread, CreateStack());
209
210 std::string stackvalue("stackvalue");
211 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
212 std::string ivalue = stackvalue + std::to_string(i);
213 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
214 JSAPIStack::Push(thread, toor, value);
215 }
216 // test GetOwnProperty
217 int testInt = 1;
218 JSHandle<JSTaggedValue> stackKey1(thread, JSTaggedValue(testInt));
219 EXPECT_TRUE(JSAPIStack::GetOwnProperty(thread, toor, stackKey1));
220 testInt = 20;
221 JSHandle<JSTaggedValue> stackKey2(thread, JSTaggedValue(testInt));
222 EXPECT_FALSE(JSAPIStack::GetOwnProperty(thread, toor, stackKey2));
223 EXPECT_EXCEPTION();
224
225 // test GetOwnProperty exception
226 JSHandle<JSTaggedValue> undefined(thread, JSTaggedValue::Undefined());
227 EXPECT_FALSE(JSAPIStack::GetOwnProperty(thread, toor, undefined));
228 EXPECT_EXCEPTION();
229 }
230
231 /**
232 * @tc.name: GetProperty
233 * @tc.desc:
234 * @tc.type: FUNC
235 * @tc.require:
236 */
HWTEST_F_L0(JSAPIStackTest,GetProperty)237 HWTEST_F_L0(JSAPIStackTest, GetProperty)
238 {
239 JSHandle<JSAPIStack> toor(thread, CreateStack());
240 uint32_t elementsNums = 8;
241 for (uint32_t i = 0; i < elementsNums; i++) {
242 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
243 JSAPIStack::Push(thread, toor, value);
244 }
245 for (uint32_t i = 0; i < elementsNums; i++) {
246 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
247 OperationResult getPropertyRes = JSAPIStack::GetProperty(thread, toor, key);
248 EXPECT_EQ(getPropertyRes.GetValue().GetTaggedValue(), JSTaggedValue(i));
249 }
250
251 // test GetProperty Exception
252 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(-1));
253 OperationResult getPropertyRes = JSAPIStack::GetProperty(thread, toor, key);
254 EXPECT_EQ(getPropertyRes.GetValue().GetTaggedValue(), JSTaggedValue::Exception());
255 EXPECT_EXCEPTION();
256
257 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(elementsNums));
258 OperationResult getPropertyRes1 = JSAPIStack::GetProperty(thread, toor, key1);
259 EXPECT_EQ(getPropertyRes1.GetValue().GetTaggedValue(), JSTaggedValue::Exception());
260 EXPECT_EXCEPTION();
261 }
262
263 /**
264 * @tc.name: SetProperty
265 * @tc.desc:
266 * @tc.type: FUNC
267 * @tc.require:
268 */
HWTEST_F_L0(JSAPIStackTest,SetProperty)269 HWTEST_F_L0(JSAPIStackTest, SetProperty)
270 {
271 JSHandle<JSAPIStack> toor(thread, CreateStack());
272 uint32_t elementsNums = 8;
273 for (uint32_t i = 0; i < elementsNums; i++) {
274 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
275 JSAPIStack::Push(thread, toor, value);
276 }
277 for (uint32_t i = 0; i < elementsNums; i++) {
278 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
279 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 2)); // 2 : It means double
280 bool setPropertyRes = JSAPIStack::SetProperty(thread, toor, key, value);
281 EXPECT_EQ(setPropertyRes, true);
282 }
283 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(-1));
284 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(-1));
285 EXPECT_FALSE(JSAPIStack::SetProperty(thread, toor, key, value));
286 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(elementsNums));
287 EXPECT_FALSE(JSAPIStack::SetProperty(thread, toor, key1, value));
288 }
289
290 /**
291 * @tc.name: Has
292 * @tc.desc:
293 * @tc.type: FUNC
294 * @tc.require:
295 */
HWTEST_F_L0(JSAPIStackTest,Has)296 HWTEST_F_L0(JSAPIStackTest, Has)
297 {
298 JSHandle<JSAPIStack> toor(thread, CreateStack());
299
300 // test Has empty
301 EXPECT_FALSE(toor->Has(JSTaggedValue(0)));
302
303 uint32_t elementsNums = 8;
304 for (uint32_t i = 0; i < elementsNums; i++) {
305 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
306 JSAPIStack::Push(thread, toor, value);
307 }
308 for (uint32_t i = 0; i < elementsNums; i++) {
309 EXPECT_TRUE(toor->Has(JSTaggedValue(i)));
310 }
311 EXPECT_FALSE(toor->Has(JSTaggedValue(elementsNums)));
312 }
313
314 /**
315 * @tc.name: OwnKeys
316 * @tc.desc:
317 * @tc.type: FUNC
318 * @tc.require:
319 */
HWTEST_F_L0(JSAPIStackTest,OwnKeys)320 HWTEST_F_L0(JSAPIStackTest, OwnKeys)
321 {
322 JSHandle<JSAPIStack> toor(thread, CreateStack());
323 uint32_t elementsNums = 8;
324 for (uint32_t i = 0; i < elementsNums; i++) {
325 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
326 JSAPIStack::Push(thread, toor, value);
327 }
328 JSHandle<TaggedArray> keyArray = JSAPIStack::OwnKeys(thread, toor);
329 EXPECT_TRUE(keyArray->GetClass()->IsTaggedArray());
330 EXPECT_TRUE(keyArray->GetLength() == elementsNums);
331 for (uint32_t i = 0; i < elementsNums; i++) {
332 ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*(base::NumberHelper::NumberToString(thread, JSTaggedValue(i))),
333 EcmaString::Cast(keyArray->Get(i).GetTaggedObject())));
334 }
335 }
336 } // namespace panda::test
337