1 /**
2 * Copyright (c) 2025 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 #include <gtest/gtest.h>
16 #include <algorithm>
17 #include "asm_test.h"
18 #include "assembly-field.h"
19
20 namespace test::utils {
21
AsmTest()22 AsmTest::AsmTest()
23 {
24 ark::mem::MemConfig::Initialize(0, 0, ark::es2panda::COMPILER_SIZE, 0, 0, 0);
25 ark::PoolManager::Initialize(ark::PoolType::MMAP);
26 }
~AsmTest()27 AsmTest::~AsmTest()
28 {
29 ark::PoolManager::Finalize();
30 ark::mem::MemConfig::Finalize();
31 }
32
GetFunction(std::string_view functionName,const std::map<std::string,ark::pandasm::Function> & table)33 ark::pandasm::Function *AsmTest::GetFunction(std::string_view functionName,
34 const std::map<std::string, ark::pandasm::Function> &table)
35 {
36 auto it = table.find(functionName.data());
37 if (it == table.end()) {
38 return nullptr;
39 }
40 return const_cast<ark::pandasm::Function *>(&it->second);
41 }
42
GetRecord(std::string_view recordName,const std::unique_ptr<ark::pandasm::Program> & program)43 ark::pandasm::Record *AsmTest::GetRecord(std::string_view recordName,
44 const std::unique_ptr<ark::pandasm::Program> &program)
45 {
46 auto it = program->recordTable.find(recordName.data());
47 if (it == program->recordTable.end()) {
48 return nullptr;
49 }
50 return &it->second;
51 }
52
CompareActualWithExpected(const std::string & expectedValue,ark::pandasm::ScalarValue * scalarValue,const std::string & field)53 void AsmTest::CompareActualWithExpected(const std::string &expectedValue, ark::pandasm::ScalarValue *scalarValue,
54 const std::string &field)
55 {
56 std::string actualValue = std::visit(
57 [](const auto &value) -> std::string {
58 using ValueType = std::decay_t<decltype(value)>;
59 if constexpr (std::is_same_v<ValueType, std::string>) {
60 return value;
61 } else if constexpr (std::is_arithmetic_v<ValueType>) {
62 return std::to_string(value);
63 } else {
64 return "Unsupported type";
65 }
66 },
67 scalarValue->GetValue());
68
69 ASSERT_EQ(actualValue, expectedValue) << "Value mismatch for " + field;
70 }
71
CheckAnnoDecl(ark::pandasm::Program * program,const std::string & annoName,const std::vector<std::pair<std::string,std::string>> & expectedAnnotations)72 void AsmTest::CheckAnnoDecl(ark::pandasm::Program *program, const std::string &annoName,
73 const std::vector<std::pair<std::string, std::string>> &expectedAnnotations)
74 {
75 const auto &recordTable = program->recordTable;
76 ASSERT_FALSE(recordTable.empty()) << "No records found in the program.";
77 auto found = recordTable.find(annoName);
78 ASSERT_NE(found, recordTable.end());
79
80 for (size_t i = 0; i < expectedAnnotations.size(); i++) {
81 auto scalarValue = found->second.fieldList[i].metadata->GetValue();
82 if (scalarValue) {
83 CompareActualWithExpected(expectedAnnotations[i].second, &*scalarValue, found->second.fieldList[i].name);
84 }
85 }
86 }
87
CheckLiteralArrayTable(ark::pandasm::Program * program,const std::vector<std::pair<std::string,std::vector<AnnotationValueType>>> & expectedLiteralArrayTable)88 void AsmTest::CheckLiteralArrayTable(
89 ark::pandasm::Program *program,
90 const std::vector<std::pair<std::string, std::vector<AnnotationValueType>>> &expectedLiteralArrayTable)
91 {
92 const auto &literalarrayTable = program->literalarrayTable;
93 ASSERT_FALSE(literalarrayTable.empty()) << "literalarrayTable is empty!";
94 for (const auto &literalArray : expectedLiteralArrayTable) {
95 auto found = literalarrayTable.find(literalArray.first);
96 ASSERT_NE(found, literalarrayTable.end());
97 size_t i = 1;
98 for (const auto &value : literalArray.second) {
99 constexpr int STRIDE = 2;
100 ASSERT_EQ(value, found->second.literals[i].value) << "Value mismatch for " + literalArray.first;
101 i += STRIDE;
102 }
103 }
104 }
105
CheckAnnotation(const std::vector<std::pair<std::string,std::string>> & expectedValues,const ark::pandasm::AnnotationData & annotation)106 void AsmTest::CheckAnnotation(const std::vector<std::pair<std::string, std::string>> &expectedValues,
107 const ark::pandasm::AnnotationData &annotation)
108 {
109 for (const auto &element : annotation.GetElements()) {
110 auto it = std::find_if(expectedValues.begin(), expectedValues.end(),
111 [&element](const auto &pair) { return pair.first == element.GetName(); });
112 if (it != expectedValues.end()) {
113 CompareActualWithExpected(it->second, element.GetValue()->GetAsScalar(), element.GetName());
114 }
115 }
116 }
117
CheckRecordAnnotations(ark::pandasm::Program * program,const std::string & recordName,const AnnotationMap & expectedAnnotations)118 void AsmTest::CheckRecordAnnotations(ark::pandasm::Program *program, const std::string &recordName,
119 const AnnotationMap &expectedAnnotations)
120 {
121 const auto &recordTable = program->recordTable;
122 ASSERT_FALSE(recordTable.empty()) << "No records found in the program.";
123 auto found = recordTable.find(recordName);
124 ASSERT_NE(found, recordTable.end());
125
126 for (const auto &expected : expectedAnnotations) {
127 auto annotations = found->second.metadata->GetAnnotations();
128 auto it = std::find_if(annotations.begin(), annotations.end(),
129 [&expected](const ark::pandasm::AnnotationData &annotation) {
130 return annotation.GetName() == expected.first;
131 });
132
133 ASSERT_NE(it, annotations.end()) << recordName << " missing expected annotation: " << expected.first;
134
135 // Check the fields for the matched annotation name
136 CheckAnnotation(expected.second, *it);
137 }
138 }
139
CheckModuleAnnotation(ark::pandasm::Program * program,const std::string & recordName,bool isModule,const std::vector<std::string> & expectedAnnotations)140 void AsmTest::CheckModuleAnnotation(ark::pandasm::Program *program, const std::string &recordName, bool isModule,
141 const std::vector<std::string> &expectedAnnotations)
142 {
143 const auto &recordTable = program->recordTable;
144 ASSERT_FALSE(recordTable.empty()) << "No records found in the program.";
145 auto found = recordTable.find(recordName);
146 ASSERT_NE(found, recordTable.end());
147
148 auto annotations = found->second.metadata->GetAnnotations();
149 auto it = std::find_if(annotations.begin(), annotations.end(), [](const ark::pandasm::AnnotationData &annotation) {
150 return annotation.GetName() == std::string {ark::es2panda::compiler::Signatures::ETS_ANNOTATION_MODULE};
151 });
152 if (isModule) {
153 ASSERT_NE(it, annotations.end()) << recordName << " missing expected annotation: "
154 << ark::es2panda::compiler::Signatures::ETS_ANNOTATION_MODULE;
155 } else {
156 ASSERT_EQ(it, annotations.end()) << recordName << " has annotation: "
157 << ark::es2panda::compiler::Signatures::ETS_ANNOTATION_MODULE
158 << ", but shouldn't";
159 return;
160 }
161 ASSERT_EQ(it->GetElements().size(), 1);
162 const auto &element = it->GetElements()[0];
163 ASSERT_EQ(element.GetName(), std::string {ark::es2panda::compiler::Signatures::ANNOTATION_KEY_EXPORTED})
164 << recordName << "module annotation missing element "
165 << ark::es2panda::compiler::Signatures::ANNOTATION_KEY_EXPORTED;
166
167 for (const auto &val : element.GetValue()->GetAsArray()->GetValues()) {
168 auto name = val.GetValue<ark::pandasm::Type>().GetName();
169 auto foundExpected = std::find(expectedAnnotations.begin(), expectedAnnotations.end(), name);
170 ASSERT_NE(foundExpected, expectedAnnotations.end()) << "Value mismatch for " + name;
171 }
172 }
173
CheckRecordWithoutAnnotations(ark::pandasm::Program * program,const std::string & recordName,bool isModule)174 void AsmTest::CheckRecordWithoutAnnotations(ark::pandasm::Program *program, const std::string &recordName,
175 bool isModule)
176 {
177 const auto &recordTable = program->recordTable;
178 ASSERT_FALSE(recordTable.empty()) << "No records found in the program.";
179 auto found = recordTable.find(recordName);
180 ASSERT_NE(found, recordTable.end());
181 if (isModule) {
182 ASSERT_EQ(found->second.metadata->GetAnnotations().size(), 1);
183 } else {
184 ASSERT(found->second.metadata->GetAnnotations().empty());
185 }
186 }
187
CheckFunctionAnnotations(ark::pandasm::Program * program,const std::string & functionName,bool isStatic,const AnnotationMap & expectedAnnotations)188 void AsmTest::CheckFunctionAnnotations(ark::pandasm::Program *program, const std::string &functionName, bool isStatic,
189 const AnnotationMap &expectedAnnotations)
190 {
191 const auto &functionTable = isStatic ? program->functionStaticTable : program->functionInstanceTable;
192 auto found = functionTable.find(functionName);
193 ASSERT_NE(found, functionTable.end()) << "Unexpected function Name: " << functionName;
194
195 for (const auto &expected : expectedAnnotations) {
196 auto annotations = found->second.metadata->GetAnnotations();
197 auto it = std::find_if(annotations.begin(), annotations.end(),
198 [&expected](const ark::pandasm::AnnotationData &annotation) {
199 return annotation.GetName() == expected.first;
200 });
201
202 ASSERT_NE(it, annotations.end()) << functionName << " missing expected annotation: " << expected.first;
203
204 // Check the fields for the matched annotation name
205 CheckAnnotation(expected.second, *it);
206 }
207 }
208
CheckFunctionWithoutAnnotations(ark::pandasm::Program * program,const std::string & functionName,bool isStatic)209 void AsmTest::CheckFunctionWithoutAnnotations(ark::pandasm::Program *program, const std::string &functionName,
210 bool isStatic)
211 {
212 const auto &functionTable = isStatic ? program->functionStaticTable : program->functionInstanceTable;
213 auto found = functionTable.find(functionName);
214 ASSERT_NE(found, functionTable.end()) << "Unexpected function Name: " << functionName;
215 ASSERT(found->second.metadata->GetAnnotations().empty());
216 }
217
CheckFunctionParameterAnnotations(ark::pandasm::Program * program,const std::string & functionName,bool isStatic,const uint32_t & paramIndex,const AnnotationMap & expectedAnnotations)218 void AsmTest::CheckFunctionParameterAnnotations(ark::pandasm::Program *program, const std::string &functionName,
219 bool isStatic, const uint32_t ¶mIndex,
220 const AnnotationMap &expectedAnnotations)
221 {
222 const auto &functionTable = isStatic ? program->functionStaticTable : program->functionInstanceTable;
223 auto found = functionTable.find(functionName);
224 ASSERT_NE(found, functionTable.end());
225 ASSERT_LT(paramIndex, found->second.params.size());
226
227 for (const auto &expected : expectedAnnotations) {
228 auto annotations = found->second.params.at(paramIndex).GetOrCreateMetadata().GetAnnotations();
229 auto it = std::find_if(annotations.begin(), annotations.end(),
230 [&expected](const ark::pandasm::AnnotationData &annotation) {
231 return annotation.GetName() == expected.first;
232 });
233
234 ASSERT_NE(it, annotations.end()) << functionName << "param at " << paramIndex
235 << " missing expected annotation: " << expected.first;
236
237 // Check the fields for the matched annotation name
238 CheckAnnotation(expected.second, *it);
239 }
240 }
241
CheckFunctionParameterWithoutAnnotations(ark::pandasm::Program * program,const std::string & functionName,bool isStatic,const uint32_t & paramIndex)242 void AsmTest::CheckFunctionParameterWithoutAnnotations(ark::pandasm::Program *program, const std::string &functionName,
243 bool isStatic, const uint32_t ¶mIndex)
244 {
245 const auto &functionTable = isStatic ? program->functionStaticTable : program->functionInstanceTable;
246 auto found = functionTable.find(functionName);
247 ASSERT_NE(found, functionTable.end());
248 ASSERT_LT(paramIndex, found->second.params.size());
249 ASSERT(found->second.params.at(paramIndex).GetOrCreateMetadata().GetAnnotations().empty());
250 }
251
CheckClassFieldAnnotations(ark::pandasm::Program * program,const std::string & recordName,const std::string & fieldName,const AnnotationMap & expectedAnnotations)252 void AsmTest::CheckClassFieldAnnotations(ark::pandasm::Program *program, const std::string &recordName,
253 const std::string &fieldName, const AnnotationMap &expectedAnnotations)
254 {
255 const auto &recordTable = program->recordTable;
256 auto found = recordTable.find(recordName);
257 ASSERT_NE(found, recordTable.end());
258 auto &filedList = found->second.fieldList;
259 auto result = std::find_if(filedList.begin(), filedList.end(),
260 [&fieldName](const ark::pandasm::Field &field) { return field.name == fieldName; });
261 ASSERT_NE(result, filedList.end()) << "Cannot find classProperty '" << fieldName << "'.";
262 for (const auto &expected : expectedAnnotations) {
263 auto annotations = result->metadata->GetAnnotations();
264 auto it = std::find_if(annotations.begin(), annotations.end(),
265 [&expected](const ark::pandasm::AnnotationData &annotation) {
266 return annotation.GetName() == expected.first;
267 });
268
269 ASSERT_NE(it, annotations.end()) << fieldName << " missing expected annotation: " << expected.first;
270
271 // Check the fields for the matched annotation name
272 CheckAnnotation(expected.second, *it);
273 }
274 }
275
CheckClassFieldWithoutAnnotations(ark::pandasm::Program * program,const std::string & recordName,const std::string & fieldName)276 void AsmTest::CheckClassFieldWithoutAnnotations(ark::pandasm::Program *program, const std::string &recordName,
277 const std::string &fieldName)
278 {
279 const auto &recordTable = program->recordTable;
280 auto found = recordTable.find(recordName);
281 ASSERT_NE(found, recordTable.end());
282 auto &filedList = found->second.fieldList;
283 auto result = std::find_if(filedList.begin(), filedList.end(),
284 [&fieldName](const ark::pandasm::Field &field) { return field.name == fieldName; });
285 ASSERT_NE(result, filedList.end()) << "Cannot find classProperty '" << fieldName << "'.";
286 ASSERT(result->metadata->GetAnnotations().empty());
287 }
288
SetCurrentProgram(std::string_view src)289 void AsmTest::SetCurrentProgram(std::string_view src)
290 {
291 int argc = 1;
292 const char *argv = "../../../../bin/es2panda"; // NOLINT(modernize-avoid-c-arrays)
293 static constexpr std::string_view FILE_NAME = "dummy.ets";
294
295 program_ = GetProgram(argc, &argv, FILE_NAME, src);
296 ASSERT_NE(program_.get(), nullptr);
297 }
298
GetCurrentProgram(std::string_view src)299 std::unique_ptr<ark::pandasm::Program> AsmTest::GetCurrentProgram(std::string_view src)
300 {
301 static constexpr std::string_view FILE_NAME = "annotation.ets";
302 std::array<char const *, 2> args = {"../../../../../bin/es2panda",
303 "--ets-unnamed"}; // NOLINT(modernize-avoid-c-arrays)
304
305 auto program = GetProgram(args.size(), args.data(), FILE_NAME, src);
306 return program;
307 }
308
309 } // namespace test::utils
310