mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			222 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
"""
 | 
						|
Copyright (c) 2018, Arm Limited
 | 
						|
SPDX-License-Identifier: Apache-2.0
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
 | 
						|
 | 
						|
UNIT TEST BUILD & RUN
 | 
						|
"""
 | 
						|
 | 
						|
import os
 | 
						|
import logging
 | 
						|
import sys
 | 
						|
import psutil
 | 
						|
from shutil import copy
 | 
						|
 | 
						|
from .utils import execute_program
 | 
						|
from .get_tools import get_make_tool, \
 | 
						|
                       get_cmake_tool, \
 | 
						|
                       get_cxx_tool, \
 | 
						|
                       get_c_tool, \
 | 
						|
                       get_valgrind_tool
 | 
						|
from .settings import DEFAULT_CMAKE_GENERATORS
 | 
						|
 | 
						|
class UnitTestTool(object):
 | 
						|
    """
 | 
						|
    Unit test tool to:
 | 
						|
        - prepare build directory
 | 
						|
        - create makefiles
 | 
						|
        - build unit tests
 | 
						|
        - run unit tests
 | 
						|
        - generate code coverage reports
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self,
 | 
						|
                 make_program=None):
 | 
						|
        """
 | 
						|
        Constructor
 | 
						|
 | 
						|
        Keyword arguments:
 | 
						|
        make_program - Make tool to use
 | 
						|
        """
 | 
						|
 | 
						|
        self.make_program = make_program
 | 
						|
 | 
						|
        if self.make_program is None:
 | 
						|
            self.make_program = get_make_tool()
 | 
						|
 | 
						|
    def create_makefiles(self,
 | 
						|
                         path_to_src=None,
 | 
						|
                         generator=None,
 | 
						|
                         coverage_output_type=None,
 | 
						|
                         debug=False,
 | 
						|
                         valgrind=False):
 | 
						|
        """
 | 
						|
        Create Makefiles and prepare targets with CMake.
 | 
						|
 | 
						|
        Keyword arguments:
 | 
						|
        path_to_src - Path to source directory
 | 
						|
        generator - Type of Makefiles to generate
 | 
						|
        coverage_output_type - Generate HTML, XML or both reports
 | 
						|
        debug - Target debug or release build
 | 
						|
        """
 | 
						|
 | 
						|
        if generator is None:
 | 
						|
            generator = DEFAULT_CMAKE_GENERATORS.get(self.make_program,
 | 
						|
                                                     "Unix Makefiles")
 | 
						|
 | 
						|
        cmake = get_cmake_tool()
 | 
						|
 | 
						|
        if cmake is None:
 | 
						|
            logging.error(
 | 
						|
                "No CMake found in Path. Install all the required tools.")
 | 
						|
            sys.exit(1)
 | 
						|
 | 
						|
        args = [cmake,
 | 
						|
                "-G",
 | 
						|
                generator,
 | 
						|
                "-DBUILD_TESTING=ON"
 | 
						|
                "-DCMAKE_MAKE_PROGRAM=%s" % self.make_program,
 | 
						|
                "-DCMAKE_CXX_COMPILER=%s" % get_cxx_tool(),
 | 
						|
                "-DCMAKE_C_COMPILER=%s" % get_c_tool()]
 | 
						|
 | 
						|
        if debug:
 | 
						|
            args.append("-DCMAKE_BUILD_TYPE=Debug")
 | 
						|
 | 
						|
        if coverage_output_type:
 | 
						|
            args.append("-DCOVERAGE:STRING=%s" % coverage_output_type)
 | 
						|
 | 
						|
        if valgrind:
 | 
						|
            valgrind = get_valgrind_tool()
 | 
						|
            if valgrind is None:
 | 
						|
                logging.error(
 | 
						|
                    "No Valgrind found in Path. Install all the required tools.\n")
 | 
						|
                sys.exit(1)
 | 
						|
            args.append("-DVALGRIND=1")
 | 
						|
            args.append("-DMEMORYCHECK_COMMAND_OPTIONS=\"--track-origins=yes\" \"--leak-check=full\" \"--show-reachable=yes\" \"--error-exitcode=1\"")
 | 
						|
        else:
 | 
						|
            args.append("-DVALGRIND=0")
 | 
						|
 | 
						|
        if path_to_src is not None:
 | 
						|
            args.append(path_to_src)
 | 
						|
 | 
						|
        execute_program(args,
 | 
						|
                        "CMake failed to run successfully. See error message.")
 | 
						|
 | 
						|
    def build_tests(self):
 | 
						|
        """
 | 
						|
        Build unit tests and libraries to be tested.
 | 
						|
        """
 | 
						|
 | 
						|
        args = [self.make_program]
 | 
						|
 | 
						|
        # Speed up compilation by running on more than one core
 | 
						|
        count = psutil.cpu_count()
 | 
						|
        args.append("-j{}".format(count+1))
 | 
						|
 | 
						|
        if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
 | 
						|
            args.append("VERBOSE=1")
 | 
						|
 | 
						|
        execute_program(args,
 | 
						|
                        "Building unit tests failed.",
 | 
						|
                        "Unit tests built successfully.")
 | 
						|
 | 
						|
    def run_tests(self, filter_regex=None, valgrind=False):
 | 
						|
        """
 | 
						|
        Run unit tests.
 | 
						|
 | 
						|
        Keyword arguments:
 | 
						|
        filter_regex - Regular expression to select which tests to run
 | 
						|
        """
 | 
						|
 | 
						|
        args = [self.make_program, "test"]
 | 
						|
        if valgrind:
 | 
						|
            if filter_regex:
 | 
						|
                args.append("ARGS=-R %s -V -D ExperimentalMemCheck" % filter_regex)
 | 
						|
            else:
 | 
						|
                args.append("ARGS=-V -D ExperimentalMemCheck")
 | 
						|
        else:
 | 
						|
            if filter_regex:
 | 
						|
                args.append("ARGS=-R %s -V -D ExperimentalTest" % filter_regex)
 | 
						|
            else:
 | 
						|
                args.append("ARGS=-V -D ExperimentalTest")
 | 
						|
 | 
						|
        if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
 | 
						|
            args.append("VERBOSE=1")
 | 
						|
 | 
						|
        execute_program(args, "Unit test run failed.")
 | 
						|
 | 
						|
    def prepare_build_directory(self,
 | 
						|
                                path_to_src=None,
 | 
						|
                                build_path=None,
 | 
						|
                                clean=False):
 | 
						|
        """
 | 
						|
        Create build directory if not exist and
 | 
						|
        change current working directory to it
 | 
						|
 | 
						|
        Keyword arguments:
 | 
						|
        path_to_src - Path to source directory
 | 
						|
        build_path - Path to build directory
 | 
						|
        clean - Clean build directory
 | 
						|
        """
 | 
						|
 | 
						|
        if build_path is None:
 | 
						|
            build_path = os.getcwd()
 | 
						|
 | 
						|
        # Clean CMake data if exists.
 | 
						|
        if clean:
 | 
						|
            self._clean_build(build_path)
 | 
						|
 | 
						|
        # Create build directory if not exist.
 | 
						|
        if not os.path.exists(build_path):
 | 
						|
            os.makedirs(build_path)
 | 
						|
            filename = ".mbedignore"
 | 
						|
            inputfile = os.path.join(path_to_src, filename)
 | 
						|
            outputfile = os.path.join(build_path, filename)
 | 
						|
            copy(inputfile, outputfile)
 | 
						|
 | 
						|
        # Change current working directory to build directory.
 | 
						|
        os.chdir(build_path)
 | 
						|
 | 
						|
    def _clean_build(self, build_path=None):
 | 
						|
        """
 | 
						|
        Try clean build directory
 | 
						|
 | 
						|
        Keyword arguments:
 | 
						|
        build_path - Path to build directory
 | 
						|
        """
 | 
						|
 | 
						|
        logging.info("Cleaning build directory...")
 | 
						|
 | 
						|
        if os.path.exists(os.path.join(build_path, "CMakeCache.txt")):
 | 
						|
            args = [self.make_program,
 | 
						|
                    "-C",
 | 
						|
                    build_path,
 | 
						|
                    "--no-print-directory",
 | 
						|
                    "clean"]
 | 
						|
 | 
						|
            # Remove coverage files
 | 
						|
            for root, _, files in os.walk(build_path):
 | 
						|
                for current_file in files:
 | 
						|
                    if current_file.endswith((".gcno", ".gcda")):
 | 
						|
                        os.remove(os.path.join(root, current_file))
 | 
						|
 | 
						|
            execute_program(args,
 | 
						|
                            "Clean step failed.",
 | 
						|
                            "Clean done.")
 | 
						|
 | 
						|
        else:
 | 
						|
            logging.warning("%s does not exist or \
 | 
						|
            does not contain previous build data.", build_path)
 |