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/layout_info-inl.h"
17#include "ecmascript/property_attributes.h"
18#include "ecmascript/tests/test_helper.h"
19
20using namespace panda::ecmascript;
21
22namespace panda::test {
23class LayoutInfoTest : public BaseTestWithScope<false> {
24};
25
26HWTEST_F_L0(LayoutInfoTest, SetNumberOfElements)
27{
28    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
29    int32_t infoLength = 2; // 2: len
30    JSHandle<LayoutInfo> layoutInfoHandle = factory->CreateLayoutInfo(infoLength);
31    EXPECT_TRUE(*layoutInfoHandle != nullptr);
32
33    layoutInfoHandle->SetNumberOfElements(thread, 100);
34    EXPECT_EQ(layoutInfoHandle->NumberOfElements(), 100);
35}
36
37HWTEST_F_L0(LayoutInfoTest, SetPropertyInit)
38{
39    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
40    int32_t infoLength = 3;
41    PropertyAttributes defaultAttr = PropertyAttributes::Default();
42    defaultAttr.SetNormalAttr(infoLength);
43    JSHandle<JSTaggedValue> key(factory->NewFromASCII("key"));
44    JSHandle<LayoutInfo> layoutInfoHandle = factory->CreateLayoutInfo(infoLength);
45    EXPECT_TRUE(*layoutInfoHandle != nullptr);
46
47    layoutInfoHandle->SetPropertyInit(thread, 0, key.GetTaggedValue(), defaultAttr);
48    EXPECT_EQ(layoutInfoHandle->GetKey(0), key.GetTaggedValue());
49    EXPECT_EQ(layoutInfoHandle->GetAttr(0).GetNormalAttr(), static_cast<uint32_t>(infoLength));
50}
51
52HWTEST_F_L0(LayoutInfoTest, SetSortedIndex)
53{
54    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
55    int32_t infoLength = 5;
56    PropertyAttributes defaultAttr = PropertyAttributes::Default();
57    defaultAttr.SetNormalAttr(infoLength);
58    JSHandle<JSTaggedValue> key1(factory->NewFromASCII("hello"));
59    JSHandle<JSTaggedValue> key2(factory->NewFromASCII("world"));
60    JSHandle<LayoutInfo> layoutInfoHandle = factory->CreateLayoutInfo(infoLength);
61    EXPECT_TRUE(*layoutInfoHandle != nullptr);
62
63    layoutInfoHandle->SetPropertyInit(thread, 0, key1.GetTaggedValue(), defaultAttr);
64    layoutInfoHandle->SetPropertyInit(thread, 1, key2.GetTaggedValue(), defaultAttr);
65    layoutInfoHandle->SetSortedIndex(thread, 0, infoLength - 4);
66    EXPECT_EQ(layoutInfoHandle->GetSortedIndex(0), 1U);
67    EXPECT_EQ(layoutInfoHandle->GetSortedKey(0), key2.GetTaggedValue());
68}
69
70HWTEST_F_L0(LayoutInfoTest, FindElementWithCache)
71{
72    int infoLength = 5;
73    int newPropertiesLength = 11;
74    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
75    PropertyAttributes defaultAttr = PropertyAttributes::Default();
76    JSHandle<JSTaggedValue> key1(factory->NewFromASCII("1"));
77    JSHandle<JSTaggedValue> key4(factory->NewFromASCII("4"));
78    JSHandle<JSTaggedValue> key5(factory->NewFromASCII("5"));
79    JSHandle<JSTaggedValue> key10(factory->NewFromASCII("10"));
80    JSHandle<JSTaggedValue> key11(factory->NewFromASCII("11"));
81    JSHandle<LayoutInfo> layoutInfoHandle = factory->CreateLayoutInfo(infoLength);
82    EXPECT_TRUE(*layoutInfoHandle != nullptr);
83    for (int i = 0; i < infoLength; i++) {
84        JSHandle<JSTaggedValue> elements(thread, JSTaggedValue(i));
85        JSHandle<JSTaggedValue> elementsKey(JSTaggedValue::ToString(thread, elements));
86        defaultAttr.SetOffset(i);
87        layoutInfoHandle->AddKey(thread, i, elementsKey.GetTaggedValue(), defaultAttr);
88    }
89    int propertiesNumber = layoutInfoHandle->NumberOfElements();
90    int result = 0;
91    result = layoutInfoHandle->FindElementWithCache(thread, nullptr, key1.GetTaggedValue(), propertiesNumber);
92    EXPECT_EQ(result, 1); // 1: Index corresponding to key1
93    result = layoutInfoHandle->FindElementWithCache(thread, nullptr, key5.GetTaggedValue(), propertiesNumber);
94    EXPECT_EQ(result, -1); // -1: not find
95    // extend layoutInfo
96    JSHandle<LayoutInfo> newLayoutInfo = factory->ExtendLayoutInfo(layoutInfoHandle, newPropertiesLength);
97    for (int i = 5; i < newPropertiesLength; i++) {
98        JSHandle<JSTaggedValue> elements(thread, JSTaggedValue(i));
99        JSHandle<JSTaggedValue> elementsKey(JSTaggedValue::ToString(thread, elements));
100        defaultAttr.SetOffset(i);
101        newLayoutInfo->AddKey(thread, i, elementsKey.GetTaggedValue(), defaultAttr);
102    }
103    result = newLayoutInfo->FindElementWithCache(thread, nullptr, key4.GetTaggedValue(), newPropertiesLength);
104    EXPECT_EQ(result, 4); // 4: Index corresponding to key4
105    result = newLayoutInfo->FindElementWithCache(thread, nullptr, key10.GetTaggedValue(), newPropertiesLength);
106    EXPECT_EQ(result, 10); // 10: Index corresponding to key10
107    result = newLayoutInfo->FindElementWithCache(thread, nullptr, key5.GetTaggedValue(), newPropertiesLength);
108    EXPECT_EQ(result, 5); // 5: Index corresponding to key5
109    result = newLayoutInfo->FindElementWithCache(thread, nullptr, key11.GetTaggedValue(), newPropertiesLength);
110    EXPECT_EQ(result, -1); // -1: not find
111}
112
113void GetAllKeysCommon(JSThread *thread, bool enumKeys = false)
114{
115    int infoLength = 5;
116    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
117    PropertyAttributes defaultAttr = PropertyAttributes::Default();
118    JSHandle<JSTaggedValue> key3(factory->NewFromASCII("3"));
119
120    JSHandle<JSObject> objectHandle = factory->NewEmptyJSObject();
121    JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(infoLength);
122    JSHandle<LayoutInfo> layoutInfoHandle = factory->CreateLayoutInfo(infoLength);
123    EXPECT_TRUE(*layoutInfoHandle != nullptr);
124    std::vector<JSTaggedValue> keyVector;
125    // Add key to layout info
126    for (int i = 0; i < infoLength; i++) {
127        JSHandle<JSTaggedValue> elements(thread, JSTaggedValue(i));
128        JSHandle<JSTaggedValue> elementsKey(JSTaggedValue::ToString(thread, elements));
129        defaultAttr.SetOffset(i);
130        if (enumKeys) {
131            if (i != 3) { // 3: index
132                defaultAttr.SetEnumerable(false);
133            } else {
134                defaultAttr.SetEnumerable(true);
135            }
136        }
137        layoutInfoHandle->AddKey(thread, i, elementsKey.GetTaggedValue(), defaultAttr);
138    }
139    if (enumKeys) {
140        uint32_t keys = 0;
141        layoutInfoHandle->GetAllEnumKeys(thread, infoLength, 0, keyArray, &keys, objectHandle); // 0: offset
142        EXPECT_EQ(keyArray->Get(0), key3.GetTaggedValue());
143        EXPECT_EQ(keys, 1U);
144    } else {
145        layoutInfoHandle->GetAllKeys(thread, infoLength, 0, *keyArray, objectHandle); // 0: offset
146        layoutInfoHandle->GetAllKeysForSerialization(infoLength, keyVector);
147        EXPECT_EQ(keyArray->GetLength(), keyVector.size());
148
149        for (int i = 0;i < infoLength; i++) {
150            bool result = JSTaggedValue::SameValue(keyArray->Get(i), keyVector[i]);
151            EXPECT_TRUE(result);
152        }
153    }
154}
155
156HWTEST_F_L0(LayoutInfoTest, GetAllKeys)
157{
158    GetAllKeysCommon(thread);
159}
160
161HWTEST_F_L0(LayoutInfoTest, GetAllEnumKeys)
162{
163    GetAllKeysCommon(thread, true);
164}
165}  // namespace panda::ecmascript
166