• 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_set.h"
17 #include "ecmascript/ecma_string.h"
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/global_env.h"
20 
21 #include "ecmascript/js_array.h"
22 #include "ecmascript/js_handle.h"
23 #include "ecmascript/js_hclass.h"
24 #include "ecmascript/js_object-inl.h"
25 #include "ecmascript/js_set.h"
26 #include "ecmascript/js_set_iterator.h"
27 #include "ecmascript/js_tagged_value.h"
28 #include "ecmascript/js_thread.h"
29 #include "ecmascript/object_factory.h"
30 #include "ecmascript/tests/test_helper.h"
31 #include "utils/bit_utils.h"
32 
33 using namespace panda::ecmascript;
34 using namespace panda::ecmascript::builtins;
35 
36 namespace panda::test {
37 using BuiltinsSet = ecmascript::builtins::BuiltinsSet;
38 using JSSet = ecmascript::JSSet;
39 
40 class BuiltinsSetTest : public testing::Test {
41 public:
SetUpTestCase()42     static void SetUpTestCase()
43     {
44         GTEST_LOG_(INFO) << "SetUpTestCase";
45     }
46 
TearDownTestCase()47     static void TearDownTestCase()
48     {
49         GTEST_LOG_(INFO) << "TearDownCase";
50     }
51 
SetUp()52     void SetUp() override
53     {
54         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
55     }
56 
TearDown()57     void TearDown() override
58     {
59         TestHelper::DestroyEcmaVMWithScope(instance, scope);
60     }
61 
62     PandaVM *instance {nullptr};
63     EcmaHandleScope *scope {nullptr};
64     JSThread *thread {nullptr};
65 
66     class TestClass : public base::BuiltinsBase {
67     public:
TestFunc(EcmaRuntimeCallInfo * argv)68         static JSTaggedValue TestFunc(EcmaRuntimeCallInfo *argv)
69         {
70             JSTaggedValue key = GetCallArg(argv, 0).GetTaggedValue();
71             if (key.IsUndefined()) {
72                 return JSTaggedValue::Undefined();
73             }
74             JSArray *jsArray = JSArray::Cast(GetThis(argv)->GetTaggedObject());
75             int length = jsArray->GetArrayLength() + 1;
76             jsArray->SetArrayLength(argv->GetThread(), length);
77             return JSTaggedValue::Undefined();
78         }
79     };
80 };
81 
CreateBuiltinsSet(JSThread * thread)82 JSSet *CreateBuiltinsSet(JSThread *thread)
83 {
84     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
85     JSHandle<JSFunction> newTarget(env->GetBuiltinsSetFunction());
86     // 4 : test case
87     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 4);
88     ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
89     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
90 
91     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
92     JSTaggedValue result = BuiltinsSet::SetConstructor(ecmaRuntimeCallInfo.get());
93 
94     EXPECT_TRUE(result.IsECMAObject());
95     return JSSet::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData()));
96 }
97 // new Set("abrupt").toString()
HWTEST_F_L0(BuiltinsSetTest,CreateAndGetSize)98 HWTEST_F_L0(BuiltinsSetTest, CreateAndGetSize)
99 {
100     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
101     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
102     JSHandle<JSFunction> newTarget(env->GetBuiltinsSetFunction());
103     JSHandle<JSSet> set(thread, CreateBuiltinsSet(thread));
104 
105     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
106     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
107     ecmaRuntimeCallInfo->SetThis(set.GetTaggedValue());
108     ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
109     {
110         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
111         JSTaggedValue result = BuiltinsSet::GetSize(ecmaRuntimeCallInfo.get());
112 
113         EXPECT_EQ(result.GetRawData(), JSTaggedValue(0).GetRawData());
114     }
115 
116     JSHandle<TaggedArray> array(factory->NewTaggedArray(5));
117     for (int i = 0; i < 5; i++) {
118         array->Set(thread, i, JSTaggedValue(i));
119     }
120 
121     JSHandle<JSArray> values = JSArray::CreateArrayFromList(thread, array);
122     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
123     ecmaRuntimeCallInfo1->SetFunction(newTarget.GetTaggedValue());
124     ecmaRuntimeCallInfo1->SetThis(set.GetTaggedValue());
125     ecmaRuntimeCallInfo1->SetCallArg(0, values.GetTaggedValue());
126     ecmaRuntimeCallInfo1->SetNewTarget(newTarget.GetTaggedValue());
127     {
128         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
129         JSTaggedValue result1 = BuiltinsSet::SetConstructor(ecmaRuntimeCallInfo1.get());
130 
131         EXPECT_EQ(JSSet::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()))->GetSize(), 5);
132     }
133 }
134 
HWTEST_F_L0(BuiltinsSetTest,AddAndHas)135 HWTEST_F_L0(BuiltinsSetTest, AddAndHas)
136 {
137     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
138     // create jsSet
139     JSHandle<JSSet> set(thread, CreateBuiltinsSet(thread));
140     JSHandle<JSTaggedValue> key(thread, factory->NewFromCanBeCompressString("key").GetTaggedValue());
141 
142     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
143     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
144     ecmaRuntimeCallInfo->SetThis(set.GetTaggedValue());
145     ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
146 
147     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
148     JSTaggedValue result1 = BuiltinsSet::Has(ecmaRuntimeCallInfo.get());
149 
150     EXPECT_EQ(result1.GetRawData(), JSTaggedValue::False().GetRawData());
151 
152     // test Add()
153     JSTaggedValue result2 = BuiltinsSet::Add(ecmaRuntimeCallInfo.get());
154     EXPECT_TRUE(result2.IsECMAObject());
155     JSSet *jsSet = JSSet::Cast(reinterpret_cast<TaggedObject *>(result2.GetRawData()));
156     EXPECT_EQ(jsSet->GetSize(), 1);
157 
158     // test Has()
159     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
160     ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
161     ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(jsSet));
162     ecmaRuntimeCallInfo1->SetCallArg(0, key.GetTaggedValue());
163     {
164         [[maybe_unused]] auto prevLocal = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
165         JSTaggedValue result3 = BuiltinsSet::Has(ecmaRuntimeCallInfo1.get());
166 
167         EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
168     }
169 
170     // test -0.0
171     JSHandle<JSTaggedValue> negativeZero(thread, JSTaggedValue(-0.0));
172     JSHandle<JSTaggedValue> positiveZero(thread, JSTaggedValue(+0.0));
173     auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
174     ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
175     ecmaRuntimeCallInfo2->SetThis(JSTaggedValue(jsSet));
176     ecmaRuntimeCallInfo2->SetCallArg(0, negativeZero.GetTaggedValue());
177     {
178         [[maybe_unused]] auto prevLocal = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get());
179         BuiltinsSet::Add(ecmaRuntimeCallInfo.get());
180     }
181 
182     auto ecmaRuntimeCallInfo3 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
183     ecmaRuntimeCallInfo3->SetFunction(JSTaggedValue::Undefined());
184     ecmaRuntimeCallInfo3->SetThis(JSTaggedValue(jsSet));
185     ecmaRuntimeCallInfo3->SetCallArg(0, positiveZero.GetTaggedValue());
186     {
187         [[maybe_unused]] auto prevLocal = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo3.get());
188         JSTaggedValue result4 = BuiltinsSet::Has(ecmaRuntimeCallInfo3.get());
189 
190         EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
191     }
192 }
193 
HWTEST_F_L0(BuiltinsSetTest,ForEach)194 HWTEST_F_L0(BuiltinsSetTest, ForEach)
195 {
196     // generate a set has 5 entry{key1,key2,key3,key4,key5}
197     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
198     JSHandle<JSSet> set(thread, CreateBuiltinsSet(thread));
199     char keyArray[] = "key0";
200     for (int i = 0; i < 5; i++) {
201         keyArray[3] = '1' + i;
202         JSHandle<JSTaggedValue> key(factory->NewFromCanBeCompressString(keyArray));
203         auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
204         ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
205         ecmaRuntimeCallInfo->SetThis(set.GetTaggedValue());
206         ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
207 
208         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
209         JSTaggedValue result1 = BuiltinsSet::Add(ecmaRuntimeCallInfo.get());
210 
211         EXPECT_TRUE(result1.IsECMAObject());
212         JSSet *jsSet = JSSet::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()));
213         EXPECT_EQ(jsSet->GetSize(), i + 1);
214     }
215     // test foreach
216     JSHandle<JSArray> jsArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
217     JSHandle<JSFunction> func =
218         factory->NewJSFunction(thread->GetEcmaVM()->GetGlobalEnv(), reinterpret_cast<void *>(TestClass::TestFunc));
219 
220     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
221     ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
222     ecmaRuntimeCallInfo1->SetThis(set.GetTaggedValue());
223     ecmaRuntimeCallInfo1->SetCallArg(0, func.GetTaggedValue());
224     ecmaRuntimeCallInfo1->SetCallArg(1, jsArray.GetTaggedValue());
225 
226     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
227     JSTaggedValue result2 = BuiltinsSet::ForEach(ecmaRuntimeCallInfo1.get());
228 
229     EXPECT_EQ(result2.GetRawData(), JSTaggedValue::VALUE_UNDEFINED);
230     EXPECT_EQ(jsArray->GetArrayLength(), 5);
231 }
232 
HWTEST_F_L0(BuiltinsSetTest,DeleteAndRemove)233 HWTEST_F_L0(BuiltinsSetTest, DeleteAndRemove)
234 {
235     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
236     // create jsSet
237     JSHandle<JSSet> set(thread, CreateBuiltinsSet(thread));
238 
239     // add 40 keys
240     char keyArray[] = "key0";
241     for (int i = 0; i < 40; i++) {
242         keyArray[3] = '1' + i;
243         JSHandle<JSTaggedValue> key(factory->NewFromCanBeCompressString(keyArray));
244 
245         auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
246         ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
247         ecmaRuntimeCallInfo->SetThis(set.GetTaggedValue());
248         ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
249 
250         [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
251         JSTaggedValue result1 = BuiltinsSet::Add(ecmaRuntimeCallInfo.get());
252 
253         EXPECT_TRUE(result1.IsECMAObject());
254         JSSet *jsSet = JSSet::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()));
255         EXPECT_EQ(jsSet->GetSize(), i + 1);
256     }
257     // whether jsSet has delete key
258     keyArray[3] = '1' + 8;
259     JSHandle<JSTaggedValue> deleteKey(factory->NewFromCanBeCompressString(keyArray));
260 
261     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
262     ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
263     ecmaRuntimeCallInfo1->SetThis(set.GetTaggedValue());
264     ecmaRuntimeCallInfo1->SetCallArg(0, deleteKey.GetTaggedValue());
265 
266     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
267     JSTaggedValue result2 = BuiltinsSet::Has(ecmaRuntimeCallInfo1.get());
268 
269     EXPECT_EQ(result2.GetRawData(), JSTaggedValue::True().GetRawData());
270 
271     // delete
272     JSTaggedValue result3 = BuiltinsSet::Delete(ecmaRuntimeCallInfo1.get());
273 
274     EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
275 
276     // check deleteKey is deleted
277     JSTaggedValue result4 = BuiltinsSet::Has(ecmaRuntimeCallInfo1.get());
278 
279     EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
280 
281     JSTaggedValue result5 = BuiltinsSet::GetSize(ecmaRuntimeCallInfo1.get());
282 
283     EXPECT_EQ(result5.GetRawData(), JSTaggedValue(39).GetRawData());
284 
285     // clear
286     JSTaggedValue result6 = BuiltinsSet::Clear(ecmaRuntimeCallInfo1.get());
287     EXPECT_EQ(result6.GetRawData(), JSTaggedValue::VALUE_UNDEFINED);
288     EXPECT_EQ(set->GetSize(), 0);
289 }
290 
HWTEST_F_L0(BuiltinsSetTest,Species)291 HWTEST_F_L0(BuiltinsSetTest, Species)
292 {
293     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
294     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
295     JSHandle<JSTaggedValue> set(thread, CreateBuiltinsSet(thread));
296     JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol();
297     EXPECT_TRUE(!speciesSymbol->IsUndefined());
298 
299     JSHandle<JSFunction> newTarget(env->GetBuiltinsSetFunction());
300 
301     JSTaggedValue value =
302         JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(newTarget), speciesSymbol).GetValue().GetTaggedValue();
303     JSHandle<JSTaggedValue> valueHandle(thread, value);
304     EXPECT_EQ(value, newTarget.GetTaggedValue());
305 
306     // to string tag
307     JSHandle<JSTaggedValue> toStringTagSymbol = env->GetToStringTagSymbol();
308     JSHandle<EcmaString> stringTag(JSObject::GetProperty(thread, set, toStringTagSymbol).GetValue());
309     JSHandle<EcmaString> str = factory->NewFromCanBeCompressString("Set");
310     EXPECT_TRUE(!stringTag.GetTaggedValue().IsUndefined());
311     EXPECT_TRUE(EcmaString::StringsAreEqual(*str, *stringTag));
312 
313     JSHandle<JSFunction> constructor = JSHandle<JSFunction>::Cast(JSTaggedValue::ToObject(thread, valueHandle));
314     EXPECT_EQ(JSHandle<JSObject>(set)->GetPrototype(thread), constructor->GetFunctionPrototype());
315 
316     JSHandle<JSTaggedValue> key1(factory->NewFromCanBeCompressString("add"));
317     JSTaggedValue value1 = JSObject::GetProperty(thread, set, key1).GetValue().GetTaggedValue();
318     EXPECT_FALSE(value1.IsUndefined());
319 
320     JSHandle<JSTaggedValue> key2(factory->NewFromCanBeCompressString("has"));
321     JSTaggedValue value2 = JSObject::GetProperty(thread, set, key1).GetValue().GetTaggedValue();
322     EXPECT_FALSE(value2.IsUndefined());
323 
324     JSHandle<JSTaggedValue> key3(factory->NewFromCanBeCompressString("clear"));
325     JSTaggedValue value3 = JSObject::GetProperty(thread, set, key1).GetValue().GetTaggedValue();
326     EXPECT_FALSE(value3.IsUndefined());
327 
328     JSHandle<JSTaggedValue> key4(factory->NewFromCanBeCompressString("size"));
329     JSTaggedValue value4 = JSObject::GetProperty(thread, set, key1).GetValue().GetTaggedValue();
330     EXPECT_FALSE(value4.IsUndefined());
331 
332     JSHandle<JSTaggedValue> key5(factory->NewFromCanBeCompressString("delete"));
333     JSTaggedValue value5 = JSObject::GetProperty(thread, set, key1).GetValue().GetTaggedValue();
334     EXPECT_FALSE(value5.IsUndefined());
335 
336     JSHandle<JSTaggedValue> key6(factory->NewFromCanBeCompressString("forEach"));
337     JSTaggedValue value6 = JSObject::GetProperty(thread, set, key1).GetValue().GetTaggedValue();
338     EXPECT_FALSE(value6.IsUndefined());
339 }
340 
HWTEST_F_L0(BuiltinsSetTest,GetIterator)341 HWTEST_F_L0(BuiltinsSetTest, GetIterator)
342 {
343     JSHandle<JSTaggedValue> set(thread, CreateBuiltinsSet(thread));
344 
345     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
346     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
347     ecmaRuntimeCallInfo->SetThis(set.GetTaggedValue());
348     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
349 
350     // test Values()
351     JSTaggedValue result = BuiltinsSet::Values(ecmaRuntimeCallInfo.get());
352     JSHandle<JSSetIterator> iter(thread, result);
353     EXPECT_TRUE(iter->IsJSSetIterator());
354     EXPECT_EQ(IterationKind::VALUE, IterationKind(iter->GetIterationKind()));
355     EXPECT_EQ(JSSet::Cast(set.GetTaggedValue().GetTaggedObject())->GetLinkedSet(), iter->GetIteratedSet());
356 
357     // test entrys()
358     JSTaggedValue result2 = BuiltinsSet::Entries(ecmaRuntimeCallInfo.get());
359     JSHandle<JSSetIterator> iter2(thread, result2);
360     EXPECT_TRUE(iter2->IsJSSetIterator());
361     EXPECT_EQ(IterationKind::KEY_AND_VALUE, iter2->GetIterationKind());
362 }
363 }  // namespace panda::test
364