1/*
2 * Copyright (c) 2022 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/containers/containers_private.h"
17#include "ecmascript/containers/containers_treeset.h"
18#include "ecmascript/ecma_runtime_call_info.h"
19#include "ecmascript/global_env.h"
20#include "ecmascript/js_api/js_api_tree_set.h"
21#include "ecmascript/js_api/js_api_tree_set_iterator.h"
22#include "ecmascript/js_handle.h"
23#include "ecmascript/js_tagged_value-inl.h"
24#include "ecmascript/js_thread.h"
25#include "ecmascript/object_factory.h"
26#include "ecmascript/tests/test_helper.h"
27#include "ecmascript/containers/tests/containers_test_helper.h"
28
29using namespace panda::ecmascript;
30using namespace panda::ecmascript::containers;
31
32namespace panda::test {
33class ContainersTreeSetTest : public testing::Test {
34public:
35    static void SetUpTestCase()
36    {
37        GTEST_LOG_(INFO) << "SetUpTestCase";
38    }
39
40    static void TearDownTestCase()
41    {
42        GTEST_LOG_(INFO) << "TearDownCase";
43    }
44
45    void SetUp() override
46    {
47        TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
48    }
49
50    void TearDown() override
51    {
52        TestHelper::DestroyEcmaVMWithScope(instance, scope);
53    }
54
55    EcmaVM *instance {nullptr};
56    EcmaHandleScope *scope {nullptr};
57    JSThread *thread {nullptr};
58
59    class TestClass : public base::BuiltinsBase {
60    public:
61        static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
62        {
63            JSThread *thread = argv->GetThread();
64            JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
65            JSHandle<JSTaggedValue> key = GetCallArg(argv, 1);
66            JSHandle<JSAPITreeSet> set(GetCallArg(argv, 2)); // 2 means the second arg
67            EXPECT_EQ(key.GetTaggedValue(), value.GetTaggedValue());
68            JSAPITreeSet::Delete(thread, set, key);
69
70            JSHandle<JSAPITreeSet> jsTreeSet(GetThis(argv));
71            JSAPITreeSet::Add(thread, jsTreeSet, key);
72            return JSTaggedValue::Undefined();
73        }
74
75        static JSTaggedValue TestCompareFunction(EcmaRuntimeCallInfo *argv)
76        {
77            JSThread *thread = argv->GetThread();
78            JSHandle<JSTaggedValue> valueX = GetCallArg(argv, 0);
79            JSHandle<JSTaggedValue> valueY = GetCallArg(argv, 1);
80
81            if (valueX->IsString() && valueY->IsString()) {
82                auto xHandle = JSHandle<EcmaString>(valueX);
83                auto yHandle = JSHandle<EcmaString>(valueY);
84                int result = EcmaStringAccessor::Compare(thread->GetEcmaVM(), xHandle, yHandle);
85                if (result < 0) {
86                    return JSTaggedValue(1);
87                }
88                if (result == 0) {
89                    return JSTaggedValue(0);
90                }
91                return JSTaggedValue(-1);
92            }
93
94            if (valueX->IsNumber() && valueY->IsString()) {
95                return JSTaggedValue(1);
96            }
97            if (valueX->IsString() && valueY->IsNumber()) {
98                return JSTaggedValue(-1);
99            }
100
101            ComparisonResult res = ComparisonResult::UNDEFINED;
102            if (valueX->IsNumber() && valueY->IsNumber()) {
103                res = JSTaggedValue::StrictNumberCompare(valueY->GetNumber(), valueX->GetNumber());
104            } else {
105                res = JSTaggedValue::Compare(thread, valueY, valueX);
106            }
107            return res == ComparisonResult::GREAT ?
108                JSTaggedValue(1) : (res == ComparisonResult::LESS ? JSTaggedValue(-1) : JSTaggedValue(0));
109        }
110    };
111
112protected:
113    JSTaggedValue InitializeTreeSetConstructor()
114    {
115        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
116        JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
117
118        JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
119        JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
120        JSHandle<JSTaggedValue> value =
121            JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
122
123        auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
124        objCallInfo->SetFunction(JSTaggedValue::Undefined());
125        objCallInfo->SetThis(value.GetTaggedValue());
126        objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::TreeSet)));
127        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
128        JSTaggedValue result = ContainersPrivate::Load(objCallInfo);
129        TestHelper::TearDownFrame(thread, prev);
130
131        return result;
132    }
133
134    JSHandle<JSAPITreeSet> CreateJSAPITreeSet(JSTaggedValue compare = JSTaggedValue::Undefined())
135    {
136        JSHandle<JSTaggedValue> compareHandle(thread, compare);
137        JSHandle<JSFunction> newTarget(thread, InitializeTreeSetConstructor());
138        auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
139        objCallInfo->SetFunction(newTarget.GetTaggedValue());
140        objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
141        objCallInfo->SetThis(JSTaggedValue::Undefined());
142        objCallInfo->SetCallArg(0, compareHandle.GetTaggedValue());
143
144        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
145        JSTaggedValue result = ContainersTreeSet::TreeSetConstructor(objCallInfo);
146        TestHelper::TearDownFrame(thread, prev);
147        JSHandle<JSAPITreeSet> set(thread, result);
148        return set;
149    }
150};
151
152// new TreeSet()
153HWTEST_F_L0(ContainersTreeSetTest, TreeSetConstructor)
154{
155    // Initialize twice and return directly the second time
156    InitializeTreeSetConstructor();
157    JSHandle<JSFunction> newTarget(thread, InitializeTreeSetConstructor());
158
159    auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
160    objCallInfo->SetFunction(newTarget.GetTaggedValue());
161    objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
162    objCallInfo->SetThis(JSTaggedValue::Undefined());
163
164    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
165    JSTaggedValue result = ContainersTreeSet::TreeSetConstructor(objCallInfo);
166    TestHelper::TearDownFrame(thread, prev);
167
168    ASSERT_TRUE(result.IsJSAPITreeSet());
169    JSHandle<JSAPITreeSet> setHandle(thread, result);
170    JSTaggedValue resultProto = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(setHandle));
171    JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
172    ASSERT_EQ(resultProto, funcProto);
173    int size = setHandle->GetSize();
174    ASSERT_EQ(size, 0);
175
176    // test TreeSetConstructor exception
177    objCallInfo->SetCallArg(0, JSTaggedValue(0));
178    CONTAINERS_API_EXCEPTION_TEST(ContainersTreeSet, TreeSetConstructor, objCallInfo);
179    objCallInfo->SetNewTarget(JSTaggedValue::Undefined());
180    CONTAINERS_API_EXCEPTION_TEST(ContainersTreeSet, TreeSetConstructor, objCallInfo);
181}
182
183// treeset.add(value), treeset.has(value)
184HWTEST_F_L0(ContainersTreeSetTest, AddAndHas)
185{
186    constexpr int NODE_NUMBERS = 8;
187    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
188    for (int i = 0; i < NODE_NUMBERS; i++) {
189        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
190        callInfo->SetFunction(JSTaggedValue::Undefined());
191        callInfo->SetThis(tset.GetTaggedValue());
192        callInfo->SetCallArg(0, JSTaggedValue(i));
193
194        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
195        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
196        TestHelper::TearDownFrame(thread, prev);
197        EXPECT_TRUE(result.IsTrue());
198        EXPECT_EQ(tset->GetSize(), i + 1);
199    }
200    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS);
201
202    // test add string
203    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
204    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
205    std::string myKey("mykey");
206    for (int i = 0; i < NODE_NUMBERS; i++) {
207        std::string ikey = myKey + std::to_string(i);
208        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
209
210        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
211        callInfo->SetFunction(JSTaggedValue::Undefined());
212        callInfo->SetThis(tset.GetTaggedValue());
213        callInfo->SetCallArg(0, key.GetTaggedValue());
214
215        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
216        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
217        TestHelper::TearDownFrame(thread, prev);
218        EXPECT_TRUE(result.IsTrue());
219        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS + i + 1);
220    }
221    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2);
222
223    for (int i = 0; i < NODE_NUMBERS; i++) {
224        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
225        callInfo->SetFunction(JSTaggedValue::Undefined());
226        callInfo->SetThis(tset.GetTaggedValue());
227        callInfo->SetCallArg(0, JSTaggedValue(i));
228
229        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
230        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
231        TestHelper::TearDownFrame(thread, prev);
232        EXPECT_TRUE(result.IsTrue());
233    }
234    for (int i = 0; i < NODE_NUMBERS; i++) {
235        std::string ikey = myKey + std::to_string(i);
236        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
237
238        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
239        callInfo->SetFunction(JSTaggedValue::Undefined());
240        callInfo->SetThis(tset.GetTaggedValue());
241        callInfo->SetCallArg(0, key.GetTaggedValue());
242
243        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
244        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
245        TestHelper::TearDownFrame(thread, prev);
246        EXPECT_TRUE(result.IsTrue());
247    }
248}
249
250// treeset.remove(key)
251HWTEST_F_L0(ContainersTreeSetTest, Remove)
252{
253    constexpr int NODE_NUMBERS = 64;
254    constexpr int REMOVE_SIZE = 48;
255    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
256    for (int i = 0; i < NODE_NUMBERS; i++) {
257        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
258        callInfo->SetFunction(JSTaggedValue::Undefined());
259        callInfo->SetThis(tset.GetTaggedValue());
260        callInfo->SetCallArg(0, JSTaggedValue(i));
261
262        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
263        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
264        TestHelper::TearDownFrame(thread, prev);
265        EXPECT_TRUE(result.IsTrue());
266        EXPECT_EQ(tset->GetSize(), i + 1);
267    }
268
269    for (int i = 0; i < REMOVE_SIZE; i++) {
270        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
271        callInfo->SetFunction(JSTaggedValue::Undefined());
272        callInfo->SetThis(tset.GetTaggedValue());
273        callInfo->SetCallArg(0, JSTaggedValue(i));
274
275        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
276        JSTaggedValue rvalue = ContainersTreeSet::Remove(callInfo);
277        TestHelper::TearDownFrame(thread, prev);
278        EXPECT_TRUE(rvalue.IsTrue());
279    }
280    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - REMOVE_SIZE);
281
282    for (int i = 0; i < NODE_NUMBERS; i++) {
283        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
284        callInfo->SetFunction(JSTaggedValue::Undefined());
285        callInfo->SetThis(tset.GetTaggedValue());
286        callInfo->SetCallArg(0, JSTaggedValue(i));
287
288        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
289        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
290        TestHelper::TearDownFrame(thread, prev);
291        if (i < REMOVE_SIZE) {
292            EXPECT_TRUE(result.IsFalse());
293        } else {
294            EXPECT_TRUE(result.IsTrue());
295        }
296    }
297
298    // test add string
299    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
300    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
301    std::string myKey("mykey");
302    for (int i = 0; i < NODE_NUMBERS; i++) {
303        std::string ikey = myKey + std::to_string(i);
304        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
305
306        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
307        callInfo->SetFunction(JSTaggedValue::Undefined());
308        callInfo->SetThis(tset.GetTaggedValue());
309        callInfo->SetCallArg(0, key.GetTaggedValue());
310
311        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
312        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
313        TestHelper::TearDownFrame(thread, prev);
314        EXPECT_TRUE(result.IsTrue());
315        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - REMOVE_SIZE + i + 1);
316    }
317    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2 - REMOVE_SIZE);
318
319    for (int i = 0; i < REMOVE_SIZE; i++) {
320        std::string ikey = myKey + std::to_string(i);
321        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
322
323        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
324        callInfo->SetFunction(JSTaggedValue::Undefined());
325        callInfo->SetThis(tset.GetTaggedValue());
326        callInfo->SetCallArg(0, key.GetTaggedValue());
327
328        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
329        JSTaggedValue rvalue = ContainersTreeSet::Remove(callInfo);
330        TestHelper::TearDownFrame(thread, prev);
331        EXPECT_TRUE(rvalue.IsTrue());
332    }
333    EXPECT_EQ(tset->GetSize(), (NODE_NUMBERS - REMOVE_SIZE) * 2);
334    for (int i = 0; i < NODE_NUMBERS; i++) {
335        std::string ikey = myKey + std::to_string(i);
336        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
337
338        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
339        callInfo->SetFunction(JSTaggedValue::Undefined());
340        callInfo->SetThis(tset.GetTaggedValue());
341        callInfo->SetCallArg(0, key.GetTaggedValue());
342
343        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
344        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
345        TestHelper::TearDownFrame(thread, prev);
346        if (i < REMOVE_SIZE) {
347            EXPECT_TRUE(result.IsFalse());
348        } else {
349            EXPECT_TRUE(result.IsTrue());
350        }
351    }
352}
353
354// treeset.getFirstValue(), treeset.getLastValue()
355HWTEST_F_L0(ContainersTreeSetTest, GetFirstValueAndGetLastValue)
356{
357    constexpr int NODE_NUMBERS = 8;
358    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
359    for (int i = 0; i < NODE_NUMBERS; i++) {
360        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
361        callInfo->SetFunction(JSTaggedValue::Undefined());
362        callInfo->SetThis(tset.GetTaggedValue());
363        callInfo->SetCallArg(0, JSTaggedValue(i));
364
365        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
366        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
367        TestHelper::TearDownFrame(thread, prev);
368        EXPECT_TRUE(result.IsTrue());
369        EXPECT_EQ(tset->GetSize(), i + 1);
370    }
371    // test getFirstValue
372    {
373        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
374        callInfo->SetFunction(JSTaggedValue::Undefined());
375        callInfo->SetThis(tset.GetTaggedValue());
376
377        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
378        JSTaggedValue result = ContainersTreeSet::GetFirstValue(callInfo);
379        TestHelper::TearDownFrame(thread, prev);
380        EXPECT_EQ(result, JSTaggedValue(0));
381    }
382    // test getLastValue
383    {
384        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
385        callInfo->SetFunction(JSTaggedValue::Undefined());
386        callInfo->SetThis(tset.GetTaggedValue());
387
388        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
389        JSTaggedValue result = ContainersTreeSet::GetLastValue(callInfo);
390        TestHelper::TearDownFrame(thread, prev);
391        EXPECT_EQ(result, JSTaggedValue(NODE_NUMBERS - 1));
392    }
393
394    // test add string
395    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
396    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
397    std::string myKey("mykey");
398    for (int i = 0; i < NODE_NUMBERS; i++) {
399        std::string ikey = myKey + std::to_string(i);
400        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
401
402        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
403        callInfo->SetFunction(JSTaggedValue::Undefined());
404        callInfo->SetThis(tset.GetTaggedValue());
405        callInfo->SetCallArg(0, key.GetTaggedValue());
406
407        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
408        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
409        TestHelper::TearDownFrame(thread, prev);
410        EXPECT_TRUE(result.IsTrue());
411        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS + i + 1);
412    }
413    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2);
414
415    // test getFirstValue
416    {
417        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
418        callInfo->SetFunction(JSTaggedValue::Undefined());
419        callInfo->SetThis(tset.GetTaggedValue());
420
421        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
422        JSTaggedValue result = ContainersTreeSet::GetFirstValue(callInfo);
423        TestHelper::TearDownFrame(thread, prev);
424        EXPECT_EQ(result, JSTaggedValue(0));
425    }
426    // test getLastValue
427    {
428        std::string ikey = myKey + std::to_string(NODE_NUMBERS - 1);
429        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
430
431        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
432        callInfo->SetFunction(JSTaggedValue::Undefined());
433        callInfo->SetThis(tset.GetTaggedValue());
434
435        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
436        JSTaggedValue result = ContainersTreeSet::GetLastValue(callInfo);
437        TestHelper::TearDownFrame(thread, prev);
438        EXPECT_EQ(result, key.GetTaggedValue());
439    }
440}
441
442// treeset.clear()
443HWTEST_F_L0(ContainersTreeSetTest, Clear)
444{
445    constexpr int NODE_NUMBERS = 8;
446    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
447    for (int i = 0; i < NODE_NUMBERS; i++) {
448        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
449        callInfo->SetFunction(JSTaggedValue::Undefined());
450        callInfo->SetThis(tset.GetTaggedValue());
451        callInfo->SetCallArg(0, JSTaggedValue(i));
452
453        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
454        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
455        TestHelper::TearDownFrame(thread, prev);
456        EXPECT_TRUE(result.IsTrue());
457        EXPECT_EQ(tset->GetSize(), i + 1);
458    }
459    // test clear
460    {
461        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
462        callInfo->SetFunction(JSTaggedValue::Undefined());
463        callInfo->SetThis(tset.GetTaggedValue());
464
465        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
466        ContainersTreeSet::Clear(callInfo);
467        TestHelper::TearDownFrame(thread, prev);
468        EXPECT_EQ(tset->GetSize(), 0);
469    }
470    for (int i = 0; i < NODE_NUMBERS; i++) {
471        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
472        callInfo->SetFunction(JSTaggedValue::Undefined());
473        callInfo->SetThis(tset.GetTaggedValue());
474        callInfo->SetCallArg(0, JSTaggedValue(i));
475
476        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
477        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
478        TestHelper::TearDownFrame(thread, prev);
479        EXPECT_TRUE(result.IsFalse());
480    }
481
482    // test add string
483    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
484    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
485    std::string myKey("mykey");
486    for (int i = 0; i < NODE_NUMBERS; i++) {
487        std::string ikey = myKey + std::to_string(i);
488        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
489
490        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
491        callInfo->SetFunction(JSTaggedValue::Undefined());
492        callInfo->SetThis(tset.GetTaggedValue());
493        callInfo->SetCallArg(0, key.GetTaggedValue());
494
495        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
496        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
497        TestHelper::TearDownFrame(thread, prev);
498        EXPECT_TRUE(result.IsTrue());
499        EXPECT_EQ(tset->GetSize(), i + 1);
500    }
501    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS);
502    // test clear
503    {
504        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
505        callInfo->SetFunction(JSTaggedValue::Undefined());
506        callInfo->SetThis(tset.GetTaggedValue());
507
508        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
509        ContainersTreeSet::Clear(callInfo);
510        TestHelper::TearDownFrame(thread, prev);
511        EXPECT_EQ(tset->GetSize(), 0);
512    }
513    for (int i = 0; i < NODE_NUMBERS; i++) {
514        std::string ikey = myKey + std::to_string(i);
515        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
516
517        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
518        callInfo->SetFunction(JSTaggedValue::Undefined());
519        callInfo->SetThis(tset.GetTaggedValue());
520        callInfo->SetCallArg(0, key.GetTaggedValue());
521
522        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
523        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
524        TestHelper::TearDownFrame(thread, prev);
525        EXPECT_TRUE(result.IsFalse());
526    }
527}
528
529// treeset.getLowerValue(value), treeset.getHigherValue(value)
530HWTEST_F_L0(ContainersTreeSetTest, GetLowerValueAndGetHigherValue)
531{
532    constexpr int NODE_NUMBERS = 8;
533    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
534    for (int i = 0; i < NODE_NUMBERS; i++) {
535        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
536        callInfo->SetFunction(JSTaggedValue::Undefined());
537        callInfo->SetThis(tset.GetTaggedValue());
538        callInfo->SetCallArg(0, JSTaggedValue(i));
539
540        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
541        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
542        TestHelper::TearDownFrame(thread, prev);
543        EXPECT_TRUE(result.IsTrue());
544        EXPECT_EQ(tset->GetSize(), i + 1);
545    }
546
547    // test getLowerValue
548    for (int i = 0; i <= NODE_NUMBERS; i++) {
549        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
550        callInfo->SetFunction(JSTaggedValue::Undefined());
551        callInfo->SetThis(tset.GetTaggedValue());
552        callInfo->SetCallArg(0, JSTaggedValue(i));
553        if (i == NODE_NUMBERS) {
554            callInfo->SetCallArg(0, JSTaggedValue::Undefined());
555        }
556
557        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
558        JSTaggedValue result = ContainersTreeSet::GetLowerValue(callInfo);
559        TestHelper::TearDownFrame(thread, prev);
560        if (i == 0) {
561            EXPECT_EQ(result, JSTaggedValue::Undefined());
562        } else {
563            EXPECT_EQ(result, JSTaggedValue(i - 1));
564        }
565    }
566    // test getHigherValue
567    for (int i = 0; i <= NODE_NUMBERS; i++) {
568        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
569        callInfo->SetFunction(JSTaggedValue::Undefined());
570        callInfo->SetThis(tset.GetTaggedValue());
571        callInfo->SetCallArg(0, JSTaggedValue(i));
572
573        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
574        JSTaggedValue result = ContainersTreeSet::GetHigherValue(callInfo);
575        TestHelper::TearDownFrame(thread, prev);
576        if (i >= NODE_NUMBERS - 1) {
577            EXPECT_EQ(result, JSTaggedValue::Undefined());
578        } else {
579            EXPECT_EQ(result, JSTaggedValue(i + 1));
580        }
581    }
582
583    // test add string
584    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
585    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
586    std::string myKey("mykey");
587    for (int i = 0; i < NODE_NUMBERS; i++) {
588        std::string ikey = myKey + std::to_string(i);
589        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
590
591        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
592        callInfo->SetFunction(JSTaggedValue::Undefined());
593        callInfo->SetThis(tset.GetTaggedValue());
594        callInfo->SetCallArg(0, key.GetTaggedValue());
595
596        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
597        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
598        TestHelper::TearDownFrame(thread, prev);
599        EXPECT_TRUE(result.IsTrue());
600        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS + i + 1);
601    }
602    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2);
603
604    // test getLowerValue
605    // using to compare the result of GetLowerValue
606    JSMutableHandle<JSTaggedValue> resultKey(thread, JSTaggedValue::Undefined());
607    for (int i = 0; i <= NODE_NUMBERS; i++) {
608        std::string ikey = myKey + std::to_string(i);
609        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
610        std::string rkey = myKey + std::to_string(i - 1);
611        resultKey.Update(factory->NewFromStdString(rkey).GetTaggedValue());
612
613        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
614        callInfo->SetFunction(JSTaggedValue::Undefined());
615        callInfo->SetThis(tset.GetTaggedValue());
616        callInfo->SetCallArg(0, key.GetTaggedValue());
617
618        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
619        JSTaggedValue result = ContainersTreeSet::GetLowerValue(callInfo);
620        TestHelper::TearDownFrame(thread, prev);
621        if (i == 0) {
622            EXPECT_EQ(result, JSTaggedValue(NODE_NUMBERS - 1));
623        } else {
624            EXPECT_EQ(result, resultKey.GetTaggedValue());
625        }
626    }
627    // test getHigherValue
628    for (int i = 0; i < NODE_NUMBERS; i++) {
629        std::string ikey = myKey + std::to_string(i);
630        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
631        std::string rkey = myKey + std::to_string(i + 1);
632        resultKey.Update(factory->NewFromStdString(rkey).GetTaggedValue());
633
634        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
635        callInfo->SetFunction(JSTaggedValue::Undefined());
636        callInfo->SetThis(tset.GetTaggedValue());
637        callInfo->SetCallArg(0, key.GetTaggedValue());
638
639        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
640        JSTaggedValue result = ContainersTreeSet::GetHigherValue(callInfo);
641        TestHelper::TearDownFrame(thread, prev);
642        if (i == NODE_NUMBERS - 1) {
643            EXPECT_EQ(result, JSTaggedValue::Undefined());
644        } else {
645            EXPECT_TRUE(JSTaggedValue::SameValue(result, resultKey.GetTaggedValue()));
646        }
647    }
648}
649
650// treeset.popFirst(), treeset.popLast()
651HWTEST_F_L0(ContainersTreeSetTest, PopFirstAndPopLast)
652{
653    constexpr int NODE_NUMBERS = 8;
654    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
655    for (int i = 0; i < NODE_NUMBERS; i++) {
656        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
657        callInfo->SetFunction(JSTaggedValue::Undefined());
658        callInfo->SetThis(tset.GetTaggedValue());
659        callInfo->SetCallArg(0, JSTaggedValue(i));
660
661        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
662        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
663        TestHelper::TearDownFrame(thread, prev);
664        EXPECT_TRUE(result.IsTrue());
665        EXPECT_EQ(tset->GetSize(), i + 1);
666    }
667
668    // test popFirst
669    {
670        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
671        callInfo->SetFunction(JSTaggedValue::Undefined());
672        callInfo->SetThis(tset.GetTaggedValue());
673
674        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
675        JSTaggedValue result = ContainersTreeSet::PopFirst(callInfo);
676        TestHelper::TearDownFrame(thread, prev);
677        EXPECT_EQ(result, JSTaggedValue(0));
678        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - 1);
679    }
680    // test popLast
681    {
682        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
683        callInfo->SetFunction(JSTaggedValue::Undefined());
684        callInfo->SetThis(tset.GetTaggedValue());
685
686        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
687        JSTaggedValue result = ContainersTreeSet::PopLast(callInfo);
688        TestHelper::TearDownFrame(thread, prev);
689        EXPECT_EQ(result, JSTaggedValue(NODE_NUMBERS - 1));
690        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - 2); // 2 means two elements
691    }
692
693    // test add string
694    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
695    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
696    std::string myKey("mykey");
697    for (int i = 0; i < NODE_NUMBERS; i++) {
698        std::string ikey = myKey + std::to_string(i);
699        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
700
701        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
702        callInfo->SetFunction(JSTaggedValue::Undefined());
703        callInfo->SetThis(tset.GetTaggedValue());
704        callInfo->SetCallArg(0, key.GetTaggedValue());
705
706        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
707        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
708        TestHelper::TearDownFrame(thread, prev);
709        EXPECT_TRUE(result.IsTrue());
710        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS + i - 1);
711    }
712    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2 - 2);
713
714    // test popFirst
715    {
716        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
717        callInfo->SetFunction(JSTaggedValue::Undefined());
718        callInfo->SetThis(tset.GetTaggedValue());
719
720        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
721        JSTaggedValue result = ContainersTreeSet::PopFirst(callInfo);
722        TestHelper::TearDownFrame(thread, prev);
723        EXPECT_EQ(result, JSTaggedValue(1));
724        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2 - 3); // 3 means three elements
725    }
726    // test popLast
727    {
728        std::string ikey = myKey + std::to_string(NODE_NUMBERS - 1);
729        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
730
731        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
732        callInfo->SetFunction(JSTaggedValue::Undefined());
733        callInfo->SetThis(tset.GetTaggedValue());
734
735        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
736        JSTaggedValue result = ContainersTreeSet::PopLast(callInfo);
737        TestHelper::TearDownFrame(thread, prev);
738        EXPECT_EQ(result, key.GetTaggedValue());
739        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2 - 4); // 4 means four elements
740    }
741}
742
743// testset.isEmpty()
744HWTEST_F_L0(ContainersTreeSetTest, IsEmpty)
745{
746    constexpr int NODE_NUMBERS = 8;
747    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
748    // test isEmpty
749    {
750        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
751        callInfo->SetFunction(JSTaggedValue::Undefined());
752        callInfo->SetThis(tset.GetTaggedValue());
753
754        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
755        JSTaggedValue result = ContainersTreeSet::IsEmpty(callInfo);
756        TestHelper::TearDownFrame(thread, prev);
757        EXPECT_TRUE(result.IsTrue());
758        EXPECT_EQ(tset->GetSize(), 0);
759    }
760
761    // add elements
762    for (int i = 0; i < NODE_NUMBERS; i++) {
763        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
764        callInfo->SetFunction(JSTaggedValue::Undefined());
765        callInfo->SetThis(tset.GetTaggedValue());
766        callInfo->SetCallArg(0, JSTaggedValue(i));
767
768        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
769        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
770        TestHelper::TearDownFrame(thread, prev);
771        EXPECT_TRUE(result.IsTrue());
772        EXPECT_EQ(tset->GetSize(), i + 1);
773    }
774    // test isEmpty
775    {
776        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
777        callInfo->SetFunction(JSTaggedValue::Undefined());
778        callInfo->SetThis(tset.GetTaggedValue());
779
780        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
781        JSTaggedValue result = ContainersTreeSet::IsEmpty(callInfo);
782        TestHelper::TearDownFrame(thread, prev);
783        EXPECT_TRUE(result.IsFalse());
784        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS);
785    }
786}
787
788// treeset.values(), treeset.entries()
789HWTEST_F_L0(ContainersTreeSetTest, KeysAndValuesAndEntries)
790{
791    constexpr int NODE_NUMBERS = 8;
792    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
793    for (int i = 0; i < NODE_NUMBERS; i++) {
794        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
795        callInfo->SetFunction(JSTaggedValue::Undefined());
796        callInfo->SetThis(tset.GetTaggedValue());
797        callInfo->SetCallArg(0, JSTaggedValue(i));
798
799        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
800        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
801        TestHelper::TearDownFrame(thread, prev);
802        EXPECT_TRUE(result.IsTrue());
803        EXPECT_EQ(tset->GetSize(), i + 1);
804    }
805
806    // test values
807    auto callInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
808    callInfo1->SetFunction(JSTaggedValue::Undefined());
809    callInfo1->SetThis(tset.GetTaggedValue());
810    [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo1);
811    JSHandle<JSTaggedValue> iterValues(thread, ContainersTreeSet::Values(callInfo1));
812    TestHelper::TearDownFrame(thread, prev1);
813    EXPECT_TRUE(iterValues->IsJSAPITreeSetIterator());
814    {
815        JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
816        for (int i = 0; i < NODE_NUMBERS; i++) {
817            auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
818            callInfo->SetFunction(JSTaggedValue::Undefined());
819            callInfo->SetThis(iterValues.GetTaggedValue());
820
821            [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
822            result.Update(JSAPITreeSetIterator::Next(callInfo));
823            TestHelper::TearDownFrame(thread, prev);
824            EXPECT_EQ(i, JSIterator::IteratorValue(thread, result)->GetInt());
825        }
826    }
827    // test add string
828    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
829    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
830    std::string myKey("mykey");
831    for (int i = 0; i < NODE_NUMBERS; i++) {
832        std::string ikey = myKey + std::to_string(i);
833        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
834
835        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
836        callInfo->SetFunction(JSTaggedValue::Undefined());
837        callInfo->SetThis(tset.GetTaggedValue());
838        callInfo->SetCallArg(0, key.GetTaggedValue());
839
840        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
841        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
842        TestHelper::TearDownFrame(thread, prev);
843        EXPECT_TRUE(result.IsTrue());
844        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS + i + 1);
845    }
846    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2);
847    {
848        JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
849        for (int i = 0; i < NODE_NUMBERS; i++) {
850            std::string ikey = myKey + std::to_string(i);
851            key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
852
853            auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
854            callInfo->SetFunction(JSTaggedValue::Undefined());
855            callInfo->SetThis(iterValues.GetTaggedValue());
856
857            [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
858            result.Update(JSAPITreeSetIterator::Next(callInfo));
859            TestHelper::TearDownFrame(thread, prev);
860            JSHandle<JSTaggedValue> itRes = JSIterator::IteratorValue(thread, result);
861            EXPECT_TRUE(JSTaggedValue::SameValue(key, itRes));
862        }
863    }
864    // test entries
865    {
866        auto callInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
867        callInfo2->SetFunction(JSTaggedValue::Undefined());
868        callInfo2->SetThis(tset.GetTaggedValue());
869        [[maybe_unused]] auto prev2 = TestHelper::SetupFrame(thread, callInfo2);
870        JSHandle<JSTaggedValue> iter(thread, ContainersTreeSet::Entries(callInfo2));
871        TestHelper::TearDownFrame(thread, prev2);
872        EXPECT_TRUE(iter->IsJSAPITreeSetIterator());
873
874        JSHandle<JSTaggedValue> first(thread, JSTaggedValue(0));
875        JSHandle<JSTaggedValue> second(thread, JSTaggedValue(1));
876        JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
877        JSMutableHandle<JSTaggedValue> entries(thread, JSTaggedValue::Undefined());
878        for (int i = 0; i < NODE_NUMBERS; i++) {
879            auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
880            callInfo->SetFunction(JSTaggedValue::Undefined());
881            callInfo->SetThis(iter.GetTaggedValue());
882
883            [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
884            result.Update(JSAPITreeSetIterator::Next(callInfo));
885            TestHelper::TearDownFrame(thread, prev);
886            entries.Update(JSIterator::IteratorValue(thread, result).GetTaggedValue());
887            EXPECT_EQ(i, JSObject::GetProperty(thread, entries, first).GetValue()->GetInt());
888            EXPECT_EQ(i, JSObject::GetProperty(thread, entries, second).GetValue()->GetInt());
889        }
890        for (int i = 0; i < NODE_NUMBERS; i++) {
891            std::string ikey = myKey + std::to_string(i);
892            key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
893
894            auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
895            callInfo->SetFunction(JSTaggedValue::Undefined());
896            callInfo->SetThis(iter.GetTaggedValue());
897
898            [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
899            result.Update(JSAPITreeSetIterator::Next(callInfo));
900            TestHelper::TearDownFrame(thread, prev);
901            entries.Update(JSIterator::IteratorValue(thread, result).GetTaggedValue());
902            EXPECT_TRUE(JSTaggedValue::SameValue(key, JSObject::GetProperty(thread, entries, first).GetValue()));
903            EXPECT_TRUE(JSTaggedValue::SameValue(key, JSObject::GetProperty(thread, entries, second).GetValue()));
904        }
905    }
906}
907
908// treeset.ForEach(callbackfn, this)
909HWTEST_F_L0(ContainersTreeSetTest, ForEach)
910{
911    constexpr int NODE_NUMBERS = 8;
912    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet();
913    for (int i = 0; i < NODE_NUMBERS; i++) {
914        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
915        callInfo->SetFunction(JSTaggedValue::Undefined());
916        callInfo->SetThis(tset.GetTaggedValue());
917        callInfo->SetCallArg(0, JSTaggedValue(i));
918
919        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
920        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
921        TestHelper::TearDownFrame(thread, prev);
922        EXPECT_TRUE(result.IsTrue());
923        EXPECT_EQ(tset->GetSize(), i + 1);
924    }
925
926    // test foreach function with TestForEachFunc;
927    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
928    JSHandle<JSAPITreeSet> dset = CreateJSAPITreeSet();
929    {
930        JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
931        JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachFunc));
932        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
933        callInfo->SetFunction(JSTaggedValue::Undefined());
934        callInfo->SetThis(tset.GetTaggedValue());
935        callInfo->SetCallArg(0, func.GetTaggedValue());
936        callInfo->SetCallArg(1, dset.GetTaggedValue());
937
938        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
939        ContainersTreeSet::ForEach(callInfo);
940        TestHelper::TearDownFrame(thread, prev);
941    }
942
943    EXPECT_EQ(dset->GetSize(), NODE_NUMBERS / 2);
944    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS / 2);
945    for (int i = 0; i < NODE_NUMBERS; i += 2) {
946        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
947        callInfo->SetFunction(JSTaggedValue::Undefined());
948        callInfo->SetThis(dset.GetTaggedValue());
949        callInfo->SetCallArg(0, JSTaggedValue(i));
950
951        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
952        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
953        TestHelper::TearDownFrame(thread, prev);
954        EXPECT_TRUE(result.IsTrue());
955    }
956
957    // test add string
958    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
959    std::string myKey("mykey");
960    for (int i = 0; i < NODE_NUMBERS; i++) {
961        std::string ikey = myKey + std::to_string(i);
962        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
963
964        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
965        callInfo->SetFunction(JSTaggedValue::Undefined());
966        callInfo->SetThis(tset.GetTaggedValue());
967        callInfo->SetCallArg(0, key.GetTaggedValue());
968
969        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
970        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
971        TestHelper::TearDownFrame(thread, prev);
972        EXPECT_TRUE(result.IsTrue());
973        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS / 2 + i + 1);
974    }
975    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS / 2 + NODE_NUMBERS);
976    {
977        JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
978        JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachFunc));
979        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
980        callInfo->SetFunction(JSTaggedValue::Undefined());
981        callInfo->SetThis(tset.GetTaggedValue());
982        callInfo->SetCallArg(0, func.GetTaggedValue());
983        callInfo->SetCallArg(1, dset.GetTaggedValue());
984
985        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
986        ContainersTreeSet::ForEach(callInfo);
987        TestHelper::TearDownFrame(thread, prev);
988    }
989    EXPECT_EQ(dset->GetSize(), NODE_NUMBERS + 2);
990    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - 2);
991    for (int i = 0; i < NODE_NUMBERS; i += 2) {
992        std::string ikey = myKey + std::to_string(i);
993        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
994
995        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
996        callInfo->SetFunction(JSTaggedValue::Undefined());
997        callInfo->SetThis(dset.GetTaggedValue());
998        callInfo->SetCallArg(0, key.GetTaggedValue());
999
1000        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
1001        JSTaggedValue result = ContainersTreeSet::Has(callInfo);
1002        TestHelper::TearDownFrame(thread, prev);
1003        EXPECT_TRUE(result.IsTrue());
1004    }
1005}
1006
1007HWTEST_F_L0(ContainersTreeSetTest, CustomCompareFunctionTest)
1008{
1009    constexpr int NODE_NUMBERS = 8;
1010    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1011    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1012    JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestCompareFunction));
1013    JSHandle<JSAPITreeSet> tset = CreateJSAPITreeSet(func.GetTaggedValue());
1014    for (int i = 0; i < NODE_NUMBERS; i++) {
1015        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
1016        callInfo->SetFunction(JSTaggedValue::Undefined());
1017        callInfo->SetThis(tset.GetTaggedValue());
1018        callInfo->SetCallArg(0, JSTaggedValue(i));
1019
1020        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
1021        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
1022        TestHelper::TearDownFrame(thread, prev);
1023        EXPECT_TRUE(result.IsTrue());
1024        EXPECT_EQ(tset->GetSize(), i + 1);
1025    }
1026    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS);
1027
1028    // test add string
1029    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1030    std::string myKey("mykey");
1031    for (int i = 0; i < NODE_NUMBERS; i++) {
1032        std::string ikey = myKey + std::to_string(i);
1033        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
1034
1035        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
1036        callInfo->SetFunction(JSTaggedValue::Undefined());
1037        callInfo->SetThis(tset.GetTaggedValue());
1038        callInfo->SetCallArg(0, key.GetTaggedValue());
1039
1040        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
1041        JSTaggedValue result = ContainersTreeSet::Add(callInfo);
1042        TestHelper::TearDownFrame(thread, prev);
1043        EXPECT_TRUE(result.IsTrue());
1044        EXPECT_EQ(tset->GetSize(), NODE_NUMBERS + i + 1);
1045    }
1046    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS * 2);
1047
1048    // test sort
1049    auto callInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
1050    callInfo1->SetFunction(JSTaggedValue::Undefined());
1051    callInfo1->SetThis(tset.GetTaggedValue());
1052    [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo1);
1053    JSHandle<JSTaggedValue> iterValues(thread, ContainersTreeSet::Values(callInfo1));
1054    TestHelper::TearDownFrame(thread, prev1);
1055    EXPECT_TRUE(iterValues->IsJSAPITreeSetIterator());
1056    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
1057    for (int i = 0; i < NODE_NUMBERS; i++) {
1058        std::string ikey = myKey + std::to_string(NODE_NUMBERS - 1 - i);
1059        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
1060
1061        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
1062        callInfo->SetFunction(JSTaggedValue::Undefined());
1063        callInfo->SetThis(iterValues.GetTaggedValue());
1064
1065        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
1066        result.Update(JSAPITreeSetIterator::Next(callInfo));
1067        TestHelper::TearDownFrame(thread, prev);
1068        JSHandle<JSTaggedValue> itRes = JSIterator::IteratorValue(thread, result);
1069        EXPECT_TRUE(JSTaggedValue::SameValue(key, itRes));
1070    }
1071    for (int i = 0; i < NODE_NUMBERS; i++) {
1072        auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
1073        callInfo->SetFunction(JSTaggedValue::Undefined());
1074        callInfo->SetThis(iterValues.GetTaggedValue());
1075
1076        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
1077        result.Update(JSAPITreeSetIterator::Next(callInfo));
1078        TestHelper::TearDownFrame(thread, prev);
1079        EXPECT_EQ((NODE_NUMBERS - 1 - i), JSIterator::IteratorValue(thread, result)->GetInt());
1080    }
1081}
1082
1083HWTEST_F_L0(ContainersTreeSetTest, ProxyOfGetLength)
1084{
1085    constexpr uint32_t NODE_NUMBERS = 8;
1086    JSHandle<JSAPITreeSet> treeSet = CreateJSAPITreeSet();
1087    auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
1088    callInfo->SetFunction(JSTaggedValue::Undefined());
1089    JSHandle<JSProxy> proxy = CreateJSProxyHandle(thread);
1090    proxy->SetTarget(thread, treeSet.GetTaggedValue());
1091    callInfo->SetThis(proxy.GetTaggedValue());
1092
1093    for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
1094        callInfo->SetCallArg(0, JSTaggedValue(i));
1095        callInfo->SetCallArg(1, JSTaggedValue(i + 1));
1096        [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
1097        ContainersTreeSet::Add(callInfo);
1098        TestHelper::TearDownFrame(thread, prev);
1099
1100        [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo);
1101        JSTaggedValue retult = ContainersTreeSet::GetLength(callInfo);
1102        TestHelper::TearDownFrame(thread, prev1);
1103        EXPECT_EQ(retult, JSTaggedValue(i + 1));
1104    }
1105}
1106
1107HWTEST_F_L0(ContainersTreeSetTest, ExceptionReturn1)
1108{
1109    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, GetHigherValue);
1110    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, Add);
1111    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, Remove);
1112    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, Has);
1113    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, GetFirstValue);
1114    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, GetLastValue);
1115    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, Clear);
1116    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, GetLowerValue);
1117}
1118
1119HWTEST_F_L0(ContainersTreeSetTest, ExceptionReturn2)
1120{
1121    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, PopFirst);
1122    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, PopLast);
1123    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, IsEmpty);
1124    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, ForEach);
1125    CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersTreeSet, GetLength);
1126}
1127}  // namespace panda::test
1128