]>
Commit | Line | Data |
---|---|---|
f67539c2 | 1 | #!/usr/bin/env python3 |
9f95a23c TL |
2 | |
3 | # | |
4 | # Copyright(c) 2012-2018 Intel Corporation | |
5 | # SPDX-License-Identifier: BSD-3-Clause-Clear | |
6 | # | |
7 | ||
8 | import shutil | |
9 | import sys | |
10 | import re | |
9f95a23c | 11 | import os.path |
f67539c2 | 12 | import subprocess |
9f95a23c | 13 | import tests_config |
f67539c2 TL |
14 | |
15 | ||
16 | def run_command(args, verbose=True): | |
17 | result = subprocess.run(" ".join(args), shell=True, | |
18 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
19 | result.stdout = result.stdout.decode("ASCII", errors='ignore') | |
20 | result.stderr = result.stderr.decode("ASCII", errors='ignore') | |
21 | if verbose: | |
22 | print(result.stderr) | |
23 | return result | |
24 | ||
25 | ||
9f95a23c TL |
26 | # |
27 | # This script purpose is to remove unused functions definitions | |
28 | # It is giving the opportunity to unit test all functions from OCF. | |
29 | # As a parameter should be given path to file containing function, | |
30 | # which is target of testing. However that file has to be after | |
31 | # preprocessing. | |
32 | # | |
33 | # Output file of this script is not ready to make it. Before that, | |
34 | # has to be given definitions of functions, which are used by | |
35 | # tested function. | |
36 | # | |
37 | # In brief: this script allow wrapping all function calls in UT | |
38 | # | |
39 | ||
40 | class UnitTestsSourcesGenerator(object): | |
f67539c2 TL |
41 | script_file_abs_path = "" |
42 | script_dir_abs_path = "" | |
9f95a23c | 43 | |
f67539c2 TL |
44 | main_UT_dir = "" |
45 | main_env_dir = "" | |
46 | main_tested_dir = "" | |
9f95a23c | 47 | |
f67539c2 | 48 | ctags_path = "" |
9f95a23c | 49 | |
f67539c2 TL |
50 | test_catalogues_list = [] |
51 | dirs_to_include_list = [] | |
9f95a23c | 52 | |
f67539c2 TL |
53 | tests_internal_includes_list = [] |
54 | framework_includes = [] | |
9f95a23c | 55 | |
f67539c2 TL |
56 | dirs_with_tests_list = [] |
57 | test_files_paths_list = [] | |
9f95a23c | 58 | |
f67539c2 | 59 | tested_files_paths_list = [] |
9f95a23c | 60 | |
f67539c2 | 61 | includes_to_copy_dict = {} |
9f95a23c | 62 | |
f67539c2 TL |
63 | preprocessing_repo = "" |
64 | sources_to_test_repo = "" | |
9f95a23c | 65 | |
f67539c2 TL |
66 | def __init__(self): |
67 | self.script_file_abs_path = os.path.realpath(__file__) | |
68 | self.script_dir_abs_path = os.path.normpath( | |
69 | os.path.dirname(self.script_file_abs_path) + os.sep) | |
9f95a23c | 70 | |
f67539c2 | 71 | self.set_ctags_path() |
9f95a23c | 72 | |
f67539c2 TL |
73 | self.set_main_UT_dir() |
74 | self.set_main_env_dir() | |
75 | self.set_main_tested_dir() | |
9f95a23c | 76 | |
f67539c2 TL |
77 | self.test_catalogues_list = tests_config.DIRECTORIES_WITH_TESTS_LIST |
78 | self.set_includes_to_copy_dict(tests_config.INCLUDES_TO_COPY_DICT) | |
79 | self.set_dirs_to_include() | |
9f95a23c | 80 | |
f67539c2 TL |
81 | self.set_tests_internal_includes_list() |
82 | self.set_framework_includes() | |
83 | self.set_files_with_tests_list() | |
84 | self.set_tested_files_paths_list() | |
9f95a23c | 85 | |
f67539c2 TL |
86 | self.set_preprocessing_repo() |
87 | self.set_sources_to_test_repo() | |
9f95a23c | 88 | |
f67539c2 TL |
89 | def preprocessing(self): |
90 | tested_files_list = self.get_tested_files_paths_list() | |
91 | project_includes = self.get_dirs_to_include_list() | |
92 | framework_includes = self.get_tests_internal_includes_list() | |
9f95a23c | 93 | |
f67539c2 TL |
94 | gcc_flags = " -fno-inline -Dstatic= -Dinline= -E " |
95 | gcc_command_template = "gcc " | |
96 | for path in project_includes: | |
97 | gcc_command_template += " -I " + path + " " | |
9f95a23c | 98 | |
f67539c2 TL |
99 | for path in framework_includes: |
100 | gcc_command_template += " -I " + path | |
9f95a23c | 101 | |
f67539c2 | 102 | gcc_command_template += gcc_flags |
9f95a23c | 103 | |
f67539c2 TL |
104 | for path in tested_files_list: |
105 | preprocessing_dst = self.get_preprocessing_repo() \ | |
106 | + self.get_relative_path(path, self.get_main_tested_dir()) | |
107 | preprocessing_dst_dir = os.path.dirname(preprocessing_dst) | |
108 | self.create_dir_if_not_exist(preprocessing_dst_dir) | |
9f95a23c | 109 | |
f67539c2 | 110 | gcc_command = gcc_command_template + path + " > " + preprocessing_dst |
9f95a23c | 111 | |
f67539c2 | 112 | result = run_command([gcc_command]) |
9f95a23c | 113 | |
f67539c2 TL |
114 | if result.returncode != 0: |
115 | print(f"Generating preprocessing for {self.get_main_tested_dir() + path} failed!") | |
116 | print(result.output) | |
117 | run_command(["rm", "-f", preprocessing_dst]) | |
118 | continue | |
9f95a23c | 119 | |
f67539c2 | 120 | self.remove_hashes(preprocessing_dst) |
9f95a23c | 121 | |
f67539c2 | 122 | print(f"Preprocessed file {path} saved to {preprocessing_dst}") |
9f95a23c | 123 | |
f67539c2 TL |
124 | def copy_includes(self): |
125 | includes_dict = self.get_includes_to_copy_dict() | |
9f95a23c | 126 | |
f67539c2 TL |
127 | for dst, src in includes_dict.items(): |
128 | src_path = os.path.normpath(self.get_main_tested_dir() + src) | |
129 | if not os.path.isdir(src_path): | |
130 | print(f"Directory {src_path} given to include does not exists!") | |
131 | continue | |
132 | dst_path = os.path.normpath(self.get_main_UT_dir() + dst) | |
9f95a23c | 133 | |
f67539c2 TL |
134 | shutil.rmtree(dst_path, ignore_errors=True) |
135 | shutil.copytree(src_path, dst_path) | |
9f95a23c | 136 | |
f67539c2 TL |
137 | def get_user_wraps(self, path): |
138 | functions_list = self.get_functions_list(path) | |
139 | functions_list = [re.sub(r'__wrap_([\S]+)\s*[\d]+', r'\1', line) | |
140 | for line in functions_list if re.search("__wrap_", line)] | |
9f95a23c | 141 | |
f67539c2 | 142 | return functions_list |
9f95a23c | 143 | |
f67539c2 TL |
144 | def get_autowrap_file_path(self, test_file_path): |
145 | wrap_file_path = test_file_path.rsplit('.', 1)[0] | |
146 | wrap_file_path = wrap_file_path + "_generated_wraps.c" | |
147 | return wrap_file_path | |
9f95a23c | 148 | |
f67539c2 TL |
149 | def prepare_autowraps(self, test_file_path, preprocessed_file_path): |
150 | functions_to_wrap = self.get_functions_calls( | |
151 | self.get_sources_to_test_repo() + test_file_path) | |
152 | user_wraps = set(self.get_user_wraps(self.get_main_UT_dir() + test_file_path)) | |
9f95a23c | 153 | |
f67539c2 | 154 | functions_to_wrap = functions_to_wrap - user_wraps |
9f95a23c | 155 | |
f67539c2 | 156 | tags_list = self.get_functions_list(preprocessed_file_path, prototypes=True) |
9f95a23c | 157 | |
f67539c2 | 158 | wrap_list = [] |
9f95a23c | 159 | |
f67539c2 TL |
160 | with open(preprocessed_file_path) as f: |
161 | code = f.readlines() | |
162 | for function in functions_to_wrap: | |
163 | if function.startswith("env_") or function.startswith("bug") \ | |
164 | or function.startswith("memcpy"): | |
165 | # added memcpy function to list of ignored functions | |
166 | # because this is macro | |
167 | continue | |
168 | for tag in tags_list: | |
169 | if function in tag: | |
170 | name, line = tag.split() | |
171 | if name == function: | |
172 | line = int(line) | |
173 | wrap_list.append(self.get_function_wrap(code, line)) | |
174 | break | |
9f95a23c | 175 | |
f67539c2 | 176 | wrap_file_path = self.get_main_UT_dir() + self.get_autowrap_file_path(test_file_path) |
9f95a23c | 177 | |
f67539c2 TL |
178 | with open(wrap_file_path, "w") as f: |
179 | f.write("/* This file is generated by UT framework */\n") | |
180 | for wrap in wrap_list: | |
181 | f.write(wrap + "\n") | |
9f95a23c | 182 | |
f67539c2 TL |
183 | def prepare_sources_for_testing(self): |
184 | test_files_paths = self.get_files_with_tests_list() | |
9f95a23c | 185 | |
f67539c2 TL |
186 | for test_path in test_files_paths: |
187 | path = self.get_tested_file_path(self.get_main_UT_dir() + test_path) | |
9f95a23c | 188 | |
f67539c2 TL |
189 | preprocessed_tested_path = self.get_preprocessing_repo() + path |
190 | if not os.path.isfile(preprocessed_tested_path): | |
191 | print(f"No preprocessed path for {test_path} test file.") | |
192 | continue | |
9f95a23c | 193 | |
f67539c2 | 194 | tested_src = self.get_src_to_test(test_path, preprocessed_tested_path) |
9f95a23c | 195 | |
f67539c2 TL |
196 | self.create_dir_if_not_exist( |
197 | self.get_sources_to_test_repo() + os.path.dirname(test_path)) | |
9f95a23c | 198 | |
f67539c2 TL |
199 | with open(self.get_sources_to_test_repo() + test_path, "w") as f: |
200 | f.writelines(tested_src) | |
201 | print( | |
202 | f"Sources for {test_path} saved in + \ | |
203 | {self.get_sources_to_test_repo() + test_path}") | |
9f95a23c | 204 | |
f67539c2 | 205 | self.prepare_autowraps(test_path, preprocessed_tested_path) |
9f95a23c | 206 | |
f67539c2 TL |
207 | def create_main_cmake_lists(self): |
208 | buf = "cmake_minimum_required(VERSION 2.6.0)\n\n" | |
209 | buf += "project(OCF_unit_tests C)\n\n" | |
9f95a23c | 210 | |
f67539c2 | 211 | buf += "enable_testing()\n\n" |
9f95a23c | 212 | |
f67539c2 TL |
213 | buf += "include_directories(\n" |
214 | dirs_to_inc = self.get_dirs_to_include_list() + self.get_framework_includes() \ | |
215 | + self.get_tests_internal_includes_list() | |
216 | for path in dirs_to_inc: | |
217 | buf += "\t" + path + "\n" | |
218 | buf += ")\n\n" | |
9f95a23c | 219 | |
f67539c2 TL |
220 | includes = self.get_tests_internal_includes_list() |
221 | for path in includes: | |
222 | buf += "\nadd_subdirectory(" + path + ")" | |
223 | buf += "\n\n" | |
9f95a23c | 224 | |
f67539c2 TL |
225 | test_files = self.get_files_with_tests_list() |
226 | test_dirs_to_include = [os.path.dirname(path) for path in test_files] | |
9f95a23c | 227 | |
f67539c2 | 228 | test_dirs_to_include = self.remove_duplicates_from_list(test_dirs_to_include) |
9f95a23c | 229 | |
f67539c2 TL |
230 | for path in test_dirs_to_include: |
231 | buf += "\nadd_subdirectory(" + self.get_sources_to_test_repo() + path + ")" | |
9f95a23c | 232 | |
f67539c2 TL |
233 | with open(self.get_main_UT_dir() + "CMakeLists.txt", "w") as f: |
234 | f.writelines(buf) | |
9f95a23c | 235 | |
f67539c2 | 236 | print(f"Main CMakeLists.txt generated written to {self.get_main_UT_dir()} CMakeLists.txt") |
9f95a23c | 237 | |
f67539c2 TL |
238 | def generate_cmakes_for_tests(self): |
239 | test_files_paths = self.get_files_with_tests_list() | |
9f95a23c | 240 | |
f67539c2 TL |
241 | for test_path in test_files_paths: |
242 | tested_file_path = self.get_sources_to_test_repo() + test_path | |
243 | if not os.path.isfile(tested_file_path): | |
244 | print(f"No source to test for {test_path} test") | |
245 | continue | |
9f95a23c | 246 | |
f67539c2 | 247 | test_file_path = self.get_main_UT_dir() + test_path |
9f95a23c | 248 | |
f67539c2 | 249 | cmake_buf = self.generate_test_cmake_buf(test_file_path, tested_file_path) |
9f95a23c | 250 | |
f67539c2 TL |
251 | cmake_path = self.get_sources_to_test_repo() + test_path |
252 | cmake_path = os.path.splitext(cmake_path)[0] + ".cmake" | |
253 | with open(cmake_path, "w") as f: | |
254 | f.writelines(cmake_buf) | |
255 | print(f"cmake file for {test_path} written to {cmake_path}") | |
9f95a23c | 256 | |
f67539c2 TL |
257 | cmake_lists_path = os.path.dirname(cmake_path) + os.sep |
258 | self.update_cmakelists(cmake_lists_path, cmake_path) | |
9f95a23c | 259 | |
f67539c2 TL |
260 | def generate_test_cmake_buf(self, test_file_path, tested_file_path): |
261 | test_file_name = os.path.basename(test_file_path) | |
262 | target_name = os.path.splitext(test_file_name)[0] | |
9f95a23c | 263 | |
f67539c2 TL |
264 | add_executable = "add_executable(" + target_name + " " + test_file_path + " " + \ |
265 | tested_file_path + ")\n" | |
9f95a23c | 266 | |
f67539c2 | 267 | libraries = "target_link_libraries(" + target_name + " libcmocka.so ocf_env)\n" |
9f95a23c | 268 | |
f67539c2 | 269 | add_test = "add_test(" + target_name + " ${CMAKE_CURRENT_BINARY_DIR}/" + target_name + ")\n" |
9f95a23c | 270 | |
f67539c2 TL |
271 | tgt_properties = "set_target_properties(" + target_name + "\n" + \ |
272 | "PROPERTIES\n" + \ | |
273 | "COMPILE_FLAGS \"-fno-inline -Dstatic= -Dinline= -w \"\n" | |
9f95a23c | 274 | |
f67539c2 TL |
275 | link_flags = self.generate_cmake_link_flags(test_file_path) |
276 | tgt_properties += link_flags + ")" | |
9f95a23c | 277 | |
f67539c2 | 278 | buf = add_executable + libraries + add_test + tgt_properties |
9f95a23c | 279 | |
f67539c2 | 280 | return buf |
9f95a23c | 281 | |
f67539c2 TL |
282 | def generate_cmake_link_flags(self, path): |
283 | ret = "" | |
9f95a23c | 284 | |
f67539c2 TL |
285 | autowraps_path = self.get_autowrap_file_path(path) |
286 | functions_to_wrap = self.get_functions_to_wrap(path) | |
287 | functions_to_wrap += self.get_functions_to_wrap(autowraps_path) | |
9f95a23c | 288 | |
f67539c2 TL |
289 | for function_name in functions_to_wrap: |
290 | ret += ",--wrap=" + function_name | |
291 | if len(ret) > 0: | |
292 | ret = "LINK_FLAGS \"-Wl" + ret + "\"\n" | |
9f95a23c | 293 | |
f67539c2 | 294 | return ret |
9f95a23c | 295 | |
f67539c2 TL |
296 | def update_cmakelists(self, cmake_lists_path, cmake_name): |
297 | with open(cmake_lists_path + "CMakeLists.txt", "a+") as f: | |
298 | f.seek(0, os.SEEK_SET) | |
299 | new_line = "include(" + os.path.basename(cmake_name) + ")\n" | |
9f95a23c | 300 | |
f67539c2 TL |
301 | if new_line not in f.read(): |
302 | f.write(new_line) | |
9f95a23c | 303 | |
f67539c2 TL |
304 | def get_functions_to_wrap(self, path): |
305 | functions_list = self.get_functions_list(path) | |
306 | functions_list = [re.sub(r'__wrap_([\S]+)\s*[\d]+', r'\1', line) for line in functions_list | |
307 | if re.search("__wrap_", line)] | |
9f95a23c | 308 | |
f67539c2 | 309 | return functions_list |
9f95a23c | 310 | |
f67539c2 TL |
311 | def get_functions_to_leave(self, path): |
312 | with open(path) as f: | |
313 | lines = f.readlines() | |
314 | buf = ''.join(lines) | |
9f95a23c | 315 | |
f67539c2 | 316 | tags_pattern = re.compile(r"<functions_to_leave>[\s\S]*</functions_to_leave>") |
9f95a23c | 317 | |
f67539c2 TL |
318 | buf = re.findall(tags_pattern, buf) |
319 | if not len(buf) > 0: | |
320 | return [] | |
9f95a23c | 321 | |
f67539c2 | 322 | buf = buf[0] |
9f95a23c | 323 | |
f67539c2 TL |
324 | buf = re.sub(r'<.*>', '', buf) |
325 | buf = re.sub(r'[^a-zA-Z0-9_\n]+', '', buf) | |
9f95a23c | 326 | |
f67539c2 TL |
327 | ret = buf.split("\n") |
328 | ret = [name for name in ret if name] | |
329 | return ret | |
9f95a23c | 330 | |
f67539c2 TL |
331 | def get_functions_list(self, file_path, prototypes=None): |
332 | ctags_path = self.get_ctags_path() | |
9f95a23c | 333 | |
f67539c2 TL |
334 | ctags_args = "--c-types=f" |
335 | if prototypes: | |
336 | ctags_args += " --c-kinds=+p" | |
337 | # find all functions' definitions | put tabs instead of spaces | | |
338 | # take only columns with function name and line number | sort in descending order | |
339 | result = run_command([ctags_path, "-x", ctags_args, file_path, | |
340 | "--language-force=c | sed \"s/ \\+/\t/g\" | cut -f 1,3 | sort -nsr " | |
341 | "-k 2"]) | |
9f95a23c | 342 | |
f67539c2 TL |
343 | # 'output' is string, but it has to be changed to list |
344 | output = list(filter(None, result.stdout.split("\n"))) | |
345 | return output | |
9f95a23c | 346 | |
f67539c2 TL |
347 | def remove_functions_from_list(self, functions_list, to_remove_list): |
348 | ret = functions_list[:] | |
349 | for function_name in to_remove_list: | |
350 | ret = [line for line in ret if not re.search(r'\b%s\b' % function_name, line)] | |
351 | return ret | |
9f95a23c | 352 | |
f67539c2 TL |
353 | def get_src_to_test(self, test_path, preprocessed_tested_path): |
354 | functions_to_leave = self.get_functions_to_leave(self.get_main_UT_dir() + test_path) | |
9f95a23c | 355 | |
f67539c2 TL |
356 | functions_to_leave.append(self.get_tested_function_name(self.get_main_UT_dir() + test_path)) |
357 | functions_list = self.get_functions_list(preprocessed_tested_path) | |
9f95a23c | 358 | |
f67539c2 | 359 | functions_list = self.remove_functions_from_list(functions_list, functions_to_leave) |
9f95a23c | 360 | |
f67539c2 TL |
361 | with open(preprocessed_tested_path) as f: |
362 | ret = f.readlines() | |
363 | for function in functions_list: | |
364 | line = function.split("\t")[1] | |
365 | line = int(line) | |
9f95a23c | 366 | |
f67539c2 | 367 | self.remove_function_body(ret, line) |
9f95a23c | 368 | |
f67539c2 | 369 | return ret |
9f95a23c | 370 | |
f67539c2 TL |
371 | def set_tested_files_paths_list(self): |
372 | test_files_list = self.get_files_with_tests_list() | |
9f95a23c | 373 | |
f67539c2 TL |
374 | for f in test_files_list: |
375 | self.tested_files_paths_list.append(self.get_main_tested_dir() | |
376 | + self.get_tested_file_path( | |
377 | self.get_main_UT_dir() + f)) | |
9f95a23c | 378 | |
f67539c2 TL |
379 | self.tested_files_paths_list = self.remove_duplicates_from_list( |
380 | self.tested_files_paths_list) | |
9f95a23c | 381 | |
f67539c2 TL |
382 | def get_tested_files_paths_list(self): |
383 | return self.tested_files_paths_list | |
9f95a23c | 384 | |
f67539c2 TL |
385 | def get_files_with_tests_list(self): |
386 | return self.test_files_paths_list | |
9f95a23c | 387 | |
f67539c2 TL |
388 | def set_files_with_tests_list(self): |
389 | test_catalogues_list = self.get_tests_catalouges_list() | |
390 | for catalogue in test_catalogues_list: | |
391 | dir_with_tests_path = self.get_main_UT_dir() + catalogue | |
9f95a23c | 392 | |
f67539c2 TL |
393 | for path, dirs, files in os.walk(dir_with_tests_path): |
394 | test_files = self.get_test_files_from_dir(path + os.sep) | |
9f95a23c | 395 | |
f67539c2 TL |
396 | for test_file_name in test_files: |
397 | test_rel_path = os.path.relpath(path + os.sep + test_file_name, | |
398 | self.get_main_UT_dir()) | |
399 | self.test_files_paths_list.append(test_rel_path) | |
9f95a23c | 400 | |
f67539c2 TL |
401 | def are_markups_valid(self, path): |
402 | file_path = self.get_tested_file_path(path) | |
403 | function_name = self.get_tested_function_name(path) | |
9f95a23c | 404 | |
f67539c2 TL |
405 | if file_path is None: |
406 | print(f"{path} file has no tested_file tag!") | |
407 | return None | |
408 | elif not os.path.isfile(self.get_main_tested_dir() + file_path): | |
409 | print(f"Tested file given in {path} does not exist!") | |
410 | return None | |
9f95a23c | 411 | |
f67539c2 TL |
412 | if function_name is None: |
413 | print(f"{path} file has no tested_function_name tag!") | |
414 | return None | |
9f95a23c | 415 | |
f67539c2 | 416 | return True |
9f95a23c | 417 | |
f67539c2 TL |
418 | def create_dir_if_not_exist(self, path): |
419 | if not os.path.isdir(path): | |
420 | try: | |
421 | os.makedirs(path) | |
422 | except Exception: | |
423 | pass | |
424 | return True | |
425 | return None | |
9f95a23c | 426 | |
f67539c2 TL |
427 | def get_tested_file_path(self, test_file_path): |
428 | with open(test_file_path) as f: | |
429 | buf = f.readlines() | |
430 | buf = ''.join(buf) | |
9f95a23c | 431 | |
f67539c2 TL |
432 | tags_pattern = re.compile(r"<tested_file_path>[\s\S]*</tested_file_path>") |
433 | buf = re.findall(tags_pattern, buf) | |
9f95a23c | 434 | |
f67539c2 TL |
435 | if not len(buf) > 0: |
436 | return None | |
9f95a23c | 437 | |
f67539c2 | 438 | buf = buf[0] |
9f95a23c | 439 | |
f67539c2 TL |
440 | buf = re.sub(r'<[^>]*>', '', buf) |
441 | buf = re.sub(r'\s+', '', buf) | |
9f95a23c | 442 | |
f67539c2 TL |
443 | if len(buf) > 0: |
444 | return buf | |
9f95a23c | 445 | |
f67539c2 | 446 | return None |
9f95a23c | 447 | |
f67539c2 TL |
448 | def get_tested_function_name(self, test_file_path): |
449 | with open(test_file_path) as f: | |
450 | buf = f.readlines() | |
451 | buf = ''.join(buf) | |
9f95a23c | 452 | |
f67539c2 TL |
453 | tags_pattern = re.compile(r"<tested_function>[\s\S]*</tested_function>") |
454 | buf = re.findall(tags_pattern, buf) | |
9f95a23c | 455 | |
f67539c2 TL |
456 | if not len(buf) > 0: |
457 | return None | |
9f95a23c | 458 | |
f67539c2 | 459 | buf = buf[0] |
9f95a23c | 460 | |
f67539c2 TL |
461 | buf = re.sub(r'<[^>]*>', '', buf) |
462 | buf = re.sub('//', '', buf) | |
463 | buf = re.sub(r'\s+', '', buf) | |
9f95a23c | 464 | |
f67539c2 TL |
465 | if len(buf) > 0: |
466 | return buf | |
9f95a23c | 467 | |
f67539c2 TL |
468 | return None |
469 | ||
470 | def get_test_files_from_dir(self, path): | |
471 | ret = os.listdir(path) | |
472 | ret = [name for name in ret if os.path.isfile(path + os.sep + name) | |
473 | and (name.endswith(".c") or name.endswith(".h"))] | |
474 | ret = [name for name in ret if self.are_markups_valid(path + name)] | |
475 | ||
476 | return ret | |
477 | ||
478 | def get_list_of_directories(self, path): | |
479 | if not os.path.isdir(path): | |
480 | return [] | |
481 | ||
482 | ret = os.listdir(path) | |
483 | ret = [name for name in ret if not os.path.isfile(path + os.sep + name)] | |
484 | ret = [os.path.normpath(name) + os.sep for name in ret] | |
485 | ||
486 | return ret | |
487 | ||
488 | def remove_hashes(self, path): | |
489 | with open(path) as f: | |
490 | buf = f.readlines() | |
491 | ||
492 | buf = [l for l in buf if not re.search(r'.*#.*', l)] | |
493 | ||
494 | with open(path, "w") as f: | |
495 | f.writelines(buf) | |
496 | ||
497 | return | |
498 | for i in range(len(padding)): | |
499 | try: | |
500 | padding[i] = padding[i].split("#")[0] | |
501 | except ValueError: | |
502 | continue | |
503 | ||
504 | f = open(path, "w") | |
505 | f.writelines(padding) | |
506 | f.close() | |
507 | ||
508 | def find_function_end(self, code_lines_list, first_line_of_function_index): | |
509 | brackets_counter = 0 | |
510 | current_line_index = first_line_of_function_index | |
511 | ||
512 | while True: | |
513 | if "{" in code_lines_list[current_line_index]: | |
514 | brackets_counter += code_lines_list[current_line_index].count("{") | |
515 | brackets_counter -= code_lines_list[current_line_index].count("}") | |
516 | break | |
517 | else: | |
518 | current_line_index += 1 | |
519 | ||
520 | while brackets_counter > 0: | |
521 | current_line_index += 1 | |
522 | if "{" in code_lines_list[current_line_index]: | |
523 | brackets_counter += code_lines_list[current_line_index].count("{") | |
524 | brackets_counter -= code_lines_list[current_line_index].count("}") | |
525 | elif "}" in code_lines_list[current_line_index]: | |
526 | brackets_counter -= code_lines_list[current_line_index].count("}") | |
527 | ||
528 | return current_line_index | |
529 | ||
530 | def get_functions_calls(self, file_to_compile): | |
531 | out_dir = "/tmp/ocf_ut" | |
532 | out_file = out_dir + "/ocf_obj.o" | |
533 | self.create_dir_if_not_exist(out_dir) | |
534 | cmd = "/usr/bin/gcc -o " + out_file + " -c " + file_to_compile + " &> /dev/null" | |
535 | run_command([cmd], verbose=None) | |
536 | result = run_command(["/usr/bin/nm -u " + out_file + " | cut -f2 -d\'U\'"]) | |
537 | return set(result.stdout.split()) | |
538 | ||
539 | def remove_function_body(self, code_lines_list, line_id): | |
540 | try: | |
541 | while "{" not in code_lines_list[line_id]: | |
542 | if ";" in code_lines_list[line_id]: | |
543 | return | |
544 | line_id += 1 | |
545 | except IndexError: | |
546 | return | |
547 | ||
548 | last_line_id = self.find_function_end(code_lines_list, line_id) | |
549 | ||
550 | code_lines_list[line_id] = code_lines_list[line_id].split("{")[0] | |
551 | code_lines_list[line_id] += ";" | |
552 | ||
553 | del code_lines_list[line_id + 1: last_line_id + 1] | |
554 | ||
555 | def get_function_wrap(self, code_lines_list, line_id): | |
556 | ret = [] | |
557 | # Line numbering starts with one, list indexing with zero | |
558 | line_id -= 1 | |
559 | ||
560 | # If returned type is not present, it should be in line above | |
561 | try: | |
562 | code_lines_list[line_id].split("(")[0].rsplit()[1] | |
563 | except IndexError: | |
564 | line_id -= 1 | |
565 | ||
566 | while True: | |
567 | ret.append(code_lines_list[line_id]) | |
568 | if ")" in code_lines_list[line_id]: | |
569 | break | |
570 | line_id += 1 | |
571 | ||
572 | # Tags list contains both prototypes and definitions, here we recoginze | |
573 | # with which one we deals | |
574 | delimiter = "" | |
575 | try: | |
576 | if "{" in ret[-1] or "{" in ret[-2]: | |
577 | delimter = "{" | |
578 | else: | |
579 | delimiter = ";" | |
580 | except IndexError: | |
581 | delimiter = ";" | |
582 | ||
583 | ret[-1] = ret[-1].split(delimiter)[0] | |
584 | ret[-1] += "{}" | |
585 | ||
586 | function_name = "" | |
587 | line_with_name = 0 | |
588 | try: | |
589 | function_name = ret[line_with_name].split("(")[0].rsplit(maxsplit=1)[1] | |
590 | except IndexError: | |
591 | line_with_name = 1 | |
592 | function_name = ret[line_with_name].split("(")[0] | |
593 | ||
594 | function_new_name = "__wrap_" + function_name.replace("*", "") | |
595 | ret[0] = ret[0].replace(function_name, function_new_name) | |
596 | ||
597 | return ''.join(ret) | |
598 | ||
599 | def set_ctags_path(self): | |
600 | result = run_command(["/usr/bin/ctags --version &> /dev/null"]) | |
601 | if result.returncode == 0: | |
602 | path = "/usr/bin/ctags " | |
603 | result = run_command([path, "--c-types=f"], verbose=None) | |
604 | if not re.search("unrecognized option", result.stdout, re.IGNORECASE): | |
605 | self.ctags_path = path | |
606 | return | |
607 | ||
608 | result = run_command(["/usr/local/bin/ctags --version &> /dev/null"]) | |
609 | if result.returncode == 0: | |
610 | path = "/usr/local/bin/ctags " | |
611 | result = run_command(["path", "--c-types=f"], verbose=None) | |
612 | if not re.search("unrecognized option", result.stdout, re.IGNORECASE): | |
613 | self.ctags_path = path | |
614 | return | |
615 | ||
616 | print("ERROR: Current ctags version don't support \"--c-types=f\" parameter!") | |
617 | exit(1) | |
618 | ||
619 | def get_ctags_path(self): | |
620 | return self.ctags_path | |
621 | ||
622 | def get_tests_catalouges_list(self): | |
623 | return self.test_catalogues_list | |
624 | ||
625 | def get_relative_path(self, original_path, part_to_remove): | |
626 | return original_path.split(part_to_remove, 1)[1] | |
627 | ||
628 | def get_dirs_to_include_list(self): | |
629 | return self.dirs_to_include_list | |
630 | ||
631 | def set_dirs_to_include(self): | |
632 | self.dirs_to_include_list = [self.get_main_tested_dir() + name | |
633 | for name in | |
634 | tests_config.DIRECTORIES_TO_INCLUDE_FROM_PROJECT_LIST] | |
635 | ||
636 | def set_tests_internal_includes_list(self): | |
637 | self.tests_internal_includes_list = [self.get_main_UT_dir() + name | |
638 | for name in | |
639 | tests_config.DIRECTORIES_TO_INCLUDE_FROM_UT_LIST] | |
640 | ||
641 | def set_preprocessing_repo(self): | |
642 | self.preprocessing_repo = self.get_main_UT_dir() \ | |
643 | + tests_config.PREPROCESSED_SOURCES_REPOSITORY | |
644 | ||
645 | def set_sources_to_test_repo(self): | |
646 | self.sources_to_test_repo = self.get_main_UT_dir() + tests_config.SOURCES_TO_TEST_REPOSITORY | |
9f95a23c | 647 | |
f67539c2 TL |
648 | def get_sources_to_test_repo(self): |
649 | return self.sources_to_test_repo | |
650 | ||
651 | def get_preprocessing_repo(self): | |
652 | return self.preprocessing_repo | |
653 | ||
654 | def get_tests_internal_includes_list(self): | |
655 | return self.tests_internal_includes_list | |
656 | ||
657 | def get_script_dir_path(self): | |
658 | return os.path.normpath(self.script_dir_abs_path) + os.sep | |
659 | ||
660 | def get_main_UT_dir(self): | |
661 | return os.path.normpath(self.main_UT_dir) + os.sep | |
662 | ||
663 | def get_main_env_dir(self): | |
664 | return os.path.normpath(self.main_env_dir) + os.sep | |
665 | ||
666 | def get_main_tested_dir(self): | |
667 | return os.path.normpath(self.main_tested_dir) + os.sep | |
668 | ||
669 | def remove_duplicates_from_list(self, l): | |
670 | return list(set(l)) | |
9f95a23c | 671 | |
f67539c2 TL |
672 | def set_framework_includes(self): |
673 | self.framework_includes = tests_config.FRAMEWORK_DIRECTORIES_TO_INCLUDE_LIST | |
674 | ||
675 | def get_framework_includes(self): | |
676 | return self.framework_includes | |
9f95a23c | 677 | |
f67539c2 TL |
678 | def set_includes_to_copy_dict(self, files_to_copy_dict): |
679 | self.includes_to_copy_dict = files_to_copy_dict | |
9f95a23c | 680 | |
f67539c2 TL |
681 | def get_includes_to_copy_dict(self): |
682 | return self.includes_to_copy_dict | |
9f95a23c | 683 | |
f67539c2 TL |
684 | def set_main_env_dir(self): |
685 | main_env_dir = os.path.normpath(os.path.normpath(self.get_script_dir_path() | |
686 | + os.sep | |
687 | + tests_config. | |
688 | MAIN_DIRECTORY_OF_ENV_FILES)) | |
689 | if not os.path.isdir(main_env_dir): | |
690 | print("Given path to main env directory is wrong!") | |
691 | sys.exit(1) | |
9f95a23c | 692 | |
f67539c2 | 693 | self.main_env_dir = main_env_dir |
9f95a23c | 694 | |
f67539c2 TL |
695 | def set_main_UT_dir(self): |
696 | main_UT_dir = os.path.normpath(os.path.normpath(self.get_script_dir_path() | |
697 | + os.sep | |
698 | + tests_config. | |
699 | MAIN_DIRECTORY_OF_UNIT_TESTS)) | |
700 | if not os.path.isdir(main_UT_dir): | |
701 | print("Given path to main UT directory is wrong!") | |
702 | sys.exit(1) | |
9f95a23c | 703 | |
f67539c2 | 704 | self.main_UT_dir = main_UT_dir |
9f95a23c | 705 | |
f67539c2 TL |
706 | def set_main_tested_dir(self): |
707 | main_tested_dir = os.path.normpath(os.path.normpath(self.get_script_dir_path() | |
708 | + os.sep | |
709 | + tests_config. | |
710 | MAIN_DIRECTORY_OF_TESTED_PROJECT)) | |
711 | if not os.path.isdir(main_tested_dir): | |
712 | print("Given path to main tested directory is wrong!") | |
713 | sys.exit(1) | |
9f95a23c | 714 | |
f67539c2 | 715 | self.main_tested_dir = main_tested_dir |
9f95a23c | 716 | |
9f95a23c TL |
717 | |
718 | def __main__(): | |
f67539c2 TL |
719 | generator = UnitTestsSourcesGenerator() |
720 | generator.copy_includes() | |
721 | generator.preprocessing() | |
722 | generator.prepare_sources_for_testing() | |
723 | generator.create_main_cmake_lists() | |
724 | generator.generate_cmakes_for_tests() | |
9f95a23c | 725 | |
f67539c2 | 726 | print("Files for testing generated!") |
9f95a23c | 727 | |
9f95a23c TL |
728 | |
729 | if __name__ == "__main__": | |
f67539c2 | 730 | __main__() |