• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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), &params);
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