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 "abc2program_test_utils.h"
17 #include <algorithm>
18 #include <filesystem>
19 #include <fstream>
20 #include <regex>
21 #include <vector>
22
23 #include "common/abc_file_utils.h"
24 #include "dump_utils.h"
25
26 namespace panda::abc2program {
27
28 std::set<std::string> Abc2ProgramTestUtils::helloworld_expected_program_strings_ = {"",
29 ".#*#add",
30 ".#*#asyncArrowFunc",
31 ".#*#asyncGenerateFunc",
32 ".#*#asyncSendableFunction",
33 ".#*#foo",
34 ".#*#generateFunc",
35 ".#*#goo",
36 ".#*#hoo",
37 ".#*#sendableFunction",
38 ".#~@0=#HelloWorld",
39 ".#~@1=#Lit",
40 ".#~@2=#NestedLiteralArray",
41 "HelloWorld",
42 "error",
43 "hello",
44 "inner catch",
45 "masg",
46 "max",
47 "min",
48 "msg",
49 "null",
50 "num",
51 "outter catch",
52 "print",
53 "prototype",
54 "str",
55 "string",
56 "toString",
57 "varA",
58 "x"};
59 std::vector<std::string> Abc2ProgramTestUtils::helloworld_expected_record_names_ = {
60 "_ESExpectedPropertyCountAnnotation",
61 "_ESModuleRecord",
62 "_ESSlotNumberAnnotation",
63 "_ESScopeNamesRecord",
64 "_GLOBAL"
65 };
66 std::vector<std::string> Abc2ProgramTestUtils::helloworld_expected_literal_array_keys_ = {
67 "_ESModuleRecord",
68 "_ESScopeNamesRecord",
69 "_GLOBAL",
70 "_GLOBAL",
71 "_GLOBAL",
72 "_GLOBAL",
73 "_GLOBAL"
74 };
75
76 std::set<size_t> Abc2ProgramTestUtils::helloworld_expected_literals_sizes_ = {2, 6, 8, 10, 21};
77
78 template <typename T>
ValidateStrings(const T & strings,const T & expected_strings)79 bool Abc2ProgramTestUtils::ValidateStrings(const T &strings, const T &expected_strings)
80 {
81 if (strings.size() != expected_strings.size()) {
82 return false;
83 }
84 for (const std::string &expected_string : expected_strings) {
85 const auto string_iter = std::find(strings.begin(), strings.end(), expected_string);
86 if (string_iter == strings.end()) {
87 return false;
88 }
89 }
90 return true;
91 }
92
ValidateProgramStrings(const std::set<std::string> & program_strings)93 bool Abc2ProgramTestUtils::ValidateProgramStrings(const std::set<std::string> &program_strings)
94 {
95 return ValidateStrings(program_strings, helloworld_expected_program_strings_);
96 }
97
ValidateRecordNames(const std::vector<std::string> & record_names)98 bool Abc2ProgramTestUtils::ValidateRecordNames(const std::vector<std::string> &record_names)
99 {
100 return ValidateStrings(record_names, helloworld_expected_record_names_);
101 }
102
ValidateLiteralArrayKeys(const std::vector<std::string> & literal_array_keys)103 bool Abc2ProgramTestUtils::ValidateLiteralArrayKeys(const std::vector<std::string> &literal_array_keys)
104 {
105 if (literal_array_keys.size() != helloworld_expected_literal_array_keys_.size()) {
106 return false;
107 }
108 for (size_t i = 0; i < literal_array_keys.size(); ++i) {
109 if (literal_array_keys[i].find(helloworld_expected_literal_array_keys_[i]) != 0) {
110 return false;
111 }
112 }
113 return true;
114 }
115
ValidateLiteralsSizes(const std::set<size_t> & literal_array_sizes)116 bool Abc2ProgramTestUtils::ValidateLiteralsSizes(const std::set<size_t> &literal_array_sizes)
117 {
118 return (literal_array_sizes == helloworld_expected_literals_sizes_);
119 }
120
ValidateDumpResult(const std::string & result_file_name,const std::string & expected_file_name)121 bool Abc2ProgramTestUtils::ValidateDumpResult(
122 const std::string &result_file_name, const std::string &expected_file_name)
123 {
124 std::ifstream result_file(result_file_name);
125 if (!result_file.is_open()) {
126 return false;
127 }
128 std::ifstream expected_file(expected_file_name);
129 if (!expected_file.is_open()) {
130 return false;
131 }
132 bool is_same = true;
133 std::string result_line;
134 std::string expected_line;
135 // Validate each line of dump results file, including empty lines.
136 while (!result_file.eof() && !expected_file.eof()) {
137 std::getline(result_file, result_line);
138 std::getline(expected_file, expected_line);
139 if (result_line != expected_line && !ValidateLine(result_line, expected_line)) {
140 is_same = false;
141 break;
142 }
143 }
144 bool is_eof = result_file.eof() && expected_file.eof();
145 result_file.close();
146 expected_file.close();
147 return is_same && is_eof;
148 }
149
ValidateLine(const std::string & result_line,const std::string & expected_line)150 bool Abc2ProgramTestUtils::ValidateLine(const std::string &result_line, const std::string &expected_line)
151 {
152 // Split input strings by white spaces.
153 std::regex white_space("\\s+");
154 std::vector<std::string> result_substrs(
155 std::sregex_token_iterator(result_line.begin(), result_line.end(), white_space, -1),
156 std::sregex_token_iterator());
157 std::vector<std::string> expected_substrs(
158 std::sregex_token_iterator(expected_line.begin(), expected_line.end(), white_space, -1),
159 std::sregex_token_iterator());
160 // Compare all divived sub-strings.
161 if (result_substrs.size() != expected_substrs.size()) {
162 return false;
163 }
164 for (size_t i = 0; i != result_substrs.size(); ++i) {
165 /* It's acceptable if:
166 * 0. the sub-strings are same.
167 * 1. the sub-string is a regular file path, for example, path of the input abc file, which
168 * could be different on different computers.
169 * 2. the sub-strings are literal array names with offset, offset could be modified when
170 * abc file version changed.
171 */
172 if (result_substrs[i] != expected_substrs[i] &&
173 !std::filesystem::is_regular_file(std::filesystem::path(result_substrs[i])) &&
174 !ValidateLiteralArrayName(result_substrs[i], expected_substrs[i])) {
175 return false;
176 }
177 }
178 return true;
179 }
180
ValidateLiteralArrayName(const std::string & result,const std::string & expected)181 bool Abc2ProgramTestUtils::ValidateLiteralArrayName(const std::string &result, const std::string &expected)
182 {
183 // Extract the record name from a literal array name, for example, extract "_GLOBAL" from "_GLOBAL_1466".
184 // The record name of input string 'result' should be same as that of 'expected'.
185 auto res_end_pos = result.rfind(UNDERLINE);
186 auto exp_end_pos = expected.rfind(UNDERLINE);
187 if (res_end_pos == std::string::npos || exp_end_pos == std::string::npos || res_end_pos != exp_end_pos) {
188 return false;
189 }
190 auto res_start_pos = result.rfind(DUMP_CONTENT_COLON, res_end_pos) + 1;
191 auto exp_start_pos = expected.rfind(DUMP_CONTENT_COLON, exp_end_pos) + 1;
192 if (res_start_pos != exp_start_pos) {
193 return false;
194 }
195 auto res_name = result.substr(res_start_pos, res_end_pos - res_start_pos);
196 if (std::find(helloworld_expected_literal_array_keys_.begin(),
197 helloworld_expected_literal_array_keys_.end(),
198 res_name) == helloworld_expected_literal_array_keys_.end()) {
199 return false;
200 }
201 auto exp_name = expected.substr(exp_start_pos, exp_end_pos - exp_start_pos);
202 return res_name == exp_name;
203 }
204
RemoveDumpResultFile(const std::string & file_name)205 void Abc2ProgramTestUtils::RemoveDumpResultFile(const std::string &file_name)
206 {
207 std::filesystem::remove(std::filesystem::path(file_name));
208 }
209 } // namespace panda::abc2program
210