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_deque.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_deque.h" 21#include "ecmascript/js_api/js_api_deque_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 29using namespace panda::ecmascript; 30using namespace panda::ecmascript::containers; 31 32namespace panda::test { 33class ContainersDequeTest : public testing::Test { 34public: 35 static void SetUpTestCase() 36 { 37 GTEST_LOG_(INFO) << "SetUpTestCase"; 38 } 39 40 static void TearDownTestCase() 41 { 42 GTEST_LOG_(INFO) << "TearDownCase"; 43 } 44 45 void SetUp() override 46 { 47 TestHelper::CreateEcmaVMWithScope(instance, thread, scope); 48 } 49 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: 61 static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv) 62 { 63 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 64 JSHandle<JSTaggedValue> key = GetCallArg(argv, 1); 65 JSHandle<JSTaggedValue> deque = GetCallArg(argv, 2); // 2 means the secode arg 66 if (!deque->IsUndefined()) { 67 if (value->IsNumber()) { 68 TaggedArray *elements = TaggedArray::Cast(JSAPIDeque::Cast(deque.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 }; 77protected: 78 JSTaggedValue InitializeDequeConstructor() 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::Deque))); 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 99 JSHandle<JSAPIDeque> CreateJSAPIDeque(JSTaggedValue compare = JSTaggedValue::Undefined()) 100 { 101 JSHandle<JSTaggedValue> compareHandle(thread, compare); 102 JSHandle<JSFunction> newTarget(thread, InitializeDequeConstructor()); 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 = ContainersDeque::DequeConstructor(objCallInfo); 111 TestHelper::TearDownFrame(thread, prev); 112 JSHandle<JSAPIDeque> deque(thread, result); 113 return deque; 114 } 115}; 116 117HWTEST_F_L0(ContainersDequeTest, DequeConstructor) 118{ 119 InitializeDequeConstructor(); 120 JSHandle<JSFunction> newTarget(thread, InitializeDequeConstructor()); 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 = ContainersDeque::DequeConstructor(objCallInfo); 129 TestHelper::TearDownFrame(thread, prev); 130 131 ASSERT_TRUE(result.IsJSAPIDeque()); 132 JSHandle<JSAPIDeque> deque(thread, result); 133 JSTaggedValue resultProto = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(deque)); 134 JSTaggedValue funcProto = newTarget->GetFunctionPrototype(); 135 ASSERT_EQ(resultProto, funcProto); 136 137 // test DequeConstructor exception 138 objCallInfo->SetNewTarget(JSTaggedValue::Undefined()); 139 CONTAINERS_API_EXCEPTION_TEST(ContainersDeque, DequeConstructor, objCallInfo); 140} 141 142HWTEST_F_L0(ContainersDequeTest, InsertFrontAndGetFirst) 143{ 144 constexpr uint32_t NODE_NUMBERS = 8; 145 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(); 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(deque.GetTaggedValue()); 150 callInfo->SetCallArg(0, JSTaggedValue(i)); 151 152 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 153 JSTaggedValue result = ContainersDeque::InsertFront(callInfo); 154 TestHelper::TearDownFrame(thread, prev); 155 EXPECT_EQ(result, JSTaggedValue::True()); 156 EXPECT_EQ(ContainersDeque::GetFirst(callInfo), JSTaggedValue(i)); 157 } 158} 159 160HWTEST_F_L0(ContainersDequeTest, InsertEndAndGetLast) 161{ 162 constexpr uint32_t NODE_NUMBERS = 8; 163 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(); 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(deque.GetTaggedValue()); 168 callInfo->SetCallArg(0, JSTaggedValue(i)); 169 170 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 171 JSTaggedValue result = ContainersDeque::InsertEnd(callInfo); 172 TestHelper::TearDownFrame(thread, prev); 173 EXPECT_EQ(result, JSTaggedValue::True()); 174 EXPECT_EQ(ContainersDeque::GetLast(callInfo), JSTaggedValue(i)); 175 } 176} 177 178HWTEST_F_L0(ContainersDequeTest, Has) 179{ 180 constexpr uint32_t NODE_NUMBERS = 8; 181 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(); 182 for (uint32_t i = 0; i < NODE_NUMBERS; i++) { 183 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 184 callInfo->SetFunction(JSTaggedValue::Undefined()); 185 callInfo->SetThis(deque.GetTaggedValue()); 186 callInfo->SetCallArg(0, JSTaggedValue(i)); 187 188 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 189 ContainersDeque::InsertEnd(callInfo); 190 TestHelper::TearDownFrame(thread, prev); 191 } 192 193 int num = 7; 194 for (uint32_t i = 0; i < NODE_NUMBERS; i++) { 195 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); 196 callInfo->SetFunction(JSTaggedValue::Undefined()); 197 callInfo->SetThis(deque.GetTaggedValue()); 198 callInfo->SetCallArg(0, JSTaggedValue(i)); 199 200 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 201 JSTaggedValue result = ContainersDeque::Has(callInfo); 202 TestHelper::TearDownFrame(thread, prev); 203 EXPECT_EQ(result, JSTaggedValue::True()); 204 } 205 num = 7; 206 for (uint32_t i = 0; i < NODE_NUMBERS; i++) { 207 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); 208 callInfo->SetFunction(JSTaggedValue::Undefined()); 209 callInfo->SetThis(deque.GetTaggedValue()); 210 callInfo->SetCallArg(0, JSTaggedValue(i + 8)); 211 212 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 213 JSTaggedValue result = ContainersDeque::Has(callInfo); 214 TestHelper::TearDownFrame(thread, prev); 215 EXPECT_EQ(result, JSTaggedValue::False()); 216 } 217} 218 219HWTEST_F_L0(ContainersDequeTest, PopFirst) 220{ 221 constexpr uint32_t NODE_NUMBERS = 8; 222 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(); 223 for (uint32_t i = 0; i < NODE_NUMBERS; i++) { 224 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 225 callInfo->SetFunction(JSTaggedValue::Undefined()); 226 callInfo->SetThis(deque.GetTaggedValue()); 227 callInfo->SetCallArg(0, JSTaggedValue(i)); 228 229 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 230 ContainersDeque::InsertFront(callInfo); 231 TestHelper::TearDownFrame(thread, prev); 232 EXPECT_EQ(ContainersDeque::PopFirst(callInfo), JSTaggedValue(i)); 233 } 234} 235 236HWTEST_F_L0(ContainersDequeTest, PopLast) 237{ 238 constexpr uint32_t NODE_NUMBERS = 8; 239 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(); 240 for (uint32_t i = 0; i < NODE_NUMBERS; i++) { 241 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 242 callInfo->SetFunction(JSTaggedValue::Undefined()); 243 callInfo->SetThis(deque.GetTaggedValue()); 244 callInfo->SetCallArg(0, JSTaggedValue(i)); 245 246 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 247 ContainersDeque::InsertEnd(callInfo); 248 TestHelper::TearDownFrame(thread, prev); 249 EXPECT_EQ(ContainersDeque::PopLast(callInfo), JSTaggedValue(i)); 250 } 251} 252 253HWTEST_F_L0(ContainersDequeTest, ForEach) 254{ 255 constexpr uint32_t NODE_NUMBERS = 8; 256 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(); 257 for (uint32_t i = 0; i < NODE_NUMBERS; i++) { 258 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 259 callInfo->SetFunction(JSTaggedValue::Undefined()); 260 callInfo->SetThis(deque.GetTaggedValue()); 261 callInfo->SetCallArg(0, JSTaggedValue(i)); 262 263 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 264 ContainersDeque::InsertEnd(callInfo); 265 TestHelper::TearDownFrame(thread, prev); 266 } 267 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 268 JSHandle<JSAPIDeque> dlist = CreateJSAPIDeque(); 269 { 270 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 271 JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachFunc)); 272 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 273 callInfo->SetFunction(JSTaggedValue::Undefined()); 274 callInfo->SetThis(deque.GetTaggedValue()); 275 callInfo->SetCallArg(0, func.GetTaggedValue()); 276 callInfo->SetCallArg(1, dlist.GetTaggedValue()); 277 278 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 279 ContainersDeque::ForEach(callInfo); 280 TestHelper::TearDownFrame(thread, prev); 281 } 282} 283 284HWTEST_F_L0(ContainersDequeTest, ProxyOfGetSize) 285{ 286 constexpr uint32_t NODE_NUMBERS = 10; 287 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(); 288 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 289 callInfo->SetFunction(JSTaggedValue::Undefined()); 290 JSHandle<JSProxy> proxy = CreateJSProxyHandle(thread); 291 proxy->SetTarget(thread, deque.GetTaggedValue()); 292 callInfo->SetThis(proxy.GetTaggedValue()); 293 294 for (uint32_t i = 0; i < NODE_NUMBERS; i++) { 295 callInfo->SetCallArg(0, JSTaggedValue(i)); 296 callInfo->SetCallArg(1, JSTaggedValue(i + 1)); 297 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo); 298 ContainersDeque::InsertFront(callInfo); 299 TestHelper::TearDownFrame(thread, prev); 300 301 [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo); 302 JSTaggedValue retult = ContainersDeque::GetSize(callInfo); 303 TestHelper::TearDownFrame(thread, prev1); 304 EXPECT_EQ(retult, JSTaggedValue(i + 1)); 305 } 306} 307 308HWTEST_F_L0(ContainersDequeTest, ExceptionReturn) 309{ 310 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, InsertFront); 311 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, InsertEnd); 312 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetFirst); 313 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetLast); 314 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, Has); 315 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, PopFirst); 316 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, PopLast); 317 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, ForEach); 318 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetIteratorObj); 319 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetSize); 320} 321} // namespace panda::test 322