diff --git a/tools/test.py b/tools/test.py index c993794cb50..39107c5b487 100644 --- a/tools/test.py +++ b/tools/test.py @@ -31,7 +31,7 @@ from tools.build_api import build_project, build_library from tools.build_api import print_build_memory_usage_results from tools.targets import TARGET_MAP -from tools.utils import mkdir, ToolException, NotSupportedException +from tools.utils import mkdir, ToolException, NotSupportedException, args_error from tools.test_exporters import ReportExporter, ResultExporterType from utils import argparse_filestring_type, argparse_lowercase_type, argparse_many from tools.toolchains import mbedToolchain @@ -95,6 +95,16 @@ options = parser.parse_args() + if not options.mcu: + args_error(parser, "[ERROR] You should specify an MCU") + + mcu = options.mcu[0] + + if not options.tool: + args_error(parser, "[ERROR] You should specify a TOOLCHAIN") + + toolchain = options.tool[0] + # Filter tests by path if specified if options.paths: all_paths = options.paths @@ -106,7 +116,7 @@ # Find all tests in the relevant paths for path in all_paths: - all_tests.update(find_tests(path)) + all_tests.update(find_tests(path, mcu, toolchain, options.options)) # Filter tests by name if specified if options.names: @@ -150,16 +160,13 @@ if not base_source_paths: base_source_paths = ['.'] - - target = options.mcu[0] - build_report = {} build_properties = {} library_build_success = False try: # Build sources - build_library(base_source_paths, options.build_dir, target, options.tool[0], + build_library(base_source_paths, options.build_dir, mcu, toolchain, options=options.options, jobs=options.jobs, clean=options.clean, @@ -186,7 +193,7 @@ print "Failed to build library" else: # Build all the tests - test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, target, options.tool[0], + test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, mcu, toolchain, options=options.options, clean=options.clean, report=build_report, diff --git a/tools/test_api.py b/tools/test_api.py index 6797cae9240..8aaa9bd2258 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -58,8 +58,7 @@ from tools.build_api import add_result_to_report from tools.build_api import scan_for_source_paths from tools.libraries import LIBRARIES, LIBRARY_MAP -from tools.toolchains import TOOLCHAIN_BIN_PATH -from tools.toolchains import TOOLCHAINS +from tools.toolchains import TOOLCHAINS, TOOLCHAIN_BIN_PATH, TOOLCHAIN_CLASSES from tools.test_exporters import ReportExporter, ResultExporterType from tools.utils import argparse_filestring_type from tools.utils import argparse_uppercase_type @@ -1987,33 +1986,19 @@ def test_path_to_name(path): return "-".join(name_parts).lower() -def find_tests(base_dir): +def find_tests(base_dir, target, toolchain, options): """Given any directory, walk through the subdirectories and find all tests""" - def find_test_in_directory(directory, tests_path): - """Given a 'TESTS' directory, return a dictionary of test names and test paths. - The formate of the dictionary is {"test-name": "./path/to/test"}""" - test = None - if tests_path in directory: - head, test_case_directory = os.path.split(directory) - if test_case_directory != tests_path and test_case_directory != "host_tests": - head, test_group_directory = os.path.split(head) - if test_group_directory != tests_path and test_case_directory != "host_tests": - test = { - "name": test_path_to_name(directory), - "path": directory - } - - return test + # If the 'target' argument is a string, convert it to a target instance + target = TARGET_MAP[target] + toolchain = TOOLCHAIN_CLASSES[toolchain](target) + resources = toolchain.scan_resources(base_dir) - tests_path = 'TESTS' tests = {} - dirs = scan_for_source_paths(base_dir) - for directory in dirs: - test = find_test_in_directory(directory, tests_path) - if test: - tests[test['name']] = test['path'] + for directory in resources.test_directories: + test_name = test_path_to_name(directory) + tests[test_name] = directory return tests diff --git a/tools/toolchains/__init__.py b/tools/toolchains/__init__.py index 20262619062..6ad370e4b5b 100644 --- a/tools/toolchains/__init__.py +++ b/tools/toolchains/__init__.py @@ -28,7 +28,7 @@ from tools.config import Config from multiprocessing import Pool, cpu_count -from tools.utils import run_cmd, mkdir, rel_path, ToolException, NotSupportedException, split_path +from tools.utils import run_cmd, mkdir, rel_path, ToolException, NotSupportedException, split_path, directory_in_path, is_test_directory from tools.settings import BUILD_OPTIONS, MBED_ORG_USER import tools.hooks as hooks from tools.memap import MemapParser @@ -94,6 +94,10 @@ def __init__(self, base_path=None): # Features self.features = {} + + # Tests + self.test_directories = [] + def __add__(self, resources): if resources is None: @@ -496,7 +500,7 @@ def _add_dir(self, path, resources, base_path, exclude_paths=None): for d in copy(dirs): dir_path = join(root, d) # Add internal repo folders/files. This is needed for exporters - if d == '.hg': + if d == '.hg' and not directory_in_path('TESTS', relpath(root, path)): resources.repo_dirs.append(dir_path) resources.repo_files.extend(self.scan_repository(dir_path)) @@ -506,10 +510,11 @@ def _add_dir(self, path, resources, base_path, exclude_paths=None): # Ignore toolchain that do not match the current TOOLCHAIN (d.startswith('TOOLCHAIN_') and d[10:] not in labels['TOOLCHAIN']) or # Ignore .mbedignore files - self.is_ignored(join(dir_path,"")) or - # Ignore TESTS dir - (d == 'TESTS')): + self.is_ignored(join(dir_path,""))): dirs.remove(d) + elif is_test_directory(relpath(dir_path, path)): + resources.test_directories.append(dir_path) + dirs.remove(d) elif d.startswith('FEATURE_'): # Recursively scan features but ignore them in the current scan. # These are dynamically added by the config system if the conditions are matched @@ -525,9 +530,10 @@ def _add_dir(self, path, resources, base_path, exclude_paths=None): # Add root to include paths resources.inc_dirs.append(root) - for file in files: - file_path = join(root, file) - self._add_file(file_path, resources, base_path) + if not directory_in_path('TESTS', relpath(root, path)): + for file in files: + file_path = join(root, file) + self._add_file(file_path, resources, base_path) # A helper function for both scan_resources and _add_dir. _add_file adds one file # (*file_path*) to the resources object based on the file type. diff --git a/tools/utils.py b/tools/utils.py index 8c33e36d4e0..28100e199ad 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -83,6 +83,22 @@ def find_cmd_abspath(cmd): return abspath +def directory_in_path(directory, path): + """ Returns True if `directory` is found within `path`. + Ex. directory_in_path("dir", "/is/dir/in/here") returns True + Ex. directory_in_path("dir", "/is/my_dir/in/here") returns False + """ + head, tail = split(path) + + while tail: + if tail == directory: + return True + else: + head, tail = split(head) + + return False + + def mkdir(path): if not exists(path): makedirs(path) @@ -140,6 +156,23 @@ def split_path(path): return base, name, ext +def is_test_directory(path): + """Given a path, return true if it is a test case directory. + Directory must follow this pattern: TESTS/testgroup/testcase. This + would return True.""" + tests_path = 'TESTS' + if directory_in_path(tests_path, path): + head, test_case_directory = split(path) + if test_case_directory != tests_path and test_case_directory != "host_tests": + head, test_group_directory = split(head) + if test_group_directory != tests_path and test_case_directory != "host_tests": + head, candidate_tests_path = split(head) + if candidate_tests_path == tests_path: + return True + + return False + + def args_error(parser, message): print "\n\n%s\n\n" % message parser.print_help()