1 /*
2 * Copyright (c) 2025 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/module/module_manager_map.h"
17 #include "ecmascript/tests/test_helper.h"
18
19 using namespace panda::ecmascript;
20
21 namespace panda::test {
22
23 class ModuleManagerMapTest : public BaseTestWithScope<false> {
24 public:
SetUp()25 void SetUp() override
26 {
27 JSRuntimeOptions options;
28 instance = JSNApi::CreateEcmaVM(options);
29 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
30 thread = instance->GetJSThread();
31 thread->ManagedCodeBegin();
32 scope = new EcmaHandleScope(thread);
33 instance->SetEnableForceGC(false);
34 }
35
36 protected:
37 ModuleManagerMap<int> map;
38 };
39
40 // --- GCRoot Tests ---
41
HWTEST_F_L0(ModuleManagerMapTest,GCRoot)42 HWTEST_F_L0(ModuleManagerMapTest, GCRoot)
43 {
44 // Test default constructor
45 GCRoot root;
46 ASSERT_EQ(root.Read().GetRawData(), JSTaggedValue::Hole().GetRawData());
47
48 // Test regular and move constructor
49 {
50 JSTaggedValue value(static_cast<JSTaggedType>(42));
51 GCRoot root1(value);
52
53 GCRoot root2(std::move(root1));
54 ASSERT_EQ(root2.Read().GetRawData(), value.GetRawData());
55 }
56
57 // Test move assignment
58 {
59 JSTaggedValue value1(static_cast<JSTaggedType>(42));
60
61 JSTaggedValue value2(static_cast<JSTaggedType>(84));
62
63 GCRoot root1(value1);
64 GCRoot root2(value2);
65
66 root2 = std::move(root1);
67 ASSERT_EQ(root2.Read().GetRawData(), value1.GetRawData());
68 }
69
70 // Test read barrier
71 {
72 JSTaggedValue value(static_cast<JSTaggedType>(42));
73 GCRoot root(value);
74
75 JSTaggedValue read_value = root.Read();
76 ASSERT_EQ(read_value.GetRawData(), value.GetRawData());
77 }
78
79 // Test Hash er
80 {
81 JSTaggedValue value1(static_cast<JSTaggedType>(42));
82 JSTaggedValue value2(static_cast<JSTaggedType>(42));
83 JSTaggedValue value3(static_cast<JSTaggedType>(84));
84
85 GCRoot root1(value1);
86 GCRoot root2(value2);
87 GCRoot root3(value3);
88
89 GCRoot::GCRootHash hasher;
90
91 // Same values should have same hash
92 ASSERT_EQ(hasher(root1), hasher(root2));
93
94 // Different values should have different hashes
95 ASSERT_NE(hasher(root1), hasher(root3));
96
97 // Template version should work with raw types
98 ASSERT_EQ(hasher(root1), hasher(value1.GetRawData()));
99 }
100 }
101
HWTEST_F_L0(ModuleManagerMapTest,InsertAndFind)102 HWTEST_F_L0(ModuleManagerMapTest, InsertAndFind)
103 {
104 JSTaggedValue value(static_cast<JSTaggedType>(42));
105
106 map.Insert(1, value);
107
108 auto result = map.Find(1);
109 ASSERT_TRUE(result.has_value());
110 ASSERT_EQ(result->GetRawData(), value.GetRawData());
111 }
112
HWTEST_F_L0(ModuleManagerMapTest,EmplaceAndFind)113 HWTEST_F_L0(ModuleManagerMapTest, EmplaceAndFind)
114 {
115 JSTaggedValue value(static_cast<JSTaggedType>(42));
116
117 map.Emplace(1, value);
118
119 auto result = map.Find(1);
120 ASSERT_TRUE(result.has_value());
121 ASSERT_EQ(result->GetRawData(), value.GetRawData());
122 }
123
HWTEST_F_L0(ModuleManagerMapTest,EmplaceDoesNotOverwrite)124 HWTEST_F_L0(ModuleManagerMapTest, EmplaceDoesNotOverwrite)
125 {
126 JSTaggedValue value1(static_cast<JSTaggedType>(42));
127 JSTaggedValue value2(static_cast<JSTaggedType>(84));
128
129 map.Insert(1, value1);
130 map.Emplace(1, value2); // Should not overwrite
131
132 auto result = map.Find(1);
133 ASSERT_TRUE(result.has_value());
134 ASSERT_EQ(result->GetRawData(), value1.GetRawData()); // Should still be original value
135 }
136
HWTEST_F_L0(ModuleManagerMapTest,InsertOverwrites)137 HWTEST_F_L0(ModuleManagerMapTest, InsertOverwrites)
138 {
139 JSTaggedValue value1(static_cast<JSTaggedType>(42));
140 JSTaggedValue value2(static_cast<JSTaggedType>(84));
141
142 map.Insert(1, value1);
143 map.Insert(1, value2); // Should overwrite
144
145 auto result = map.Find(1);
146 ASSERT_TRUE(result.has_value());
147 ASSERT_EQ(result->GetRawData(), value2.GetRawData()); // Should be new value
148 }
149
HWTEST_F_L0(ModuleManagerMapTest,FindNonExistent)150 HWTEST_F_L0(ModuleManagerMapTest, FindNonExistent)
151 {
152 auto result = map.Find(999);
153 ASSERT_FALSE(result.has_value());
154 }
155
HWTEST_F_L0(ModuleManagerMapTest,ForEach)156 HWTEST_F_L0(ModuleManagerMapTest, ForEach)
157 {
158 JSTaggedValue value1(static_cast<JSTaggedType>(42));
159 JSTaggedValue value2(static_cast<JSTaggedType>(84));
160
161 map.Insert(1, value1);
162 map.Insert(2, value2);
163
164 std::vector<std::pair<int, JSTaggedValue>> collected;
165 map.ForEach([&](auto it) { collected.emplace_back(it->first, it->second.Read()); });
166
167 ASSERT_EQ(collected.size(), 2U);
168
169 // Sort for deterministic comparison
170 std::sort(collected.begin(), collected.end(), [](const auto &a, const auto &b) { return a.first < b.first; });
171
172 ASSERT_EQ(collected[0].first, 1);
173 ASSERT_EQ(collected[0].second.GetRawData(), value1.GetRawData());
174 ASSERT_EQ(collected[1].first, 2);
175 ASSERT_EQ(collected[1].second.GetRawData(), value2.GetRawData());
176 }
177
HWTEST_F_L0(ModuleManagerMapTest,Erase)178 HWTEST_F_L0(ModuleManagerMapTest, Erase)
179 {
180 JSTaggedValue value(static_cast<JSTaggedType>(42));
181
182 map.Insert(1, value);
183 ASSERT_TRUE(map.Find(1).has_value());
184
185 map.Erase(1);
186 ASSERT_FALSE(map.Find(1).has_value());
187 ASSERT_EQ(map.Size(), 0U);
188 }
189
HWTEST_F_L0(ModuleManagerMapTest,Size)190 HWTEST_F_L0(ModuleManagerMapTest, Size)
191 {
192 ASSERT_EQ(map.Size(), 0U);
193
194 map.Insert(1, JSTaggedValue(static_cast<JSTaggedType>(42)));
195 ASSERT_EQ(map.Size(), 1U);
196
197 map.Insert(2, JSTaggedValue(static_cast<JSTaggedType>(84)));
198 ASSERT_EQ(map.Size(), 2U);
199
200 map.Erase(1);
201 ASSERT_EQ(map.Size(), 1U);
202 }
203
HWTEST_F_L0(ModuleManagerMapTest,Clear)204 HWTEST_F_L0(ModuleManagerMapTest, Clear)
205 {
206 map.Insert(1, JSTaggedValue(static_cast<JSTaggedType>(42)));
207 map.Insert(2, JSTaggedValue(static_cast<JSTaggedType>(84)));
208
209 ASSERT_EQ(map.Size(), 2U);
210
211 map.Clear();
212
213 ASSERT_EQ(map.Size(), 0U);
214 ASSERT_FALSE(map.Find(1).has_value());
215 ASSERT_FALSE(map.Find(2).has_value());
216 }
217
HWTEST_F_L0(ModuleManagerMapTest,TemplateKeyType)218 HWTEST_F_L0(ModuleManagerMapTest, TemplateKeyType)
219 {
220 ModuleManagerMap<std::string> string_map;
221 JSTaggedValue value(static_cast<JSTaggedType>(42));
222
223 string_map.Insert("test_key", value);
224
225 auto result = string_map.Find("test_key");
226 ASSERT_TRUE(result.has_value());
227 ASSERT_EQ(result->GetRawData(), value.GetRawData());
228
229 ASSERT_FALSE(string_map.Find("non_existent").has_value());
230 }
231 } // namespace panda::test
232