|
@@ -4,7 +4,6 @@ import os
|
|
|
import re
|
|
import re
|
|
|
import shutil
|
|
import shutil
|
|
|
import subprocess
|
|
import subprocess
|
|
|
-import hashlib
|
|
|
|
|
|
|
|
|
|
from copy import deepcopy
|
|
from copy import deepcopy
|
|
|
import CreateSectionTable
|
|
import CreateSectionTable
|
|
@@ -31,6 +30,7 @@ class Parser(object):
|
|
|
|
|
|
|
|
TAG_PATTERN = re.compile("([^=]+)(=)?(.+)?")
|
|
TAG_PATTERN = re.compile("([^=]+)(=)?(.+)?")
|
|
|
DESCRIPTION_PATTERN = re.compile("\[([^]\[]+)\]")
|
|
DESCRIPTION_PATTERN = re.compile("\[([^]\[]+)\]")
|
|
|
|
|
+ CONFIG_PATTERN = re.compile(r"{([^}]+)}")
|
|
|
|
|
|
|
|
# file path (relative to idf path)
|
|
# file path (relative to idf path)
|
|
|
TAG_DEF_FILE = os.path.join("tools", "unit-test-app", "tools", "TagDefinition.yml")
|
|
TAG_DEF_FILE = os.path.join("tools", "unit-test-app", "tools", "TagDefinition.yml")
|
|
@@ -49,7 +49,7 @@ class Parser(object):
|
|
|
self.idf_path = idf_path
|
|
self.idf_path = idf_path
|
|
|
self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), "r"))
|
|
self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), "r"))
|
|
|
self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), "r"))
|
|
self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), "r"))
|
|
|
- self.config_dependency = yaml.load(open(os.path.join(idf_path, self.CONFIG_DEPENDENCY_FILE), "r"))
|
|
|
|
|
|
|
+ self.config_dependencies = yaml.load(open(os.path.join(idf_path, self.CONFIG_DEPENDENCY_FILE), "r"))
|
|
|
# used to check if duplicated test case names
|
|
# used to check if duplicated test case names
|
|
|
self.test_case_names = set()
|
|
self.test_case_names = set()
|
|
|
self.parsing_errors = []
|
|
self.parsing_errors = []
|
|
@@ -150,23 +150,56 @@ class Parser(object):
|
|
|
pass
|
|
pass
|
|
|
return p
|
|
return p
|
|
|
|
|
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def parse_tags_internal(sdkconfig, config_dependencies, config_pattern):
|
|
|
|
|
+ required_tags = []
|
|
|
|
|
+
|
|
|
|
|
+ def compare_config(config):
|
|
|
|
|
+ return config in sdkconfig
|
|
|
|
|
+
|
|
|
|
|
+ def process_condition(condition):
|
|
|
|
|
+ matches = config_pattern.findall(condition)
|
|
|
|
|
+ if matches:
|
|
|
|
|
+ for config in matches:
|
|
|
|
|
+ compare_result = compare_config(config)
|
|
|
|
|
+ # replace all configs in condition with True or False according to compare result
|
|
|
|
|
+ condition = re.sub(config_pattern, str(compare_result), condition, count=1)
|
|
|
|
|
+ # Now the condition is a python condition, we can use eval to compute its value
|
|
|
|
|
+ ret = eval(condition)
|
|
|
|
|
+ else:
|
|
|
|
|
+ # didn't use complex condition. only defined one condition for the tag
|
|
|
|
|
+ ret = compare_config(condition)
|
|
|
|
|
+ return ret
|
|
|
|
|
+
|
|
|
|
|
+ for tag in config_dependencies:
|
|
|
|
|
+ if process_condition(config_dependencies[tag]):
|
|
|
|
|
+ required_tags.append(tag)
|
|
|
|
|
+
|
|
|
|
|
+ return required_tags
|
|
|
|
|
+
|
|
|
def parse_tags(self, sdkconfig_file):
|
|
def parse_tags(self, sdkconfig_file):
|
|
|
"""
|
|
"""
|
|
|
Some test configs could requires different DUTs.
|
|
Some test configs could requires different DUTs.
|
|
|
For example, if CONFIG_SPIRAM_SUPPORT is enabled, we need WROVER-Kit to run test.
|
|
For example, if CONFIG_SPIRAM_SUPPORT is enabled, we need WROVER-Kit to run test.
|
|
|
This method will get tags for runners according to ConfigDependency.yml(maps tags to sdkconfig).
|
|
This method will get tags for runners according to ConfigDependency.yml(maps tags to sdkconfig).
|
|
|
|
|
|
|
|
- :param sdkconfig_file: sdkconfig file of the unit test config
|
|
|
|
|
|
|
+ We support to the following syntax::
|
|
|
|
|
+
|
|
|
|
|
+ # define the config which requires the tag
|
|
|
|
|
+ 'tag_a': 'config_a="value_a"'
|
|
|
|
|
+ # define the condition for the tag
|
|
|
|
|
+ 'tag_b': '{config A} and (not {config B} or (not {config C} and {config D}))'
|
|
|
|
|
+
|
|
|
|
|
+ :param sdkconfig_file: sdk config file of the unit test config
|
|
|
:return: required tags for runners
|
|
:return: required tags for runners
|
|
|
"""
|
|
"""
|
|
|
- required_tags = []
|
|
|
|
|
|
|
+
|
|
|
with open(sdkconfig_file, "r") as f:
|
|
with open(sdkconfig_file, "r") as f:
|
|
|
configs_raw_data = f.read()
|
|
configs_raw_data = f.read()
|
|
|
|
|
+
|
|
|
configs = configs_raw_data.splitlines(False)
|
|
configs = configs_raw_data.splitlines(False)
|
|
|
- for tag in self.config_dependency:
|
|
|
|
|
- if self.config_dependency[tag] in configs:
|
|
|
|
|
- required_tags.append(tag)
|
|
|
|
|
- return required_tags
|
|
|
|
|
|
|
+
|
|
|
|
|
+ return self.parse_tags_internal(configs, self.config_dependencies, self.CONFIG_PATTERN)
|
|
|
|
|
|
|
|
def parse_one_test_case(self, name, description, file_name, config_name, tags):
|
|
def parse_one_test_case(self, name, description, file_name, config_name, tags):
|
|
|
"""
|
|
"""
|
|
@@ -254,6 +287,18 @@ def test_parser():
|
|
|
prop = parser.parse_case_properities("[esp32][[ignore=b]][]][test_env=AAA]]")
|
|
prop = parser.parse_case_properities("[esp32][[ignore=b]][]][test_env=AAA]]")
|
|
|
assert prop["module"] == "esp32" and prop["ignore"] == "b" and prop["test_env"] == "AAA"
|
|
assert prop["module"] == "esp32" and prop["ignore"] == "b" and prop["test_env"] == "AAA"
|
|
|
|
|
|
|
|
|
|
+ config_dependency = {
|
|
|
|
|
+ 'a': '123',
|
|
|
|
|
+ 'b': '456',
|
|
|
|
|
+ 'c': 'not {123}',
|
|
|
|
|
+ 'd': '{123} and not {456}',
|
|
|
|
|
+ 'e': '{123} and not {789}',
|
|
|
|
|
+ 'f': '({123} and {456}) or ({123} and {789})'
|
|
|
|
|
+ }
|
|
|
|
|
+ sdkconfig = ["123", "789"]
|
|
|
|
|
+ tags = parser.parse_tags_internal(sdkconfig, config_dependency, parser.CONFIG_PATTERN)
|
|
|
|
|
+ assert tags == ['a', 'd', 'f']
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def main():
|
|
def main():
|
|
|
test_parser()
|
|
test_parser()
|