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/ecma_string.h"
18#include "ecmascript/ecma_vm.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_function.h"
23#include "ecmascript/js_handle.h"
24#include "ecmascript/js_iterator.h"
25#include "ecmascript/js_object-inl.h"
26#include "ecmascript/js_tagged_value.h"
27#include "ecmascript/object_factory.h"
28#include "ecmascript/tagged_tree.h"
29#include "ecmascript/tests/ecma_test_common.h"
30
31using namespace panda;
32
33using namespace panda::ecmascript;
34
35namespace panda::test {
36class JSAPITreeSetTest : public BaseTestWithScope<false> {
37protected:
38    JSAPITreeSet *CreateTreeSet()
39    {
40        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
41        auto result = TestCommon::CreateContainerTaggedValue(thread, containers::ContainerTag::TreeSet);
42        JSHandle<JSTaggedValue> constructor(thread, result);
43        JSHandle<JSAPITreeSet> set(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
44        JSTaggedValue internal = TaggedTreeSet::Create(thread);
45        set->SetTreeSet(thread, internal);
46        return *set;
47    }
48
49    JSHandle<JSAPITreeSet> TestCommon(JSMutableHandle<JSTaggedValue>& key, std::string& myKey, uint32_t nums)
50    {
51        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
52        // test JSAPITreeSet
53        JSHandle<JSAPITreeSet> tset(thread, CreateTreeSet());
54        for (int i = 0; i < nums; i++) {
55            std::string ikey = myKey + std::to_string(i);
56            key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
57            JSAPITreeSet::Add(thread, tset, key);
58        }
59        EXPECT_EQ(tset->GetSize(), nums);
60        return tset;
61    }
62};
63
64HWTEST_F_L0(JSAPITreeSetTest, TreeSetCreate)
65{
66    JSAPITreeSet *set = CreateTreeSet();
67    EXPECT_TRUE(set != nullptr);
68}
69
70HWTEST_F_L0(JSAPITreeSetTest, TreeSetAddAndHas)
71{
72    constexpr int NODE_NUMBERS = 8;
73    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
74    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
75
76    // test JSAPITreeSet
77    std::string myKey("mykey");
78    auto tset = TestCommon(key, myKey, NODE_NUMBERS);
79
80    // test Add exception
81    key.Update(JSTaggedValue::Hole());
82    JSAPITreeSet::Add(thread, tset, key);
83    EXPECT_EXCEPTION();
84
85    for (int i = 0; i < NODE_NUMBERS; i++) {
86        std::string ikey = myKey + std::to_string(i);
87        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
88
89        // test has
90        bool has = JSAPITreeSet::Has(thread, tset, key);
91        EXPECT_EQ(has, true);
92    }
93}
94
95HWTEST_F_L0(JSAPITreeSetTest, TreeSetDeleteAndHas)
96{
97    constexpr int NODE_NUMBERS = 64;
98    constexpr int REMOVE_SIZE = 48;
99    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
100    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
101
102    // test JSAPITreeSet
103    std::string myKey("mykey");
104    auto tset = TestCommon(key, myKey, NODE_NUMBERS);
105
106    // test delete
107    {
108        std::string ikey = myKey + std::to_string(NODE_NUMBERS);
109        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
110        bool success = JSAPITreeSet::Delete(thread, tset, key);
111        EXPECT_EQ(success, false);
112    }
113
114    for (int i = 0; i < REMOVE_SIZE; i++) {
115        std::string ikey = myKey + std::to_string(i);
116        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
117        bool success = JSAPITreeSet::Delete(thread, tset, key);
118        EXPECT_EQ(success, true);
119    }
120    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - REMOVE_SIZE);
121
122    for (int i = 0; i < REMOVE_SIZE; i++) {
123        std::string ikey = myKey + std::to_string(i);
124        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
125
126        // test has
127        bool has = JSAPITreeSet::Has(thread, tset, key);
128        EXPECT_EQ(has, false);
129    }
130
131    for (int i = REMOVE_SIZE; i < NODE_NUMBERS; i++) {
132        std::string ikey = myKey + std::to_string(i);
133        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
134
135        // test has
136        bool has = JSAPITreeSet::Has(thread, tset, key);
137        EXPECT_EQ(has, true);
138    }
139}
140
141HWTEST_F_L0(JSAPITreeSetTest, TreeSetClear)
142{
143    constexpr int NODE_NUMBERS = 8;
144    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
145    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
146
147    // test TaggedTreeSet
148    std::string myKey("mykey");
149    auto tset = TestCommon(key, myKey, NODE_NUMBERS);
150
151    JSAPITreeSet::Clear(thread, tset);
152    EXPECT_EQ(tset->GetSize(), 0);
153    for (int i = 0; i < NODE_NUMBERS; i++) {
154        std::string ikey = myKey + std::to_string(i);
155        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
156
157        // test has
158        bool has = JSAPITreeSet::Has(thread, tset, key);
159        EXPECT_EQ(has, false);
160    }
161}
162
163HWTEST_F_L0(JSAPITreeSetTest, TreeSetPop)
164{
165    constexpr int NODE_NUMBERS = 8;
166    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
167    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
168
169    // test TaggedTreeSet
170    JSHandle<JSAPITreeSet> tset(thread, CreateTreeSet());
171
172    // test popFirst and popLast of empty treeset
173    JSTaggedValue fvalue1 = JSAPITreeSet::PopFirst(thread, tset);
174    EXPECT_EQ(fvalue1, JSTaggedValue::Undefined());
175    JSTaggedValue lvalue1 = JSAPITreeSet::PopFirst(thread, tset);
176    EXPECT_EQ(lvalue1, JSTaggedValue::Undefined());
177
178    std::string myKey("mykey");
179    for (int i = 0; i < NODE_NUMBERS; i++) {
180        std::string ikey = myKey + std::to_string(i);
181        key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
182        JSAPITreeSet::Add(thread, tset, key);
183    }
184    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS);
185
186    // test popFirst
187    std::string fkey = myKey + std::to_string(0);
188    key.Update(factory->NewFromStdString(fkey).GetTaggedValue());
189    JSTaggedValue fvalue = JSAPITreeSet::PopFirst(thread, tset);
190    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - 1);
191    EXPECT_EQ(fvalue, key.GetTaggedValue());
192    bool has = JSAPITreeSet::Has(thread, tset, key);
193    EXPECT_EQ(has, false);
194
195    // test popLast
196    std::string lkey = myKey + std::to_string(NODE_NUMBERS - 1);
197    key.Update(factory->NewFromStdString(lkey).GetTaggedValue());
198    JSTaggedValue lvalue = JSAPITreeSet::PopLast(thread, tset);
199    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS - 2);
200    EXPECT_EQ(lvalue, key.GetTaggedValue());
201    has = JSAPITreeSet::Has(thread, tset, key);
202    EXPECT_EQ(has, false);
203}
204
205HWTEST_F_L0(JSAPITreeSetTest, JSAPITreeSetIterator)
206{
207    constexpr int NODE_NUMBERS = 8;
208    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
209    JSHandle<JSAPITreeSet> tset(thread, CreateTreeSet());
210
211    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
212    for (int i = 0; i < NODE_NUMBERS; i++) {
213        key.Update(JSTaggedValue(i));
214        JSAPITreeSet::Add(thread, tset, key);
215    }
216
217    // test key or value
218    JSHandle<JSTaggedValue> keyIter(factory->NewJSAPITreeSetIterator(tset, IterationKind::KEY));
219    JSHandle<JSTaggedValue> valueIter(factory->NewJSAPITreeSetIterator(tset, IterationKind::VALUE));
220    JSMutableHandle<JSTaggedValue> keyIterResult(thread, JSTaggedValue::Undefined());
221    JSMutableHandle<JSTaggedValue> valueIterResult(thread, JSTaggedValue::Undefined());
222    for (int i = 0; i < NODE_NUMBERS / 2; i++) {
223        keyIterResult.Update(JSIterator::IteratorStep(thread, keyIter).GetTaggedValue());
224        valueIterResult.Update(JSIterator::IteratorStep(thread, valueIter).GetTaggedValue());
225        EXPECT_EQ(i, JSIterator::IteratorValue(thread, keyIterResult)->GetInt());
226        EXPECT_EQ(i, JSIterator::IteratorValue(thread, valueIterResult)->GetInt());
227    }
228
229    // test key and value
230    JSHandle<JSTaggedValue> indexKey(thread, JSTaggedValue(0));
231    JSHandle<JSTaggedValue> elementKey(thread, JSTaggedValue(1));
232    JSHandle<JSTaggedValue> iter(factory->NewJSAPITreeSetIterator(tset, IterationKind::KEY_AND_VALUE));
233    JSMutableHandle<JSTaggedValue> iterResult(thread, JSTaggedValue::Undefined());
234    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
235    for (int i = 0; i < NODE_NUMBERS; i++) {
236        iterResult.Update(JSIterator::IteratorStep(thread, iter).GetTaggedValue());
237        result.Update(JSIterator::IteratorValue(thread, iterResult).GetTaggedValue());
238        EXPECT_EQ(i, JSObject::GetProperty(thread, result, indexKey).GetValue()->GetInt());
239        EXPECT_EQ(i, JSObject::GetProperty(thread, result, elementKey).GetValue()->GetInt());
240    }
241
242    // test delete
243    key.Update(JSTaggedValue(NODE_NUMBERS / 2));
244    bool success = JSAPITreeSet::Delete(thread, tset, key);
245    EXPECT_EQ(success, true);
246    for (int i = NODE_NUMBERS / 2 + 1; i < NODE_NUMBERS; i++) {
247        keyIterResult.Update(JSIterator::IteratorStep(thread, keyIter).GetTaggedValue());
248        valueIterResult.Update(JSIterator::IteratorStep(thread, valueIter).GetTaggedValue());
249        EXPECT_EQ(i, JSIterator::IteratorValue(thread, keyIterResult)->GetInt());
250        EXPECT_EQ(i, JSIterator::IteratorValue(thread, valueIterResult)->GetInt());
251    }
252
253    // test set
254    key.Update(JSTaggedValue(NODE_NUMBERS));
255    JSAPITreeSet::Add(thread, tset, key);
256    keyIterResult.Update(JSIterator::IteratorStep(thread, keyIter).GetTaggedValue());
257    EXPECT_EQ(NODE_NUMBERS, JSIterator::IteratorValue(thread, keyIterResult)->GetInt());
258
259    // test end
260    keyIterResult.Update(JSIterator::IteratorStep(thread, keyIter).GetTaggedValue());
261    EXPECT_EQ(JSTaggedValue::False(), keyIterResult.GetTaggedValue());
262}
263
264HWTEST_F_L0(JSAPITreeSetTest, TreeSetGetKey)
265{
266    constexpr int NODE_NUMBERS = 8;
267    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
268
269    // init treeset
270    JSHandle<JSAPITreeSet> tset(thread, CreateTreeSet());
271    for (int i = 0; i < NODE_NUMBERS; i++) {
272        key.Update(JSTaggedValue(i));
273        JSAPITreeSet::Add(thread, tset, key);
274    }
275    EXPECT_EQ(tset->GetSize(), NODE_NUMBERS);
276
277    // test GetKey
278    for (int i = 0; i < NODE_NUMBERS; i++) {
279        EXPECT_EQ(tset->GetKey(i), JSTaggedValue(i));
280    }
281    EXPECT_EQ(tset->GetKey(-1), JSTaggedValue::Undefined());
282}
283}  // namespace panda::test
284