Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions tools/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
33 changes: 9 additions & 24 deletions tools/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
22 changes: 14 additions & 8 deletions tools/toolchains/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed

resources.repo_dirs.append(dir_path)
resources.repo_files.extend(self.scan_repository(dir_path))

Expand All @@ -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)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not have similar logic to features discovery/accumulation?

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
Expand All @@ -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.
Expand Down
33 changes: 33 additions & 0 deletions tools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down