1/* 2 * Copyright (c) 2021 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_weak_map.h" 17 18#include "ecmascript/base/builtins_base.h" 19#include "ecmascript/ecma_runtime_call_info.h" 20#include "ecmascript/ecma_string.h" 21#include "ecmascript/ecma_vm.h" 22#include "ecmascript/global_env.h" 23#include "ecmascript/js_array.h" 24#include "ecmascript/js_handle.h" 25#include "ecmascript/js_hclass.h" 26#include "ecmascript/js_map_iterator.h" 27#include "ecmascript/js_object-inl.h" 28#include "ecmascript/js_tagged_value.h" 29#include "ecmascript/js_thread.h" 30#include "ecmascript/js_weak_container.h" 31#include "ecmascript/object_factory.h" 32#include "ecmascript/tagged_array-inl.h" 33#include "ecmascript/tests/test_helper.h" 34 35using namespace panda::ecmascript; 36using namespace panda::ecmascript::builtins; 37 38namespace panda::test { 39using BuiltinsWeakMap = ecmascript::builtins::BuiltinsWeakMap; 40using JSWeakMap = ecmascript::JSWeakMap; 41 42class BuiltinsWeakMapTest : public BaseTestWithScope<false> { 43}; 44 45static JSObject *JSObjectTestCreate(JSThread *thread) 46{ 47 EcmaVM *ecmaVM = thread->GetEcmaVM(); 48 ObjectFactory *factory = ecmaVM->GetFactory(); 49 [[maybe_unused]] EcmaHandleScope scope(thread); 50 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv(); 51 JSHandle<JSTaggedValue> jsFunc = globalEnv->GetObjectFunction(); 52 return *factory->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc); 53} 54 55JSWeakMap *CreateBuiltinsWeakMap(JSThread *thread) 56{ 57 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 58 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction()); 59 // 4 : test case 60 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, newTarget.GetTaggedValue(), 4); 61 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue()); 62 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); 63 64 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 65 JSTaggedValue result = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo); 66 TestHelper::TearDownFrame(thread, prev); 67 68 EXPECT_TRUE(result.IsECMAObject()); 69 return JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())); 70} 71 72// new Map("abrupt").toString() 73HWTEST_F_L0(BuiltinsWeakMapTest, CreateAndGetSize) 74{ 75 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 76 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 77 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction()); 78 JSHandle<JSWeakMap> map(thread, CreateBuiltinsWeakMap(thread)); 79 80 JSHandle<TaggedArray> array(factory->NewTaggedArray(1)); 81 JSHandle<TaggedArray> internalArray(factory->NewTaggedArray(2)); 82 JSTaggedValue value(JSObjectTestCreate(thread)); 83 internalArray->Set(thread, 0, value); 84 internalArray->Set(thread, 1, JSTaggedValue(0)); 85 auto result = JSArray::CreateArrayFromList(thread, internalArray); 86 array->Set(thread, 0, result); 87 88 JSHandle<JSArray> values = JSArray::CreateArrayFromList(thread, array); 89 90 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); 91 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue()); 92 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue()); 93 ecmaRuntimeCallInfo->SetCallArg(0, values.GetTaggedValue()); 94 ecmaRuntimeCallInfo->SetNewTarget(newTarget.GetTaggedValue()); 95 96 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 97 98 JSTaggedValue result1 = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo); 99 JSHandle<JSWeakMap> weakMap(thread, JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()))); 100 EXPECT_EQ(weakMap->GetSize(), 1); 101} 102 103HWTEST_F_L0(BuiltinsWeakMapTest, SetAndHas) 104{ 105 // create jsWeakMap 106 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread)); 107 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread)); 108 109 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 110 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 111 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue()); 112 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue()); 113 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1))); 114 115 { 116 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 117 JSTaggedValue result1 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo); 118 TestHelper::TearDownFrame(thread, prev); 119 120 EXPECT_EQ(result1.GetRawData(), JSTaggedValue::False().GetRawData()); 121 } 122 123 // test Set() 124 JSTaggedValue result2 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo); 125 EXPECT_TRUE(result2.IsECMAObject()); 126 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result2.GetRawData())); 127 EXPECT_EQ(jsWeakMap->GetSize(), 1); 128 129 // test Has() 130 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 131 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); 132 ecmaRuntimeCallInfo1->SetCallArg(0, key.GetTaggedValue()); 133 ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1))); 134 ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(jsWeakMap)); 135 { 136 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1); 137 JSTaggedValue result3 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1); 138 TestHelper::TearDownFrame(thread, prev); 139 140 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData()); 141 } 142} 143 144void KeySetCommon(JSThread* thread, JSHandle<JSWeakMap>& weakMap, JSHandle<JSTaggedValue>& key, int32_t val) 145{ 146 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); 147 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 148 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue()); 149 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue()); 150 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(val)); 151 152 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 153 JSTaggedValue result1 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo); 154 TestHelper::TearDownFrame(thread, prev); 155 156 EXPECT_TRUE(result1.IsECMAObject()); 157 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())); 158 EXPECT_EQ(jsWeakMap->GetSize(), static_cast<int>(val) + 1); 159} 160 161HWTEST_F_L0(BuiltinsWeakMapTest, DeleteAndRemove) 162{ 163 // create jsWeakMap 164 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread)); 165 166 // add 40 keys 167 JSTaggedValue lastKey(JSTaggedValue::Undefined()); 168 for (int i = 0; i < 40; i++) { 169 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread)); 170 KeySetCommon(thread, weakMap, key, static_cast<int32_t>(i)); 171 lastKey = key.GetTaggedValue(); 172 } 173 174 // whether jsWeakMap has delete lastKey 175 176 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); 177 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); 178 ecmaRuntimeCallInfo1->SetThis(weakMap.GetTaggedValue()); 179 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey); 180 181 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1); 182 JSTaggedValue result2 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1); 183 TestHelper::TearDownFrame(thread, prev); 184 185 EXPECT_EQ(result2.GetRawData(), JSTaggedValue::True().GetRawData()); 186 187 // delete 188 JSTaggedValue result3 = BuiltinsWeakMap::Delete(ecmaRuntimeCallInfo1); 189 190 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData()); 191 192 // check deleteKey is deleted 193 JSTaggedValue result4 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1); 194 195 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData()); 196} 197 198HWTEST_F_L0(BuiltinsWeakMapTest, SymbolKey) 199{ 200 // create jsWeakMap 201 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread)); 202 203 // add 2 symbol keys 204 JSTaggedValue lastKey(JSTaggedValue::Undefined()); 205 for (int i = 0; i < 2; i++) { 206 JSHandle<JSSymbol> symbolKey = thread->GetEcmaVM()->GetFactory()->NewJSSymbol(); 207 JSHandle<JSTaggedValue> key(symbolKey); 208 KeySetCommon(thread, weakMap, key, static_cast<int32_t>(i)); 209 lastKey = key.GetTaggedValue(); 210 } 211 212 // check whether jsWeakMap can get and delete lastKey 213 214 auto ecmaRuntimeCallInfo1 = 215 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means 1 call arg 216 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); 217 ecmaRuntimeCallInfo1->SetThis(weakMap.GetTaggedValue()); 218 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey); 219 220 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1); 221 // get 222 JSTaggedValue result2 = BuiltinsWeakMap::Get(ecmaRuntimeCallInfo1); 223 TestHelper::TearDownFrame(thread, prev); 224 EXPECT_EQ(result2, JSTaggedValue(1)); 225 226 // delete 227 JSTaggedValue result3 = BuiltinsWeakMap::Delete(ecmaRuntimeCallInfo1); 228 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData()); 229 230 // check deleteKey is deleted 231 JSTaggedValue result4 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1); 232 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData()); 233} 234} // namespace panda::test 235