1 /**
2 * Copyright (c) 2024 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 <cassert>
17 #include <cstring>
18 #include <gtest/gtest.h>
19 #include <numeric>
20
21 #include "libabckit/include/c/abckit.h"
22 #include "helpers/helpers.h"
23 #include "libabckit/include/c/metadata_core.h"
24 #include "libabckit/include/c/statuses.h"
25
26 namespace libabckit::test {
27
28 namespace {
29
30 auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
31 auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
32 auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
33
34 class LibAbcKitInspectApiEnumeratorsTest : public ::testing::Test {};
35
36 using NamesT = std::unordered_map<std::string, std::vector<std::string>>;
37
38 // clang-format off
39 NamesT g_m1NamesDynamic = {
40 {"m0N0N0F0", {"enumerators0_dynamic", "M0N0", "M0N0N0"}},
41 {"M0N0C0", {"enumerators0_dynamic", "M0N0", "M0N0C0"}},
42 {"M0N0C0F0", {"enumerators0_dynamic", "M0N0", "M0N0C0"}},
43 {"M0N0C0F1", {"enumerators0_dynamic", "M0N0", "M0N0C0"}},
44 {"M0N0C0F2", {"enumerators0_dynamic", "M0N0", "M0N0C0"}},
45 {"C", {"enumerators0_dynamic", "M0N0", "A", "B", "C"}},
46 {"D", {"enumerators0_dynamic", "M0N0", "A", "B", "C"}},
47 {"I", {"enumerators0_dynamic", "M0N0", "A", "B"}},
48 {"m0N0F0", {"enumerators0_dynamic", "M0N0"}},
49 {"m0N0F1", {"enumerators0_dynamic", "M0N0"}},
50 {"m0N0F2", {"enumerators0_dynamic", "M0N0"}},
51 {"M0C0", {"enumerators0_dynamic", "M0C0"}},
52 {"M0C0F0", {"enumerators0_dynamic", "M0C0"}},
53 {"M0C0F1", {"enumerators0_dynamic", "M0C0"}},
54 {"M0C0F2", {"enumerators0_dynamic", "M0C0"}},
55 {"m0F0", {"enumerators0_dynamic"}},
56 {"M0F0C0", {"enumerators0_dynamic", "m0F0", "M0F0C0"}},
57 {"M0F0C0F0", {"enumerators0_dynamic", "m0F0", "M0F0C0"}},
58 {"m0F1", {"enumerators0_dynamic"}},
59 {"m0F2", {"enumerators0_dynamic"}},
60 {"enumerators0_dynamic.#~@2=@2*#", {"enumerators0_dynamic"}},
61 {"enumerators0_dynamic.#&@3&A&B~C>D*#E", {"enumerators0_dynamic"}},
62 {"enumerators0_dynamic.#&@3&A&B~C>D*#E^1", {"enumerators0_dynamic"}},
63 {"enumerators0_dynamic.#&@3&A&B~C>D*E^1*#G", {"enumerators0_dynamic"}},
64 {"enumerators0_dynamic.#&@3&A&B~C>D*E*#F", {"enumerators0_dynamic"}},
65 {"enumerators0_dynamic.#&@3&A&B~C>D*#", {"enumerators0_dynamic"}},
66 {"enumerators0_dynamic.#&@3&A&B~C>D**#", {"enumerators0_dynamic"}},
67 {"enumerators0_dynamic.#&@3&A&B~C>D***#H", {"enumerators0_dynamic"}},
68 {"enumerators0_dynamic.#*@0*#", {"enumerators0_dynamic"}},
69 {"enumerators0_dynamic.#*@0*#^1", {"enumerators0_dynamic"}},
70 {"func_main_0", {"enumerators0_dynamic"}},
71 };
72
73 NamesT g_m2NamesDynamic = {
74 {"M1N0C0", {"modules/enumerators1_dynamic", "M1N0", "M1N0C0"}},
75 {"M1N0C0F0", {"modules/enumerators1_dynamic", "M1N0", "M1N0C0"}},
76 {"M1N0C0F1", {"modules/enumerators1_dynamic", "M1N0", "M1N0C0"}},
77 {"M1N0C0F2", {"modules/enumerators1_dynamic", "M1N0", "M1N0C0"}},
78 {"m1N0F0", {"modules/enumerators1_dynamic", "M1N0"}},
79 {"m1N0F1", {"modules/enumerators1_dynamic", "M1N0"}},
80 {"M1C0", {"modules/enumerators1_dynamic", "M1C0"}},
81 {"M1C0F0", {"modules/enumerators1_dynamic", "M1C0"}},
82 {"M1C0F1", {"modules/enumerators1_dynamic", "M1C0"}},
83 {"M1C0F2", {"modules/enumerators1_dynamic", "M1C0"}},
84 {"m1F0", {"modules/enumerators1_dynamic"}},
85 {"m1F1", {"modules/enumerators1_dynamic"}},
86 {"modules/enumerators1_dynamic.#*@0*#", {"modules/enumerators1_dynamic"}},
87 {"func_main_0", {"modules/enumerators1_dynamic"}},
88 };
89 // clang-format on
90
91 std::unordered_map<std::string, NamesT> g_namesDynamic = {
92 {"enumerators0_dynamic", g_m1NamesDynamic},
93 {"modules/enumerators1_dynamic", g_m2NamesDynamic},
94 };
95
96 std::unordered_map<std::string, NamesT> g_namesStatic = {
97 {"enumerators0_dynamic", g_m1NamesDynamic},
98 {"modules/enumerators1_dynamic", g_m2NamesDynamic},
99 };
100
GetCbNamespace(std::vector<std::string> & curNames,std::function<void (AbckitCoreNamespace *)> & cbNamespace,std::function<void (AbckitCoreClass *)> & cbClass,std::function<void (AbckitCoreFunction *)> & cbFunc)101 std::function<void(AbckitCoreNamespace *)> GetCbNamespace(std::vector<std::string> &curNames,
102 std::function<void(AbckitCoreNamespace *)> &cbNamespace,
103 std::function<void(AbckitCoreClass *)> &cbClass,
104 std::function<void(AbckitCoreFunction *)> &cbFunc)
105 {
106 return [&](AbckitCoreNamespace *n) {
107 auto namespaceName = helpers::AbckitStringToString(g_implI->namespaceGetName(n));
108 curNames.emplace_back(namespaceName);
109 g_implI->namespaceEnumerateNamespaces(n, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
110 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
111 return true;
112 });
113 g_implI->namespaceEnumerateClasses(n, &cbClass, [](AbckitCoreClass *c, void *cb) {
114 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
115 return true;
116 });
117 g_implI->namespaceEnumerateTopLevelFunctions(n, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
118 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(f);
119 return true;
120 });
121 curNames.pop_back();
122 };
123 }
124
EnumerateAllMethodsInModule(AbckitFile * file,std::function<void (AbckitCoreClass *)> & cbClass,std::function<void (AbckitCoreFunction *)> & cbFunc,std::vector<std::string> & curNames,std::string & curModuleName)125 void EnumerateAllMethodsInModule(AbckitFile *file, std::function<void(AbckitCoreClass *)> &cbClass,
126 std::function<void(AbckitCoreFunction *)> &cbFunc, std::vector<std::string> &curNames,
127 std::string &curModuleName)
128 {
129 std::function<void(AbckitCoreNamespace *)> cbNamespace = GetCbNamespace(curNames, cbNamespace, cbClass, cbFunc);
130
131 std::function<void(AbckitCoreModule *)> cbModule = [&](AbckitCoreModule *m) {
132 curModuleName = helpers::AbckitStringToString(g_implI->moduleGetName(m));
133 curNames.emplace_back(curModuleName);
134 g_implI->moduleEnumerateNamespaces(m, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
135 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
136 return true;
137 });
138 g_implI->moduleEnumerateClasses(m, &cbClass, [](AbckitCoreClass *c, void *cb) {
139 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
140 return true;
141 });
142 g_implI->moduleEnumerateTopLevelFunctions(m, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
143 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m);
144 return true;
145 });
146 curNames.pop_back();
147 };
148
149 g_implI->fileEnumerateModules(file, &cbModule, [](AbckitCoreModule *m, void *cb) {
150 (*reinterpret_cast<std::function<void(AbckitCoreModule *)> *>(cb))(m);
151 return true;
152 });
153 }
154
155 struct TestStructType {
156 size_t anonFuncsCounter = 0;
157 std::string nameModuleToSearch;
158 std::vector<std::string> namesOfAnonFuncs;
159 };
160
161 } // namespace
162
EnumerateAllMethods(const std::string & inputPath,std::unordered_map<std::string,NamesT> & expectedNames)163 static void EnumerateAllMethods(const std::string &inputPath, std::unordered_map<std::string, NamesT> &expectedNames)
164 {
165 AbckitFile *file = nullptr;
166 helpers::AssertOpenAbc(inputPath.c_str(), &file);
167
168 size_t funcsCounter = 0;
169 std::vector<std::string> curNames {};
170 std::string curModuleName {};
171
172 std::function<void(AbckitCoreClass *)> cbClass;
173
174 std::function<void(AbckitCoreFunction *)> cbFunc = [&](AbckitCoreFunction *f) {
175 auto funcName = helpers::AbckitStringToString(g_implI->functionGetName(f));
176 ASSERT_EQ(expectedNames.count(curModuleName), 1);
177 auto &moduleNames = expectedNames[curModuleName];
178 ASSERT_EQ(moduleNames.count(funcName.data()), 1);
179 auto &funcNames = moduleNames[funcName.data()];
180 ASSERT_EQ(funcNames.size(), curNames.size());
181 ASSERT_TRUE(std::equal(funcNames.begin(), funcNames.end(), curNames.begin()));
182 funcsCounter++;
183 curNames.emplace_back(funcName);
184 g_implI->functionEnumerateNestedFunctions(f, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
185 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(f);
186 return true;
187 });
188 g_implI->functionEnumerateNestedClasses(f, &cbClass, [](AbckitCoreClass *c, void *cb) {
189 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
190 return true;
191 });
192 curNames.pop_back();
193 };
194
195 cbClass = [&](AbckitCoreClass *c) {
196 auto className = helpers::AbckitStringToString(g_implI->classGetName(c));
197 curNames.emplace_back(className);
198 g_implI->classEnumerateMethods(c, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
199 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m);
200 return true;
201 });
202 curNames.pop_back();
203 };
204
205 EnumerateAllMethodsInModule(file, cbClass, cbFunc, curNames, curModuleName);
206 ASSERT_EQ(funcsCounter, std::accumulate(expectedNames.begin(), expectedNames.end(), 0,
207 [](size_t x, auto y) { return x + y.second.size(); }));
208
209 g_impl->closeFile(file);
210 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
211 }
212
EnumerateAnonymousFunctions(const char * abcFilePath,TestStructType & testStruct)213 static void EnumerateAnonymousFunctions(const char *abcFilePath, TestStructType &testStruct)
214 {
215 std::cerr << __PRETTY_FUNCTION__ << '\n';
216 AbckitFile *file = nullptr;
217 std::cerr << __PRETTY_FUNCTION__ << '\n';
218 helpers::AssertOpenAbc(abcFilePath, &file);
219 std::cerr << __PRETTY_FUNCTION__ << '\n';
220
221 g_implI->fileEnumerateModules(file, &testStruct, [](AbckitCoreModule *m, void *data) {
222 auto testStruct = reinterpret_cast<TestStructType *>(data);
223
224 auto strModule = g_implI->moduleGetName(m);
225 EXPECT_TRUE(g_impl->getLastError() == ABCKIT_STATUS_NO_ERROR);
226 auto nameModule = helpers::AbckitStringToString(strModule);
227 if (nameModule != testStruct->nameModuleToSearch) {
228 return true;
229 }
230 g_implI->moduleEnumerateAnonymousFunctions(m, data, [](AbckitCoreFunction *func, void *data1) {
231 auto testStruct = reinterpret_cast<TestStructType *>(data1);
232
233 auto strFunc = g_implI->functionGetName(func);
234 EXPECT_TRUE(g_impl->getLastError() == ABCKIT_STATUS_NO_ERROR);
235
236 auto nameFunc = helpers::AbckitStringToString(strFunc);
237
238 auto &funcs = testStruct->namesOfAnonFuncs;
239
240 auto iter = std::find_if(funcs.begin(), funcs.end(),
241 [&nameFunc](const std::string &name) { return nameFunc == name; });
242
243 EXPECT_TRUE(iter != funcs.end());
244 testStruct->anonFuncsCounter++;
245 return true;
246 });
247 return true;
248 });
249 std::cerr << __PRETTY_FUNCTION__ << '\n';
250
251 ASSERT_EQ(testStruct.anonFuncsCounter, testStruct.namesOfAnonFuncs.size());
252 g_impl->closeFile(file);
253 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
254 }
255
256 // Test: test-kind=api, api=InspectApiImpl::fileEnumerateModules, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicFileEnumerateModules)257 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicFileEnumerateModules)
258 {
259 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
260 g_namesDynamic);
261 }
262
263 // Test: test-kind=api, api=InspectApiImpl::moduleEnumerateNamespaces, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicModuleEnumerateNamespaces)264 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicModuleEnumerateNamespaces)
265 {
266 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
267 g_namesDynamic);
268 }
269
270 // Test: test-kind=api, api=InspectApiImpl::moduleEnumerateClasses, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicModuleEnumerateClasses)271 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicModuleEnumerateClasses)
272 {
273 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
274 g_namesDynamic);
275 }
276
277 // Test: test-kind=api, api=InspectApiImpl::moduleEnumerateTopLevelFunctions, abc-kind=ArkTS1, category=positive,
278 // extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicModuleEnumerateTopLevelFunctions)279 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicModuleEnumerateTopLevelFunctions)
280 {
281 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
282 g_namesDynamic);
283 }
284
285 // Test: test-kind=api, api=InspectApiImpl::namespaceGetName, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicNamespaceGetName)286 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicNamespaceGetName)
287 {
288 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
289 g_namesDynamic);
290 }
291
292 // Test: test-kind=api, api=InspectApiImpl::namespaceEnumerateNamespaces, abc-kind=ArkTS1, category=positive,
293 // extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicNamespaceEnumerateNamespaces)294 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicNamespaceEnumerateNamespaces)
295 {
296 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
297 g_namesDynamic);
298 }
299
300 // Test: test-kind=api, api=InspectApiImpl::namespaceEnumerateClasses, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicNamespaceEnumerateClasses)301 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicNamespaceEnumerateClasses)
302 {
303 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
304 g_namesDynamic);
305 }
306
307 // Test: test-kind=api, api=InspectApiImpl::namespaceEnumerateTopLevelFunctions, abc-kind=ArkTS1, category=positive,
308 // extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicNamespaceEnumerateTopLevelFunctions)309 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicNamespaceEnumerateTopLevelFunctions)
310 {
311 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
312 g_namesDynamic);
313 }
314
315 // Test: test-kind=api, api=InspectApiImpl::classEnumerateMethods, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicClassEnumerateMethods)316 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicClassEnumerateMethods)
317 {
318 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
319 g_namesDynamic);
320 }
321
322 // Test: test-kind=api, api=InspectApiImpl::functionEnumerateNestedFunctions, abc-kind=ArkTS1, category=positive,
323 // extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicFunctionEnumerateNestedFunctions)324 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicFunctionEnumerateNestedFunctions)
325 {
326 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
327 g_namesDynamic);
328 }
329
330 // Test: test-kind=api, api=InspectApiImpl::functionEnumerateNestedClasses, abc-kind=ArkTS1, category=positive,
331 // extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicFunctionEnumerateNestedClasses)332 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicFunctionEnumerateNestedClasses)
333 {
334 EnumerateAllMethods(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
335 g_namesDynamic);
336 }
337
338 // Test: test-kind=api, api=InspectApiImpl::moduleEnumerateAnonymousFunctions, abc-kind=ArkTS1, category=positive,
339 // extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,DynamicClassEnumerateAnonymousFunctions)340 TEST_F(LibAbcKitInspectApiEnumeratorsTest, DynamicClassEnumerateAnonymousFunctions)
341 {
342 std::cerr << __PRETTY_FUNCTION__ << '\n';
343 TestStructType testStruct;
344 testStruct.nameModuleToSearch = "enumerators0_dynamic";
345 testStruct.namesOfAnonFuncs = {
346 "enumerators0_dynamic.#&@3&A&B~C>D*#",
347 "enumerators0_dynamic.#&@3&A&B~C>D**#",
348 "enumerators0_dynamic.#&@3&A&B~C>D*#E",
349 "enumerators0_dynamic.#&@3&A&B~C>D*#E^1",
350 "enumerators0_dynamic.#&@3&A&B~C>D***#H",
351 "enumerators0_dynamic.#&@3&A&B~C>D*E*#F",
352 "enumerators0_dynamic.#&@3&A&B~C>D*E^1*#G",
353 "enumerators0_dynamic.#*@0*#",
354 "enumerators0_dynamic.#*@0*#^1",
355 "enumerators0_dynamic.#~@2=@2*#",
356 };
357
358 EnumerateAnonymousFunctions(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators0_dynamic.abc",
359 testStruct);
360 }
361
362 // Test: test-kind=api, api=InspectApiImpl::moduleEnumerateAnonymousFunctions, abc-kind=ArkTS2, category=positive,
363 // extension=c
TEST_F(LibAbcKitInspectApiEnumeratorsTest,StaticClassEnumerateAnonymousFunctions)364 TEST_F(LibAbcKitInspectApiEnumeratorsTest, StaticClassEnumerateAnonymousFunctions)
365 {
366 TestStructType testStruct;
367 testStruct.nameModuleToSearch = "enumerators_static";
368 testStruct.namesOfAnonFuncs = std::vector<std::string> {"lambda$invoke$0:void;", "lambda$invoke$1:void;"};
369
370 EnumerateAnonymousFunctions(ABCKIT_ABC_DIR "ut/metadata_core/inspect_api/enumerators/enumerators_static.abc",
371 testStruct);
372 }
373
374 } // namespace libabckit::test
375