mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			add coverage filtering
							parent
							
								
									b5ee0c0e27
								
							
						
					
					
						commit
						04c98b0223
					
				| 
						 | 
				
			
			@ -23,12 +23,14 @@ UNIT TEST BUILD & RUN
 | 
			
		|||
from __future__ import print_function
 | 
			
		||||
import os
 | 
			
		||||
import logging
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from unit_test.options import get_options_parser, \
 | 
			
		||||
                              pretty_print_test_options
 | 
			
		||||
from unit_test.settings import DEFAULT_CMAKE_GENERATORS
 | 
			
		||||
from unit_test.test import UnitTestTool
 | 
			
		||||
from unit_test.new import UnitTestGeneratorTool
 | 
			
		||||
from unit_test.coverage import CoverageAPI
 | 
			
		||||
 | 
			
		||||
def _mbed_unittest_test(options, cwd, pwd):
 | 
			
		||||
    if options is None:
 | 
			
		||||
| 
						 | 
				
			
			@ -80,14 +82,28 @@ def _mbed_unittest_test(options, cwd, pwd):
 | 
			
		|||
        tool.build_tests()
 | 
			
		||||
 | 
			
		||||
    if options.run_only:
 | 
			
		||||
        tool.run_tests(filter_regex=options.test_regex)
 | 
			
		||||
 | 
			
		||||
        # If code coverage generation:
 | 
			
		||||
        if options.coverage:
 | 
			
		||||
            # Run tests and generate reports
 | 
			
		||||
            tool.generate_coverage_report(coverage_output_type=options.coverage,
 | 
			
		||||
                                          excludes=[pwd, options.build],
 | 
			
		||||
                                          build_path=options.build)
 | 
			
		||||
        else:
 | 
			
		||||
            tool.run_tests(filter_regex=options.test_regex) # Only run tests
 | 
			
		||||
            cov_api = CoverageAPI(
 | 
			
		||||
                mbed_os_root=os.path.normpath(os.path.join(pwd, "..")),
 | 
			
		||||
                build_dir=options.build)
 | 
			
		||||
 | 
			
		||||
            # Generate reports
 | 
			
		||||
            outputs = [options.coverage]
 | 
			
		||||
            if options.coverage == "both":
 | 
			
		||||
                outputs = ["html", "xml"]
 | 
			
		||||
 | 
			
		||||
            excludes = [pwd, options.build]
 | 
			
		||||
 | 
			
		||||
            if not options.include_headers:
 | 
			
		||||
                excludes.append(re.compile(".*\\.h"))
 | 
			
		||||
 | 
			
		||||
            cov_api.generate_reports(outputs=outputs,
 | 
			
		||||
                                     excludes=excludes,
 | 
			
		||||
                                     filter_regex=options.test_regex,
 | 
			
		||||
                                     build_path=options.build)
 | 
			
		||||
 | 
			
		||||
def _mbed_unittest_new(options, pwd):
 | 
			
		||||
    if options is None:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,136 @@
 | 
			
		|||
