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_symbol.h" 17 18#include "ecmascript/ecma_runtime_call_info.h" 19#include "ecmascript/ecma_string.h" 20#include "ecmascript/ecma_vm.h" 21#include "ecmascript/global_env.h" 22#include "ecmascript/js_function.h" 23#include "ecmascript/js_handle.h" 24#include "ecmascript/js_hclass.h" 25#include "ecmascript/js_object-inl.h" 26#include "ecmascript/js_primitive_ref.h" 27#include "ecmascript/js_tagged_value-inl.h" 28#include "ecmascript/js_thread.h" 29#include "ecmascript/object_factory.h" 30#include "ecmascript/symbol_table.h" 31#include "ecmascript/tests/test_helper.h" 32 33using namespace panda::ecmascript; 34using namespace panda::ecmascript::builtins; 35 36namespace panda::test { 37using Symbol = ecmascript::builtins::BuiltinsSymbol; 38using BuiltinsBase = panda::ecmascript::base::BuiltinsBase; 39 40class BuiltinsSymbolTest : public BaseTestWithScope<false> { 41}; 42 43enum class AlgorithmType { 44 TO_STRING, 45 VALUE_OF, 46 KEY_FOR, 47 BUILTIN_VALUE_OF, 48 BUILTIN_FOR, 49 BUILTIN_KEY_FOR, 50 BUILTIN_TO_PRIMITIVE, 51}; 52 53JSTaggedValue SymbolAlgorithm(JSThread *thread, JSTaggedValue thisArg, std::vector<JSTaggedValue>& args, 54 uint32_t argLen = 8, AlgorithmType type = AlgorithmType::TO_STRING) 55{ 56 auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), argLen); 57 ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined()); 58 ecmaRuntimeCallInfos->SetThis(thisArg); 59 for (size_t i = 0; i < args.size(); i++) { 60 ecmaRuntimeCallInfos->SetCallArg(i, args[i]); 61 } 62 auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos); 63 JSTaggedValue result; 64 switch (type) { 65 case AlgorithmType::TO_STRING: 66 result = Symbol::ToString(ecmaRuntimeCallInfos); 67 break; 68 case AlgorithmType::VALUE_OF: 69 result = Symbol::ValueOf(ecmaRuntimeCallInfos); 70 break; 71 case AlgorithmType::KEY_FOR: 72 result = Symbol::KeyFor(ecmaRuntimeCallInfos); 73 break; 74 case AlgorithmType::BUILTIN_VALUE_OF: 75 result = BuiltinsSymbol::ValueOf(ecmaRuntimeCallInfos); 76 break; 77 case AlgorithmType::BUILTIN_FOR: 78 result = BuiltinsSymbol::For(ecmaRuntimeCallInfos); 79 break; 80 case AlgorithmType::BUILTIN_KEY_FOR: 81 result = BuiltinsSymbol::KeyFor(ecmaRuntimeCallInfos); 82 break; 83 case AlgorithmType::BUILTIN_TO_PRIMITIVE: 84 result = BuiltinsSymbol::ToPrimitive(ecmaRuntimeCallInfos); 85 break; 86 default: 87 break; 88 } 89 TestHelper::TearDownFrame(thread, prev); 90 return result; 91} 92 93// new Symbol.toString() 94HWTEST_F_L0(BuiltinsSymbolTest, SymbolNoParameterToString) 95{ 96 auto ecmaVM = thread->GetEcmaVM(); 97 98 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewJSSymbol(); 99 100 std::vector<JSTaggedValue> args{}; 101 auto result = SymbolAlgorithm(thread, symbol.GetTaggedValue(), args, 4, AlgorithmType::TO_STRING); 102 JSHandle<EcmaString> resultHandle(thread, reinterpret_cast<EcmaString *>(result.GetRawData())); 103 ASSERT_TRUE(result.IsString()); 104 105 auto symbolValue = ecmaVM->GetFactory()->NewFromASCII("Symbol()"); 106 ASSERT_EQ(EcmaStringAccessor::Compare(ecmaVM, symbolValue, resultHandle), 0); 107 108 // Undefined not Object 109 result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 4, AlgorithmType::TO_STRING); 110 111 EXPECT_TRUE(thread->HasPendingException()); 112 EXPECT_EQ(result, JSTaggedValue::Exception()); 113 thread->ClearException(); 114 115 // No Symbol data 116 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 117 JSHandle<TaggedArray> array(factory->NewTaggedArray(3)); 118 result = SymbolAlgorithm(thread, array.GetTaggedValue(), args, 4, AlgorithmType::TO_STRING); 119 EXPECT_TRUE(thread->HasPendingException()); 120 EXPECT_EQ(result, JSTaggedValue::Exception()); 121 thread->ClearException(); 122} 123 124// new Symbol("aaa").toString() 125HWTEST_F_L0(BuiltinsSymbolTest, SymbolWithParameterToString) 126{ 127 auto ecmaVM = thread->GetEcmaVM(); 128 129 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar("aaa"); 130 std::vector<JSTaggedValue> args{}; 131 auto result = SymbolAlgorithm(thread, symbol.GetTaggedValue(), args, 4, AlgorithmType::TO_STRING); 132 JSHandle<EcmaString> resultHandle(thread, reinterpret_cast<EcmaString *>(result.GetRawData())); 133 ASSERT_TRUE(result.IsString()); 134 135 auto symbolValue = ecmaVM->GetFactory()->NewFromASCII("Symbol(aaa)"); 136 ASSERT_EQ(EcmaStringAccessor::Compare(ecmaVM, symbolValue, resultHandle), 0); 137} 138 139// new Symbol().valueOf() 140HWTEST_F_L0(BuiltinsSymbolTest, SymbolNoParameterValueOf) 141{ 142 auto ecmaVM = thread->GetEcmaVM(); 143 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv(); 144 145 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewJSSymbol(); 146 147 std::vector<JSTaggedValue> args{}; 148 auto result = SymbolAlgorithm(thread, symbol.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_VALUE_OF); 149 150 EXPECT_TRUE(result.IsSymbol()); 151 ASSERT_EQ(result.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true); 152 153 JSHandle<JSFunction> symbolObject(env->GetSymbolFunction()); 154 JSHandle<JSTaggedValue> symbolValue(symbol); 155 JSHandle<JSPrimitiveRef> symbolRef = ecmaVM->GetFactory()->NewJSPrimitiveRef(symbolObject, symbolValue); 156 157 auto otherResult = SymbolAlgorithm(thread, symbolRef.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_VALUE_OF); 158 EXPECT_TRUE(otherResult.IsSymbol()); 159 ASSERT_EQ(otherResult.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true); 160 161 // Undefined not Object 162 result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 4, AlgorithmType::VALUE_OF); 163 EXPECT_TRUE(thread->HasPendingException()); 164 EXPECT_EQ(result, JSTaggedValue::Exception()); 165 thread->ClearException(); 166 167 // No Symbol data 168 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 169 JSHandle<TaggedArray> array(factory->NewTaggedArray(3)); 170 result = SymbolAlgorithm(thread, array.GetTaggedValue(), args, 4, AlgorithmType::VALUE_OF); 171 EXPECT_TRUE(thread->HasPendingException()); 172 EXPECT_EQ(result, JSTaggedValue::Exception()); 173 thread->ClearException(); 174} 175 176// new Symbol("bbb").valueOf() 177HWTEST_F_L0(BuiltinsSymbolTest, SymbolWithParameterValueOf) 178{ 179 auto ecmaVM = thread->GetEcmaVM(); 180 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv(); 181 182 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar("bbb"); 183 184 std::vector<JSTaggedValue> args{}; 185 auto result = SymbolAlgorithm(thread, symbol.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_VALUE_OF); 186 187 EXPECT_TRUE(result.IsSymbol()); 188 ASSERT_EQ(result.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true); 189 190 JSHandle<JSFunction> symbolObject(env->GetSymbolFunction()); 191 JSHandle<JSTaggedValue> symbolValue(symbol); 192 JSHandle<JSPrimitiveRef> symbolRef = ecmaVM->GetFactory()->NewJSPrimitiveRef(symbolObject, symbolValue); 193 194 auto otherResult = SymbolAlgorithm(thread, symbolRef.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_VALUE_OF); 195 EXPECT_TRUE(otherResult.IsSymbol()); 196 ASSERT_EQ(otherResult.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true); 197} 198 199// new Symbol().for 200HWTEST_F_L0(BuiltinsSymbolTest, SymbolWithParameterFor) 201{ 202 auto ecmaVM = thread->GetEcmaVM(); 203 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv(); 204 205 JSHandle<SymbolTable> tableHandle(env->GetRegisterSymbols()); 206 207 JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII("ccc"); 208 ASSERT_EQ(EcmaStringAccessor(string).GetLength(), 3U); 209 JSHandle<JSTaggedValue> string_handle(string); 210 ASSERT_EQ(tableHandle->ContainsKey(string_handle.GetTaggedValue()), false); 211 212 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewSymbolWithTableWithChar("ccc"); 213 214 std::vector<JSTaggedValue> args{string.GetTaggedValue()}; 215 auto result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_FOR); 216 ASSERT_EQ(tableHandle->ContainsKey(string_handle.GetTaggedValue()), true); 217 218 JSTaggedValue target(*symbol); 219 ASSERT_EQ(result.GetRawData() == target.GetRawData(), true); 220} 221 222// Symbol.keyFor (sym) 223HWTEST_F_L0(BuiltinsSymbolTest, SymbolKeyFor) 224{ 225 auto ecmaVM = thread->GetEcmaVM(); 226 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv(); 227 228 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar("bbb"); 229 230 std::vector<JSTaggedValue> args{symbol.GetTaggedValue()}; 231 auto result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_KEY_FOR); 232 ASSERT_EQ(result.GetRawData(), JSTaggedValue::VALUE_UNDEFINED); 233 234 JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII("ccc"); 235 ASSERT_EQ(EcmaStringAccessor(string).GetLength(), 3U); 236 237 args[0] = string.GetTaggedValue(); 238 SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_FOR); 239 240 JSHandle<JSSymbol> otherSymbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar("ccc"); 241 args[0] = otherSymbol.GetTaggedValue(); 242 auto otherResult = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_KEY_FOR); 243 ASSERT_TRUE(otherResult.IsString()); 244 JSHandle<SymbolTable> tableHandle(env->GetRegisterSymbols()); 245 JSTaggedValue stringValue(*string); 246 ASSERT_EQ(tableHandle->ContainsKey(stringValue), true); 247 248 // not symbol 249 args[0] = JSTaggedValue::Undefined(); 250 result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::KEY_FOR); 251 EXPECT_TRUE(thread->HasPendingException()); 252 EXPECT_EQ(result, JSTaggedValue::Exception()); 253 thread->ClearException(); 254} 255 256// Symbol.ToPrimitive() 257HWTEST_F_L0(BuiltinsSymbolTest, SymbolToPrimitive) 258{ 259 auto ecmaVM = thread->GetEcmaVM(); 260 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv(); 261 262 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewJSSymbol(); 263 264 std::vector<JSTaggedValue> args{}; 265 auto result = SymbolAlgorithm(thread, symbol.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_TO_PRIMITIVE); 266 267 EXPECT_TRUE(result.IsSymbol()); 268 ASSERT_EQ(result.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true); 269 270 JSHandle<JSFunction> symbolObject(env->GetSymbolFunction()); 271 JSHandle<JSTaggedValue> symbolValue(symbol); 272 JSHandle<JSPrimitiveRef> symbolRef = ecmaVM->GetFactory()->NewJSPrimitiveRef(symbolObject, symbolValue); 273 274 auto otherResult = 275 SymbolAlgorithm(thread, symbolRef.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_TO_PRIMITIVE); 276 EXPECT_TRUE(otherResult.IsSymbol()); 277 ASSERT_EQ(otherResult.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true); 278} 279 280// constructor 281HWTEST_F_L0(BuiltinsSymbolTest, SymbolConstructor) 282{ 283 auto ecmaVM = thread->GetEcmaVM(); 284 285 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); 286 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 287 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); 288 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined()); 289 290 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 291 JSTaggedValue result = BuiltinsSymbol::SymbolConstructor(ecmaRuntimeCallInfo); 292 TestHelper::TearDownFrame(thread, prev); 293 EXPECT_TRUE(result.IsSymbol()); 294 JSSymbol *sym = reinterpret_cast<JSSymbol *>(result.GetRawData()); 295 ASSERT_EQ(sym->GetDescription().IsUndefined(), true); 296 297 JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII("ddd"); 298 299 auto otherEcmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); 300 otherEcmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 301 otherEcmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); 302 otherEcmaRuntimeCallInfo->SetCallArg(0, string.GetTaggedValue()); 303 304 prev = TestHelper::SetupFrame(thread, otherEcmaRuntimeCallInfo); 305 JSTaggedValue result1 = BuiltinsSymbol::SymbolConstructor(otherEcmaRuntimeCallInfo); 306 TestHelper::TearDownFrame(thread, prev); 307 JSHandle<EcmaString> resultString = JSTaggedValue::ToString( 308 thread, JSHandle<JSTaggedValue>(thread, reinterpret_cast<JSSymbol *>(result1.GetRawData())->GetDescription())); 309 ASSERT_EQ(EcmaStringAccessor::Compare(ecmaVM, resultString, string), 0); 310} 311 312HWTEST_F_L0(BuiltinsSymbolTest, SymbolGetter) 313{ 314 auto ecmaVM = thread->GetEcmaVM(); 315 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv(); 316 317 JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar(""); 318 JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII(""); 319 320 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); 321 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 322 ecmaRuntimeCallInfo->SetThis(symbol.GetTaggedValue()); 323 324 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 325 JSTaggedValue result = BuiltinsSymbol::DescriptionGetter(ecmaRuntimeCallInfo); 326 TestHelper::TearDownFrame(thread, prev); 327 ASSERT_TRUE(result.IsString()); 328 EcmaString *resString = reinterpret_cast<EcmaString *>(result.GetRawData()); 329 ASSERT_EQ(EcmaStringAccessor(resString).GetLength(), 0U); 330 ASSERT_EQ(EcmaStringAccessor::StringsAreEqual(resString, *string), true); 331 332 // value is not symbol 333 JSHandle<JSFunction> symbolObject(env->GetSymbolFunction()); 334 JSHandle<JSTaggedValue> symbolValue(symbol); 335 JSHandle<JSPrimitiveRef> symbolRef = ecmaVM->GetFactory()->NewJSPrimitiveRef(symbolObject, symbolValue); 336 ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); 337 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 338 ecmaRuntimeCallInfo->SetThis(symbolRef.GetTaggedValue()); 339 340 prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 341 result = BuiltinsSymbol::DescriptionGetter(ecmaRuntimeCallInfo); 342 TestHelper::TearDownFrame(thread, prev); 343 ASSERT_TRUE(result.IsString()); 344 resString = reinterpret_cast<EcmaString *>(result.GetRawData()); 345 ASSERT_EQ(EcmaStringAccessor(resString).GetLength(), 0U); 346 ASSERT_EQ(EcmaStringAccessor::StringsAreEqual(resString, *string), true); 347 348 // Undefined 349 ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); 350 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 351 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); 352 353 prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 354 result = BuiltinsSymbol::DescriptionGetter(ecmaRuntimeCallInfo); 355 TestHelper::TearDownFrame(thread, prev); 356 EXPECT_TRUE(thread->HasPendingException()); 357 EXPECT_EQ(result, JSTaggedValue::Exception()); 358 thread->ClearException(); 359} 360} // namespace panda::test 361