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