• 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 "libabckit/include/cpp/abckit_cpp.h"
17 
18 #include "helpers/helpers_runtime.h"
19 #include "helpers/helpers.h"
20 #include "libabckit/include/c/isa/isa_dynamic.h"
21 #include "libabckit/src/include_v2/c/isa/isa_static.h"
22 #include "libabckit/include/c/metadata_core.h"
23 
24 #include <gtest/gtest.h>
25 #include <string_view>
26 #include <unordered_set>
27 
28 namespace libabckit::test {
29 
30 class LibAbcKitCppTest : public ::testing::Test {};
31 // CC-OFFNXT(WordsTool.95) sensitive word conflict
32 // NOLINTNEXTLINE(google-build-using-namespace)
33 using namespace abckit;
34 
35 // CC-OFFNXT(G.FUD.06) perf critical
GetAllFunctions(const File * file)36 inline std::vector<core::Function> GetAllFunctions(const File *file)
37 {
38     std::vector<core::Function> functions;
39 
40     for (auto &module : file->GetModules()) {
41         for (auto &klass : module.GetClasses()) {
42             for (auto &function : klass.GetAllMethods()) {
43                 functions.push_back(function);
44             }
45         }
46         for (auto &function : module.GetTopLevelFunctions()) {
47             functions.push_back(function);
48         }
49     }
50 
51     return functions;
52 }
53 
54 // Test: test-kind=api, api=BasicBlock::AddInstFront, abc-kind=ArkTS1, category=internal, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest1)55 TEST_F(LibAbcKitCppTest, CppTest1)
56 {
57     auto output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc", "cpp_test_dynamic");
58     EXPECT_TRUE(helpers::Match(output, "foo logic\nbar logic\n"));
59 
60     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
61 
62     for (const auto &function : GetAllFunctions(&file)) {
63         abckit::Graph graph = function.CreateGraph();
64         abckit::BasicBlock curBB = graph.GetStartBb().GetSuccByIdx(0);
65 
66         // Insert `print("Func start: " + funcName)`
67         std::string funcStart = "Func start: " + function.GetName();
68         abckit::Instruction loadString = graph.DynIsa().CreateLoadString(funcStart);
69         curBB.AddInstFront(loadString);
70         abckit::Instruction print = graph.DynIsa().CreateTryldglobalbyname("print").InsertAfter(loadString);
71         graph.DynIsa().CreateCallarg1(print, loadString).InsertAfter(print);
72 
73         // Find all `return` instructions
74         std::string funcEnd = "Func end: " + function.GetName();
75 
76         auto instCb = [&](const abckit::Instruction &inst) {
77             AbckitIsaApiDynamicOpcode opcode = inst.GetGraph()->DynIsa().GetOpcode(inst);
78             if (opcode == ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN ||
79                 opcode == ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED) {
80                 abckit::Instruction endStr = graph.DynIsa().CreateLoadString(funcEnd).InsertBefore(inst);
81                 graph.DynIsa().CreateCallarg1(print, endStr).InsertBefore(inst);
82             }
83         };
84 
85         std::vector<abckit::Instruction> instructions;
86         for (auto &block : graph.GetBlocksRPO()) {
87             for (auto &inst : block.GetInstructions()) {
88                 instCb(inst);
89             }
90         }
91         function.SetGraph(graph);
92     }
93 
94     file.WriteAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_modified_1.abc");
95 
96     output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_modified_1.abc", "cpp_test_dynamic");
97     EXPECT_TRUE(helpers::Match(output,
98                                "Func start: func_main_0\n"
99                                "Func start: A\n"
100                                "Func end: A\n"
101                                "Func start: foo\n"
102                                "foo logic\n"
103                                "Func start: bar\n"
104                                "bar logic\n"
105                                "Func end: bar\n"
106                                "Func end: foo\n"
107                                "Func end: func_main_0\n"));
108 }
109 
110 // Test: test-kind=api, api=Function::AddAnnotation, abc-kind=ArkTS1, category=positive, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest2)111 TEST_F(LibAbcKitCppTest, CppTest2)
112 {
113     auto output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc", "cpp_test_dynamic");
114     EXPECT_TRUE(helpers::Match(output, "foo logic\nbar logic\n"));
115 
116     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
117 
118     std::vector<abckit::core::Function> allFunctions = GetAllFunctions(&file);
119 
120     auto findFunctionsWithAnnotationInterface = [&funcs = allFunctions](std::vector<abckit::core::Function> &found,
121                                                                         const std::string &annoName) {
122         for (auto &func : funcs) {
123             auto annos = func.GetAnnotations();
124             auto foundAnno = std::find_if(begin(annos), end(annos), [&annoName](core::Annotation &anno) {
125                 return anno.GetInterface().GetName() == annoName;
126             });
127             if (foundAnno != annos.end()) {
128                 found.push_back(func);
129             }
130         }
131     };
132 
133     std::vector<abckit::core::Function> annotatedBefore;
134     findFunctionsWithAnnotationInterface(annotatedBefore, "MyAnnoName");
135 
136     std::vector<abckit::core::AnnotationInterface> foundAnnoInterfaces;
137     for (auto &fModule : file.GetModules()) {
138         for (auto &aiInterface : fModule.GetAnnotationInterfaces()) {
139             if (aiInterface.GetName() == "MyAnnoName") {
140                 foundAnnoInterfaces.emplace_back(aiInterface);
141             }
142         }
143     }
144 
145     ASSERT_EQ(foundAnnoInterfaces.size(), 1);
146 
147     for (auto &func : allFunctions) {
148         abckit::arkts::Function arktsFunc(func);
149         arktsFunc.AddAnnotation(abckit::arkts::AnnotationInterface(foundAnnoInterfaces[0]));
150     }
151 
152     std::vector<abckit::core::Function> annotatedAfter;
153     findFunctionsWithAnnotationInterface(annotatedAfter, "MyAnnoName");
154 
155     ASSERT_EQ(annotatedBefore.size(), 1);
156     ASSERT_EQ(annotatedAfter.size(), 4U);
157 
158     int found = 0;
159     for (auto &item : annotatedAfter) {
160         if (item == annotatedBefore.front()) {
161             if (++found > 1) {
162                 break;
163             }
164         }
165     }
166     ASSERT_EQ(found, 1);
167 
168     file.WriteAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_modified_2.abc");
169 
170     output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_modified_2.abc", "cpp_test_dynamic");
171     EXPECT_TRUE(helpers::Match(output, "foo logic\nbar logic\n"));
172 }
173 
174 // Test: test-kind=api, api=File::CreateValueU1, abc-kind=ArkTS1, category=positive, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest3)175 TEST_F(LibAbcKitCppTest, CppTest3)
176 {
177     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_js.abc");
178     abckit::Value res = file.CreateValueU1(true);
179     bool val = res.GetU1();
180     ASSERT_TRUE(val);
181     file.WriteAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_js_modified_3.abc");
182 }
183 
184 // Test: test-kind=api, api=File::CreateLiteralBool, abc-kind=ArkTS1, category=internal, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest4)185 TEST_F(LibAbcKitCppTest, CppTest4)
186 {
187     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_js.abc");
188     abckit::Literal res = file.CreateLiteralBool(true);
189     bool val = res.GetBool();
190     ASSERT_TRUE(val);
191     file.WriteAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_js_modified_4.abc");
192 }
193 
194 // Test: test-kind=api, api=File::CreateLiteralArray, abc-kind=ArkTS1, category=internal, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest5)195 TEST_F(LibAbcKitCppTest, CppTest5)
196 {
197     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_js.abc");
198     const double val1 = 0.7;
199     const int val2 = 7U;
200     abckit::LiteralArray larr =
201         file.CreateLiteralArray(std::vector {file.CreateLiteralDouble(val1), file.CreateLiteralU32(val2)});
202     abckit::Literal res = file.CreateLiteralLiteralArray(larr);
203     abckit::LiteralArray val = res.GetLiteralArray();
204 
205     EXPECT_TRUE(larr == val);
206     file.WriteAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_js_modified_5.abc");
207 }
208 
209 // Test: test-kind=api, api=Annotation::AddAndGetElement, abc-kind=ArkTS1, category=positive, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest6)210 TEST_F(LibAbcKitCppTest, CppTest6)
211 {
212     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
213 
214     std::vector<abckit::core::Function> funcs;
215 
216     for (auto &func : GetAllFunctions(&file)) {
217         if (func.GetName() != "foo") {
218             continue;
219         }
220 
221         funcs.push_back(func);
222         break;
223     }
224 
225     ASSERT_EQ(funcs.size(), 1);
226     auto func = funcs[0];
227     auto anns = func.GetAnnotations();
228     ASSERT_EQ(anns.size(), 1);
229 
230     abckit::core::Annotation ann = anns[0];
231     abckit::core::AnnotationInterface anni = ann.GetInterface();
232     auto name = anni.GetName();
233     EXPECT_TRUE(name == "MyAnnoName");
234 
235     const double initVal = 0.12;
236     constexpr std::string_view NEW_NAME = "newValue";
237     abckit::Value value = file.CreateValueDouble(initVal);
238 
239     abckit::arkts::AnnotationElement annel = arkts::Annotation(ann).AddAndGetElement(value, NEW_NAME);
240     EXPECT_TRUE(annel.GetName() == NEW_NAME);
241     EXPECT_TRUE(value.GetDouble() == initVal);
242 
243     file.WriteAbc(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic_mofdified_6.abc");
244 }
245 
246 // Test: test-kind=api, api=Module::GetNamespaces, abc-kind=ArkTS1, category=positive, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest7)247 TEST_F(LibAbcKitCppTest, CppTest7)
248 {
249     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
250 
251     std::vector<std::string> nsNames;
252 
253     for (auto &mdl : file.GetModules()) {
254         for (auto &ns : mdl.GetNamespaces()) {
255             nsNames.push_back(ns.GetName());
256         }
257     }
258 
259     ASSERT_TRUE(nsNames.size() == 1);
260     ASSERT_EQ(nsNames[0], "MyNamespace");
261 }
262 
263 // Test: test-kind=api, api=AnnotationInterface::GetFields, abc-kind=ArkTS1, category=internal, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest8)264 TEST_F(LibAbcKitCppTest, CppTest8)
265 {
266     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
267 
268     std::vector<std::string> annFieldNames;
269 
270     for (auto &mdl : file.GetModules()) {
271         for (auto &anni : mdl.GetAnnotationInterfaces()) {
272             for (auto &anniField : anni.GetFields()) {
273                 annFieldNames.push_back(anniField.GetName());
274             }
275         }
276     }
277 
278     ASSERT_TRUE(annFieldNames.size() == 4U);
279     ASSERT_EQ(annFieldNames[0U], "a");
280     ASSERT_EQ(annFieldNames[1U], "b");
281     ASSERT_EQ(annFieldNames[2U], "d");
282     ASSERT_EQ(annFieldNames[3U], "str");
283 }
284 
285 // Test: test-kind=api, api=ImportDescriptor::GetName, abc-kind=ArkTS1, category=positive, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest9)286 TEST_F(LibAbcKitCppTest, CppTest9)
287 {
288     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
289 
290     std::vector<std::string> importNames;
291 
292     for (auto &mdl : file.GetModules()) {
293         for (auto &imp : mdl.GetImports()) {
294             importNames.push_back(imp.GetName());
295         }
296     }
297 
298     ASSERT_TRUE(importNames.size() == 1);
299     ASSERT_EQ(importNames[0], "TsExport");
300 }
301 
302 // Test: test-kind=api, api=Module::GetExports, abc-kind=ArkTS1, category=positive, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest10)303 TEST_F(LibAbcKitCppTest, CppTest10)
304 {
305     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
306 
307     std::vector<std::string> exportNames;
308 
309     for (auto &mdl : file.GetModules()) {
310         for (auto &exp : mdl.GetExports()) {
311             exportNames.push_back(exp.GetName());
312         }
313     }
314 
315     ASSERT_TRUE(exportNames.size() == 1);
316     ASSERT_EQ(exportNames[0], "bar");
317 }
318 
319 // Test: test-kind=internal, abc-kind=ArkTS1, category=internal, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest11)320 TEST_F(LibAbcKitCppTest, CppTest11)
321 {
322     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
323 
324     // Test checks that Module is hashable
325     std::unordered_set<abckit::core::Module> moduleSet;
326 
327     for (auto &mdl : file.GetModules()) {
328         moduleSet.insert(mdl);
329     }
330 }
331 
332 // Test: test-kind=internal, abc-kind=ArkTS1, category=internal, extension=cpp
TEST_F(LibAbcKitCppTest,CppTest12)333 TEST_F(LibAbcKitCppTest, CppTest12)
334 {
335     abckit::File file(ABCKIT_ABC_DIR "cpp/tests/cpp_test_dynamic.abc");
336     abckit::core::Function func = GetAllFunctions(&file)[0];
337     abckit::Graph graph = func.CreateGraph();
338     abckit::BasicBlock bb = graph.GetStartBb();
339     abckit::Instruction inst = bb.GetFirstInst();
340     while (inst) {
341         ASSERT_TRUE(inst);
342         inst = inst.GetNext();
343     }
344     ASSERT_FALSE(inst);
345 }
346 
347 }  // namespace libabckit::test
348