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