1# 2# Copyright (C) 2016 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16"""Generates coverage reports using outputs from GCC. 17 18The GenerateCoverageReport() function returns HTML to display the coverage 19at each line of code in a provided source file. Coverage information is 20parsed from .gcno and .gcda file contents and combined with the source file 21to reconstruct a coverage report. GenerateLineCoverageVector() is a helper 22function that produces a vector of line counts and GenerateCoverageHTML() 23uses the vector and source to produce the HTML coverage report. 24""" 25 26import cgi 27import io 28import logging 29import os 30from vts.utils.python.coverage import gcda_parser 31from vts.utils.python.coverage import gcno_parser 32 33GEN_TAG = "/gen/" 34 35def GenerateLineCoverageVector(gcno_file_summary, exclude_paths, coverage_dict): 36 """Process the gcno_file_summary and update the coverage dictionary. 37 38 Create a coverage vector for each source file contained in gcno_file_summary 39 and update the corresponding item in coverage_dict. 40 41 Args: 42 gcno_file_summary: FileSummary object after gcno and gcda files have 43 been parsed. 44 exclude_paths: a list of paths should be ignored in the coverage report. 45 coverage_dict: a dictionary for each source file and its corresponding 46 coverage vector. 47 """ 48 for ident in gcno_file_summary.functions: 49 func = gcno_file_summary.functions[ident] 50 file_name = func.src_file_name 51 if GEN_TAG in file_name: 52 logging.debug("Skip generated source file %s.", file_name) 53 continue 54 skip_file = False 55 for path in exclude_paths: 56 if file_name.startswith(path): 57 skip_file = True 58 break 59 if skip_file: 60 logging.debug("Skip excluded source file %s.", file_name) 61 continue 62 63 src_lines_counts = coverage_dict[file_name] if file_name in coverage_dict else [] 64 for block in func.blocks: 65 for line in block.lines: 66 if line > len(src_lines_counts): 67 src_lines_counts.extend([-1] * 68 (line - len(src_lines_counts))) 69 if src_lines_counts[line - 1] < 0: 70 src_lines_counts[line - 1] = 0 71 src_lines_counts[line - 1] += block.count 72 coverage_dict[file_name] = src_lines_counts 73 74 75def GetCoverageStats(src_lines_counts): 76 """Returns the coverage stats. 77 78 Args: 79 src_lines_counts: A list of non-negative integers or -1 representing 80 the number of times the i-th line was executed. 81 -1 indicates a line that is not executable. 82 83 Returns: 84 integer, the number of lines instrumented for coverage measurement 85 integer, the number of executed or covered lines 86 """ 87 total = 0 88 covered = 0 89 if not src_lines_counts or not isinstance(src_lines_counts, list): 90 logging.error("GetCoverageStats: input invalid.") 91 return total, covered 92 93 for line in src_lines_counts: 94 if line < 0: 95 continue 96 total += 1 97 if line > 0: 98 covered += 1 99 return total, covered 100 101