• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 using namespace panda::ecmascript;
34 using namespace panda::ecmascript::builtins;
35 
36 namespace panda::test {
37 using Symbol = ecmascript::builtins::BuiltinsSymbol;
38 using BuiltinsBase = panda::ecmascript::base::BuiltinsBase;
39 
40 class BuiltinsSymbolTest : public BaseTestWithScope<false> {
41 };
42 
43 enum 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 
SymbolAlgorithm(JSThread * thread,JSTaggedValue thisArg,std::vector<JSTaggedValue> & args,uint32_t argLen=8,AlgorithmType type=AlgorithmType::TO_STRING)53 JSTaggedValue 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()
HWTEST_F_L0(BuiltinsSymbolTest,SymbolNoParameterToString)94 HWTEST_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()
HWTEST_F_L0(BuiltinsSymbolTest,SymbolWithParameterToString)125 HWTEST_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()
HWTEST_F_L0(BuiltinsSymbolTest,SymbolNoParameterValueOf)140 HWTEST_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()
HWTEST_F_L0(BuiltinsSymbolTest,SymbolWithParameterValueOf)177 HWTEST_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
HWTEST_F_L0(BuiltinsSymbolTest,SymbolWithParameterFor)200 HWTEST_F_L0(BuiltinsSymbolTest, SymbolWithParameterFor)
201 {
202     auto ecmaVM = thread->GetEcmaVM();
203 
204     JSHandle<SymbolTable> tableHandle(thread, ecmaVM->GetRegisterSymbols());
205 
206     JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII("ccc");
207     ASSERT_EQ(EcmaStringAccessor(string).GetLength(), 3U);
208     JSHandle<JSTaggedValue> string_handle(string);
209     ASSERT_EQ(tableHandle->ContainsKey(thread, string_handle.GetTaggedValue()), false);
210 
211     JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewSymbolWithTableWithChar("ccc");
212 
213     std::vector<JSTaggedValue> args{string.GetTaggedValue()};
214     auto result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_FOR);
215     ASSERT_EQ(tableHandle->ContainsKey(thread, string_handle.GetTaggedValue()), true);
216 
217     JSTaggedValue target(*symbol);
218     ASSERT_EQ(result.GetRawData() == target.GetRawData(), true);
219 }
220 
221 // Symbol.keyFor (sym)
HWTEST_F_L0(BuiltinsSymbolTest,SymbolKeyFor)222 HWTEST_F_L0(BuiltinsSymbolTest, SymbolKeyFor)
223 {
224     auto ecmaVM = thread->GetEcmaVM();
225 
226     JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar("bbb");
227 
228     std::vector<JSTaggedValue> args{symbol.GetTaggedValue()};
229     auto result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_KEY_FOR);
230     ASSERT_EQ(result.GetRawData(), JSTaggedValue::VALUE_UNDEFINED);
231 
232     JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII("ccc");
233     ASSERT_EQ(EcmaStringAccessor(string).GetLength(), 3U);
234 
235     args[0] = string.GetTaggedValue();
236     SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_FOR);
237 
238     JSHandle<JSSymbol> otherSymbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar("ccc");
239     args[0] = otherSymbol.GetTaggedValue();
240     auto otherResult = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::BUILTIN_KEY_FOR);
241     ASSERT_TRUE(otherResult.IsString());
242     JSHandle<SymbolTable> tableHandle(thread, ecmaVM->GetRegisterSymbols());
243     JSTaggedValue stringValue(*string);
244     ASSERT_EQ(tableHandle->ContainsKey(thread, stringValue), true);
245 
246     // not symbol
247     args[0] = JSTaggedValue::Undefined();
248     result = SymbolAlgorithm(thread, JSTaggedValue::Undefined(), args, 6, AlgorithmType::KEY_FOR);
249     EXPECT_TRUE(thread->HasPendingException());
250     EXPECT_EQ(result, JSTaggedValue::Exception());
251     thread->ClearException();
252 }
253 
254 // Symbol.ToPrimitive()
HWTEST_F_L0(BuiltinsSymbolTest,SymbolToPrimitive)255 HWTEST_F_L0(BuiltinsSymbolTest, SymbolToPrimitive)
256 {
257     auto ecmaVM = thread->GetEcmaVM();
258     JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
259 
260     JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewJSSymbol();
261 
262     std::vector<JSTaggedValue> args{};
263     auto result = SymbolAlgorithm(thread, symbol.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_TO_PRIMITIVE);
264 
265     EXPECT_TRUE(result.IsSymbol());
266     ASSERT_EQ(result.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true);
267 
268     JSHandle<JSFunction> symbolObject(env->GetSymbolFunction());
269     JSHandle<JSTaggedValue> symbolValue(symbol);
270     JSHandle<JSPrimitiveRef> symbolRef = ecmaVM->GetFactory()->NewJSPrimitiveRef(symbolObject, symbolValue);
271 
272     auto otherResult =
273         SymbolAlgorithm(thread, symbolRef.GetTaggedValue(), args, 4, AlgorithmType::BUILTIN_TO_PRIMITIVE);
274     EXPECT_TRUE(otherResult.IsSymbol());
275     ASSERT_EQ(otherResult.GetRawData() == (JSTaggedValue(*symbol)).GetRawData(), true);
276 }
277 
278 // constructor
HWTEST_F_L0(BuiltinsSymbolTest,SymbolConstructor)279 HWTEST_F_L0(BuiltinsSymbolTest, SymbolConstructor)
280 {
281     auto ecmaVM = thread->GetEcmaVM();
282 
283     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
284     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
285     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
286     ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
287 
288     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
289     JSTaggedValue result = BuiltinsSymbol::SymbolConstructor(ecmaRuntimeCallInfo);
290     TestHelper::TearDownFrame(thread, prev);
291     EXPECT_TRUE(result.IsSymbol());
292     JSSymbol *sym = reinterpret_cast<JSSymbol *>(result.GetRawData());
293     ASSERT_EQ(sym->GetDescription(thread).IsUndefined(), true);
294 
295     JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII("ddd");
296 
297     auto otherEcmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
298     otherEcmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
299     otherEcmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
300     otherEcmaRuntimeCallInfo->SetCallArg(0, string.GetTaggedValue());
301 
302     prev = TestHelper::SetupFrame(thread, otherEcmaRuntimeCallInfo);
303     JSTaggedValue result1 = BuiltinsSymbol::SymbolConstructor(otherEcmaRuntimeCallInfo);
304     TestHelper::TearDownFrame(thread, prev);
305     JSHandle<EcmaString> resultString = JSTaggedValue::ToString(
306         thread,
307         JSHandle<JSTaggedValue>(thread, reinterpret_cast<JSSymbol *>(result1.GetRawData())->GetDescription(thread)));
308     ASSERT_EQ(EcmaStringAccessor::Compare(ecmaVM, resultString, string), 0);
309 }
310 
HWTEST_F_L0(BuiltinsSymbolTest,SymbolGetter)311 HWTEST_F_L0(BuiltinsSymbolTest, SymbolGetter)
312 {
313     auto ecmaVM = thread->GetEcmaVM();
314     JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
315 
316     JSHandle<JSSymbol> symbol = ecmaVM->GetFactory()->NewPublicSymbolWithChar("");
317     JSHandle<EcmaString> string = ecmaVM->GetFactory()->NewFromASCII("");
318 
319     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
320     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
321     ecmaRuntimeCallInfo->SetThis(symbol.GetTaggedValue());
322 
323     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
324     JSTaggedValue result = BuiltinsSymbol::DescriptionGetter(ecmaRuntimeCallInfo);
325     TestHelper::TearDownFrame(thread, prev);
326     ASSERT_TRUE(result.IsString());
327     EcmaString *resString = reinterpret_cast<EcmaString *>(result.GetRawData());
328     ASSERT_EQ(EcmaStringAccessor(resString).GetLength(), 0U);
329     ASSERT_EQ(EcmaStringAccessor::StringsAreEqual(thread, resString, *string), true);
330 
331     // value is not symbol
332     JSHandle<JSFunction> symbolObject(env->GetSymbolFunction());
333     JSHandle<JSTaggedValue> symbolValue(symbol);
334     JSHandle<JSPrimitiveRef> symbolRef = ecmaVM->GetFactory()->NewJSPrimitiveRef(symbolObject, symbolValue);
335     ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
336     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
337     ecmaRuntimeCallInfo->SetThis(symbolRef.GetTaggedValue());
338 
339     prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
340     result = BuiltinsSymbol::DescriptionGetter(ecmaRuntimeCallInfo);
341     TestHelper::TearDownFrame(thread, prev);
342     ASSERT_TRUE(result.IsString());
343     resString = reinterpret_cast<EcmaString *>(result.GetRawData());
344     ASSERT_EQ(EcmaStringAccessor(resString).GetLength(), 0U);
345     ASSERT_EQ(EcmaStringAccessor::StringsAreEqual(thread, resString, *string), true);
346 
347     // Undefined
348     ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
349     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
350     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
351 
352     prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
353     result = BuiltinsSymbol::DescriptionGetter(ecmaRuntimeCallInfo);
354     TestHelper::TearDownFrame(thread, prev);
355     EXPECT_TRUE(thread->HasPendingException());
356     EXPECT_EQ(result, JSTaggedValue::Exception());
357     thread->ClearException();
358 }
359 }  // namespace panda::test
360