import platform
import shlex
import re
from functools import total_ordering
from maple_test.utils import PASS, EXEC_FLAG, SEPARATE_FILE_DIRECTIVE, ERRCHECK_FLAG, EXPECT_FLAG, DEPENDENCE_FLAG, TIMEOUT_FLAG, LEVEL_FLAG
from maple_test.utils import read_file, safe_print
from maple_test.utils import split_comment, filter_line, filter_command_line, precheck_flag, filter_level
from maple_test.utils import FAIL, UNRESOLVED
from maple_test import configs
is_initialized = False
def ensure_config_initialized():
global is_initialized
if not is_initialized:
_, _, _ = configs.init_config()
is_initialized = True
class Case:
def __init__(self, path, test_path, comment, condition, run_script, level=None):
if level is None:
level = set()
if path != test_path:
self.name = str(path)
self.path = test_path / path
self.test_name = test_path.name
else:
self.name = str(path.name)
self.path = path
self.test_name = path.parent.name
self.test_path = test_path
self.relative_path = path
self.comment = comment
try:
_, comment_lines = split_comment(comment, read_file(self.path), )
except UnicodeDecodeError as e:
safe_print('[WARNING] ignore {} for {}.'.format(self.name, e))
self.commands = []
self.expect = []
self.dependence = {}
self.timeout = 300
self.level = False
else:
self.level = extract_level(comment_lines, level, condition)
self.commands = enumerate_compares(extract_commands(comment_lines, condition, run_script))
self.expect = extract_expect(comment_lines)
self.dependence = extract_dependence(comment_lines, condition)
self.separation_by_files = extract_separation_by_files(comment_lines, self.path, condition)
self.timeout = extract_timeout(comment_lines, condition)
if not self.level:
self.relative_path = ''
def __repr__(self):
return str(self.relative_path)
def extract_expect(comment_lines):
expect_line = [filter_line(line, EXPECT_FLAG) for line in comment_lines]
expect_line = [line for line in expect_line if line]
if not expect_line:
return PASS
return expect_line[-1]
def extract_dependence(comment_lines, condition):
support_separartor = ",; "
dependence = []
for line in comment_lines:
line = filter_line(line, DEPENDENCE_FLAG, condition)
if not line:
continue
parser = shlex.shlex(line)
parser.whitespace = parser.whitespace + support_separartor
parser.whitespace_split = True
dependence += list(parser)
return set(dependence)
def extract_separation_by_files(comment_lines, filepath, condition):
need_separation = False
for line in comment_lines:
if filter_line(line, SEPARATE_FILE_DIRECTIVE, condition):
need_separation = True
break
if not need_separation:
return []
separation = []
cur_file_lines = []
cur_file_path = ""
with open(filepath) as file:
for line in file:
match = re.match(r'//\s*' + SEPARATE_FILE_DIRECTIVE + '\s*:\s*(.+)\s*', line)
if not match:
cur_file_lines.append(line)
else:
if cur_file_path != "":
separation.append((cur_file_path, '\n'.join(cur_file_lines)))
cur_file_lines = []
cur_file_path = match.group(1).strip()
if cur_file_path == "":
raise Exception('ERROR: Specify file in separation "' + line + '"')
if cur_file_path != "":
separation.append((cur_file_path, ''.join(cur_file_lines)))
separation_files = ', '.join([("'" + filepath + "'") for (filepath, _) in separation])
return separation
def extract_timeout(comment_lines, condition):
timeout = None
for line in comment_lines:
line = filter_line(line, TIMEOUT_FLAG, condition)
if not line:
continue
timeout = float(line)
return timeout
def extract_commands(comment_lines, condition, run_script):
commands = []
for command in comment_lines:
command_info = filter_command_line(command, condition, run_script, configs.get_val("compatible"))
if not command_info:
continue
commands.append(command_info)
return commands
def extract_level(comment_lines, target_level, condition):
if not target_level:
return True
found_flag = False
for line in comment_lines:
filtered_line = filter_line(line, LEVEL_FLAG, condition)
if not filtered_line:
continue
found_flag = True
if filter_level(filtered_line, target_level):
return True
return filter_level("0", target_level) if not found_flag else False
def enumerate_compares(commands):
def isCommandPipedIntoCompare(command):
last = command['cmd'][-1]
if command['PIPE'] and last.strip().startswith("compare"):
return True
return False
count_of_compares = sum(1 for command in commands if isCommandPipedIntoCompare(command))
i = 1
if count_of_compares > 1:
for command in commands:
if isCommandPipedIntoCompare(command):
command['cmd'][-1] += f' --compare_number={i}'
i += 1
return commands
def read_list(content):
if not content:
return {"*"}, {}
include_flag = "[ALL-TEST-CASE]"
exclude_flag = "[EXCLUDE-TEST-CASE]"
case_list = set()
exclude_case_list = set()
is_exclude = False
for line in content:
line = line.strip()
if str(line).startswith('#') or not line:
continue
if line.find(include_flag) != -1:
is_exclude = False
elif line.find(exclude_flag) != -1:
is_exclude = True
elif is_exclude:
exclude_case_list.add(line)
else:
case_list.add(line)
if not case_list:
case_list = {"*"}
return case_list, exclude_case_list
@total_ordering
class Result:
def __init__(self, case, task, cfg, status, commands, commands_result, log_file):
self.case = case
self.task = task
self.cfg = cfg
self.time = None
self.status = status
self.commands = commands
self.commands_result = commands_result
self.log_file = log_file
def gen_xml(self, root):
from xml.etree import ElementTree
case = ElementTree.SubElement(
root,
"testcase",
name=str(self.case),
classname="{}.{}".format(self.task, self.cfg),
)
if self.status == FAIL:
failure = ElementTree.SubElement(case, "failure")
if isinstance(self.commands_result, str):
failure.text = "Test case preparation failed, "
failure.text += self.commands_result
else:
failure.text = "List of commands:\n"
for cmd in self.commands:
failure.text += "EXEC: {}\n".format(cmd)
failure.text += "----\n"
failure.text += self.command_result_to_text(self.commands_result[-1])
elif self.status == UNRESOLVED:
skipped = ElementTree.SubElement(case, "skipped")
skipped.text = "No valid command statement was found."
def command_result_to_text(self, result):
text = "EXEC: {}\n".format(result.get("cmd"))
text += "Return code: {}\n".format(result.get("return_code"))
text += "Stdout: \n{}\n".format(result.get("stdout"))
text += "Stderr: \n{}\n".format(result.get("stderr"))
return text
def gen_json_result(self):
from collections import OrderedDict
result = OrderedDict()
result["name"] = "{}".format(self.case)
result["cfg"] = "{}".format(self.cfg)
result["result"] = self.status
result["commands"] = self.commands
result["output"] = self.commands_result
result["log_file"] = self.log_file
return result
def __lt__(self, other):
return self.case < other.case