| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 | #!/usr/bin/env python2# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.import reimport sysfrom optparse import OptionParser# the gcov report follows certain pattern. Each file will have two lines# of report, from which we can extract the file name, total lines and coverage# percentage.def parse_gcov_report(gcov_input):    per_file_coverage = {}    total_coverage = None    for line in sys.stdin:        line = line.strip()        # --First line of the coverage report (with file name in it)?        match_obj = re.match("^File '(.*)'$", line)        if match_obj:            # fetch the file name from the first line of the report.            current_file = match_obj.group(1)            continue        # -- Second line of the file report (with coverage percentage)        match_obj = re.match("^Lines executed:(.*)% of (.*)", line)        if match_obj:            coverage = float(match_obj.group(1))            lines = int(match_obj.group(2))            if current_file is not None:                per_file_coverage[current_file] = (coverage, lines)                current_file = None            else:                # If current_file is not set, we reach the last line of report,                # which contains the summarized coverage percentage.                total_coverage = (coverage, lines)            continue        # If the line's pattern doesn't fall into the above categories. We        # can simply ignore them since they're either empty line or doesn't        # find executable lines of the given file.        current_file = None    return per_file_coverage, total_coveragedef get_option_parser():    usage = "Parse the gcov output and generate more human-readable code " +\            "coverage report."    parser = OptionParser(usage)    parser.add_option(        "--interested-files", "-i",        dest="filenames",        help="Comma separated files names. if specified, we will display " +             "the coverage report only for interested source files. " +             "Otherwise we will display the coverage report for all " +             "source files."    )    return parserdef display_file_coverage(per_file_coverage, total_coverage):    # To print out auto-adjustable column, we need to know the longest    # length of file names.    max_file_name_length = max(        len(fname) for fname in per_file_coverage.keys()    )    # -- Print header    # size of separator is determined by 3 column sizes:    # file name, coverage percentage and lines.    header_template = \        "%" + str(max_file_name_length) + "s\t%s\t%s"    separator = "-" * (max_file_name_length + 10 + 20)    print header_template % ("Filename", "Coverage", "Lines")  # noqa: E999 T25377293 Grandfathered in    print separator    # -- Print body    # template for printing coverage report for each file.    record_template = "%" + str(max_file_name_length) + "s\t%5.2f%%\t%10d"    for fname, coverage_info in per_file_coverage.items():        coverage, lines = coverage_info        print record_template % (fname, coverage, lines)    # -- Print footer    if total_coverage:        print separator        print record_template % ("Total", total_coverage[0], total_coverage[1])def report_coverage():    parser = get_option_parser()    (options, args) = parser.parse_args()    interested_files = set()    if options.filenames is not None:        interested_files = set(f.strip() for f in options.filenames.split(','))    # To make things simple, right now we only read gcov report from the input    per_file_coverage, total_coverage = parse_gcov_report(sys.stdin)    # Check if we need to display coverage info for interested files.    if len(interested_files):        per_file_coverage = dict(            (fname, per_file_coverage[fname]) for fname in interested_files            if fname in per_file_coverage        )        # If we only interested in several files, it makes no sense to report        # the total_coverage        total_coverage = None    if not len(per_file_coverage):        print >> sys.stderr, "Cannot find coverage info for the given files."        return    display_file_coverage(per_file_coverage, total_coverage)if __name__ == "__main__":    report_coverage()
 |