"""
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GENERATE TEST CODE COVERAGE
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import logging
 | 
			
		||||
import posixpath
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from .utils import execute_program
 | 
			
		||||
from .get_tools import get_gcov_program, \
 | 
			
		||||
                       get_gcovr_program
 | 
			
		||||
 | 
			
		||||
class CoverageAPI(object):
 | 
			
		||||
    """
 | 
			
		||||
    Generate code coverage reports for unit tests.
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, mbed_os_root=None, build_dir=None):
 | 
			
		||||
        self.root = mbed_os_root
 | 
			
		||||
 | 
			
		||||
        if not self.root:
 | 
			
		||||
            self.root = os.path.normpath(os.path.join(
 | 
			
		||||
                os.path.dirname(os.path.realpath(__file__)),
 | 
			
		||||
                "../.."))
 | 
			
		||||
 | 
			
		||||
        self.build_dir = build_dir
 | 
			
		||||
 | 
			
		||||
        if not self.build_dir:
 | 
			
		||||
            logging.error("No build directory given for CoverageAPI.")
 | 
			
		||||
 | 
			
		||||
    def _gen_cmd(self, coverage_type, excludes, filter_regex):
 | 
			
		||||
        # Generate coverage generation command:
 | 
			
		||||
        args = [get_gcovr_program(),
 | 
			
		||||
                "--gcov-executable",
 | 
			
		||||
                get_gcov_program(),
 | 
			
		||||
                "-r",
 | 
			
		||||
                os.path.relpath(self.root, self.build_dir),
 | 
			
		||||
                "."]
 | 
			
		||||
 | 
			
		||||
        if coverage_type == "html":
 | 
			
		||||
            args.extend(["--html",
 | 
			
		||||
                         "--html-detail",
 | 
			
		||||
                         "-o",
 | 
			
		||||
                         "./coverage/index.html"])
 | 
			
		||||
        elif coverage_type == "xml":
 | 
			
		||||
            args.extend(["-x",
 | 
			
		||||
                         "-o",
 | 
			
		||||
                         "./coverage.xml"])
 | 
			
		||||
 | 
			
		||||
        # Add exclude filters:
 | 
			
		||||
        for path in excludes:
 | 
			
		||||
            # Use posix separators if path is string
 | 
			
		||||
            if isinstance(path, ("".__class__, u"".__class__)):
 | 
			
		||||
                path = path.replace("\\", "/")
 | 
			
		||||
                args.extend(["-e", path])
 | 
			
		||||
            # Use regular expressions as is
 | 
			
		||||
            elif isinstance(path, type(re.compile(""))):
 | 
			
		||||
                args.extend(["-e", path.pattern])
 | 
			
		||||
 | 
			
		||||
        # Add include filters:
 | 
			
		||||
        if filter_regex:
 | 
			
		||||
            filters = filter_regex.split(",")
 | 
			
		||||
 | 
			
		||||
            for filt in filters:
 | 
			
		||||
                regex = "(.+/)?%s" % filt.replace("-", "/")
 | 
			
		||||
                args.extend(["-f", regex])
 | 
			
		||||
 | 
			
		||||
        if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
 | 
			
		||||
            args.append("-v")
 | 
			
		||||
 | 
			
		||||
        return args
 | 
			
		||||
 | 
			
		||||
    def generate_reports(self,
 | 
			
		||||
                         outputs,
 | 
			
		||||
                         excludes=None,
 | 
			
		||||
                         filter_regex=None,
 | 
			
		||||
                         build_path=None):
 | 
			
		||||
        """
 | 
			
		||||
        Run tests to generate coverage data, and generate coverage reports.
 | 
			
		||||
 | 
			
		||||
        Positional arguments:
 | 
			
		||||
        outputs - list of types to generate
 | 
			
		||||
 | 
			
		||||
        Keyword arguments:
 | 
			
		||||
        excludes - list of paths to exclude from the report
 | 
			
		||||
        filter_regex - comma-separated string to use for test filtering
 | 
			
		||||
        build_path - build path
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        if get_gcovr_program() is None:
 | 
			
		||||
            logging.error("No gcovr tool found in path. \
 | 
			
		||||
            Cannot generate coverage reports.")
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if build_path is None:
 | 
			
		||||
            build_path = os.getcwd()
 | 
			
		||||
 | 
			
		||||
        if outputs is None:
 | 
			
		||||
            outputs = []
 | 
			
		||||
 | 
			
		||||
        if excludes is None:
 | 
			
		||||
            excludes = []
 | 
			
		||||
 | 
			
		||||
        for output in outputs:
 | 
			
		||||
            if output == "html":
 | 
			
		||||
                # Create build directory if not exist.
 | 
			
		||||
                coverage_path = os.path.join(build_path, "coverage")
 | 
			
		||||
                if not os.path.exists(coverage_path):
 | 
			
		||||
                    os.mkdir(coverage_path)
 | 
			
		||||
 | 
			
		||||
            args = self._gen_cmd(output, excludes, filter_regex)
 | 
			
		||||
 | 
			
		||||
            if output == "html":
 | 
			
		||||
                execute_program(args,
 | 
			
		||||
                                "HTML code coverage report generation failed.",
 | 
			
		||||
                                "HTML code coverage report created.")
 | 
			
		||||
            elif output == "xml":
 | 
			
		||||
                execute_program(args,
 | 
			
		||||
                                "XML code coverage report generation failed.",
 | 
			
		||||
                                "XML code coverage report created.")
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +75,11 @@ def get_options_parser():
 | 
			
		|||
                        help="Generate code coverage report",
 | 
			
		||||
                        dest="coverage")
 | 
			
		||||
 | 
			
		||||
    parser.add_argument("--include-headers",
 | 
			
		||||
                        action="store_true",
 | 
			
		||||
                        help="Include headers to coverage reports, defaults to false.",
 | 
			
		||||
                        dest="include_headers")
 | 
			
		||||
 | 
			
		||||
    parser.add_argument("-m",
 | 
			
		||||
                        "--make-program",
 | 
			
		||||
                        default=get_make_tool(),
 | 
			
		||||
| 
						 | 
				
			
			@ -140,3 +145,4 @@ Mbed OS unit testing:
 | 
			
		|||
    if options.coverage:
 | 
			
		||||
        logging.info(" [%s]  \tGenerate coverage reports", "SET")
 | 
			
		||||
        logging.info(" \t\t - Output: %s", options.coverage)
 | 
			
		||||
        logging.info(" \t\t - Include headers: %s", options.include_headers)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,9 +27,7 @@ from .utils import execute_program
 | 
			
		|||
from .get_tools import get_make_tool, \
 | 
			
		||||
                       get_cmake_tool, \
 | 
			
		||||
                       get_cxx_tool, \
 | 
			
		||||
                       get_c_tool, \
 | 
			
		||||
                       get_gcov_program, \
 | 
			
		||||
                       get_gcovr_program
 | 
			
		||||
                       get_c_tool
 | 
			
		||||
from .settings import DEFAULT_CMAKE_GENERATORS
 | 
			
		||||
 | 
			
		||||
class UnitTestTool(object):
 | 
			
		||||
| 
						 | 
				
			
			@ -115,80 +113,6 @@ class UnitTestTool(object):
 | 
			
		|||
                        "Building unit tests failed.",
 | 
			
		||||
                        "Unit tests built successfully.")
 | 
			
		||||
 | 
			
		||||
    def _get_coverage_script(self, coverage_type, excludes):
 | 
			
		||||
        args = [get_gcovr_program(),
 | 
			
		||||
                "--gcov-executable",
 | 
			
		||||
                get_gcov_program(),
 | 
			
		||||
                "-r",
 | 
			
		||||
                "../..",
 | 
			
		||||
                "."]
 | 
			
		||||
 | 
			
		||||
        if coverage_type == "html":
 | 
			
		||||
            args.extend(["--html",
 | 
			
		||||
                         "--html-detail",
 | 
			
		||||
                         "-o",
 | 
			
		||||
                         "./coverage/index.html"])
 | 
			
		||||
        elif coverage_type == "xml":
 | 
			
		||||
            args.extend(["-x",
 | 
			
		||||
                         "-o",
 | 
			
		||||
                         "./coverage.xml"])
 | 
			
		||||
 | 
			
		||||
        for path in excludes:
 | 
			
		||||
            args.extend(["-e", path.replace("\\", "/")])
 | 
			
		||||
 | 
			
		||||
        #Exclude header files from report
 | 
			
		||||
        args.extend(["-e", ".*\.h"])
 | 
			
		||||
 | 
			
		||||
        if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
 | 
			
		||||
            args.append("-v")
 | 
			
		||||
 | 
			
		||||
        return args
 | 
			
		||||
 | 
			
		||||
    def generate_coverage_report(self,
 | 
			
		||||
                                 coverage_output_type=None,
 | 
			
		||||
                                 excludes=None,
 | 
			
		||||
                                 build_path=None):
 | 
			
		||||
        """
 | 
			
		||||
        Run tests to generate coverage data, and generate coverage reports.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        self.run_tests()
 | 
			
		||||
 | 
			
		||||
        if get_gcovr_program() is None:
 | 
			
		||||
            logging.error("No gcovr tool found in path. \
 | 
			
		||||
            Cannot generate coverage report.")
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if build_path is None:
 | 
			
		||||
            build_path = os.getcwd()
 | 
			
		||||
 | 
			
		||||
        if coverage_output_type is None:
 | 
			
		||||
            logging.warning("No coverage output type give. \
 | 
			
		||||
                            Cannot generate coverage reports.")
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if excludes is None:
 | 
			
		||||
            excludes = []
 | 
			
		||||
 | 
			
		||||
        if coverage_output_type == "html" or coverage_output_type == "both":
 | 
			
		||||
            # Create build directory if not exist.
 | 
			
		||||
            coverage_path = os.path.join(build_path, "coverage")
 | 
			
		||||
            if not os.path.exists(coverage_path):
 | 
			
		||||
                os.mkdir(coverage_path)
 | 
			
		||||
 | 
			
		||||
            args = self._get_coverage_script("html", excludes)
 | 
			
		||||
 | 
			
		||||
            execute_program(args,
 | 
			
		||||
                            "HTML code coverage report generation failed.",
 | 
			
		||||
                            "HTML code coverage report created.")
 | 
			
		||||
 | 
			
		||||
        if coverage_output_type == "xml" or coverage_output_type == "both":
 | 
			
		||||
            args = self._get_coverage_script("xml", excludes)
 | 
			
		||||
 | 
			
		||||
            execute_program(args,
 | 
			
		||||
                            "XML code coverage report generation failed.",
 | 
			
		||||
                            "XML code coverage report created.")
 | 
			
		||||
 | 
			
		||||
    def run_tests(self, filter_regex=None):
 | 
			
		||||
        """
 | 
			
		||||
        Run unit tests.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue