• 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/containers/containers_stack.h"
17 #include "ecmascript/containers/containers_private.h"
18 #include "ecmascript/ecma_runtime_call_info.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_handle.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/js_thread.h"
25 #include "ecmascript/object_factory.h"
26 #include "ecmascript/tests/test_helper.h"
27 #include "ecmascript/containers/tests/containers_test_helper.h"
28 
29 using namespace panda::ecmascript;
30 using namespace panda::ecmascript::containers;
31 
32 namespace panda::test {
33 class ContainersStackTest : public testing::Test {
34 public:
SetUpTestCase()35     static void SetUpTestCase()
36     {
37         GTEST_LOG_(INFO) << "SetUpTestCase";
38     }
39 
TearDownTestCase()40     static void TearDownTestCase()
41     {
42         GTEST_LOG_(INFO) << "TearDownCase";
43     }
44 
SetUp()45     void SetUp() override
46     {
47         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
48     }
49 
TearDown()50     void TearDown() override
51     {
52         TestHelper::DestroyEcmaVMWithScope(instance, scope);
53     }
54 
55     EcmaVM *instance {nullptr};
56     EcmaHandleScope *scope {nullptr};
57     JSThread *thread {nullptr};
58 
59     class TestClass : public base::BuiltinsBase {
60     public:
TestForEachFunc(EcmaRuntimeCallInfo * argv)61         static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
62         {
63             JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
64             JSHandle<JSTaggedValue> key = GetCallArg(argv, 1);
65             JSHandle<JSTaggedValue> stack = GetCallArg(argv, 2); // 2 means the secode arg
66             if (!stack->IsUndefined()) {
67                 if (value->IsNumber()) {
68                     TaggedArray *elements = TaggedArray::Cast(JSAPIStack::Cast(stack.GetTaggedValue().
69                                             GetTaggedObject())->GetElements().GetTaggedObject());
70                     JSTaggedValue result = elements->Get(key->GetInt());
71                     EXPECT_EQ(result, value.GetTaggedValue());
72                 }
73             }
74             return JSTaggedValue::True();
75         }
76     };
77 protected:
InitializeStackConstructor()78     JSTaggedValue InitializeStackConstructor()
79     {
80         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
81         JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
82 
83         JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
84         JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
85         JSHandle<JSTaggedValue> value =
86             JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
87 
88         auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
89         objCallInfo->SetFunction(JSTaggedValue::Undefined());
90         objCallInfo->SetThis(value.GetTaggedValue());
91         objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::Stack)));
92         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
93         JSTaggedValue result = ContainersPrivate::Load(objCallInfo);
94         TestHelper::TearDownFrame(thread, prev);
95 
96         return result;
97     }
98 
CreateJSAPIStack(JSTaggedValue compare=JSTaggedValue::Undefined ())99     JSHandle<JSAPIStack> CreateJSAPIStack(JSTaggedValue compare = JSTaggedValue::Undefined())
100     {
101         JSHandle<JSTaggedValue> compareHandle(thread, compare);
102         JSHandle<JSFunction> newTarget(thread, InitializeStackConstructor());
103         auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
104         objCallInfo->SetFunction(newTarget.GetTaggedValue());
105         objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
106         objCallInfo->SetThis(JSTaggedValue::Undefined());
107         objCallInfo->SetCallArg(0, compareHandle.GetTaggedValue());
108 
109         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
110         JSTaggedValue result = ContainersStack::StackConstructor(objCallInfo);
111         TestHelper::TearDownFrame(thread, prev);
112         JSHandle<JSAPIStack> stack(thread, result);
113         return stack;
114     }
115 };
116 
HWTEST_F_L0(ContainersStackTest,StackConstructor)117 HWTEST_F_L0(ContainersStackTest, StackConstructor)
118 {
119     InitializeStackConstructor();
120     JSHandle<JSFunction> newTarget(thread, InitializeStackConstructor());
121 
122     auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
123     objCallInfo->SetFunction(newTarget.GetTaggedValue());
124     objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
125     objCallInfo->SetThis(JSTaggedValue::Undefined());
126 
127     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
128     JSTaggedValue result = ContainersStack::StackConstructor(objCallInfo);
129     TestHelper::TearDownFrame(thread, prev);
130 
131     ASSERT_TRUE(result.IsJSAPIStack());
132     JSHandle<JSAPIStack> stack(thread, result);
133     JSTaggedValue resultProto = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(stack));
134     JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
135     ASSERT_EQ(resultProto, funcProto);
136 
137     // test StackConstructor exception
138     objCallInfo->SetNewTarget(JSTaggedValue::Undefined());
139     CONTAINERS_API_EXCEPTION_TEST(ContainersStack, StackConstructor, objCallInfo);
140 }
141 
HWTEST_F_L0(ContainersStackTest,PushAndPeek)142 HWTEST_F_L0(ContainersStackTest, PushAndPeek)
143 {
144     constexpr uint32_t NODE_NUMBERS = 8;
145     JSHandle<JSAPIStack> stack = CreateJSAPIStack();
146     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
147         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
148         callInfo->SetFunction(JSTaggedValue::Undefined());
149         callInfo->SetThis(stack.GetTaggedValue());
150         callInfo->SetCallArg(0, JSTaggedValue(i));
151 
152         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
153         JSTaggedValue result = ContainersStack::Push(callInfo);
154         TestHelper::TearDownFrame(thread, prev);
155         EXPECT_EQ(result, JSTaggedValue(i));
156         EXPECT_EQ(ContainersStack::Peek(callInfo), JSTaggedValue(i));
157     }
158 }
159 
HWTEST_F_L0(ContainersStackTest,Pop)160 HWTEST_F_L0(ContainersStackTest, Pop)
161 {
162     constexpr uint32_t NODE_NUMBERS = 8;
163     JSHandle<JSAPIStack> stack = CreateJSAPIStack();
164     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
165         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
166         callInfo->SetFunction(JSTaggedValue::Undefined());
167         callInfo->SetThis(stack.GetTaggedValue());
168         callInfo->SetCallArg(0, JSTaggedValue(i));
169 
170         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
171         ContainersStack::Push(callInfo);
172         TestHelper::TearDownFrame(thread, prev);
173     }
174 
175     int num = 7;
176     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
177         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
178         callInfo->SetFunction(JSTaggedValue::Undefined());
179         callInfo->SetThis(stack.GetTaggedValue());
180         callInfo->SetCallArg(0, JSTaggedValue(i));
181 
182         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
183         JSTaggedValue result = ContainersStack::Pop(callInfo);
184         TestHelper::TearDownFrame(thread, prev);
185         EXPECT_EQ(result, JSTaggedValue(num--));
186     }
187 }
188 
HWTEST_F_L0(ContainersStackTest,IsEmpty)189 HWTEST_F_L0(ContainersStackTest, IsEmpty)
190 {
191     constexpr uint32_t NODE_NUMBERS = 8;
192     JSHandle<JSAPIStack> stack = CreateJSAPIStack();
193     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
194         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
195         callInfo->SetFunction(JSTaggedValue::Undefined());
196         callInfo->SetThis(stack.GetTaggedValue());
197         callInfo->SetCallArg(0, JSTaggedValue(i));
198 
199         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
200         ContainersStack::Push(callInfo);
201         TestHelper::TearDownFrame(thread, prev);
202         JSTaggedValue result = ContainersStack::IsEmpty(callInfo);
203         EXPECT_EQ(result, JSTaggedValue::False());
204     }
205 
206     int num = 7;
207     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
208         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
209         callInfo->SetFunction(JSTaggedValue::Undefined());
210         callInfo->SetThis(stack.GetTaggedValue());
211         callInfo->SetCallArg(0, JSTaggedValue(i));
212 
213         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
214         JSTaggedValue result = ContainersStack::Pop(callInfo);
215         TestHelper::TearDownFrame(thread, prev);
216         EXPECT_EQ(result, JSTaggedValue(num--));
217         if (num == -1) {
218             JSTaggedValue consequence = ContainersStack::IsEmpty(callInfo);
219             EXPECT_EQ(consequence, JSTaggedValue::True());
220         }
221     }
222 }
223 
HWTEST_F_L0(ContainersStackTest,Locate)224 HWTEST_F_L0(ContainersStackTest, Locate)
225 {
226     constexpr uint32_t NODE_NUMBERS = 8;
227     JSHandle<JSAPIStack> stack = CreateJSAPIStack();
228     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
229         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
230         callInfo->SetFunction(JSTaggedValue::Undefined());
231         callInfo->SetThis(stack.GetTaggedValue());
232         callInfo->SetCallArg(0, JSTaggedValue(i));
233 
234         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
235         ContainersStack::Push(callInfo);
236         JSTaggedValue result = ContainersStack::Locate(callInfo);
237         EXPECT_EQ(result, JSTaggedValue(i));
238         TestHelper::TearDownFrame(thread, prev);
239     }
240 }
241 
HWTEST_F_L0(ContainersStackTest,ForEach)242 HWTEST_F_L0(ContainersStackTest, ForEach)
243 {
244     constexpr uint32_t NODE_NUMBERS = 8;
245     JSHandle<JSAPIStack> stack = CreateJSAPIStack();
246     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
247         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
248         callInfo->SetFunction(JSTaggedValue::Undefined());
249         callInfo->SetThis(stack.GetTaggedValue());
250         callInfo->SetCallArg(0, JSTaggedValue(i));
251 
252         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
253         ContainersStack::Push(callInfo);
254         TestHelper::TearDownFrame(thread, prev);
255     }
256     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
257     JSHandle<JSAPIStack> dlist = CreateJSAPIStack();
258     {
259         JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
260         JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachFunc));
261         auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
262         callInfo->SetFunction(JSTaggedValue::Undefined());
263         callInfo->SetThis(stack.GetTaggedValue());
264         callInfo->SetCallArg(0, func.GetTaggedValue());
265         callInfo->SetCallArg(1, dlist.GetTaggedValue());
266 
267         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
268         ContainersStack::ForEach(callInfo);
269         TestHelper::TearDownFrame(thread, prev);
270     }
271 }
272 
HWTEST_F_L0(ContainersStackTest,ProxyOfGetLength)273 HWTEST_F_L0(ContainersStackTest, ProxyOfGetLength)
274 {
275     constexpr uint32_t NODE_NUMBERS = 8;
276     JSHandle<JSAPIStack> stack = CreateJSAPIStack();
277     auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
278     callInfo->SetFunction(JSTaggedValue::Undefined());
279     JSHandle<JSProxy> proxy = CreateJSProxyHandle(thread);
280     proxy->SetTarget(thread, stack.GetTaggedValue());
281     callInfo->SetThis(proxy.GetTaggedValue());
282 
283     for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
284         callInfo->SetCallArg(0, JSTaggedValue(i));
285         callInfo->SetCallArg(1, JSTaggedValue(i + 1));
286         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
287         ContainersStack::Push(callInfo);
288         TestHelper::TearDownFrame(thread, prev);
289 
290         [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo);
291         JSTaggedValue retult = ContainersStack::GetLength(callInfo);
292         TestHelper::TearDownFrame(thread, prev1);
293         EXPECT_EQ(retult, JSTaggedValue(i + 1));
294     }
295 }
296 
HWTEST_F_L0(ContainersStackTest,ExceptionReturn)297 HWTEST_F_L0(ContainersStackTest, ExceptionReturn)
298 {
299     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, IsEmpty);
300     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, Push);
301     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, Peek);
302     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, Locate);
303     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, Pop);
304     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, ForEach);
305     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, Iterator);
306     CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersStack, GetLength);
307 }
308 }  // namespace panda::test
309