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