mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
CI: modify unit test parser to parse unit test cases from build files
Previously test cases were parsed from test files
This commit is contained in:
parent
f9fba35d1d
commit
bda63abb40
145
tools/unit-test-app/CreateSectionTable.py
Normal file
145
tools/unit-test-app/CreateSectionTable.py
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
# This file is used to process section data generated by `objdump -s`
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class SectionTable(object):
|
||||||
|
|
||||||
|
class Section(object):
|
||||||
|
SECTION_START_PATTERN = re.compile("Contents of section (.+?):")
|
||||||
|
DATA_PATTERN = re.compile("([0-9a-f]{4,8})")
|
||||||
|
|
||||||
|
def __init__(self, name, start_address, data):
|
||||||
|
self.name = name
|
||||||
|
self.start_address = start_address
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
if (item["region"] == self.name or item["region"] == "any") \
|
||||||
|
and (self.start_address <= item["address"] < (self.start_address + len(self.data))):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
if isinstance(item, int):
|
||||||
|
return self.data[item - self.start_address]
|
||||||
|
elif isinstance(item, slice):
|
||||||
|
start = item.start if item.start is None else item.start - self.start_address
|
||||||
|
stop = item.stop if item.stop is None else item.stop - self.start_address
|
||||||
|
return self.data[start:stop]
|
||||||
|
return self.data[item]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s [%08x - %08x]" % (self.name, self.start_address, self.start_address+len(self.data))
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse_raw_data(cls, raw_data):
|
||||||
|
name = ""
|
||||||
|
data = ""
|
||||||
|
start_address = 0
|
||||||
|
# first find start line
|
||||||
|
for i, line in enumerate(raw_data):
|
||||||
|
if line.find("Contents of section ") != -1: # do strcmp first to speed up
|
||||||
|
match = cls.SECTION_START_PATTERN.search(line)
|
||||||
|
if match is not None:
|
||||||
|
name = match.group(1)
|
||||||
|
raw_data = raw_data[i+1:]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# do some error handling
|
||||||
|
raw_data = [""] # add a dummy first data line
|
||||||
|
pass
|
||||||
|
|
||||||
|
def process_data_line(line_to_process):
|
||||||
|
# first remove the ascii part
|
||||||
|
hex_part = line_to_process.split(" ")[0]
|
||||||
|
# process rest part
|
||||||
|
data_list = cls.DATA_PATTERN.findall(hex_part)
|
||||||
|
try:
|
||||||
|
_address = int(data_list[0], base=16)
|
||||||
|
except IndexError:
|
||||||
|
_address = -1
|
||||||
|
|
||||||
|
def hex_to_str(hex_data):
|
||||||
|
if len(hex_data) % 2 == 1:
|
||||||
|
hex_data = "0" + hex_data # append zero at the beginning
|
||||||
|
_length = len(hex_data)
|
||||||
|
return "".join([chr(int(hex_data[_i:_i+2], base=16))
|
||||||
|
for _i in range(0, _length, 2)])
|
||||||
|
pass
|
||||||
|
|
||||||
|
return _address, "".join([hex_to_str(x) for x in data_list[1:]])
|
||||||
|
|
||||||
|
# handle first line:
|
||||||
|
address, _data = process_data_line(raw_data[0])
|
||||||
|
if address != -1:
|
||||||
|
start_address = address
|
||||||
|
data += _data
|
||||||
|
raw_data = raw_data[1:]
|
||||||
|
for i, line in enumerate(raw_data):
|
||||||
|
address, _data = process_data_line(line)
|
||||||
|
if address == -1:
|
||||||
|
raw_data = raw_data[i:]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
data += _data
|
||||||
|
else:
|
||||||
|
# do error handling
|
||||||
|
raw_data = []
|
||||||
|
pass
|
||||||
|
return cls(name, start_address, data) if start_address != -1 else None,\
|
||||||
|
None if len(raw_data) == 0 else raw_data
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self, file_name):
|
||||||
|
with open(file_name, "rb") as f:
|
||||||
|
raw_data = f.readlines()
|
||||||
|
self.table = []
|
||||||
|
while raw_data:
|
||||||
|
section, raw_data = self.Section.parse_raw_data(raw_data)
|
||||||
|
self.table.append(section)
|
||||||
|
|
||||||
|
def get_unsigned_int(self, region, address, size=4, endian="LE"):
|
||||||
|
if address % 4 != 0 or size % 4 != 0:
|
||||||
|
print "warning: try to access without 4 bytes aligned"
|
||||||
|
key = {"address": address, "region": region}
|
||||||
|
for section in self.table:
|
||||||
|
if key in section:
|
||||||
|
tmp = section[address:address+size]
|
||||||
|
value = 0
|
||||||
|
for i in range(size):
|
||||||
|
if endian == "LE":
|
||||||
|
value += ord(tmp[i]) << (i*8)
|
||||||
|
elif endian == "BE":
|
||||||
|
value += ord(tmp[i]) << ((size - i - 1) * 8)
|
||||||
|
else:
|
||||||
|
print "only support LE or BE for parameter endian"
|
||||||
|
assert False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
value = None
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_string(self, region, address):
|
||||||
|
value = None
|
||||||
|
key = {"address": address, "region": region}
|
||||||
|
for section in self.table:
|
||||||
|
if key in section:
|
||||||
|
value = section[address:]
|
||||||
|
for i, c in enumerate(value):
|
||||||
|
if c == '\0':
|
||||||
|
value = value[:i]
|
||||||
|
break
|
||||||
|
break
|
||||||
|
return value
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -1,9 +1,9 @@
|
|||||||
import yaml
|
import yaml
|
||||||
import os
|
import os
|
||||||
import os.path
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
|
import CreateSectionTable
|
||||||
|
|
||||||
|
|
||||||
MODULE_MAP = yaml.load(open("ModuleDefinition.yml", "r"))
|
MODULE_MAP = yaml.load(open("ModuleDefinition.yml", "r"))
|
||||||
@ -39,40 +39,28 @@ IDF_PATH = os.getcwd()
|
|||||||
|
|
||||||
class Parser(object):
|
class Parser(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse_test_folders(cls):
|
def parse_test_addresses(cls):
|
||||||
test_folder_paths = list()
|
table = CreateSectionTable.SectionTable(os.path.join(IDF_PATH, "tools", "unit-test-app", "build", "tmp"))
|
||||||
os.chdir(os.path.join(IDF_PATH, "components"))
|
file_index = 1
|
||||||
component_dirs = [d for d in os.listdir(".") if os.path.isdir(d)]
|
test_index = 1
|
||||||
for dir in component_dirs:
|
with open(os.path.join(IDF_PATH, "tools", "unit-test-app", "build", "tests"), "r") as file:
|
||||||
os.chdir(dir)
|
for line in file:
|
||||||
if "test" in os.listdir("."):
|
line = line.split()
|
||||||
test_folder_paths.append(os.path.join(os.getcwd(), "test"))
|
test = int(line[0],16)
|
||||||
os.chdir("..")
|
section = line[3]
|
||||||
Parser.parse_test_files(test_folder_paths)
|
name_addr = table.get_unsigned_int(section, test, 4)
|
||||||
|
desc_addr = table.get_unsigned_int(section, test + 4, 4)
|
||||||
@classmethod
|
name = table.get_string("any", name_addr)
|
||||||
def parse_test_files(cls, test_folder_paths):
|
desc = table.get_string("any", desc_addr)
|
||||||
for path in test_folder_paths:
|
Parser.parse_test_cases(file_index, test_index, "%s, %s" % (name, desc))
|
||||||
os.chdir(path)
|
file_index += 1
|
||||||
for file_path in os.listdir("."):
|
test_index += 1
|
||||||
if file_path[-2:] == ".c":
|
|
||||||
Parser.read_test_file(os.path.join(os.getcwd(), file_path), len(test_cases)+1)
|
|
||||||
os.chdir(os.path.join("..", ".."))
|
os.chdir(os.path.join("..", ".."))
|
||||||
Parser.dump_test_cases(test_cases)
|
Parser.dump_test_cases(test_cases)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def read_test_file(cls, test_file_path, file_index):
|
|
||||||
test_index = 0
|
|
||||||
with open(test_file_path, "r") as file:
|
|
||||||
for line in file:
|
|
||||||
if re.match("TEST_CASE", line):
|
|
||||||
test_index += 1
|
|
||||||
tags = re.split(r"[\[\]\"]", line)
|
|
||||||
Parser.parse_test_cases(file_index, test_index, tags)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse_test_cases(cls, file_index, test_index, tags):
|
def parse_test_cases(cls, file_index, test_index, tags):
|
||||||
|
tags = re.split(r"[\[\]\"]", tags)
|
||||||
ci_ready = "Yes"
|
ci_ready = "Yes"
|
||||||
test_env = "UT_T1_1"
|
test_env = "UT_T1_1"
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
@ -80,7 +68,7 @@ class Parser(object):
|
|||||||
ci_ready = "No"
|
ci_ready = "No"
|
||||||
if re.match("test_env=", tag):
|
if re.match("test_env=", tag):
|
||||||
test_env = tag[9:]
|
test_env = tag[9:]
|
||||||
module_name = tags[4]
|
module_name = tags[1]
|
||||||
try:
|
try:
|
||||||
MODULE_MAP[module_name]
|
MODULE_MAP[module_name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -91,14 +79,14 @@ class Parser(object):
|
|||||||
test_case = dict(TEST_CASE_PATTERN)
|
test_case = dict(TEST_CASE_PATTERN)
|
||||||
test_case.update({"module": MODULE_MAP[module_name]['module'],
|
test_case.update({"module": MODULE_MAP[module_name]['module'],
|
||||||
"CI ready": ci_ready,
|
"CI ready": ci_ready,
|
||||||
"cmd set": ["IDFUnitTest/UnitTest", [tags[1]]],
|
"cmd set": ["IDFUnitTest/UnitTest", [tags[0][:-2]]],
|
||||||
"ID": id,
|
"ID": id,
|
||||||
"test point 2": module_name,
|
"test point 2": module_name,
|
||||||
"steps": tags[1],
|
"steps": tags[0][:-2],
|
||||||
"comment": tags[1],
|
"comment": tags[0][:-2],
|
||||||
"test environment": test_env,
|
"test environment": test_env,
|
||||||
"sub module": MODULE_MAP[module_name]['sub module'],
|
"sub module": MODULE_MAP[module_name]['sub module'],
|
||||||
"summary": tags[1]})
|
"summary": tags[0][:-2]})
|
||||||
if test_case["CI ready"] == "Yes":
|
if test_case["CI ready"] == "Yes":
|
||||||
if test_ids.has_key(test_env):
|
if test_ids.has_key(test_env):
|
||||||
test_ids[test_env].append(id)
|
test_ids[test_env].append(id)
|
||||||
@ -160,7 +148,10 @@ class Parser(object):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
Parser.parse_test_folders()
|
os.chdir(os.path.join(IDF_PATH, "tools", "unit-test-app", "build"))
|
||||||
|
os.system('xtensa-esp32-elf-objdump -t unit-test-app.elf | grep test_desc > tests')
|
||||||
|
os.system('xtensa-esp32-elf-objdump -s unit-test-app.elf > tmp')
|
||||||
|
Parser.parse_test_addresses()
|
||||||
Parser.parse_gitlab_ci()
|
Parser.parse_gitlab_ci()
|
||||||
Parser.dump_ci_config()
|
Parser.dump_ci_config()
|
||||||
Parser.copy_module_def_file()
|
Parser.copy_module_def_file()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user