Clone of official tools

Revision:
13:ab47a20b66f0
Parent:
0:66f3b5499f7f
Child:
20:835f6355470d
--- a/test_api.py	Tue Jun 14 11:33:06 2016 +0100
+++ b/test_api.py	Thu Jul 14 20:21:19 2016 +0100
@@ -55,6 +55,7 @@
 from tools.build_api import prep_properties
 from tools.build_api import create_result
 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.test_exporters import ReportExporter, ResultExporterType
@@ -897,7 +898,7 @@
                                                       reset=host_test_reset,
                                                       reset_tout=reset_tout,
                                                       copy_method=selected_copy_method,
-                                                      program_cycle_s=target_by_mcu.program_cycle_s())
+                                                      program_cycle_s=target_by_mcu.program_cycle_s)
                 single_test_result, single_test_output, single_testduration, single_timeout = host_test_result
 
             # Store test result
@@ -1960,62 +1961,44 @@
         name_parts.insert(0, tail)
         head, tail = os.path.split(head)
     
-    return "-".join(name_parts)
+    return "-".join(name_parts).lower()
 
 def find_tests(base_dir):
     """Given any directory, walk through the subdirectories and find all tests"""
     
-    def find_tests_in_tests_directory(directory):
+    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"}"""
-        tests = {}
+        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
+                    }
         
-        for d in os.listdir(directory):
-            # dir name host_tests is reserved for host python scripts.
-            if d != "host_tests":
-                # Loop on test case directories
-                for td in os.listdir(os.path.join(directory, d)):
-                    # Add test case to the results if it is a directory
-                    test_case_path = os.path.join(directory, d, td)
-                    if os.path.isdir(test_case_path):
-                        tests[test_path_to_name(test_case_path)] = test_case_path
-        
-        return tests
-    
+        return test
+
     tests_path = 'TESTS'
-    
-    # Determine if "base_dir" is already a "TESTS" directory
-    _, top_folder = os.path.split(base_dir)
+    tests = {}
+    dirs = scan_for_source_paths(base_dir)
     
-    if top_folder == tests_path:
-        # Already pointing at a "TESTS" directory
-        return find_tests_in_tests_directory(base_dir)
-    else:
-        # Not pointing at a "TESTS" directory, so go find one!
-        tests = {}
-        
-        for root, dirs, files in os.walk(base_dir):
-            # Don't search build directories
-            if '.build' in dirs:
-                dirs.remove('.build')
-            
-            # If a "TESTS" directory is found, find the tests inside of it
-            if tests_path in dirs:
-                # Remove it from the directory walk
-                dirs.remove(tests_path)
-                
-                # Get the tests inside of the "TESTS" directory
-                new_tests = find_tests_in_tests_directory(os.path.join(root, tests_path))
-                if new_tests:
-                    tests.update(new_tests)
-        
-        return tests
+    for directory in dirs:
+        test = find_test_in_directory(directory, tests_path)
+        if test:
+            tests[test['name']] = test['path']
     
-def print_tests(tests, format="list"):
+    return tests
+    
+def print_tests(tests, format="list", sort=True):
     """Given a dictionary of tests (as returned from "find_tests"), print them
     in the specified format"""
     if format == "list":
-        for test_name, test_path in tests.iteritems():
+        for test_name in sorted(tests.keys()):
+            test_path = tests[test_name]
             print "Test Case:"
             print "    Name: %s" % test_name
             print "    Path: %s" % test_path
@@ -2025,32 +2008,65 @@
         print "Unknown format '%s'" % format
         sys.exit(1)
 
+def norm_relative_path(path, start):
+    """This function will create a normalized, relative path. It mimics the
+    python os.path.relpath function, but also normalizes a Windows-syle path
+    that use backslashes to a Unix style path that uses forward slashes."""
+    path = os.path.normpath(path)
+    path = os.path.relpath(path, start)
+    path = path.replace("\\", "/")
+    return path
+
 def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
         options=None, clean=False, notify=None, verbose=False, jobs=1,
-        silent=False, report=None, properties=None):
+        macros=None, silent=False, report=None, properties=None,
+        continue_on_build_fail=False):
     """Given the data structure from 'find_tests' and the typical build parameters,
-    build all the tests and return a test build data structure"""
+    build all the tests
+    
+    Returns a tuple of the build result (True or False) followed by the test
+    build data structure"""
+    
+    execution_directory = "."
+
+    base_path = norm_relative_path(build_path, execution_directory)
+
+    target_name = target if isinstance(target, str) else target.name
     
     test_build = {
-        "platform": target.name,
+        "platform": target_name,
         "toolchain": toolchain_name,
-        "base_path": build_path,
+        "base_path": base_path,
         "baud_rate": 9600,
         "binary_type": "bootable",
         "tests": {}
     }
     
+    result = True
+    
     for test_name, test_path in tests.iteritems():
         test_build_path = os.path.join(build_path, test_path)
         src_path = base_source_paths + [test_path]
-        bin_file = build_project(src_path, test_build_path, target, toolchain_name,
-                                 options=options,
-                                 jobs=jobs,
-                                 clean=clean,
-                                 name=test_name,
-                                 report=report,
-                                 properties=properties,
-                                 verbose=verbose)
+        bin_file = None
+        try:
+            bin_file = build_project(src_path, test_build_path, target, toolchain_name,
+                                     options=options,
+                                     jobs=jobs,
+                                     clean=clean,
+                                     macros=macros,
+                                     name=test_name,
+                                     report=report,
+                                     properties=properties,
+                                     verbose=verbose)
+
+        except Exception, e:
+            if not isinstance(e, NotSupportedException):
+                result = False
+                
+                if continue_on_build_fail:
+                    continue
+                else:
+                    break
         
         # If a clean build was carried out last time, disable it for the next build.
         # Otherwise the previously built test will be deleted.
@@ -2058,27 +2074,27 @@
             clean = False
         
         # Normalize the path
-        bin_file = os.path.normpath(bin_file)
-        
-        test_build['tests'][test_name] = {
-            "binaries": [
-                {
-                    "path": bin_file
-                }
-            ]
-        }
-        
-        print 'Image: %s'% bin_file
+        if bin_file:
+            bin_file = norm_relative_path(bin_file, execution_directory)
+            
+            test_build['tests'][test_name] = {
+                "binaries": [
+                    {
+                        "path": bin_file
+                    }
+                ]
+            }
+            
+            print 'Image: %s'% bin_file
     
     test_builds = {}
-    test_builds["%s-%s" % (target.name, toolchain_name)] = test_build
+    test_builds["%s-%s" % (target_name, toolchain_name)] = test_build
     
     
-    return test_builds
+    return result, test_builds
     
 
-def test_spec_from_test_build(test_builds):
+def test_spec_from_test_builds(test_builds):
     return {
         "builds": test_builds
     }
-    
\ No newline at end of file