style: format python files with isort and double-quote-string-fixer
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
|
||||
import yaml
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
import CreateSectionTable
|
||||
import yaml
|
||||
|
||||
try:
|
||||
from yaml import CLoader as Loader
|
||||
@@ -17,43 +16,43 @@ except ImportError:
|
||||
from yaml import Loader as Loader
|
||||
|
||||
TEST_CASE_PATTERN = {
|
||||
"initial condition": "UTINIT1",
|
||||
"chip_target": "esp32",
|
||||
"level": "Unit",
|
||||
"execution time": 0,
|
||||
"auto test": "Yes",
|
||||
"category": "Function",
|
||||
"test point 1": "basic function",
|
||||
"version": "v1 (2016-12-06)",
|
||||
"test environment": "UT_T1_1",
|
||||
"reset": "",
|
||||
"expected result": "1. set succeed",
|
||||
"cmd set": "test_unit_test_case",
|
||||
"Test App": "UT",
|
||||
'initial condition': 'UTINIT1',
|
||||
'chip_target': 'esp32',
|
||||
'level': 'Unit',
|
||||
'execution time': 0,
|
||||
'auto test': 'Yes',
|
||||
'category': 'Function',
|
||||
'test point 1': 'basic function',
|
||||
'version': 'v1 (2016-12-06)',
|
||||
'test environment': 'UT_T1_1',
|
||||
'reset': '',
|
||||
'expected result': '1. set succeed',
|
||||
'cmd set': 'test_unit_test_case',
|
||||
'Test App': 'UT',
|
||||
}
|
||||
|
||||
|
||||
class Parser(object):
|
||||
""" parse unit test cases from build files and create files for test bench """
|
||||
|
||||
TAG_PATTERN = re.compile(r"([^=]+)(=)?(.+)?")
|
||||
DESCRIPTION_PATTERN = re.compile(r"\[([^]\[]+)\]")
|
||||
CONFIG_PATTERN = re.compile(r"{([^}]+)}")
|
||||
TEST_GROUPS_PATTERN = re.compile(r"TEST_GROUPS=(.*)$")
|
||||
TAG_PATTERN = re.compile(r'([^=]+)(=)?(.+)?')
|
||||
DESCRIPTION_PATTERN = re.compile(r'\[([^]\[]+)\]')
|
||||
CONFIG_PATTERN = re.compile(r'{([^}]+)}')
|
||||
TEST_GROUPS_PATTERN = re.compile(r'TEST_GROUPS=(.*)$')
|
||||
|
||||
# file path (relative to idf path)
|
||||
TAG_DEF_FILE = os.path.join("tools", "unit-test-app", "tools", "TagDefinition.yml")
|
||||
MODULE_DEF_FILE = os.path.join("tools", "unit-test-app", "tools", "ModuleDefinition.yml")
|
||||
CONFIG_DEPENDENCY_FILE = os.path.join("tools", "unit-test-app", "tools", "ConfigDependency.yml")
|
||||
MODULE_ARTIFACT_FILE = os.path.join("components", "idf_test", "ModuleDefinition.yml")
|
||||
TEST_CASE_FILE_DIR = os.path.join("components", "idf_test", "unit_test")
|
||||
UT_CONFIG_FOLDER = os.path.join("tools", "unit-test-app", "configs")
|
||||
ELF_FILE = "unit-test-app.elf"
|
||||
SDKCONFIG_FILE = "sdkconfig"
|
||||
STRIP_CONFIG_PATTERN = re.compile(r"(.+?)(_\d+)?$")
|
||||
TAG_DEF_FILE = os.path.join('tools', 'unit-test-app', 'tools', 'TagDefinition.yml')
|
||||
MODULE_DEF_FILE = os.path.join('tools', 'unit-test-app', 'tools', 'ModuleDefinition.yml')
|
||||
CONFIG_DEPENDENCY_FILE = os.path.join('tools', 'unit-test-app', 'tools', 'ConfigDependency.yml')
|
||||
MODULE_ARTIFACT_FILE = os.path.join('components', 'idf_test', 'ModuleDefinition.yml')
|
||||
TEST_CASE_FILE_DIR = os.path.join('components', 'idf_test', 'unit_test')
|
||||
UT_CONFIG_FOLDER = os.path.join('tools', 'unit-test-app', 'configs')
|
||||
ELF_FILE = 'unit-test-app.elf'
|
||||
SDKCONFIG_FILE = 'sdkconfig'
|
||||
STRIP_CONFIG_PATTERN = re.compile(r'(.+?)(_\d+)?$')
|
||||
TOOLCHAIN_FOR_TARGET = {
|
||||
"esp32": "xtensa-esp32-elf-",
|
||||
"esp32s2": "xtensa-esp32s2-elf-",
|
||||
'esp32': 'xtensa-esp32-elf-',
|
||||
'esp32s2': 'xtensa-esp32s2-elf-',
|
||||
}
|
||||
|
||||
def __init__(self, binary_folder):
|
||||
@@ -65,10 +64,10 @@ class Parser(object):
|
||||
self.idf_path = idf_path
|
||||
self.idf_target = idf_target
|
||||
self.ut_bin_folder = binary_folder
|
||||
self.objdump = Parser.TOOLCHAIN_FOR_TARGET.get(idf_target, "") + "objdump"
|
||||
self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), "r"), Loader=Loader)
|
||||
self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), "r"), Loader=Loader)
|
||||
self.config_dependencies = yaml.load(open(os.path.join(idf_path, self.CONFIG_DEPENDENCY_FILE), "r"),
|
||||
self.objdump = Parser.TOOLCHAIN_FOR_TARGET.get(idf_target, '') + 'objdump'
|
||||
self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), 'r'), Loader=Loader)
|
||||
self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), 'r'), Loader=Loader)
|
||||
self.config_dependencies = yaml.load(open(os.path.join(idf_path, self.CONFIG_DEPENDENCY_FILE), 'r'),
|
||||
Loader=Loader)
|
||||
# used to check if duplicated test case names
|
||||
self.test_case_names = set()
|
||||
@@ -82,7 +81,7 @@ class Parser(object):
|
||||
:param config_name: built unit test config name
|
||||
"""
|
||||
tags = self.parse_tags(os.path.join(config_output_folder, self.SDKCONFIG_FILE))
|
||||
print("Tags of config %s: %s" % (config_name, tags))
|
||||
print('Tags of config %s: %s' % (config_name, tags))
|
||||
|
||||
test_groups = self.get_test_groups(os.path.join(configs_folder, config_name))
|
||||
|
||||
@@ -91,7 +90,7 @@ class Parser(object):
|
||||
shell=True)
|
||||
subprocess.check_output('{} -s {} > section_table.tmp'.format(self.objdump, elf_file), shell=True)
|
||||
|
||||
table = CreateSectionTable.SectionTable("section_table.tmp")
|
||||
table = CreateSectionTable.SectionTable('section_table.tmp')
|
||||
test_cases = []
|
||||
|
||||
# we could split cases of same config into multiple binaries as we have limited rom space
|
||||
@@ -99,7 +98,7 @@ class Parser(object):
|
||||
match = self.STRIP_CONFIG_PATTERN.match(config_name)
|
||||
stripped_config_name = match.group(1)
|
||||
|
||||
with open("case_address.tmp", "rb") as f:
|
||||
with open('case_address.tmp', 'rb') as f:
|
||||
for line in f:
|
||||
# process symbol table like: "3ffb4310 l O .dram0.data 00000018 test_desc_33$5010"
|
||||
line = line.split()
|
||||
@@ -109,8 +108,8 @@ class Parser(object):
|
||||
name_addr = table.get_unsigned_int(section, test_addr, 4)
|
||||
desc_addr = table.get_unsigned_int(section, test_addr + 4, 4)
|
||||
function_count = table.get_unsigned_int(section, test_addr + 20, 4)
|
||||
name = table.get_string("any", name_addr)
|
||||
desc = table.get_string("any", desc_addr)
|
||||
name = table.get_string('any', name_addr)
|
||||
desc = table.get_string('any', desc_addr)
|
||||
|
||||
tc = self.parse_one_test_case(name, desc, config_name, stripped_config_name, tags)
|
||||
|
||||
@@ -119,30 +118,30 @@ class Parser(object):
|
||||
# if duplicated IDs, Unity could select incorrect case to run
|
||||
# and we need to check all cases no matter if it's going te be executed by CI
|
||||
# also add app_name here, we allow same case for different apps
|
||||
if (tc["summary"] + stripped_config_name) in self.test_case_names:
|
||||
self.parsing_errors.append("duplicated test case ID: " + tc["summary"])
|
||||
if (tc['summary'] + stripped_config_name) in self.test_case_names:
|
||||
self.parsing_errors.append('duplicated test case ID: ' + tc['summary'])
|
||||
else:
|
||||
self.test_case_names.add(tc["summary"] + stripped_config_name)
|
||||
self.test_case_names.add(tc['summary'] + stripped_config_name)
|
||||
|
||||
test_group_included = True
|
||||
if test_groups is not None and tc["group"] not in test_groups:
|
||||
if test_groups is not None and tc['group'] not in test_groups:
|
||||
test_group_included = False
|
||||
|
||||
if tc["CI ready"] == "Yes" and test_group_included:
|
||||
if tc['CI ready'] == 'Yes' and test_group_included:
|
||||
# update test env list and the cases of same env list
|
||||
if tc["test environment"] in self.test_env_tags:
|
||||
self.test_env_tags[tc["test environment"]].append(tc["ID"])
|
||||
if tc['test environment'] in self.test_env_tags:
|
||||
self.test_env_tags[tc['test environment']].append(tc['ID'])
|
||||
else:
|
||||
self.test_env_tags.update({tc["test environment"]: [tc["ID"]]})
|
||||
self.test_env_tags.update({tc['test environment']: [tc['ID']]})
|
||||
|
||||
if function_count > 1:
|
||||
tc.update({"child case num": function_count})
|
||||
tc.update({'child case num': function_count})
|
||||
|
||||
# only add cases need to be executed
|
||||
test_cases.append(tc)
|
||||
|
||||
os.remove("section_table.tmp")
|
||||
os.remove("case_address.tmp")
|
||||
os.remove('section_table.tmp')
|
||||
os.remove('case_address.tmp')
|
||||
|
||||
return test_cases
|
||||
|
||||
@@ -159,14 +158,14 @@ class Parser(object):
|
||||
"""
|
||||
tags = self.DESCRIPTION_PATTERN.findall(tags_raw)
|
||||
assert len(tags) > 0
|
||||
p = dict([(k, self.tag_def[k]["omitted"]) for k in self.tag_def])
|
||||
p["module"] = tags[0]
|
||||
p = dict([(k, self.tag_def[k]['omitted']) for k in self.tag_def])
|
||||
p['module'] = tags[0]
|
||||
|
||||
# Use the original value of the first tag as test group name
|
||||
p["group"] = p["module"]
|
||||
p['group'] = p['module']
|
||||
|
||||
if p["module"] not in self.module_map:
|
||||
p["module"] = "misc"
|
||||
if p['module'] not in self.module_map:
|
||||
p['module'] = 'misc'
|
||||
|
||||
# parsing rest tags, [type=value], =value is optional
|
||||
for tag in tags[1:]:
|
||||
@@ -174,12 +173,12 @@ class Parser(object):
|
||||
assert match is not None
|
||||
tag_type = match.group(1)
|
||||
tag_value = match.group(3)
|
||||
if match.group(2) == "=" and tag_value is None:
|
||||
if match.group(2) == '=' and tag_value is None:
|
||||
# [tag_type=] means tag_value is empty string
|
||||
tag_value = ""
|
||||
tag_value = ''
|
||||
if tag_type in p:
|
||||
if tag_value is None:
|
||||
p[tag_type] = self.tag_def[tag_type]["default"]
|
||||
p[tag_type] = self.tag_def[tag_type]['default']
|
||||
else:
|
||||
p[tag_type] = tag_value
|
||||
else:
|
||||
@@ -230,7 +229,7 @@ class Parser(object):
|
||||
:param sdkconfig_file: sdk config file of the unit test config
|
||||
:return: required tags for runners
|
||||
"""
|
||||
with open(sdkconfig_file, "r") as f:
|
||||
with open(sdkconfig_file, 'r') as f:
|
||||
configs_raw_data = f.read()
|
||||
|
||||
configs = configs_raw_data.splitlines(False)
|
||||
@@ -243,7 +242,7 @@ class Parser(object):
|
||||
:param config_file file under configs/ directory for given configuration
|
||||
:return: list of test groups, or None if TEST_GROUPS wasn't set
|
||||
"""
|
||||
with open(config_file, "r") as f:
|
||||
with open(config_file, 'r') as f:
|
||||
for line in f:
|
||||
match = self.TEST_GROUPS_PATTERN.match(line)
|
||||
if match is not None:
|
||||
@@ -263,22 +262,22 @@ class Parser(object):
|
||||
prop = self.parse_case_properties(description)
|
||||
|
||||
test_case = deepcopy(TEST_CASE_PATTERN)
|
||||
test_case.update({"config": config_name,
|
||||
"module": self.module_map[prop["module"]]['module'],
|
||||
"group": prop["group"],
|
||||
"CI ready": "No" if prop["ignore"] == "Yes" else "Yes",
|
||||
"ID": "[{}] {}".format(stripped_config_name, name),
|
||||
"test point 2": prop["module"],
|
||||
"steps": name,
|
||||
"test environment": prop["test_env"],
|
||||
"reset": prop["reset"],
|
||||
"sub module": self.module_map[prop["module"]]['sub module'],
|
||||
"summary": name,
|
||||
"multi_device": prop["multi_device"],
|
||||
"multi_stage": prop["multi_stage"],
|
||||
"timeout": int(prop["timeout"]),
|
||||
"tags": tags,
|
||||
"chip_target": self.idf_target})
|
||||
test_case.update({'config': config_name,
|
||||
'module': self.module_map[prop['module']]['module'],
|
||||
'group': prop['group'],
|
||||
'CI ready': 'No' if prop['ignore'] == 'Yes' else 'Yes',
|
||||
'ID': '[{}] {}'.format(stripped_config_name, name),
|
||||
'test point 2': prop['module'],
|
||||
'steps': name,
|
||||
'test environment': prop['test_env'],
|
||||
'reset': prop['reset'],
|
||||
'sub module': self.module_map[prop['module']]['sub module'],
|
||||
'summary': name,
|
||||
'multi_device': prop['multi_device'],
|
||||
'multi_stage': prop['multi_stage'],
|
||||
'timeout': int(prop['timeout']),
|
||||
'tags': tags,
|
||||
'chip_target': self.idf_target})
|
||||
return test_case
|
||||
|
||||
def dump_test_cases(self, test_cases):
|
||||
@@ -286,13 +285,13 @@ class Parser(object):
|
||||
dump parsed test cases to YAML file for test bench input
|
||||
:param test_cases: parsed test cases
|
||||
"""
|
||||
filename = os.path.join(self.idf_path, self.TEST_CASE_FILE_DIR, self.idf_target + ".yml")
|
||||
filename = os.path.join(self.idf_path, self.TEST_CASE_FILE_DIR, self.idf_target + '.yml')
|
||||
try:
|
||||
os.mkdir(os.path.dirname(filename))
|
||||
except OSError:
|
||||
pass
|
||||
with open(os.path.join(filename), "w+") as f:
|
||||
yaml.dump({"test cases": test_cases}, f, allow_unicode=True, default_flow_style=False)
|
||||
with open(os.path.join(filename), 'w+') as f:
|
||||
yaml.dump({'test cases': test_cases}, f, allow_unicode=True, default_flow_style=False)
|
||||
|
||||
def copy_module_def_file(self):
|
||||
""" copy module def file to artifact path """
|
||||
@@ -312,7 +311,7 @@ class Parser(object):
|
||||
config_output_folder = os.path.join(output_folder, config)
|
||||
if os.path.exists(config_output_folder):
|
||||
test_cases.extend(self.parse_test_cases_for_one_config(configs_folder, config_output_folder, config))
|
||||
test_cases.sort(key=lambda x: x["config"] + x["summary"])
|
||||
test_cases.sort(key=lambda x: x['config'] + x['summary'])
|
||||
self.dump_test_cases(test_cases)
|
||||
|
||||
|
||||
@@ -320,30 +319,30 @@ def test_parser(binary_folder):
|
||||
parser = Parser(binary_folder)
|
||||
# test parsing tags
|
||||
# parsing module only and module in module list
|
||||
prop = parser.parse_case_properties("[esp32]")
|
||||
assert prop["module"] == "esp32"
|
||||
prop = parser.parse_case_properties('[esp32]')
|
||||
assert prop['module'] == 'esp32'
|
||||
# module not in module list
|
||||
prop = parser.parse_case_properties("[not_in_list]")
|
||||
assert prop["module"] == "misc"
|
||||
prop = parser.parse_case_properties('[not_in_list]')
|
||||
assert prop['module'] == 'misc'
|
||||
# parsing a default tag, a tag with assigned value
|
||||
prop = parser.parse_case_properties("[esp32][ignore][test_env=ABCD][not_support1][not_support2=ABCD]")
|
||||
assert prop["ignore"] == "Yes" and prop["test_env"] == "ABCD" \
|
||||
and "not_support1" not in prop and "not_supported2" not in prop
|
||||
prop = parser.parse_case_properties('[esp32][ignore][test_env=ABCD][not_support1][not_support2=ABCD]')
|
||||
assert prop['ignore'] == 'Yes' and prop['test_env'] == 'ABCD' \
|
||||
and 'not_support1' not in prop and 'not_supported2' not in prop
|
||||
# parsing omitted value
|
||||
prop = parser.parse_case_properties("[esp32]")
|
||||
assert prop["ignore"] == "No" and prop["test_env"] == "UT_T1_1"
|
||||
prop = parser.parse_case_properties('[esp32]')
|
||||
assert prop['ignore'] == 'No' and prop['test_env'] == 'UT_T1_1'
|
||||
# parsing with incorrect format
|
||||
try:
|
||||
parser.parse_case_properties("abcd")
|
||||
parser.parse_case_properties('abcd')
|
||||
assert False
|
||||
except AssertionError:
|
||||
pass
|
||||
# skip invalid data parse, [type=] assigns empty string to type
|
||||
prop = parser.parse_case_properties("[esp32]abdc aaaa [ignore=]")
|
||||
assert prop["module"] == "esp32" and prop["ignore"] == ""
|
||||
prop = parser.parse_case_properties('[esp32]abdc aaaa [ignore=]')
|
||||
assert prop['module'] == 'esp32' and prop['ignore'] == ''
|
||||
# skip mis-paired []
|
||||
prop = parser.parse_case_properties("[esp32][[ignore=b]][]][test_env=AAA]]")
|
||||
assert prop["module"] == "esp32" and prop["ignore"] == "b" and prop["test_env"] == "AAA"
|
||||
prop = parser.parse_case_properties('[esp32][[ignore=b]][]][test_env=AAA]]')
|
||||
assert prop['module'] == 'esp32' and prop['ignore'] == 'b' and prop['test_env'] == 'AAA'
|
||||
|
||||
config_dependency = {
|
||||
'a': '123',
|
||||
@@ -353,7 +352,7 @@ def test_parser(binary_folder):
|
||||
'e': '{123} and not {789}',
|
||||
'f': '({123} and {456}) or ({123} and {789})'
|
||||
}
|
||||
sdkconfig = ["123", "789"]
|
||||
sdkconfig = ['123', '789']
|
||||
tags = parser.parse_tags_internal(sdkconfig, config_dependency, parser.CONFIG_PATTERN)
|
||||
assert sorted(tags) == ['a', 'd', 'f'] # sorted is required for older Python3, e.g. 3.4.8
|
||||
|
||||
|
||||
Reference in New Issue
Block a user