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