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