def testGenerateLineCoverageVector(self): """Tests that coverage vector is correctly generated. Runs GenerateLineCoverageVector on sample file and checks result. """ src_lines_counts = coverage_report.GenerateLineCoverageVector( 'sample.c', self.gcno_summary) expected = [-1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 2, 2, 2, -1, 2, -1, 2, 0, -1, 2, -1, -1, 2, 2, 502, 500, -1, -1, 2, -1, 2, -1, -1, -1, 2, -1, -1, -1, -1, 2, 2, 2] self.assertEqual(src_lines_counts, expected)
def testGenerateLineCoverageVector(self): """Tests that coverage vector is correctly generated. Runs GenerateLineCoverageVector on sample file and checks result. """ coverage_dict = dict() exclude_paths = [] src_lines_counts = coverage_report.GenerateLineCoverageVector( self.gcno_summary, exclude_paths, coverage_dict) expected = { 'sample.c': [ -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 2, 2, 2, -1, 2, -1, 2, 0, -1, 2, -1, -1, 2, 2, 502, 500, -1, -1, 2, -1, 2, -1, -1, -1, 2, -1, -1, -1, -1, 2, 2, 2 ] } self.assertEqual(coverage_dict, expected)
def _ManualProcess(self, cov_zip, revision_dict, gcda_dict, isGlobal): """Process coverage data and appends coverage reports to the report message. Opens the gcno files in the cov_zip for the specified modules and matches gcno/gcda files. Then, coverage vectors are generated for each set of matching gcno/gcda files and appended as a CoverageReportMessage to the provided report message. Unlike AutoProcess, coverage information is only processed for the modules explicitly defined in 'modules'. Args: cov_zip: the ZipFile object containing the gcno coverage artifacts. revision_dict: the dictionary from project name to project version. gcda_dict: the dictionary of gcda basenames to gcda content (binary string) isGlobal: boolean, True if the coverage data is for the entire test, False if only for the current test case. """ output_coverage_report = getattr( self, keys.ConfigKeys.IKEY_OUTPUT_COVERAGE_REPORT, True) modules = getattr(self, keys.ConfigKeys.IKEY_MODULES, None) covered_modules = set(cov_zip.namelist()) for module in modules: if MODULE_NAME not in module or GIT_PROJECT not in module: logging.error( "Coverage module must specify name and git project: %s", module) continue project = module[GIT_PROJECT] if PATH not in project or NAME not in project: logging.error("Project name and path not specified: %s", project) continue name = str(module[MODULE_NAME]) + COVERAGE_SUFFIX git_project = str(project[NAME]) git_project_path = str(project[PATH]) if name not in covered_modules: logging.error("No coverage information for module %s", name) continue if git_project not in revision_dict: logging.error( "Git project not present in device revision dict: %s", git_project) continue revision = str(revision_dict[git_project]) archive = archive_parser.Archive(cov_zip.open(name).read()) try: archive.Parse() except ValueError: logging.error("Archive could not be parsed: %s", name) continue for gcno_file_path in archive.files: file_name_path = gcno_file_path.rsplit(".", 1)[0] file_name = os.path.basename(file_name_path) gcno_content = archive.files[gcno_file_path] gcno_stream = io.BytesIO(gcno_content) try: gcno_summary = gcno_parser.GCNOParser(gcno_stream).Parse() except FileFormatError: logging.error("Error parsing gcno file %s", gcno_file_path) continue src_file_path = None # Match gcno file with gcda file gcda_name = file_name + GCDA_SUFFIX if gcda_name not in gcda_dict: logging.error("No gcda file found %s.", gcda_name) continue src_file_path = self._ExtractSourceName( gcno_summary, file_name) if not src_file_path: logging.error("No source file found for %s.", gcno_file_path) continue # Process and merge gcno/gcda data gcda_content = gcda_dict[gcda_name] gcda_stream = io.BytesIO(gcda_content) try: gcda_parser.GCDAParser(gcda_stream).Parse(gcno_summary) except FileFormatError: logging.error("Error parsing gcda file %s", gcda_content) continue if self.web and self.web.enabled: coverage_vec = coverage_report.GenerateLineCoverageVector( src_file_path, gcno_summary) total_count, covered_count = coverage_report.GetCoverageStats( coverage_vec) self.web.AddCoverageReport(coverage_vec, src_file_path, git_project, git_project_path, revision, covered_count, total_count, isGlobal) if output_coverage_report: self._OutputCoverageReport(isGlobal)
def _AutoProcess(self, cov_zip, revision_dict, gcda_dict, isGlobal): """Process coverage data and appends coverage reports to the report message. Matches gcno files with gcda files and processes them into a coverage report with references to the original source code used to build the system image. Coverage information is appended as a CoverageReportMessage to the provided report message. Git project information is automatically extracted from the build info and the source file name enclosed in each gcno file. Git project names must resemble paths and may differ from the paths to their project root by at most one. If no match is found, then coverage information will not be be processed. e.g. if the project path is test/vts, then its project name may be test/vts or <some folder>/test/vts in order to be recognized. Args: cov_zip: the ZipFile object containing the gcno coverage artifacts. revision_dict: the dictionary from project name to project version. gcda_dict: the dictionary of gcda basenames to gcda content (binary string) isGlobal: boolean, True if the coverage data is for the entire test, False if only for the current test case. """ checksum_gcno_dict = self._GetChecksumGcnoDict(cov_zip) output_coverage_report = getattr( self, keys.ConfigKeys.IKEY_OUTPUT_COVERAGE_REPORT, False) exclude_coverage_path = getattr( self, keys.ConfigKeys.IKEY_EXCLUDE_COVERAGE_PATH, []) for idx, path in enumerate(exclude_coverage_path): base_name = os.path.basename(path) if base_name and "." not in base_name: path = path if path.endswith("/") else path + "/" exclude_coverage_path[idx] = path exclude_coverage_path.extend(self._DEFAULT_EXCLUDE_PATHS) coverage_dict = dict() coverage_report_message = ReportMsg.TestReportMessage() for gcda_name in gcda_dict: if GEN_TAG in gcda_name: # skip coverage measurement for intermediate code. logging.warn("Skip for gcda file: %s", gcda_name) continue gcda_stream = io.BytesIO(gcda_dict[gcda_name]) gcda_file_parser = gcda_parser.GCDAParser(gcda_stream) file_name = gcda_name.rsplit(".", 1)[0] if not gcda_file_parser.checksum in checksum_gcno_dict: logging.info("No matching gcno file for gcda: %s", gcda_name) continue gcno_file_parsers = checksum_gcno_dict[gcda_file_parser.checksum] gcno_summary = self._FindGcnoSummary(file_name, gcno_file_parsers) if gcno_summary is None: logging.error("No gcno file found for gcda %s.", gcda_name) continue # Process and merge gcno/gcda data try: gcda_file_parser.Parse(gcno_summary) except FileFormatError: logging.error("Error parsing gcda file %s", gcda_name) continue coverage_report.GenerateLineCoverageVector( gcno_summary, exclude_coverage_path, coverage_dict) for src_file_path in coverage_dict: # Get the git project information # Assumes that the project name and path to the project root are similar revision = None for project_name in revision_dict: # Matches cases when source file root and project name are the same if src_file_path.startswith(str(project_name)): git_project_name = str(project_name) git_project_path = str(project_name) revision = str(revision_dict[project_name]) logging.debug("Source file '%s' matched with project '%s'", src_file_path, git_project_name) break parts = os.path.normpath(str(project_name)).split(os.sep, 1) # Matches when project name has an additional prefix before the # project path root. if len(parts) > 1 and src_file_path.startswith(parts[-1]): git_project_name = str(project_name) git_project_path = parts[-1] revision = str(revision_dict[project_name]) logging.debug("Source file '%s' matched with project '%s'", src_file_path, git_project_name) break if not revision: logging.info("Could not find git info for %s", src_file_path) continue coverage_vec = coverage_dict[src_file_path] total_count, covered_count = coverage_report.GetCoverageStats( coverage_vec) if self.web and self.web.enabled: self.web.AddCoverageReport(coverage_vec, src_file_path, git_project_name, git_project_path, revision, covered_count, total_count, isGlobal) else: coverage = coverage_report_message.coverage.add() coverage.total_line_count = total_count coverage.covered_line_count = covered_count coverage.line_coverage_vector.extend(coverage_vec) src_file_path = os.path.relpath(src_file_path, git_project_path) coverage.file_path = src_file_path coverage.revision = revision coverage.project_name = git_project_name if output_coverage_report: self._OutputCoverageReport(isGlobal, coverage_report_message)
def _AutoProcess(self, gcda_dict, isGlobal): """Process coverage data and appends coverage reports to the report message. Matches gcno files with gcda files and processes them into a coverage report with references to the original source code used to build the system image. Coverage information is appended as a CoverageReportMessage to the provided report message. Git project information is automatically extracted from the build info and the source file name enclosed in each gcno file. Git project names must resemble paths and may differ from the paths to their project root by at most one. If no match is found, then coverage information will not be be processed. e.g. if the project path is test/vts, then its project name may be test/vts or <some folder>/test/vts in order to be recognized. Args: gcda_dict: the dictionary of gcda basenames to gcda content (binary string) isGlobal: boolean, True if the coverage data is for the entire test, False if only for the current test case. """ revision_dict = getattr(self, _REVISION_DICT, None) checksum_gcno_dict = getattr(self, _CHECKSUM_GCNO_DICT, None) output_coverage_report = getattr( self, keys.ConfigKeys.IKEY_OUTPUT_COVERAGE_REPORT, False) for gcda_name in gcda_dict: gcda_stream = io.BytesIO(gcda_dict[gcda_name]) gcda_file_parser = gcda_parser.GCDAParser(gcda_stream) if not gcda_file_parser.checksum in checksum_gcno_dict: logging.info("No matching gcno file for gcda: %s", gcda_name) continue gcno_file_parser = checksum_gcno_dict[gcda_file_parser.checksum] try: gcno_summary = gcno_file_parser.Parse() except FileFormatError: logging.error("Error parsing gcno for gcda %s", gcda_name) continue file_name = gcda_name.rsplit(".", 1)[0] src_file_path = self._ExtractSourceName(gcno_summary, file_name) if not src_file_path: logging.error("No source file found for gcda %s.", gcda_name) continue # Process and merge gcno/gcda data try: gcda_file_parser.Parse(gcno_summary) except FileFormatError: logging.error("Error parsing gcda file %s", gcda_name) continue # Get the git project information # Assumes that the project name and path to the project root are similar revision = None for project_name in revision_dict: # Matches cases when source file root and project name are the same if src_file_path.startswith(str(project_name)): git_project_name = str(project_name) git_project_path = str(project_name) revision = str(revision_dict[project_name]) logging.info("Source file '%s' matched with project '%s'", src_file_path, git_project_name) break parts = os.path.normpath(str(project_name)).split(os.sep, 1) # Matches when project name has an additional prefix before the # project path root. if len(parts) > 1 and src_file_path.startswith(parts[-1]): git_project_name = str(project_name) git_project_path = parts[-1] revision = str(revision_dict[project_name]) logging.info("Source file '%s' matched with project '%s'", src_file_path, git_project_name) if not revision: logging.info("Could not find git info for %s", src_file_path) continue if self.web and self.web.enabled: coverage_vec = coverage_report.GenerateLineCoverageVector( src_file_path, gcno_summary) total_count, covered_count = coverage_report.GetCoverageStats( coverage_vec) self.web.AddCoverageReport(coverage_vec, src_file_path, git_project_name, git_project_path, revision, covered_count, total_count, isGlobal) if output_coverage_report: self._OutputCoverageReport(isGlobal)