summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothée Peignier <timothee.peignier@tryphon.org>2011-12-14 20:10:19 +0100
committerTimothée Peignier <timothee.peignier@tryphon.org>2011-12-14 20:10:19 +0100
commit6347cd149f5f5f9f06ade7d635dc52245fd50124 (patch)
treea04aac5495a6e7fd76f05e9f603bd1eb6a57cb51
parent79efaa3d4cabff40e0194d2e6680a5070c6476e2 (diff)
downloadnose-6347cd149f5f5f9f06ade7d635dc52245fd50124.tar.gz
remove support for old coverage module and rewrite coverage tests
-rw-r--r--functional_tests/doc_tests/test_coverage_html/coverage_html.rst57
-rw-r--r--functional_tests/doc_tests/test_coverage_html/coverage_html.rst.py3.patch16
-rw-r--r--functional_tests/doc_tests/test_coverage_html/coverage_html_fixtures.py26
-rw-r--r--functional_tests/support/coverage/blah.py (renamed from functional_tests/doc_tests/test_coverage_html/support/blah.py)0
-rw-r--r--functional_tests/support/coverage/tests/test_covered.py (renamed from functional_tests/doc_tests/test_coverage_html/support/tests/test_covered.py)0
-rw-r--r--functional_tests/test_coverage_plugin.py37
-rw-r--r--nose/plugins/cover.py153
7 files changed, 50 insertions, 239 deletions
diff --git a/functional_tests/doc_tests/test_coverage_html/coverage_html.rst b/functional_tests/doc_tests/test_coverage_html/coverage_html.rst
deleted file mode 100644
index 95f9e8a..0000000
--- a/functional_tests/doc_tests/test_coverage_html/coverage_html.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-Generating HTML Coverage with nose
-----------------------------------
-
-.. Note ::
-
- HTML coverage requires Ned Batchelder's `coverage.py`_ module.
-..
-
-Console coverage output is useful but terse. For a more browseable view of
-code coverage, the coverage plugin supports basic HTML coverage output.
-
-.. hide this from the actual documentation:
- >>> from nose.plugins.plugintest import run_buffered as run
- >>> import os
- >>> support = os.path.join(os.path.dirname(__file__), 'support')
- >>> cover_html_dir = os.path.join(support, 'cover')
- >>> cover_file = os.path.join(os.getcwd(), '.coverage')
- >>> if os.path.exists(cover_file):
- ... os.unlink(cover_file)
- ...
-
-
-The console coverage output is printed, as normal.
-
- >>> from nose.plugins.cover import Coverage
- >>> cover_html_dir = os.path.join(support, 'cover')
- >>> run(argv=[__file__, '-v', '--with-coverage', '--cover-package=blah',
- ... '--cover-html', '--cover-html-dir=' + cover_html_dir,
- ... support, ],
- ... plugins=[Coverage()]) # doctest: +REPORT_NDIFF
- test_covered.test_blah ... hi
- ok
- <BLANKLINE>
- Name Stmts Miss Cover Missing
- -------------------------------------
- blah 4 1 75% 6
- ----------------------------------------------------------------------
- Ran 1 test in ...s
- <BLANKLINE>
- OK
-
-The html coverage reports are saved to disk in the directory specified by the
-``--cover-html-dir`` option. In that directory you'll find ``index.html``
-which links to a detailed coverage report for each module in the report. The
-detail pages show the module source, colorized to indicated which lines are
-covered and which are not. There is an example of this HTML output in the
-`coverage.py`_ docs.
-
-.. hide this from the actual documentation:
- >>> os.path.exists(cover_file)
- True
- >>> os.path.exists(os.path.join(cover_html_dir, 'index.html'))
- True
- >>> os.path.exists(os.path.join(cover_html_dir, 'blah.html'))
- True
-
-.. _`coverage.py`: http://nedbatchelder.com/code/coverage/
diff --git a/functional_tests/doc_tests/test_coverage_html/coverage_html.rst.py3.patch b/functional_tests/doc_tests/test_coverage_html/coverage_html.rst.py3.patch
deleted file mode 100644
index f325a01..0000000
--- a/functional_tests/doc_tests/test_coverage_html/coverage_html.rst.py3.patch
+++ /dev/null
@@ -1,16 +0,0 @@
---- coverage_html.rst.orig 2010-08-31 23:13:33.000000000 -0700
-+++ coverage_html.rst 2010-08-31 23:14:25.000000000 -0700
-@@ -78,11 +78,11 @@
- </div>
- <div class="coverage">
- <div class="cov"><span class="num"><pre>1</pre></span><pre>def dostuff():</pre></div>
-- <div class="cov"><span class="num"><pre>2</pre></span><pre> print 'hi'</pre></div>
-+ <div class="cov"><span class="num"><pre>2</pre></span><pre> print('hi')</pre></div>
- <div class="skip"><span class="num"><pre>3</pre></span><pre></pre></div>
- <div class="skip"><span class="num"><pre>4</pre></span><pre></pre></div>
- <div class="cov"><span class="num"><pre>5</pre></span><pre>def notcov():</pre></div>
-- <div class="nocov"><span class="num"><pre>6</pre></span><pre> print 'not covered'</pre></div>
-+ <div class="nocov"><span class="num"><pre>6</pre></span><pre> print('not covered')</pre></div>
- <div class="skip"><span class="num"><pre>7</pre></span><pre></pre></div>
- </div>
- </body>
diff --git a/functional_tests/doc_tests/test_coverage_html/coverage_html_fixtures.py b/functional_tests/doc_tests/test_coverage_html/coverage_html_fixtures.py
deleted file mode 100644
index 6829dc2..0000000
--- a/functional_tests/doc_tests/test_coverage_html/coverage_html_fixtures.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import sys
-import os
-import shutil
-from nose.plugins.skip import SkipTest
-from nose.plugins.cover import Coverage
-from nose.plugins.plugintest import munge_nose_output_for_doctest
-
-# This fixture is not reentrant because we have to cleanup the files that
-# coverage produces once all tests have finished running.
-_multiprocess_shared_ = True
-
-def setup_module():
- try:
- import coverage
- if 'active' in Coverage.status:
- raise SkipTest("Coverage plugin is active. Skipping tests of "
- "plugin itself.")
- except ImportError:
- raise SkipTest("coverage module not available")
-
-def teardown_module():
- # Clean up the files produced by coverage
- cover_html_dir = os.path.join(os.path.dirname(__file__), 'support', 'cover')
- if os.path.exists(cover_html_dir):
- shutil.rmtree(cover_html_dir)
-
diff --git a/functional_tests/doc_tests/test_coverage_html/support/blah.py b/functional_tests/support/coverage/blah.py
index ef6657c..ef6657c 100644
--- a/functional_tests/doc_tests/test_coverage_html/support/blah.py
+++ b/functional_tests/support/coverage/blah.py
diff --git a/functional_tests/doc_tests/test_coverage_html/support/tests/test_covered.py b/functional_tests/support/coverage/tests/test_covered.py
index c669c5c..c669c5c 100644
--- a/functional_tests/doc_tests/test_coverage_html/support/tests/test_covered.py
+++ b/functional_tests/support/coverage/tests/test_covered.py
diff --git a/functional_tests/test_coverage_plugin.py b/functional_tests/test_coverage_plugin.py
new file mode 100644
index 0000000..d1b2632
--- /dev/null
+++ b/functional_tests/test_coverage_plugin.py
@@ -0,0 +1,37 @@
+"""Test the coverage plugin."""
+import os
+import unittest
+import shutil
+
+from nose.plugins import PluginTester
+from nose.plugins.cover import Coverage
+
+support = os.path.join(os.path.dirname(__file__), 'support')
+
+
+class TestCoveragePlugin(PluginTester, unittest.TestCase):
+ activate = "--with-coverage"
+ args = ['-v', '--cover-package=blah', '--cover-html']
+ plugins = [Coverage()]
+ suitepath = os.path.join(support, 'coverage')
+
+ def setUp(self):
+ self.cover_file = os.path.join(os.getcwd(), '.coverage')
+ self.cover_html_dir = os.path.join(os.getcwd(), 'cover')
+ if os.path.exists(self.cover_file):
+ os.unlink(self.cover_file)
+ if os.path.exists(self.cover_html_dir):
+ shutil.rmtree(self.cover_html_dir)
+ super(TestCoveragePlugin, self).setUp()
+
+ def runTest(self):
+ self.assertTrue("blah 4 1 75% 6" in self.output)
+ self.assertTrue("Ran 1 test in""" in self.output)
+ # Assert coverage html report exists
+ self.assertTrue(os.path.exists(os.path.join(self.cover_html_dir,
+ 'index.html')))
+ # Assert coverage data is saved
+ self.assertTrue(os.path.exists(self.cover_file))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/nose/plugins/cover.py b/nose/plugins/cover.py
index a055c92..f91e12a 100644
--- a/nose/plugins/cover.py
+++ b/nose/plugins/cover.py
@@ -11,7 +11,6 @@ variable.
.. _coverage: http://www.nedbatchelder.com/code/modules/coverage.html
"""
import logging
-import os
import re
import sys
from nose.plugins.base import Plugin
@@ -19,36 +18,6 @@ from nose.util import src, tolist
log = logging.getLogger(__name__)
-COVERAGE_TEMPLATE = '''<html>
-<head>
-%(title)s
-</head>
-<body>
-%(header)s
-<style>
-.coverage pre {float: left; margin: 0px 1em; border: none;
- padding: 0px; }
-.num pre { margin: 0px }
-.nocov, .nocov pre {background-color: #faa}
-.cov, .cov pre {background-color: #cfc}
-div.coverage div { clear: both; height: 1.1em}
-</style>
-<div class="stats">
-%(stats)s
-</div>
-<div class="coverage">
-%(body)s
-</div>
-</body>
-</html>
-'''
-
-COVERAGE_STATS_TEMPLATE = '''Covered: %(covered)s lines<br/>
-Missed: %(missed)s lines<br/>
-Skipped %(skipped)s lines<br/>
-Percent: %(percent)s %%<br/>
-'''
-
class Coverage(Plugin):
"""
@@ -56,25 +25,16 @@ class Coverage(Plugin):
"""
coverTests = False
coverPackages = None
- _coverInstance = None
+ coverInstance = None
+ coverErase = False
score = 200
status = {}
- def coverInstance(self):
- if not self._coverInstance:
- import coverage
- try:
- self._coverInstance = coverage.coverage(branch=self.coverBranches)
- except coverage.CoverageException:
- self._coverInstance = coverage
- return self._coverInstance
- coverInstance = property(coverInstance)
-
def options(self, parser, env):
"""
Add options to command line.
"""
- Plugin.options(self, parser, env)
+ super(Coverage, self).options(parser, env)
parser.add_option("--cover-package", action="append",
default=env.get('NOSE_COVER_PACKAGE'),
metavar="PACKAGE",
@@ -123,7 +83,7 @@ class Coverage(Plugin):
metavar="FILE",
help="Produce XML coverage information in file")
- def configure(self, options, config):
+ def configure(self, options, conf):
"""
Configure plugin.
"""
@@ -131,8 +91,8 @@ class Coverage(Plugin):
self.status.pop('active')
except KeyError:
pass
- Plugin.configure(self, options, config)
- if config.worker:
+ super(Coverage, self).configure(options, conf)
+ if conf.worker:
return
if self.enabled:
try:
@@ -142,7 +102,7 @@ class Coverage(Plugin):
"unable to import coverage module")
self.enabled = False
return
- self.conf = config
+ self.conf = conf
self.coverErase = options.cover_erase
self.coverTests = options.cover_tests
self.coverPackages = []
@@ -164,6 +124,8 @@ class Coverage(Plugin):
log.debug('Will put XML coverage report in %s', self.coverXmlFile)
if self.enabled:
self.status['active'] = True
+ self.coverInstance = coverage.coverage(auto_data=False,
+ branch=self.coverBranches, data_suffix=None)
def begin(self):
"""
@@ -173,8 +135,10 @@ class Coverage(Plugin):
self.skipModules = sys.modules.keys()[:]
if self.coverErase:
log.debug("Clearing previously collected coverage statistics")
+ self.coverInstance.combine()
self.coverInstance.erase()
self.coverInstance.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]')
+ self.coverInstance.load()
self.coverInstance.start()
def report(self, stream):
@@ -183,6 +147,7 @@ class Coverage(Plugin):
"""
log.debug("Coverage report")
self.coverInstance.stop()
+ self.coverInstance.combine()
self.coverInstance.save()
modules = [module
for name, module in sys.modules.items()
@@ -191,103 +156,11 @@ class Coverage(Plugin):
self.coverInstance.report(modules, file=stream)
if self.coverHtmlDir:
log.debug("Generating HTML coverage report")
- if hasattr(self.coverInstance, 'html_report'):
- self.coverInstance.html_report(modules, self.coverHtmlDir)
- else:
- self.report_html(modules)
+ self.coverInstance.html_report(modules, self.coverHtmlDir)
if self.coverXmlFile:
log.debug("Generating XML coverage report")
self.coverInstance.xml_report(modules, self.coverXmlFile)
- def report_html(self, modules):
- if not os.path.exists(self.coverHtmlDir):
- os.makedirs(self.coverHtmlDir)
- files = {}
- for m in modules:
- if hasattr(m, '__name__') and hasattr(m, '__file__'):
- files[m.__name__] = m.__file__
- self.coverInstance.annotate(files.values())
- global_stats = {'covered': 0, 'missed': 0, 'skipped': 0}
- file_list = []
- for m, f in files.iteritems():
- if f.endswith('pyc'):
- f = f[:-1]
- coverfile = f + ',cover'
- outfile, stats = self.htmlAnnotate(m, f, coverfile,
- self.coverHtmlDir)
- for field in ('covered', 'missed', 'skipped'):
- global_stats[field] += stats[field]
- file_list.append((stats['percent'], m, outfile, stats))
- os.unlink(coverfile)
- file_list.sort()
- global_stats['percent'] = self.computePercent(
- global_stats['covered'], global_stats['missed'])
- # Now write out an index file for the coverage HTML
- index = open(os.path.join(self.coverHtmlDir, 'index.html'), 'w')
- index.write('<html><head><title>Coverage Index</title></head>'
- '<body><p>')
- index.write(COVERAGE_STATS_TEMPLATE % global_stats)
- index.write('<table><tr><td>File</td><td>Covered</td><td>Missed'
- '</td><td>Skipped</td><td>Percent</td></tr>')
- for junk, name, outfile, stats in file_list:
- stats['a'] = '<a href="%s">%s</a>' % (outfile, name)
- index.write('<tr><td>%(a)s</td><td>%(covered)s</td><td>'
- '%(missed)s</td><td>%(skipped)s</td><td>'
- '%(percent)s %%</td></tr>' % stats)
- index.write('</table></p></html')
- index.close()
-
- def htmlAnnotate(self, name, file, coverfile, outputDir):
- log.debug('Name: %s file: %s' % (name, file, ))
- rows = []
- data = open(coverfile, 'r').read().split('\n')
- padding = len(str(len(data)))
- stats = {'covered': 0, 'missed': 0, 'skipped': 0}
- for lineno, line in enumerate(data):
- lineno += 1
- if line:
- status = line[0]
- line = line[2:]
- else:
- status = ''
- line = ''
- lineno = (' ' * (padding - len(str(lineno)))) + str(lineno)
- for old, new in (('&', '&amp;'), ('<', '&lt;'), ('>', '&gt;'),
- ('"', '&quot;'), ):
- line = line.replace(old, new)
- if status == '!':
- rows.append('<div class="nocov"><span class="num"><pre>'
- '%s</pre></span><pre>%s</pre></div>' % (lineno,
- line))
- stats['missed'] += 1
- elif status == '>':
- rows.append('<div class="cov"><span class="num"><pre>%s</pre>'
- '</span><pre>%s</pre></div>' % (lineno, line))
- stats['covered'] += 1
- else:
- rows.append('<div class="skip"><span class="num"><pre>%s</pre>'
- '</span><pre>%s</pre></div>' % (lineno, line))
- stats['skipped'] += 1
- stats['percent'] = self.computePercent(stats['covered'],
- stats['missed'])
- html = COVERAGE_TEMPLATE % {'title': '<title>%s</title>' % name,
- 'header': name,
- 'body': '\n'.join(rows),
- 'stats': COVERAGE_STATS_TEMPLATE % stats,
- }
- outfilename = name + '.html'
- outfile = open(os.path.join(outputDir, outfilename), 'w')
- outfile.write(html)
- outfile.close()
- return outfilename, stats
-
- def computePercent(self, covered, missed):
- if covered + missed == 0:
- percent = 1
- else:
- percent = covered / (covered + missed + 0.0)
- return int(percent * 100)
-
def wantModuleCoverage(self, name, module):
if not hasattr(module, '__file__'):
log.debug("no coverage of %s: no __file__", name)