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