UT framerwok: Auto generating wrap functions
Test code have to contain wraps only for those functions, which are used by test itself. Empty wraps are generated automatically by UT framework. Signed-off-by: Michal Mielewczyk <michal.mielewczyk@intel.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python3.6
|
||||
|
||||
#
|
||||
# Copyright(c) 2012-2018 Intel Corporation
|
||||
@@ -12,13 +12,14 @@ import os.path
|
||||
from collections import defaultdict
|
||||
import subprocess
|
||||
|
||||
def run_command(args):
|
||||
result = subprocess.run(" ".join(args), shell=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
result.stdout = result.stdout.decode("ASCII")
|
||||
result.stderr = result.stderr.decode("ASCII")
|
||||
print(result.stderr)
|
||||
return result
|
||||
def run_command(args, verbose=True):
|
||||
result = subprocess.run(" ".join(args), shell=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
result.stdout = result.stdout.decode("ASCII", errors='ignore')
|
||||
result.stderr = result.stderr.decode("ASCII", errors='ignore')
|
||||
if verbose:
|
||||
print(result.stderr)
|
||||
return result
|
||||
|
||||
import tests_config
|
||||
#
|
||||
@@ -127,9 +128,52 @@ class UnitTestsSourcesGenerator(object):
|
||||
continue
|
||||
dst_path = os.path.normpath(self.get_main_UT_dir() + dst)
|
||||
|
||||
shutil.rmtree(dst_path)
|
||||
shutil.rmtree(dst_path, ignore_errors=True)
|
||||
shutil.copytree(src_path, dst_path)
|
||||
|
||||
def get_user_wraps(self, path):
|
||||
functions_list = self.get_functions_list(path)
|
||||
functions_list = [re.sub(r'__wrap_([\S]+)\s*[\d]+', r'\1', line) \
|
||||
for line in functions_list if re.search("__wrap_", line)]
|
||||
|
||||
return functions_list
|
||||
|
||||
def get_autowrap_file_path(self, test_file_path):
|
||||
wrap_file_path = test_file_path.rsplit('.', 1)[0]
|
||||
wrap_file_path = wrap_file_path + "_generated_warps.c"
|
||||
return wrap_file_path
|
||||
|
||||
def prepare_autowraps(self, test_file_path, preprocessed_file_path):
|
||||
functions_to_wrap = self.get_functions_calls(
|
||||
self.get_sources_to_test_repo() + test_file_path)
|
||||
user_wraps = set(self.get_user_wraps(self.get_main_UT_dir() + test_file_path))
|
||||
|
||||
functions_to_wrap = functions_to_wrap - user_wraps
|
||||
|
||||
tags_list = self.get_functions_list(preprocessed_file_path, prototypes=True)
|
||||
|
||||
wrap_list = []
|
||||
|
||||
with open(preprocessed_file_path) as f:
|
||||
code = f.readlines()
|
||||
for function in functions_to_wrap:
|
||||
if function.startswith("env_") or function.startswith("bug"):
|
||||
continue
|
||||
for tag in tags_list:
|
||||
if function in tag:
|
||||
name, line = tag.split()
|
||||
if name == function:
|
||||
line = int(line)
|
||||
wrap_list.append(self.get_function_wrap(code, line))
|
||||
break
|
||||
|
||||
wrap_file_path = self.get_main_UT_dir() + self.get_autowrap_file_path(test_file_path)
|
||||
|
||||
with open(wrap_file_path, "w") as f:
|
||||
f.write("/* This is file is generated by UT framework */\n")
|
||||
for wrap in wrap_list:
|
||||
f.write(wrap + "\n")
|
||||
|
||||
def prepare_sources_for_testing(self):
|
||||
test_files_paths = self.get_files_with_tests_list()
|
||||
|
||||
@@ -149,6 +193,8 @@ class UnitTestsSourcesGenerator(object):
|
||||
f.writelines(tested_src)
|
||||
print(f"Sources for {test_path} saved in {self.get_sources_to_test_repo() + test_path}")
|
||||
|
||||
self.prepare_autowraps(test_path, preprocessed_tested_path)
|
||||
|
||||
def create_main_cmake_lists(self):
|
||||
buf = "cmake_minimum_required(VERSION 2.6.0)\n\n"
|
||||
buf += "project(OCF_unit_tests C)\n\n"
|
||||
@@ -227,7 +273,9 @@ class UnitTestsSourcesGenerator(object):
|
||||
def generate_cmake_link_flags(self, path):
|
||||
ret = ""
|
||||
|
||||
autowraps_path = self.get_autowrap_file_path(path)
|
||||
functions_to_wrap = self.get_functions_to_wrap(path)
|
||||
functions_to_wrap += self.get_functions_to_wrap(autowraps_path)
|
||||
|
||||
for function_name in functions_to_wrap:
|
||||
ret += ",--wrap=" + function_name
|
||||
@@ -270,12 +318,15 @@ class UnitTestsSourcesGenerator(object):
|
||||
ret = [name for name in ret if name]
|
||||
return ret
|
||||
|
||||
def get_functions_list(self, file_path):
|
||||
def get_functions_list(self, file_path, prototypes=None):
|
||||
ctags_path = self.get_ctags_path()
|
||||
|
||||
ctags_args = "--c-types=f"
|
||||
if prototypes == True:
|
||||
ctags_args += " --c-kinds=+p"
|
||||
# find all functions' definitions | put tabs instead of spaces |
|
||||
# take only columns with function name and line number | sort in descending order
|
||||
result = run_command([ctags_path, "-x", "--c-types=f", file_path,
|
||||
result = run_command([ctags_path, "-x", ctags_args, file_path,
|
||||
"--language-force=c | sed \"s/ \\+/\t/g\" | cut -f 1,3 | sort -nsr -k 2"])
|
||||
|
||||
# 'output' is string, but it has to be changed to list
|
||||
@@ -461,6 +512,16 @@ class UnitTestsSourcesGenerator(object):
|
||||
|
||||
return current_line_index
|
||||
|
||||
def get_functions_calls(self, file_to_compile):
|
||||
out_dir = "/tmp/ocf_ut"
|
||||
out_file = out_dir + "/ocf_obj.o"
|
||||
self.create_dir_if_not_exist(out_dir)
|
||||
cmd = "/usr/bin/gcc -o " + out_file + " -c " + file_to_compile + " &> /dev/null"
|
||||
run_command([cmd], verbose=None)
|
||||
result = run_command(["/usr/bin/nm -u " + out_file + " | cut -f2 -d\'U\'"])
|
||||
return set(result.stdout.split())
|
||||
|
||||
|
||||
def remove_function_body(self, code_lines_list, line_id):
|
||||
try:
|
||||
while "{" not in code_lines_list[line_id]:
|
||||
@@ -477,11 +538,56 @@ class UnitTestsSourcesGenerator(object):
|
||||
|
||||
del code_lines_list[line_id + 1: last_line_id + 1]
|
||||
|
||||
|
||||
def get_function_wrap(self, code_lines_list, line_id):
|
||||
ret = []
|
||||
# Line numbering starts with one, list indexing with zero
|
||||
line_id -= 1
|
||||
|
||||
# If returned type is not present, it should be in line above
|
||||
try:
|
||||
code_lines_list[line_id].split("(")[0].rsplit()[1]
|
||||
except IndexError:
|
||||
line_id -= 1
|
||||
|
||||
while True:
|
||||
ret.append(code_lines_list[line_id])
|
||||
if ")" in code_lines_list[line_id]:
|
||||
break
|
||||
line_id += 1
|
||||
|
||||
# Tags list contains both prototypes and definitions, here we recoginze
|
||||
# with which one we deals
|
||||
delimiter = ""
|
||||
try:
|
||||
if "{" in ret[-1] or "{" in ret[-2]:
|
||||
delimter = "{"
|
||||
else:
|
||||
delimiter =";"
|
||||
except IndexError:
|
||||
delimiter =";"
|
||||
|
||||
ret[-1] = ret[-1].split(delimiter)[0]
|
||||
ret[-1] += "{}"
|
||||
|
||||
function_name = ""
|
||||
line_with_name = 0
|
||||
try:
|
||||
function_name = ret[line_with_name].split("(")[0].rsplit(maxsplit=1)[1]
|
||||
except IndexError:
|
||||
line_with_name = 1
|
||||
function_name = ret[line_with_name].split("(")[0]
|
||||
|
||||
function_new_name = "__wrap_" + function_name.replace("*", "")
|
||||
ret[0] = ret[0].replace(function_name, function_new_name)
|
||||
|
||||
return ''.join(ret)
|
||||
|
||||
def set_ctags_path(self):
|
||||
result = run_command(["/usr/bin/ctags --version &> /dev/null"])
|
||||
if result.returncode == 0:
|
||||
path = "/usr/bin/ctags "
|
||||
result = run_command([path, "--c-types=f"])
|
||||
result = run_command([path, "--c-types=f"], verbose=None)
|
||||
if not re.search("unrecognized option", result.stdout, re.IGNORECASE):
|
||||
self.ctags_path = path
|
||||
return
|
||||
@@ -489,7 +595,7 @@ class UnitTestsSourcesGenerator(object):
|
||||
result = run_command(["/usr/local/bin/ctags --version &> /dev/null"])
|
||||
if result.returncode == 0:
|
||||
path = "/usr/local/bin/ctags "
|
||||
result = run_command(["path", "--c-types=f"])
|
||||
result = run_command(["path", "--c-types=f"], verbose=None)
|
||||
if not re.search("unrecognized option", result.stdout, re.IGNORECASE):
|
||||
self.ctags_path = path
|
||||
return
|
||||
|
Reference in New Issue
Block a user