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 <gtest/gtest.h>
17
18 #include "libabckit/include/c/extensions/arkts/metadata_arkts.h"
19 #include "helpers/helpers.h"
20 #include "helpers/helpers_runtime.h"
21 #include "helpers/visit_helper/visit_helper-inl.h"
22
23 namespace libabckit::test {
24
25 static auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
26 static auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
27 static auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
28 static auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
29 static auto g_dynG = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
30 static auto g_implArkI = AbckitGetArktsInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
31 static auto g_implArkM = AbckitGetArktsModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
32
33 static const std::string ROUTER_MAP_FILE_MODULE_NAME = "modules/routerMap";
34 static const std::string ROUTER_ANNOTATION_NAME = "Router";
35 static const std::string FUNC_MAIN_0 = "func_main_0";
36
37 class AbckitScenarioTest : public ::testing::Test {};
38
39 struct RouterAnnotation {
40 AbckitCoreClass *owner;
41 AbckitCoreAnnotation *ptrToAnno;
42 AbckitString *scheme;
43 AbckitString *path;
44 };
45
46 struct UserData {
47 AbckitString *classStr;
48 AbckitString *moduleStr;
49 RouterAnnotation routerInfo;
50 };
51
52 struct LocalData {
53 size_t idx;
54 AbckitInst *insertAfterInst;
55 AbckitCoreImportDescriptor *coreImport;
56 };
57
TransformMethod(AbckitCoreFunction * method,VisitHelper & visitor,const UserData * ud,LocalData * ld)58 static void TransformMethod(AbckitCoreFunction *method, VisitHelper &visitor, const UserData *ud, LocalData *ld)
59 {
60 visitor.TransformMethod(method, [&](AbckitFile *file, AbckitCoreFunction *method) {
61 auto ctxG = g_implI->createGraphFromFunction(method);
62 AbckitBasicBlock *startBB = g_implG->gGetStartBasicBlock(ctxG);
63 std::vector<AbckitBasicBlock *> succBBs;
64 g_implG->bbVisitSuccBlocks(startBB, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
65 auto *succs = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
66 succs->emplace_back(succBasicBlock);
67 return true;
68 });
69 AbckitInst *createEmptyArray = helpers::FindFirstInst(ctxG, ABCKIT_ISA_API_DYNAMIC_OPCODE_CREATEEMPTYARRAY);
70
71 const auto &routerInfo = ud->routerInfo;
72 std::string fullPath =
73 std::string(visitor.GetString(routerInfo.scheme)) + std::string(visitor.GetString(routerInfo.path));
74 auto arr = std::vector<AbckitLiteral *>();
75 AbckitLiteral *str = g_implM->createLiteralString(file, fullPath.data(), fullPath.size());
76 arr.emplace_back(str);
77
78 auto *litArr = g_implM->createLiteralArray(file, arr.data(), arr.size());
79 auto *createArrayWithBuffer = g_dynG->iCreateCreatearraywithbuffer(ctxG, litArr);
80
81 if (ld->insertAfterInst == nullptr) {
82 ld->insertAfterInst = createEmptyArray;
83 }
84
85 auto *ldExternal = g_dynG->iCreateLdexternalmodulevar(ctxG, ld->coreImport);
86
87 auto *classThrow =
88 g_dynG->iCreateThrowUndefinedifholewithname(ctxG, ldExternal, g_implI->classGetName(routerInfo.owner));
89
90 auto *newObj = g_dynG->iCreateNewobjrange(ctxG, 1, ldExternal);
91
92 auto *stownByIndex1 = g_dynG->iCreateStownbyindex(ctxG, newObj, createArrayWithBuffer, 1);
93
94 auto *stownByIndex2 = g_dynG->iCreateStownbyindex(ctxG, createArrayWithBuffer, createEmptyArray, ld->idx++);
95
96 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
97
98 g_implG->iInsertAfter(createArrayWithBuffer, ld->insertAfterInst);
99 g_implG->iInsertAfter(ldExternal, createArrayWithBuffer);
100 g_implG->iInsertAfter(classThrow, ldExternal);
101 g_implG->iInsertAfter(newObj, classThrow);
102 g_implG->iInsertAfter(stownByIndex1, newObj);
103 g_implG->iInsertAfter(stownByIndex2, stownByIndex1);
104
105 ld->insertAfterInst = stownByIndex2;
106
107 g_implM->functionSetGraph(method, ctxG);
108 g_impl->destroyGraph(ctxG);
109 });
110 }
111
ModifyRouterTable(AbckitCoreFunction * method,VisitHelper & visitor,const std::vector<UserData> & udContainer)112 static void ModifyRouterTable(AbckitCoreFunction *method, VisitHelper &visitor,
113 const std::vector<UserData> &udContainer)
114 {
115 LocalData ld {};
116 ld.idx = 0;
117 ld.insertAfterInst = nullptr;
118 for (const auto &ud : udContainer) {
119 const auto &className = visitor.GetString(ud.classStr);
120 AbckitArktsImportFromDynamicModuleCreateParams params {};
121 params.name = className.data();
122 params.alias = className.data();
123
124 const auto &moduleName = visitor.GetString(ud.moduleStr);
125 helpers::ModuleByNameContext ctxFinder = {nullptr, moduleName.data()};
126 g_implI->fileEnumerateModules(g_implI->functionGetFile(method), &ctxFinder, helpers::ModuleByNameFinder);
127 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
128 ASSERT_NE(ctxFinder.module, nullptr);
129 auto *newImport = g_implArkM->moduleAddImportFromArktsV1ToArktsV1(
130 g_implArkI->coreModuleToArktsModule(g_implI->functionGetModule(method)),
131 g_implArkI->coreModuleToArktsModule(ctxFinder.module), ¶ms);
132 ld.coreImport = g_implArkI->arktsImportDescriptorToCoreImportDescriptor(newImport);
133 TransformMethod(method, visitor, &ud, &ld);
134 }
135 }
136
FindMethodWithRouterTable(VisitHelper & visitor)137 static AbckitCoreFunction *FindMethodWithRouterTable(VisitHelper &visitor)
138 {
139 AbckitCoreFunction *routerFunc = nullptr;
140 visitor.EnumerateModules([&](AbckitCoreModule *mod) {
141 auto moduleName = visitor.GetString(g_implI->moduleGetName(mod));
142 if (moduleName != ROUTER_MAP_FILE_MODULE_NAME) {
143 return;
144 }
145 visitor.EnumerateModuleTopLevelFunctions(mod, [&](AbckitCoreFunction *func) {
146 auto funcName = visitor.GetString(g_implI->functionGetName(func));
147 if (funcName != FUNC_MAIN_0) {
148 return;
149 }
150 routerFunc = func;
151 });
152 });
153 return routerFunc;
154 }
155
RemoveAnnotations(const std::vector<UserData> & udContainer)156 static void RemoveAnnotations(const std::vector<UserData> &udContainer)
157 {
158 for (const auto &ud : udContainer) {
159 const auto &routerInfo = ud.routerInfo;
160 g_implArkM->classRemoveAnnotation(g_implArkI->coreClassToArktsClass(routerInfo.owner),
161 g_implArkI->coreAnnotationToArktsAnnotation(routerInfo.ptrToAnno));
162 }
163 }
164
CollectClasseInfo(VisitHelper & visitor,std::vector<UserData> & udContainer,AbckitCoreModule * mod,AbckitCoreClass * klass)165 static void CollectClasseInfo(VisitHelper &visitor, std::vector<UserData> &udContainer, AbckitCoreModule *mod,
166 AbckitCoreClass *klass)
167 {
168 visitor.EnumerateClassAnnotations(klass, [&](AbckitCoreAnnotation *anno) {
169 auto *annoClass = g_implI->annotationGetInterface(anno);
170 auto annoName = visitor.GetString(g_implI->annotationInterfaceGetName(annoClass));
171 if (annoName != ROUTER_ANNOTATION_NAME) {
172 return;
173 }
174 UserData ud {};
175 ud.classStr = g_implI->classGetName(klass);
176 ud.moduleStr = g_implI->moduleGetName(mod);
177 auto &routerInfo = ud.routerInfo;
178 routerInfo.ptrToAnno = anno;
179 routerInfo.owner = klass;
180 visitor.EnumerateAnnotationElements(anno, [&](AbckitCoreAnnotationElement *annoElem) {
181 auto annoElemName = visitor.GetString(g_implI->annotationElementGetName(annoElem));
182 auto *value = g_implI->annotationElementGetValue(annoElem);
183 if (std::string_view(annoElemName) == "scheme") {
184 routerInfo.scheme = g_implI->valueGetString(value);
185 }
186 if (std::string_view(annoElemName) == "path") {
187 routerInfo.path = g_implI->valueGetString(value);
188 }
189 });
190 udContainer.push_back(ud);
191 });
192 }
193
CollectClassesInfo(VisitHelper & visitor,std::vector<UserData> & udContainer)194 static void CollectClassesInfo(VisitHelper &visitor, std::vector<UserData> &udContainer)
195 {
196 visitor.EnumerateModules([&](AbckitCoreModule *mod) {
197 visitor.EnumerateModuleClasses(
198 mod, [&](AbckitCoreClass *klass) { CollectClasseInfo(visitor, udContainer, mod, klass); });
199 });
200 }
201
ClassHasAnnotation(VisitHelper & visitor,const UserData & ud)202 static bool ClassHasAnnotation(VisitHelper &visitor, const UserData &ud)
203 {
204 bool found = false;
205
206 auto classAnnotationsEnumCb = [&](AbckitCoreAnnotation *anno) {
207 auto *annoClass = g_implI->annotationGetInterface(anno);
208 auto annoName = visitor.GetString(g_implI->annotationInterfaceGetName(annoClass));
209 if (annoName == ROUTER_ANNOTATION_NAME) {
210 found = true;
211 }
212 };
213
214 visitor.EnumerateModules([&](AbckitCoreModule *mod) {
215 if (visitor.GetString(g_implI->moduleGetName(mod)) != visitor.GetString(ud.moduleStr)) {
216 return;
217 }
218 visitor.EnumerateModuleClasses(mod, [&](AbckitCoreClass *klass) {
219 if (visitor.GetString(g_implI->classGetName(klass)) != visitor.GetString(ud.classStr)) {
220 return;
221 }
222 visitor.EnumerateClassAnnotations(klass, classAnnotationsEnumCb);
223 });
224 });
225 return found;
226 }
227
228 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioTest,LibAbcKitTestRouterTable)229 TEST_F(AbckitScenarioTest, LibAbcKitTestRouterTable)
230 {
231 std::string inputPath = ABCKIT_ABC_DIR "scenarios/router_table/dynamic/router_table.abc";
232 std::string outputPath = ABCKIT_ABC_DIR "scenarios/router_table/dynamic/router_table_modified.abc";
233
234 auto output = helpers::ExecuteDynamicAbc(inputPath, "router_table");
235 EXPECT_TRUE(helpers::Match(output, ""));
236
237 AbckitFile *ctxI = g_impl->openAbc(inputPath.c_str(), inputPath.size());
238 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
239
240 auto visitor = VisitHelper(ctxI, g_impl, g_implI, g_implG, g_dynG);
241
242 std::vector<UserData> userData;
243
244 CollectClassesInfo(visitor, userData);
245 RemoveAnnotations(userData);
246 auto *method = FindMethodWithRouterTable(visitor);
247 ModifyRouterTable(method, visitor, userData);
248
249 g_impl->writeAbc(ctxI, outputPath.c_str(), outputPath.size());
250 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
251
252 for (const auto &ud : userData) {
253 ASSERT_FALSE(ClassHasAnnotation(visitor, ud));
254 }
255
256 output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "scenarios/router_table/dynamic/router_table_modified.abc",
257 "router_table");
258
259 g_impl->closeFile(ctxI);
260
261 EXPECT_TRUE(helpers::Match(output,
262 "xxxHandler.handle was called\n"
263 "handle1/xxx\n"));
264 }
265
266 } // namespace libabckit::test
267