diff options
-rw-r--r-- | coverage/control.py | 8 | ||||
-rw-r--r-- | coverage/report.py | 5 | ||||
-rw-r--r-- | coverage/xmlreport.py | 7 | ||||
-rw-r--r-- | test/coveragetest.py | 29 | ||||
-rw-r--r-- | test/test_cmdline.py | 13 | ||||
-rw-r--r-- | test/test_coverage.py | 26 |
6 files changed, 68 insertions, 20 deletions
diff --git a/coverage/control.py b/coverage/control.py index e041cde7..4bcb4ed4 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -304,8 +304,12 @@ class coverage(object): """ if outfile: outfile = open(outfile, "w") - reporter = XmlReporter(self, ignore_errors) - reporter.report(morfs, omit_prefixes=omit_prefixes, outfile=outfile) + try: + reporter = XmlReporter(self, ignore_errors) + reporter.report( + morfs, omit_prefixes=omit_prefixes, outfile=outfile) + finally: + outfile.close() def sysinfo(self): """Return a list of key,value pairs showing internal information.""" diff --git a/coverage/report.py b/coverage/report.py index 7f3e3e02..c2215521 100644 --- a/coverage/report.py +++ b/coverage/report.py @@ -2,7 +2,7 @@ import os from coverage.codeunit import code_unit_factory -from coverage.misc import NoSource +from coverage.misc import CoverageException, NoSource class Reporter(object): """A base class for all reporters.""" @@ -45,6 +45,9 @@ class Reporter(object): """ self.find_code_units(morfs, omit_prefixes) + if not self.code_units: + raise CoverageException("No data to report.") + self.directory = directory if self.directory and not os.path.exists(self.directory): os.makedirs(self.directory) diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py index 0fe43712..2e31d9e9 100644 --- a/coverage/xmlreport.py +++ b/coverage/xmlreport.py @@ -30,7 +30,6 @@ class XmlReporter(Reporter): """ # Initial setup. outfile = outfile or sys.stdout - self.find_code_units(morfs, omit_prefixes) # Create the DOM that will store the data. impl = xml.dom.minidom.getDOMImplementation() @@ -39,8 +38,9 @@ class XmlReporter(Reporter): "http://cobertura.sourceforge.net/xml/coverage-03.dtd" ) self.xml_out = impl.createDocument(None, "coverage", docType) + + # Write header stuff. xcoverage = self.xml_out.documentElement - xcoverage.setAttribute("version", __version__) xcoverage.setAttribute("timestamp", str(int(time.time()*1000))) xcoverage.appendChild(self.xml_out.createComment( @@ -48,8 +48,9 @@ class XmlReporter(Reporter): )) xpackages = self.xml_out.createElement("packages") xcoverage.appendChild(xpackages) - self.packages = {} + # Call xml_file for each file in the data. + self.packages = {} self.report_files(self.xml_file, morfs, omit_prefixes=omit_prefixes) lnum_tot, lhits_tot = 0, 0 diff --git a/test/coveragetest.py b/test/coveragetest.py index dffffb29..3c22a0cf 100644 --- a/test/coveragetest.py +++ b/test/coveragetest.py @@ -1,6 +1,6 @@ """Base test case class for coverage testing.""" -import difflib, imp, os, random, re, shutil, sys, tempfile, textwrap, unittest +import difflib, imp, os, random, re, shlex, shutil, sys, tempfile, textwrap, unittest import coverage from coverage.backward import set, sorted, StringIO # pylint: disable-msg=W0622 @@ -20,6 +20,9 @@ class Tee(object): f.write(data) +# Status returns for the command line. +OK, ERR = 0, 1 + class CoverageTest(unittest.TestCase): """A base class for Coverage test cases.""" @@ -253,8 +256,30 @@ class CoverageTest(unittest.TestCase): fname = os.path.join(*fparts) return os.path.normcase(os.path.abspath(os.path.realpath(fname))) + def command_line(self, args, ret=OK): + """Run `args` through the command line. + + Use this when you want to run the full coverage machinery, but in the + current process. Exceptions may be thrown from deep in the code. + Asserts that `ret` is returned by `CoverageScript.command_line`. + + Compare with `run_command`. + + Returns None. + + """ + ret_actual = coverage.CoverageScript().command_line(shlex.split(args)) + self.assertEqual(ret_actual, ret) + def run_command(self, cmd): - """ Run the command-line `cmd`, print its output. + """ Run the command-line `cmd` in a subprocess, and print its output. + + Use this when you need to test the process behavior of coverage. + + Compare with `command_line`. + + Returns the process' stdout text. + """ # Add our test modules directory to PYTHONPATH. I'm sure there's too # much path munging here, but... diff --git a/test/test_cmdline.py b/test/test_cmdline.py index 21639cdb..20c9c5d4 100644 --- a/test/test_cmdline.py +++ b/test/test_cmdline.py @@ -5,11 +5,9 @@ import mock import coverage sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k -from coveragetest import CoverageTest +from coveragetest import CoverageTest, OK, ERR -OK, ERR = 0, 1 - class CmdLineTest(CoverageTest): """Tests of execution paths through the command line interpreter.""" @@ -19,15 +17,6 @@ class CmdLineTest(CoverageTest): .coverage(cover_pylib=None, data_suffix=False, timid=None, branch=None) .load()\n""" - def command_line(self, args, ret=OK): - """Run `args` through the command line. - - Checks that `ret` is returned. - - """ - ret_actual = coverage.CoverageScript().command_line(shlex.split(args)) - self.assertEqual(ret_actual, ret) - def model_object(self): """Return a Mock suitable for use in CoverageScript.""" mk = mock.Mock() diff --git a/test/test_coverage.py b/test/test_coverage.py index 6544cddd..10cadfef 100644 --- a/test/test_coverage.py +++ b/test/test_coverage.py @@ -7,6 +7,8 @@ import os, sys, unittest import coverage coverage.use_cache(0) +from coverage.misc import CoverageException + sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k from coveragetest import CoverageTest @@ -1674,6 +1676,30 @@ class ProcessTest(CoverageTest): self.assert_matches(out, "No file to run: .*xyzzy.py") self.assert_("Traceback" not in out) + def test_no_data_to_report_on_annotate(self): + # Reporting with no data produces a nice message and no output dir. + self.assert_raises_msg( + CoverageException, "No data to report.", + self.command_line, "annotate -d ann" + ) + self.assertFalse(os.path.exists("ann")) + + def test_no_data_to_report_on_html(self): + # Reporting with no data produces a nice message and no output dir. + self.assert_raises_msg( + CoverageException, "No data to report.", + self.command_line, "html -d htmlcov" + ) + self.assertFalse(os.path.exists("htmlcov")) + + def test_no_data_to_report_on_xml(self): + # Reporting with no data produces a nice message. + self.assert_raises_msg( + CoverageException, "No data to report.", + self.command_line, "xml" + ) + # Currently, this leaves an empty coverage.xml file... :( + if __name__ == '__main__': print("Testing under Python version: %s" % sys.version) |