17757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch"""Summary reporting"""
27757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
37757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochimport sys
47757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
57757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochfrom coverage.report import Reporter
67757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochfrom coverage.results import Numbers
77757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
87757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
97757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochclass SummaryReporter(Reporter):
107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    """A reporter for writing the summary report."""
117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    def __init__(self, coverage, show_missing=True, ignore_errors=False):
137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        super(SummaryReporter, self).__init__(coverage, ignore_errors)
147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self.show_missing = show_missing
157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self.branches = coverage.data.has_arcs()
167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    def report(self, morfs, outfile=None, config=None):
187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        """Writes a report summarizing coverage statistics per module.
197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        `outfile` is a file object to write the summary to.  `config` is a
217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        CoverageConfig instance.
227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        """
247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self.find_code_units(morfs, config)
257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        # Prepare the formatting strings
277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        max_name = max([len(cu.name) for cu in self.code_units] + [5])
287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        fmt_name = "%%- %ds  " % max_name
297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        fmt_err = "%s   %s: %s\n"
307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        header = (fmt_name % "Name") + " Stmts   Miss"
317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        fmt_coverage = fmt_name + "%6d %6d"
327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if self.branches:
337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            header += " Branch BrPart"
347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            fmt_coverage += " %6d %6d"
357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        width100 = Numbers.pc_str_width()
367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        header += "%*s" % (width100+4, "Cover")
377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        fmt_coverage += "%%%ds%%%%" % (width100+3,)
387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if self.show_missing:
397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            header += "   Missing"
407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            fmt_coverage += "   %s"
417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        rule = "-" * len(header) + "\n"
427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        header += "\n"
437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        fmt_coverage += "\n"
447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if not outfile:
467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            outfile = sys.stdout
477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        # Write the header
497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        outfile.write(header)
507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        outfile.write(rule)
517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        total = Numbers()
537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        for cu in self.code_units:
557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            try:
567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                analysis = self.coverage._analyze(cu)
577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                nums = analysis.numbers
587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                args = (cu.name, nums.n_statements, nums.n_missing)
597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if self.branches:
607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    args += (nums.n_branches, nums.n_missing_branches)
617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                args += (nums.pc_covered_str,)
627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if self.show_missing:
637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    args += (analysis.missing_formatted(),)
647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                outfile.write(fmt_coverage % args)
657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                total += nums
667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            except KeyboardInterrupt:                       # pragma: no cover
677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                raise
687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            except:
697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if not self.ignore_errors:
707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    typ, msg = sys.exc_info()[:2]
717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    outfile.write(fmt_err % (cu.name, typ.__name__, msg))
727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if total.n_files > 1:
747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            outfile.write(rule)
757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            args = ("TOTAL", total.n_statements, total.n_missing)
767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if self.branches:
777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                args += (total.n_branches, total.n_missing_branches)
787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            args += (total.pc_covered_str,)
797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if self.show_missing:
807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                args += ("",)
817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            outfile.write(fmt_coverage % args)
82