summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/backtest.py6
-rw-r--r--test/backunittest.py34
-rw-r--r--test/coveragetest.py92
-rw-r--r--test/farm/html/gold_a/a.html164
-rw-r--r--test/farm/html/gold_a/index.html161
-rw-r--r--test/farm/html/gold_b_branch/b.html252
-rw-r--r--test/farm/html/gold_b_branch/index.html182
-rw-r--r--test/farm/html/gold_bom/bom.html104
-rw-r--r--test/farm/html/gold_bom/index.html90
-rw-r--r--test/farm/html/gold_isolatin1/index.html89
-rw-r--r--test/farm/html/gold_isolatin1/isolatin1.html91
-rw-r--r--test/farm/html/gold_omit_1/index.html215
-rw-r--r--test/farm/html/gold_omit_1/m1.html144
-rw-r--r--test/farm/html/gold_omit_1/m2.html144
-rw-r--r--test/farm/html/gold_omit_1/m3.html144
-rw-r--r--test/farm/html/gold_omit_1/main.html176
-rw-r--r--test/farm/html/gold_omit_2/index.html197
-rw-r--r--test/farm/html/gold_omit_2/m2.html144
-rw-r--r--test/farm/html/gold_omit_2/m3.html144
-rw-r--r--test/farm/html/gold_omit_2/main.html176
-rw-r--r--test/farm/html/gold_omit_3/index.html179
-rw-r--r--test/farm/html/gold_omit_3/m3.html144
-rw-r--r--test/farm/html/gold_omit_3/main.html176
-rw-r--r--test/farm/html/gold_omit_4/index.html197
-rw-r--r--test/farm/html/gold_omit_4/m1.html144
-rw-r--r--test/farm/html/gold_omit_4/m3.html144
-rw-r--r--test/farm/html/gold_omit_4/main.html176
-rw-r--r--test/farm/html/gold_omit_5/index.html179
-rw-r--r--test/farm/html/gold_omit_5/m1.html144
-rw-r--r--test/farm/html/gold_omit_5/main.html176
-rw-r--r--test/farm/html/gold_other/blah_blah_other.html152
-rw-r--r--test/farm/html/gold_other/here.html168
-rw-r--r--test/farm/html/gold_other/index.html179
-rw-r--r--test/farm/html/gold_partial/index.html101
-rw-r--r--test/farm/html/gold_partial/partial.html121
-rw-r--r--test/farm/html/gold_styled/a.html95
-rw-r--r--test/farm/html/gold_styled/extra.css1
-rw-r--r--test/farm/html/gold_styled/index.html89
-rw-r--r--test/farm/html/gold_styled/style.css275
-rw-r--r--test/farm/html/gold_unicode/index.html89
-rw-r--r--test/farm/html/gold_unicode/unicode.html91
-rw-r--r--test/farm/html/gold_x_xml/coverage.xml2
-rw-r--r--test/farm/html/gold_y_xml_branch/coverage.xml2
-rw-r--r--test/farm/html/run_b_branch.py8
-rw-r--r--test/farm/html/run_bom.py21
-rw-r--r--test/farm/html/run_isolatin1.py21
-rw-r--r--test/farm/html/run_partial.py32
-rw-r--r--test/farm/html/run_styled.py28
-rw-r--r--test/farm/html/run_unicode.py30
-rw-r--r--test/farm/html/src/b.py19
-rw-r--r--test/farm/html/src/bom.py11
-rw-r--r--test/farm/html/src/coverage.xml2
-rw-r--r--test/farm/html/src/extra.css1
-rw-r--r--test/farm/html/src/isolatin1.py5
-rw-r--r--test/farm/html/src/partial.py18
-rw-r--r--test/farm/html/src/tabbed.py1
-rw-r--r--test/farm/html/src/unicode.py5
-rw-r--r--test/farm/run/run_timid.py5
-rw-r--r--test/farm/run/src/chdir.py1
-rw-r--r--test/farm/run/src/showtrace.py9
-rw-r--r--test/js/index.html52
-rw-r--r--test/js/tests.js204
-rw-r--r--test/meta_coverage.py2
-rw-r--r--test/modules/pkg1/__main__.py3
-rw-r--r--test/modules/pkg1/runmod2.py3
-rw-r--r--test/modules/pkg1/sub/__main__.py3
-rw-r--r--test/modules/pkg1/sub/runmod3.py3
-rw-r--r--test/modules/runmod1.py3
-rw-r--r--test/modules/usepkgs.py2
-rw-r--r--test/moremodules/othermods/__init__.py0
-rw-r--r--test/moremodules/othermods/othera.py2
-rw-r--r--test/moremodules/othermods/otherb.py2
-rw-r--r--test/moremodules/othermods/sub/__init__.py0
-rw-r--r--test/moremodules/othermods/sub/osa.py2
-rw-r--r--test/moremodules/othermods/sub/osb.py2
-rw-r--r--test/osinfo.py6
-rw-r--r--test/qunit/jquery.tmpl.min.js10
-rw-r--r--test/qunit/qunit.css225
-rw-r--r--test/qunit/qunit.js1448
-rw-r--r--test/test_api.py294
-rw-r--r--test/test_arcs.py95
-rw-r--r--test/test_cmdline.py72
-rw-r--r--test/test_codeunit.py2
-rw-r--r--test/test_config.py48
-rw-r--r--test/test_coverage.py97
-rw-r--r--test/test_data.py31
-rw-r--r--test/test_execfile.py49
-rw-r--r--test/test_farm.py20
-rw-r--r--test/test_files.py89
-rw-r--r--test/test_html.py289
-rw-r--r--test/test_misc.py76
-rw-r--r--test/test_oddball.py43
-rw-r--r--test/test_parser.py40
-rw-r--r--test/test_phystokens.py4
-rw-r--r--test/test_process.py224
-rw-r--r--test/test_results.py1
-rw-r--r--test/test_summary.py206
-rw-r--r--test/test_templite.py2
-rw-r--r--test/test_testing.py60
-rw-r--r--test/test_xml.py89
-rw-r--r--test/try_execfile.py10
101 files changed, 7626 insertions, 2177 deletions
diff --git a/test/backtest.py b/test/backtest.py
index e8d8366d..b17aa242 100644
--- a/test/backtest.py
+++ b/test/backtest.py
@@ -1,6 +1,6 @@
"""Add things to old Pythons so I can pretend they are newer, for tests."""
-# pylint: disable-msg=W0622
+# pylint: disable=W0622
# (Redefining built-in blah)
# The whole point of this file is to redefine built-ins, so shut up about it.
@@ -30,10 +30,10 @@ else:
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT
)
- status = proc.wait()
+ output, _ = proc.communicate()
+ status = proc.returncode # pylint: disable=E1101
# Get the output, and canonicalize it to strings with newlines.
- output = proc.stdout.read()
if not isinstance(output, str):
output = output.decode('utf-8')
output = output.replace('\r', '')
diff --git a/test/backunittest.py b/test/backunittest.py
index f606185f..30da78eb 100644
--- a/test/backunittest.py
+++ b/test/backunittest.py
@@ -2,7 +2,7 @@
import difflib, re, sys, unittest
-from coverage.backward import set # pylint: disable-msg=W0622
+from coverage.backward import set # pylint: disable=W0622
def _need(method):
@@ -29,6 +29,27 @@ class TestCase(unittest.TestCase):
if exp:
self.fail(msg)
+ if _need('assertIn'):
+ def assertIn(self, member, container, msg=None):
+ """Assert that `member` is in `container`."""
+ if member not in container:
+ msg = msg or ('%r not found in %r' % (member, container))
+ self.fail(msg)
+
+ if _need('assertNotIn'):
+ def assertNotIn(self, member, container, msg=None):
+ """Assert that `member` is not in `container`."""
+ if member in container:
+ msg = msg or ('%r found in %r' % (member, container))
+ self.fail(msg)
+
+ if _need('assertGreater'):
+ def assertGreater(self, a, b, msg=None):
+ """Assert that `a` is greater than `b`."""
+ if not a > b:
+ msg = msg or ('%r not greater than %r' % (a, b))
+ self.fail(msg)
+
if _need('assertRaisesRegexp'):
def assertRaisesRegexp(self, excClass, regexp, callobj, *args, **kw):
""" Just like unittest.TestCase.assertRaises,
@@ -46,7 +67,7 @@ class TestCase(unittest.TestCase):
# Message provided, and it didn't match: fail!
raise self.failureException(
"Right exception, wrong message: "
- "'%s' doesn't match '%s'" % (excMsg, regexp)
+ "%r doesn't match %r" % (excMsg, regexp)
)
# No need to catch other exceptions: They'll fail the test all by
# themselves!
@@ -66,11 +87,12 @@ class TestCase(unittest.TestCase):
self.assertEqual(set(s1), set(s2))
if _need('assertRegexpMatches'):
- def assertRegexpMatches(self, s, regex):
- """Assert that `s` matches `regex`."""
- m = re.search(regex, s)
+ def assertRegexpMatches(self, text, regex, msg=None):
+ """Assert that `text` matches `regex`."""
+ m = re.search(regex, text)
if not m:
- raise self.failureException("%r doesn't match %r" % (s, regex))
+ msg = msg or ("%r doesn't match %r" % (text, regex))
+ raise self.failureException(msg)
if _need('assertMultiLineEqual'):
def assertMultiLineEqual(self, first, second, msg=None):
diff --git a/test/coveragetest.py b/test/coveragetest.py
index 53f0ef0b..4ae399cc 100644
--- a/test/coveragetest.py
+++ b/test/coveragetest.py
@@ -1,9 +1,10 @@
"""Base test case class for coverage testing."""
-import imp, os, random, shlex, shutil, sys, tempfile, textwrap
+import glob, imp, os, random, shlex, shutil, sys, tempfile, textwrap
import coverage
-from coverage.backward import sorted, StringIO # pylint: disable-msg=W0622
+from coverage.backward import sorted, StringIO # pylint: disable=W0622
+from coverage.backward import to_bytes
from backtest import run_command
from backunittest import TestCase
@@ -21,6 +22,12 @@ class Tee(object):
for f in self._files:
f.write(data)
+ if 0:
+ # Use this if you need to use a debugger, though it makes some tests
+ # fail, I'm not sure why...
+ def __getattr__(self, name):
+ return getattr(self._files[0], name)
+
# Status returns for the command line.
OK, ERR = 0, 1
@@ -31,6 +38,14 @@ class CoverageTest(TestCase):
run_in_temp_dir = True
def setUp(self):
+ super(CoverageTest, self).setUp()
+
+ # Tell newer unittest implementations to print long helpful messages.
+ self.longMessage = True
+
+ # tearDown will restore the original sys.path
+ self.old_syspath = sys.path[:]
+
if self.run_in_temp_dir:
# Create a temporary directory.
self.noise = str(random.random())[2:]
@@ -40,9 +55,7 @@ class CoverageTest(TestCase):
self.old_dir = os.getcwd()
os.chdir(self.temp_dir)
-
# Modules should be importable from this temp directory.
- self.old_syspath = sys.path[:]
sys.path.insert(0, '')
# Keep a counter to make every call to check_coverage unique.
@@ -66,10 +79,12 @@ class CoverageTest(TestCase):
self.old_modules = dict(sys.modules)
def tearDown(self):
- if self.run_in_temp_dir:
- # Restore the original sys.path.
- sys.path = self.old_syspath
+ super(CoverageTest, self).tearDown()
+ # Restore the original sys.path.
+ sys.path = self.old_syspath
+
+ if self.run_in_temp_dir:
# Get rid of the temporary directory.
os.chdir(self.old_dir)
shutil.rmtree(self.temp_root)
@@ -81,8 +96,14 @@ class CoverageTest(TestCase):
sys.stdout = self.old_stdout
sys.stderr = self.old_stderr
- # Remove any new modules imported during the test run. This lets us
- # import the same source files for more than one test.
+ self.clean_modules()
+
+ def clean_modules(self):
+ """Remove any new modules imported during the test run.
+
+ This lets us import the same source files for more than one test.
+
+ """
for m in [m for m in sys.modules if m not in self.old_modules]:
del sys.modules[m]
@@ -123,11 +144,12 @@ class CoverageTest(TestCase):
"""Return the data written to stderr during the test."""
return self.captured_stderr.getvalue()
- def make_file(self, filename, text=""):
+ def make_file(self, filename, text="", newline=None):
"""Create a temp file.
`filename` is the path to the file, including directories if desired,
- and `text` is the content.
+ and `text` is the content. If `newline` is provided, it is a string
+ that will be used as the line endings in the created file.
Returns the path to the file.
@@ -135,6 +157,8 @@ class CoverageTest(TestCase):
# Tests that call `make_file` should be run in a temp environment.
assert self.run_in_temp_dir
text = textwrap.dedent(text)
+ if newline:
+ text = text.replace("\n", newline)
# Make sure the directories are available.
dirs, _ = os.path.split(filename)
@@ -142,12 +166,31 @@ class CoverageTest(TestCase):
os.makedirs(dirs)
# Create the file.
- f = open(filename, 'w')
- f.write(text)
- f.close()
+ f = open(filename, 'wb')
+ try:
+ f.write(to_bytes(text))
+ finally:
+ f.close()
return filename
+ def clean_local_file_imports(self):
+ """Clean up the results of calls to `import_local_file`.
+
+ Use this if you need to `import_local_file` the same file twice in
+ one test.
+
+ """
+ # So that we can re-import files, clean them out first.
+ self.clean_modules()
+ # Also have to clean out the .pyc file, since the timestamp
+ # resolution is only one second, a changed file might not be
+ # picked up.
+ for pyc in glob.glob('*.pyc'):
+ os.remove(pyc)
+ if os.path.exists("__pycache__"):
+ shutil.rmtree("__pycache__")
+
def import_local_file(self, modname):
"""Import a local file as a module.
@@ -162,7 +205,7 @@ class CoverageTest(TestCase):
if suff[0] == '.py':
break
try:
- # pylint: disable-msg=W0631
+ # pylint: disable=W0631
# (Using possibly undefined loop variable 'suff')
mod = imp.load_module(modname, f, modfile, suff)
finally:
@@ -224,8 +267,9 @@ class CoverageTest(TestCase):
s2 = "\n".join([repr(a) for a in a2]) + "\n"
self.assertMultiLineEqual(s1, s2, msg)
- def check_coverage(self, text, lines=None, missing="", excludes=None,
- report="", arcz=None, arcz_missing="", arcz_unpredicted=""):
+ def check_coverage(self, text, lines=None, missing="", report="",
+ excludes=None, partials="",
+ arcz=None, arcz_missing="", arcz_unpredicted=""):
"""Check the coverage measurement of `text`.
The source `text` is run and measured. `lines` are the line numbers
@@ -258,6 +302,8 @@ class CoverageTest(TestCase):
cov.erase()
for exc in excludes or []:
cov.exclude(exc)
+ for par in partials or []:
+ cov.exclude(par, which='partial')
cov.start()
try: # pragma: recursive coverage
@@ -333,6 +379,16 @@ class CoverageTest(TestCase):
flist2_nice = [self.nice_file(f) for f in flist2]
self.assertSameElements(flist1_nice, flist2_nice)
+ def assert_exists(self, fname):
+ """Assert that `fname` is a file that exists."""
+ msg = "File %r should exist" % fname
+ self.assert_(os.path.exists(fname), msg)
+
+ def assert_doesnt_exist(self, fname):
+ """Assert that `fname` is a file that doesn't exist."""
+ msg = "File %r shouldn't exist" % fname
+ self.assert_(not os.path.exists(fname), msg)
+
def command_line(self, args, ret=OK, _covpkg=None):
"""Run `args` through the command line.
@@ -380,7 +436,7 @@ class CoverageTest(TestCase):
here = os.path.dirname(self.nice_file(coverage.__file__, ".."))
testmods = self.nice_file(here, 'test/modules')
zipfile = self.nice_file(here, 'test/zipmods.zip')
- pypath = self.original_environ('PYTHONPATH', "")
+ pypath = os.getenv('PYTHONPATH', '')
if pypath:
pypath += os.pathsep
pypath += testmods + os.pathsep + zipfile
diff --git a/test/farm/html/gold_a/a.html b/test/farm/html/gold_a/a.html
index b3a28792..c794525e 100644
--- a/test/farm/html/gold_a/a.html
+++ b/test/farm/html/gold_a/a.html
@@ -1,69 +1,95 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for a: 67%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>a</b> :
- <span class='pc_cov'>67%</span>
- </h1>
- <h2 class='stats'>
- 3 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>1 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='pln'><a href='#n1'>1</a></p>
-<p id='n2' class='pln'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='pln'><a href='#n6'>6</a></p>
-<p id='n7' class='stm mis'><a href='#n7'>7</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='pln'><span class='com'># A test file for HTML reporting by coverage.</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'>&lt;</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'>&nbsp; &nbsp; <span class='com'># Needed a &lt; to look at HTML entities.</span><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm run hide_run'>&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='stm mis'>&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for a: 67%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>a</b> :
+ <span class='pc_cov'>67%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 3 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>1 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='pln'><a href='#n6'>6</a></p>
+<p id='n7' class='stm mis'><a href='#n7'>7</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A test file for HTML reporting by coverage.</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'>&lt;</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'>&nbsp; &nbsp; <span class='com'># Needed a &lt; to look at HTML entities.</span><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'>&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='stm mis'>&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_a/index.html b/test/farm/html/gold_a/index.html
index 35224e6b..a821e9df 100644
--- a/test/farm/html/gold_a/index.html
+++ b/test/farm/html/gold_a/index.html
@@ -1,72 +1,89 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>67%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>3</td>
- <td>1</td>
- <td>0</td>
-
- <td class='right'>67%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='a.html'>a</a></td>
- <td>3</td>
- <td>1</td>
- <td>0</td>
-
- <td class='right'>67%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>67%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>3</td>
+ <td>1</td>
+ <td>0</td>
+
+ <td class='right'>67%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='a.html'>a</a></td>
+ <td>3</td>
+ <td>1</td>
+ <td>0</td>
+
+ <td class='right'>67%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_b_branch/b.html b/test/farm/html/gold_b_branch/b.html
index ba57e964..0258ad13 100644
--- a/test/farm/html/gold_b_branch/b.html
+++ b/test/farm/html/gold_b_branch/b.html
@@ -1,113 +1,139 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for b: 76%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>b</b> :
- <span class='pc_cov'>76%</span>
- </h1>
- <h2 class='stats'>
- 16 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>14 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>2 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- <span class='par run hide_run' onclick='toggle_lines(this, "par")'>3 partial</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='pln'><a href='#n1'>1</a></p>
-<p id='n2' class='pln'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm par run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
-<p id='n7' class='pln'><a href='#n7'>7</a></p>
-<p id='n8' class='stm mis'><a href='#n8'>8</a></p>
-<p id='n9' class='pln'><a href='#n9'>9</a></p>
-<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
-<p id='n11' class='pln'><a href='#n11'>11</a></p>
-<p id='n12' class='stm run hide_run'><a href='#n12'>12</a></p>
-<p id='n13' class='pln'><a href='#n13'>13</a></p>
-<p id='n14' class='stm par run hide_run'><a href='#n14'>14</a></p>
-<p id='n15' class='stm run hide_run'><a href='#n15'>15</a></p>
-<p id='n16' class='pln'><a href='#n16'>16</a></p>
-<p id='n17' class='stm run hide_run'><a href='#n17'>17</a></p>
-<p id='n18' class='pln'><a href='#n18'>18</a></p>
-<p id='n19' class='stm run hide_run'><a href='#n19'>19</a></p>
-<p id='n20' class='pln'><a href='#n20'>20</a></p>
-<p id='n21' class='stm par run hide_run'><a href='#n21'>21</a></p>
-<p id='n22' class='stm run hide_run'><a href='#n22'>22</a></p>
-<p id='n23' class='stm run hide_run'><a href='#n23'>23</a></p>
-<p id='n24' class='pln'><a href='#n24'>24</a></p>
-<p id='n25' class='stm mis'><a href='#n25'>25</a></p>
-<p id='n26' class='stm run hide_run'><a href='#n26'>26</a></p>
-<p id='n27' class='pln'><a href='#n27'>27</a></p>
-<p id='n28' class='stm run hide_run'><a href='#n28'>28</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='pln'><span class='com'># A test file for HTML reporting by coverage.</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>def</span> <span class='nam'>one</span><span class='op'>(</span><span class='nam'>x</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'>&nbsp; &nbsp; <span class='com'># This will be a branch that misses the else.</span><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm par run hide_run'><span class='annotate' title='no jump to this line number'>8</span>&nbsp; &nbsp; <span class='key'>if</span> <span class='nam'>x</span> <span class='op'>&lt;</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='pln'>&nbsp; &nbsp; <span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t8' class='stm mis'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'>&nbsp;</span></p>
-<p id='t9' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t10' class='stm run hide_run'><span class='nam'>one</span><span class='op'>(</span><span class='num'>1</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
-<p id='t11' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t12' class='stm run hide_run'><span class='key'>def</span> <span class='nam'>two</span><span class='op'>(</span><span class='nam'>x</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t13' class='pln'>&nbsp; &nbsp; <span class='com'># A missed else that branches to &quot;exit&quot;</span><span class='strut'>&nbsp;</span></p>
-<p id='t14' class='stm par run hide_run'><span class='annotate' title='no jump to this line number'>exit</span>&nbsp; &nbsp; <span class='key'>if</span> <span class='nam'>x</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t15' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
-<p id='t16' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t17' class='stm run hide_run'><span class='nam'>two</span><span class='op'>(</span><span class='num'>1</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
-<p id='t18' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t19' class='stm run hide_run'><span class='key'>def</span> <span class='nam'>three_way</span><span class='op'>(</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t20' class='pln'>&nbsp; &nbsp; <span class='com'># for-else can be a three-way branch.</span><span class='strut'>&nbsp;</span></p>
-<p id='t21' class='stm par run hide_run'><span class='annotate' title='no jumps to these line numbers'>25&nbsp;&nbsp; 26</span>&nbsp; &nbsp; <span class='key'>for</span> <span class='nam'>i</span> <span class='key'>in</span> <span class='nam'>range</span><span class='op'>(</span><span class='num'>10</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t22' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>if</span> <span class='nam'>i</span> <span class='op'>==</span> <span class='num'>3</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t23' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>break</span><span class='strut'>&nbsp;</span></p>
-<p id='t24' class='pln'>&nbsp; &nbsp; <span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t25' class='stm mis'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>return</span> <span class='num'>23</span><span class='strut'>&nbsp;</span></p>
-<p id='t26' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>return</span> <span class='num'>17</span><span class='strut'>&nbsp;</span></p>
-<p id='t27' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t28' class='stm run hide_run'><span class='nam'>three_way</span><span class='op'>(</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for b: 76%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>b</b> :
+ <span class='pc_cov'>76%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 16 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>14 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>2 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ <span class='par run hide_run shortkey_p' onclick='coverage.toggle_lines(this, "par")'>3 partial</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm par run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm mis'><a href='#n8'>8</a></p>
+<p id='n9' class='pln'><a href='#n9'>9</a></p>
+<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
+<p id='n11' class='pln'><a href='#n11'>11</a></p>
+<p id='n12' class='stm run hide_run'><a href='#n12'>12</a></p>
+<p id='n13' class='pln'><a href='#n13'>13</a></p>
+<p id='n14' class='stm par run hide_run'><a href='#n14'>14</a></p>
+<p id='n15' class='stm run hide_run'><a href='#n15'>15</a></p>
+<p id='n16' class='pln'><a href='#n16'>16</a></p>
+<p id='n17' class='stm run hide_run'><a href='#n17'>17</a></p>
+<p id='n18' class='pln'><a href='#n18'>18</a></p>
+<p id='n19' class='stm run hide_run'><a href='#n19'>19</a></p>
+<p id='n20' class='pln'><a href='#n20'>20</a></p>
+<p id='n21' class='stm par run hide_run'><a href='#n21'>21</a></p>
+<p id='n22' class='stm run hide_run'><a href='#n22'>22</a></p>
+<p id='n23' class='stm run hide_run'><a href='#n23'>23</a></p>
+<p id='n24' class='pln'><a href='#n24'>24</a></p>
+<p id='n25' class='stm mis'><a href='#n25'>25</a></p>
+<p id='n26' class='stm run hide_run'><a href='#n26'>26</a></p>
+<p id='n27' class='pln'><a href='#n27'>27</a></p>
+<p id='n28' class='stm run hide_run'><a href='#n28'>28</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A test file for HTML reporting by coverage.</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>def</span> <span class='nam'>one</span><span class='op'>(</span><span class='nam'>x</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'>&nbsp; &nbsp; <span class='com'># This will be a branch that misses the else.</span><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm par run hide_run'><span class='annotate' title='no jump to this line number'>8</span>&nbsp; &nbsp; <span class='key'>if</span> <span class='nam'>x</span> <span class='op'>&lt;</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'>&nbsp; &nbsp; <span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm mis'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='stm run hide_run'><span class='nam'>one</span><span class='op'>(</span><span class='num'>1</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
+<p id='t11' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t12' class='stm run hide_run'><span class='key'>def</span> <span class='nam'>two</span><span class='op'>(</span><span class='nam'>x</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t13' class='pln'>&nbsp; &nbsp; <span class='com'># A missed else that branches to &quot;exit&quot;</span><span class='strut'>&nbsp;</span></p>
+<p id='t14' class='stm par run hide_run'><span class='annotate' title='no jump to this line number'>exit</span>&nbsp; &nbsp; <span class='key'>if</span> <span class='nam'>x</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t15' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
+<p id='t16' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t17' class='stm run hide_run'><span class='nam'>two</span><span class='op'>(</span><span class='num'>1</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
+<p id='t18' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t19' class='stm run hide_run'><span class='key'>def</span> <span class='nam'>three_way</span><span class='op'>(</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t20' class='pln'>&nbsp; &nbsp; <span class='com'># for-else can be a three-way branch.</span><span class='strut'>&nbsp;</span></p>
+<p id='t21' class='stm par run hide_run'><span class='annotate' title='no jumps to these line numbers'>25&nbsp;&nbsp; 26</span>&nbsp; &nbsp; <span class='key'>for</span> <span class='nam'>i</span> <span class='key'>in</span> <span class='nam'>range</span><span class='op'>(</span><span class='num'>10</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t22' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>if</span> <span class='nam'>i</span> <span class='op'>==</span> <span class='num'>3</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t23' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>break</span><span class='strut'>&nbsp;</span></p>
+<p id='t24' class='pln'>&nbsp; &nbsp; <span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t25' class='stm mis'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>return</span> <span class='num'>23</span><span class='strut'>&nbsp;</span></p>
+<p id='t26' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>return</span> <span class='num'>17</span><span class='strut'>&nbsp;</span></p>
+<p id='t27' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t28' class='stm run hide_run'><span class='nam'>three_way</span><span class='op'>(</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_b_branch/index.html b/test/farm/html/gold_b_branch/index.html
index a37f357a..cb6ffa17 100644
--- a/test/farm/html/gold_b_branch/index.html
+++ b/test/farm/html/gold_b_branch/index.html
@@ -1,81 +1,101 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>76%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th>branches</th>
- <th>partial</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>16</td>
- <td>2</td>
- <td>0</td>
-
- <td>9</td>
- <td>4</td>
-
- <td class='right'>76%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='b.html'>b</a></td>
- <td>16</td>
- <td>2</td>
- <td>0</td>
-
- <td>9</td>
- <td>4</td>
-
- <td class='right'>76%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>76%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>b</span>
+ <span class='key'>p</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='shortkey_b'>branches</th>
+ <th class='shortkey_p'>partial</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>16</td>
+ <td>2</td>
+ <td>0</td>
+
+ <td>9</td>
+ <td>4</td>
+
+ <td class='right'>76%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='b.html'>b</a></td>
+ <td>16</td>
+ <td>2</td>
+ <td>0</td>
+
+ <td>9</td>
+ <td>4</td>
+
+ <td class='right'>76%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_bom/bom.html b/test/farm/html/gold_bom/bom.html
new file mode 100644
index 00000000..1d61a62c
--- /dev/null
+++ b/test/farm/html/gold_bom/bom.html
@@ -0,0 +1,104 @@
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for bom: 71%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>bom</b> :
+ <span class='pc_cov'>71%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 7 statements &nbsp;
+ <span class='run hide_run shortkey_r button_toggle_run'>5 run</span>
+ <span class='mis shortkey_m button_toggle_mis'>2 missing</span>
+ <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+<p id='n3' class='pln'><a href='#n3'>3</a></p>
+<p id='n4' class='stm run hide_run'><a href='#n4'>4</a></p>
+<p id='n5' class='pln'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='stm mis'><a href='#n7'>7</a></p>
+<p id='n8' class='stm mis'><a href='#n8'>8</a></p>
+<p id='n9' class='pln'><a href='#n9'>9</a></p>
+<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
+<p id='n11' class='stm run hide_run'><a href='#n11'>11</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A python source file in utf-8, with BOM</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>math</span> <span class='op'>=</span> <span class='str'>&quot;3&#215;4 = 12, &#247;2 = 6&#177;0&quot;</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>sys</span><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'><span class='key'>if</span> <span class='nam'>sys</span><span class='op'>.</span><span class='nam'>version_info</span> <span class='op'>&gt;=</span> <span class='op'>(</span><span class='num'>3</span><span class='op'>,</span> <span class='num'>0</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='stm mis'>&nbsp; &nbsp; <span class='key'>assert</span> <span class='nam'>len</span><span class='op'>(</span><span class='nam'>math</span><span class='op'>)</span> <span class='op'>==</span> <span class='num'>18</span><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm mis'>&nbsp; &nbsp; <span class='key'>assert</span> <span class='nam'>len</span><span class='op'>(</span><span class='nam'>math</span><span class='op'>.</span><span class='nam'>encode</span><span class='op'>(</span><span class='str'>&#39;utf-8&#39;</span><span class='op'>)</span><span class='op'>)</span> <span class='op'>==</span> <span class='num'>21</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>assert</span> <span class='nam'>len</span><span class='op'>(</span><span class='nam'>math</span><span class='op'>)</span> <span class='op'>==</span> <span class='num'>21</span><span class='strut'>&nbsp;</span></p>
+<p id='t11' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>assert</span> <span class='nam'>len</span><span class='op'>(</span><span class='nam'>math</span><span class='op'>.</span><span class='nam'>decode</span><span class='op'>(</span><span class='str'>&#39;utf-8&#39;</span><span class='op'>)</span><span class='op'>)</span> <span class='op'>==</span> <span class='num'>18</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.5.2</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_bom/index.html b/test/farm/html/gold_bom/index.html
new file mode 100644
index 00000000..8653b23e
--- /dev/null
+++ b/test/farm/html/gold_bom/index.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>71%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>7</td>
+ <td>2</td>
+ <td>0</td>
+
+ <td class='right'>71%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='bom.html'>bom</a></td>
+ <td>7</td>
+ <td>2</td>
+ <td>0</td>
+
+ <td class='right'>71%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.5.2</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_isolatin1/index.html b/test/farm/html/gold_isolatin1/index.html
new file mode 100644
index 00000000..6e9f3ca7
--- /dev/null
+++ b/test/farm/html/gold_isolatin1/index.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='isolatin1.html'>isolatin1</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5.2b1'>coverage.py v3.5.2b1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_isolatin1/isolatin1.html b/test/farm/html/gold_isolatin1/isolatin1.html
new file mode 100644
index 00000000..276a6c25
--- /dev/null
+++ b/test/farm/html/gold_isolatin1/isolatin1.html
@@ -0,0 +1,91 @@
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for isolatin1: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>isolatin1</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='pln'><a href='#n3'>3</a></p>
+<p id='n4' class='stm run hide_run'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A python source file in another encoding.</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='com'># -*- coding: iso8859-1 -*-</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='stm run hide_run'><span class='nam'>math</span> <span class='op'>=</span> <span class='str'>&quot;3&#215;4 = 12, &#247;2 = 6&#177;0&quot;</span><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>len</span><span class='op'>(</span><span class='nam'>math</span><span class='op'>)</span> <span class='op'>==</span> <span class='num'>18</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5.2b1'>coverage.py v3.5.2b1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_1/index.html b/test/farm/html/gold_omit_1/index.html
index 2612a88e..5616d012 100644
--- a/test/farm/html/gold_omit_1/index.html
+++ b/test/farm/html/gold_omit_1/index.html
@@ -1,99 +1,116 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>100%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>14</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='m1.html'>m1</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='m2.html'>m2</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
- <td>8</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>14</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='m1.html'>m1</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='m2.html'>m2</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='m3.html'>m3</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='main.html'>main</a></td>
+ <td>8</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_1/m1.html b/test/farm/html/gold_omit_1/m1.html
index 20b86df7..62ba1e0a 100644
--- a/test/farm/html/gold_omit_1/m1.html
+++ b/test/farm/html/gold_omit_1/m1.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m1: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m1</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m1a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m1b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m1: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m1</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m1a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m1b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_1/m2.html b/test/farm/html/gold_omit_1/m2.html
index 6cbf78ed..d75a5ba0 100644
--- a/test/farm/html/gold_omit_1/m2.html
+++ b/test/farm/html/gold_omit_1/m2.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m2: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m2</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m2a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m2b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m2: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m2</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m2a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m2b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_1/m3.html b/test/farm/html/gold_omit_1/m3.html
index 6e618619..bd99138a 100644
--- a/test/farm/html/gold_omit_1/m3.html
+++ b/test/farm/html/gold_omit_1/m3.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m3: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m3: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m3</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_1/main.html b/test/farm/html/gold_omit_1/main.html
index d7b84c45..03948718 100644
--- a/test/farm/html/gold_omit_1/main.html
+++ b/test/farm/html/gold_omit_1/main.html
@@ -1,75 +1,101 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for main: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 8 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>8 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
-<p id='n7' class='pln'><a href='#n7'>7</a></p>
-<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
-<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
-<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for main: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>main</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 8 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>8 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
+<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
+<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_2/index.html b/test/farm/html/gold_omit_2/index.html
index 6fababf4..3ce5bade 100644
--- a/test/farm/html/gold_omit_2/index.html
+++ b/test/farm/html/gold_omit_2/index.html
@@ -1,90 +1,107 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>100%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>12</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='m2.html'>m2</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
- <td>8</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>12</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='m2.html'>m2</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='m3.html'>m3</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='main.html'>main</a></td>
+ <td>8</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_2/m2.html b/test/farm/html/gold_omit_2/m2.html
index 6cbf78ed..d75a5ba0 100644
--- a/test/farm/html/gold_omit_2/m2.html
+++ b/test/farm/html/gold_omit_2/m2.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m2: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m2</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m2a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m2b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m2: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m2</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m2a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m2b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_2/m3.html b/test/farm/html/gold_omit_2/m3.html
index 6e618619..bd99138a 100644
--- a/test/farm/html/gold_omit_2/m3.html
+++ b/test/farm/html/gold_omit_2/m3.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m3: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m3: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m3</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_2/main.html b/test/farm/html/gold_omit_2/main.html
index d7b84c45..03948718 100644
--- a/test/farm/html/gold_omit_2/main.html
+++ b/test/farm/html/gold_omit_2/main.html
@@ -1,75 +1,101 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for main: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 8 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>8 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
-<p id='n7' class='pln'><a href='#n7'>7</a></p>
-<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
-<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
-<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for main: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>main</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 8 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>8 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
+<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
+<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_3/index.html b/test/farm/html/gold_omit_3/index.html
index 919fc965..fb826bf5 100644
--- a/test/farm/html/gold_omit_3/index.html
+++ b/test/farm/html/gold_omit_3/index.html
@@ -1,81 +1,98 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>100%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>10</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
- <td>8</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>10</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='m3.html'>m3</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='main.html'>main</a></td>
+ <td>8</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_3/m3.html b/test/farm/html/gold_omit_3/m3.html
index 6e618619..bd99138a 100644
--- a/test/farm/html/gold_omit_3/m3.html
+++ b/test/farm/html/gold_omit_3/m3.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m3: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m3: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m3</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_3/main.html b/test/farm/html/gold_omit_3/main.html
index d7b84c45..03948718 100644
--- a/test/farm/html/gold_omit_3/main.html
+++ b/test/farm/html/gold_omit_3/main.html
@@ -1,75 +1,101 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for main: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 8 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>8 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
-<p id='n7' class='pln'><a href='#n7'>7</a></p>
-<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
-<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
-<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for main: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>main</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 8 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>8 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
+<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
+<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_4/index.html b/test/farm/html/gold_omit_4/index.html
index 1d528d39..e437cf10 100644
--- a/test/farm/html/gold_omit_4/index.html
+++ b/test/farm/html/gold_omit_4/index.html
@@ -1,90 +1,107 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>100%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>12</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='m1.html'>m1</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
- <td>8</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>12</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='m1.html'>m1</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='m3.html'>m3</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='main.html'>main</a></td>
+ <td>8</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_4/m1.html b/test/farm/html/gold_omit_4/m1.html
index 20b86df7..62ba1e0a 100644
--- a/test/farm/html/gold_omit_4/m1.html
+++ b/test/farm/html/gold_omit_4/m1.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m1: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m1</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m1a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m1b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m1: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m1</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m1a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m1b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_4/m3.html b/test/farm/html/gold_omit_4/m3.html
index 6e618619..bd99138a 100644
--- a/test/farm/html/gold_omit_4/m3.html
+++ b/test/farm/html/gold_omit_4/m3.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m3: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m3: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m3</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m3a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m3b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_4/main.html b/test/farm/html/gold_omit_4/main.html
index d7b84c45..03948718 100644
--- a/test/farm/html/gold_omit_4/main.html
+++ b/test/farm/html/gold_omit_4/main.html
@@ -1,75 +1,101 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for main: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 8 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>8 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
-<p id='n7' class='pln'><a href='#n7'>7</a></p>
-<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
-<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
-<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for main: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>main</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 8 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>8 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
+<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
+<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_5/index.html b/test/farm/html/gold_omit_5/index.html
index 61eeceb8..4bde6b73 100644
--- a/test/farm/html/gold_omit_5/index.html
+++ b/test/farm/html/gold_omit_5/index.html
@@ -1,81 +1,98 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>100%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>10</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='m1.html'>m1</a></td>
- <td>2</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
- <td>8</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>10</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='m1.html'>m1</a></td>
+ <td>2</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='main.html'>main</a></td>
+ <td>8</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_5/m1.html b/test/farm/html/gold_omit_5/m1.html
index 20b86df7..62ba1e0a 100644
--- a/test/farm/html/gold_omit_5/m1.html
+++ b/test/farm/html/gold_omit_5/m1.html
@@ -1,59 +1,85 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for m1: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m1</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 2 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>2 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='nam'>m1a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='nam'>m1b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for m1: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>m1</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 2 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='nam'>m1a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='nam'>m1b</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_omit_5/main.html b/test/farm/html/gold_omit_5/main.html
index d7b84c45..03948718 100644
--- a/test/farm/html/gold_omit_5/main.html
+++ b/test/farm/html/gold_omit_5/main.html
@@ -1,75 +1,101 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for main: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 8 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>8 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
-<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
-<p id='n7' class='pln'><a href='#n7'>7</a></p>
-<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
-<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
-<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for main: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>main</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 8 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>8 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='stm run hide_run'><a href='#n1'>1</a></p>
+<p id='n2' class='stm run hide_run'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
+<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
+<p id='n10' class='stm run hide_run'><a href='#n10'>10</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m1</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'><span class='nam'>b</span> <span class='op'>=</span> <span class='num'>6</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m1</span><span class='op'>.</span><span class='nam'>m1a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m2</span><span class='op'>.</span><span class='nam'>m2a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='stm run hide_run'><span class='key'>assert</span> <span class='nam'>m3</span><span class='op'>.</span><span class='nam'>m3a</span> <span class='op'>==</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_other/blah_blah_other.html b/test/farm/html/gold_other/blah_blah_other.html
index 46e05aaf..ab5ae371 100644
--- a/test/farm/html/gold_other/blah_blah_other.html
+++ b/test/farm/html/gold_other/blah_blah_other.html
@@ -1,63 +1,89 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for othersrc\other: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>othersrc\other</b> :
- <span class='pc_cov'>100%</span>
- </h1>
- <h2 class='stats'>
- 1 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>1 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>0 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='pln'><a href='#n1'>1</a></p>
-<p id='n2' class='pln'><a href='#n2'>2</a></p>
-<p id='n3' class='pln'><a href='#n3'>3</a></p>
-<p id='n4' class='stm run hide_run'><a href='#n4'>4</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='pln'><span class='com'># A file in another directory.&nbsp; We&#39;re checking that it ends up in the</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='pln'><span class='com'># HTML report.</span><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='stm run hide_run'><span class='key'>print</span><span class='op'>(</span><span class='str'>&quot;This is the other src!&quot;</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for /home/ned/coverage/trunk/test/farm/html/othersrc/other: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>/home/ned/coverage/trunk/test/farm/html/othersrc/other</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 1 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>1 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='pln'><a href='#n3'>3</a></p>
+<p id='n4' class='stm run hide_run'><a href='#n4'>4</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A file in another directory.&nbsp; We&#39;re checking that it ends up in the</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='com'># HTML report.</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='stm run hide_run'><span class='key'>print</span><span class='op'>(</span><span class='str'>&quot;This is the other src!&quot;</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_other/here.html b/test/farm/html/gold_other/here.html
index 1ae248f5..1da5bcd6 100644
--- a/test/farm/html/gold_other/here.html
+++ b/test/farm/html/gold_other/here.html
@@ -1,71 +1,97 @@
-<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
-
-
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for here: 75%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(pyfile_ready);
- </script>
-</head>
-<body id='pyfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>here</b> :
- <span class='pc_cov'>75%</span>
- </h1>
- <h2 class='stats'>
- 4 statements
- <span class='run hide_run' onclick='toggle_lines(this, "run")'>3 run</span>
- <span class='mis' onclick='toggle_lines(this, "mis")'>1 missing</span>
- <span class='exc' onclick='toggle_lines(this, "exc")'>0 excluded</span>
-
- </h2>
- </div>
-</div>
-
-<div id='source'>
- <table cellspacing='0' cellpadding='0'>
- <tr>
- <td class='linenos' valign='top'>
-<p id='n1' class='pln'><a href='#n1'>1</a></p>
-<p id='n2' class='pln'><a href='#n2'>2</a></p>
-<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
-<p id='n4' class='pln'><a href='#n4'>4</a></p>
-<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
-<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
-<p id='n7' class='pln'><a href='#n7'>7</a></p>
-<p id='n8' class='stm mis'><a href='#n8'>8</a></p>
-
- </td>
- <td class='text' valign='top'>
-<p id='t1' class='pln'><span class='com'># A test file for HTML reporting by coverage.</span><span class='strut'>&nbsp;</span></p>
-<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>other</span><span class='strut'>&nbsp;</span></p>
-<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t5' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'>&lt;</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t6' class='stm run hide_run'>&nbsp; &nbsp; <span class='nam'>h</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
-<p id='t7' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t8' class='stm mis'>&nbsp; &nbsp; <span class='nam'>h</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'>&nbsp;</span></p>
-
- </td>
- </tr>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for here: 75%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>here</b> :
+ <span class='pc_cov'>75%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 4 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>3 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>1 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm mis'><a href='#n8'>8</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A test file for HTML reporting by coverage.</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>other</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'>&lt;</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'>&nbsp; &nbsp; <span class='nam'>h</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm mis'>&nbsp; &nbsp; <span class='nam'>h</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_other/index.html b/test/farm/html/gold_other/index.html
index 9021036f..7665cfe4 100644
--- a/test/farm/html/gold_other/index.html
+++ b/test/farm/html/gold_other/index.html
@@ -1,81 +1,98 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
- <title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
- <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
- <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
- <script type='text/javascript' src='coverage_html.js'></script>
- <script type='text/javascript' charset='utf-8'>
- jQuery(document).ready(index_ready);
- </script>
-</head>
-<body id='indexfile'>
-
-<div id='header'>
- <div class='content'>
- <h1>Coverage report:
- <span class='pc_cov'>80%</span>
- </h1>
- </div>
-</div>
-
-<div id='index'>
- <table class='index'>
- <thead>
-
- <tr class='tablehead' title='Click to sort'>
- <th class='name left headerSortDown'>Module</th>
- <th>statements</th>
- <th>missing</th>
- <th>excluded</th>
-
- <th class='right'>coverage</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
- <td>5</td>
- <td>1</td>
- <td>0</td>
-
- <td class='right'>80%</td>
- </tr>
- </tfoot>
- <tbody>
-
- <tr class='file'>
- <td class='name left'><a href='here.html'>here</a></td>
- <td>4</td>
- <td>1</td>
- <td>0</td>
-
- <td class='right'>75%</td>
- </tr>
-
- <tr class='file'>
- <td class='name left'><a href='othersrc_other.html'>othersrc\other</a></td>
- <td>1</td>
- <td>0</td>
- <td>0</td>
-
- <td class='right'>100%</td>
- </tr>
-
- </tbody>
- </table>
-</div>
-
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage'>coverage.py v3.3.2a1</a>
- </p>
- </div>
-</div>
-
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>80%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>5</td>
+ <td>1</td>
+ <td>0</td>
+
+ <td class='right'>80%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='_home_ned_coverage_trunk_test_farm_html_othersrc_other.html'>/home/ned/coverage/trunk/test/farm/html/othersrc/other</a></td>
+ <td>1</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ <tr class='file'>
+ <td class='name left'><a href='here.html'>here</a></td>
+ <td>4</td>
+ <td>1</td>
+ <td>0</td>
+
+ <td class='right'>75%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_partial/index.html b/test/farm/html/gold_partial/index.html
new file mode 100644
index 00000000..5556150a
--- /dev/null
+++ b/test/farm/html/gold_partial/index.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>b</span>
+ <span class='key'>p</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='shortkey_b'>branches</th>
+ <th class='shortkey_p'>partial</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>8</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td>6</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='partial.html'>partial</a></td>
+ <td>8</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td>6</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_partial/partial.html b/test/farm/html/gold_partial/partial.html
new file mode 100644
index 00000000..b9640ce4
--- /dev/null
+++ b/test/farm/html/gold_partial/partial.html
@@ -0,0 +1,121 @@
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for partial: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>partial</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 8 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>8 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ <span class='par run hide_run shortkey_p' onclick='coverage.toggle_lines(this, "par")'>0 partial</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='stm run hide_run'><a href='#n6'>6</a></p>
+<p id='n7' class='pln'><a href='#n7'>7</a></p>
+<p id='n8' class='stm run hide_run'><a href='#n8'>8</a></p>
+<p id='n9' class='stm run hide_run'><a href='#n9'>9</a></p>
+<p id='n10' class='pln'><a href='#n10'>10</a></p>
+<p id='n11' class='stm run hide_run'><a href='#n11'>11</a></p>
+<p id='n12' class='stm run hide_run'><a href='#n12'>12</a></p>
+<p id='n13' class='pln'><a href='#n13'>13</a></p>
+<p id='n14' class='pln'><a href='#n14'>14</a></p>
+<p id='n15' class='pln'><a href='#n15'>15</a></p>
+<p id='n16' class='pln'><a href='#n16'>16</a></p>
+<p id='n17' class='pln'><a href='#n17'>17</a></p>
+<p id='n18' class='stm run hide_run'><a href='#n18'>18</a></p>
+<p id='n19' class='pln'><a href='#n19'>19</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># partial branches</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='key'>while</span> <span class='nam'>True</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>break</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t8' class='stm run hide_run'><span class='key'>while</span> <span class='num'>1</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t9' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>break</span><span class='strut'>&nbsp;</span></p>
+<p id='t10' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t11' class='stm run hide_run'><span class='key'>while</span> <span class='nam'>a</span><span class='op'>:</span>&nbsp; &nbsp; &nbsp; &nbsp; <span class='com'># pragma: no branch</span><span class='strut'>&nbsp;</span></p>
+<p id='t12' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>break</span><span class='strut'>&nbsp;</span></p>
+<p id='t13' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t14' class='pln'><span class='key'>if</span> <span class='num'>0</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t15' class='pln'>&nbsp; &nbsp; <span class='nam'>never_happen</span><span class='op'>(</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
+<p id='t16' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t17' class='pln'><span class='key'>if</span> <span class='num'>1</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t18' class='stm run hide_run'>&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>13</span><span class='strut'>&nbsp;</span></p>
+<p id='t19' class='pln'><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_styled/a.html b/test/farm/html/gold_styled/a.html
new file mode 100644
index 00000000..c794525e
--- /dev/null
+++ b/test/farm/html/gold_styled/a.html
@@ -0,0 +1,95 @@
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for a: 67%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>a</b> :
+ <span class='pc_cov'>67%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 3 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>2 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>1 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='stm run hide_run'><a href='#n3'>3</a></p>
+<p id='n4' class='pln'><a href='#n4'>4</a></p>
+<p id='n5' class='stm run hide_run'><a href='#n5'>5</a></p>
+<p id='n6' class='pln'><a href='#n6'>6</a></p>
+<p id='n7' class='stm mis'><a href='#n7'>7</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A test file for HTML reporting by coverage.</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'>&lt;</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='pln'>&nbsp; &nbsp; <span class='com'># Needed a &lt; to look at HTML entities.</span><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'>&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'>&nbsp;</span></p>
+<p id='t6' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
+<p id='t7' class='stm mis'>&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_styled/extra.css b/test/farm/html/gold_styled/extra.css
new file mode 100644
index 00000000..46c41fcd
--- /dev/null
+++ b/test/farm/html/gold_styled/extra.css
@@ -0,0 +1 @@
+/* Doesn't matter what goes in here, it gets copied. */
diff --git a/test/farm/html/gold_styled/index.html b/test/farm/html/gold_styled/index.html
new file mode 100644
index 00000000..a821e9df
--- /dev/null
+++ b/test/farm/html/gold_styled/index.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>67%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>3</td>
+ <td>1</td>
+ <td>0</td>
+
+ <td class='right'>67%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='a.html'>a</a></td>
+ <td>3</td>
+ <td>1</td>
+ <td>0</td>
+
+ <td class='right'>67%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5a1'>coverage.py v3.5a1</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_styled/style.css b/test/farm/html/gold_styled/style.css
new file mode 100644
index 00000000..c40357b8
--- /dev/null
+++ b/test/farm/html/gold_styled/style.css
@@ -0,0 +1,275 @@
+/* CSS styles for Coverage. */
+/* Page-wide styles */
+html, body, h1, h2, h3, p, td, th {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-weight: inherit;
+ font-style: inherit;
+ font-size: 100%;
+ font-family: inherit;
+ vertical-align: baseline;
+ }
+
+/* Set baseline grid to 16 pt. */
+body {
+ font-family: georgia, serif;
+ font-size: 1em;
+ }
+
+html>body {
+ font-size: 16px;
+ }
+
+/* Set base font size to 12/16 */
+p {
+ font-size: .75em; /* 12/16 */
+ line-height: 1.3333em; /* 16/12 */
+ }
+
+table {
+ border-collapse: collapse;
+ }
+
+a.nav {
+ text-decoration: none;
+ color: inherit;
+ }
+a.nav:hover {
+ text-decoration: underline;
+ color: inherit;
+ }
+
+/* Page structure */
+#header {
+ background: #f8f8f8;
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ }
+
+#source {
+ padding: 1em;
+ font-family: "courier new", monospace;
+ }
+
+#indexfile #footer {
+ margin: 1em 3em;
+ }
+
+#pyfile #footer {
+ margin: 1em 1em;
+ }
+
+#footer .content {
+ padding: 0;
+ font-size: 85%;
+ font-family: verdana, sans-serif;
+ color: #666666;
+ font-style: italic;
+ }
+
+#index {
+ margin: 1em 0 0 3em;
+ }
+
+/* Header styles */
+#header .content {
+ padding: 1em 3em;
+ }
+
+h1 {
+ font-size: 1.25em;
+}
+
+h2.stats {
+ margin-top: .5em;
+ font-size: 1em;
+}
+.stats span {
+ border: 1px solid;
+ padding: .1em .25em;
+ margin: 0 .1em;
+ cursor: pointer;
+ border-color: #999 #ccc #ccc #999;
+}
+.stats span.hide_run, .stats span.hide_exc,
+.stats span.hide_mis, .stats span.hide_par,
+.stats span.par.hide_run.hide_par {
+ border-color: #ccc #999 #999 #ccc;
+}
+.stats span.par.hide_run {
+ border-color: #999 #ccc #ccc #999;
+}
+
+/* Help panel */
+#keyboard_icon {
+ float: right;
+ cursor: pointer;
+}
+
+.help_panel {
+ position: absolute;
+ background: #ffc;
+ padding: .5em;
+ border: 1px solid #883;
+ display: none;
+}
+
+#indexfile .help_panel {
+ width: 20em; height: 4em;
+}
+
+#pyfile .help_panel {
+ width: 16em; height: 8em;
+}
+
+.help_panel .legend {
+ font-style: italic;
+ margin-bottom: 1em;
+}
+
+#panel_icon {
+ float: right;
+ cursor: pointer;
+}
+
+.keyhelp {
+ margin: .75em;
+}
+
+.keyhelp .key {
+ border: 1px solid black;
+ border-color: #888 #333 #333 #888;
+ padding: .1em .35em;
+ font-family: monospace;
+ font-weight: bold;
+ background: #eee;
+}
+
+/* Source file styles */
+.linenos p {
+ text-align: right;
+ margin: 0;
+ padding: 0 .5em;
+ color: #999999;
+ font-family: verdana, sans-serif;
+ font-size: .625em; /* 10/16 */
+ line-height: 1.6em; /* 16/10 */
+ }
+.linenos p.highlight {
+ background: #ffdd00;
+ }
+.linenos p a {
+ text-decoration: none;
+ color: #999999;
+ }
+.linenos p a:hover {
+ text-decoration: underline;
+ color: #999999;
+ }
+
+td.text {
+ width: 100%;
+ }
+.text p {
+ margin: 0;
+ padding: 0 0 0 .5em;
+ border-left: 2px solid #ffffff;
+ white-space: nowrap;
+ }
+
+.text p.mis {
+ background: #ffdddd;
+ border-left: 2px solid #ff0000;
+ }
+.text p.run, .text p.run.hide_par {
+ background: #ddffdd;
+ border-left: 2px solid #00ff00;
+ }
+.text p.exc {
+ background: #eeeeee;
+ border-left: 2px solid #808080;
+ }
+.text p.par, .text p.par.hide_run {
+ background: #ffffaa;
+ border-left: 2px solid #eeee99;
+ }
+.text p.hide_run, .text p.hide_exc, .text p.hide_mis, .text p.hide_par,
+.text p.hide_run.hide_par {
+ background: inherit;
+ }
+
+.text span.annotate {
+ font-family: georgia;
+ font-style: italic;
+ color: #666;
+ float: right;
+ padding-right: .5em;
+ }
+.text p.hide_par span.annotate {
+ display: none;
+ }
+
+/* Syntax coloring */
+.text .com {
+ color: green;
+ font-style: italic;
+ line-height: 1px;
+ }
+.text .key {
+ font-weight: bold;
+ line-height: 1px;
+ }
+.text .str {
+ color: #000080;
+ }
+
+/* index styles */
+#index td, #index th {
+ text-align: right;
+ width: 5em;
+ padding: .25em .5em;
+ border-bottom: 1px solid #eee;
+ }
+#index th {
+ font-style: italic;
+ color: #333;
+ border-bottom: 1px solid #ccc;
+ cursor: pointer;
+ }
+#index th:hover {
+ background: #eee;
+ border-bottom: 1px solid #999;
+ }
+#index td.left, #index th.left {
+ padding-left: 0;
+ }
+#index td.right, #index th.right {
+ padding-right: 0;
+ }
+#index th.headerSortDown, #index th.headerSortUp {
+ border-bottom: 1px solid #000;
+ }
+#index td.name, #index th.name {
+ text-align: left;
+ width: auto;
+ }
+#index td.name a {
+ text-decoration: none;
+ color: #000;
+ }
+#index td.name a:hover {
+ text-decoration: underline;
+ color: #000;
+ }
+#index tr.total {
+ }
+#index tr.total td {
+ font-weight: bold;
+ border-top: 1px solid #ccc;
+ border-bottom: none;
+ }
+#index tr.file:hover {
+ background: #eeeeee;
+ }
diff --git a/test/farm/html/gold_unicode/index.html b/test/farm/html/gold_unicode/index.html
new file mode 100644
index 00000000..9ba1bb39
--- /dev/null
+++ b/test/farm/html/gold_unicode/index.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Coverage report</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.tablesorter.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.index_ready);
+ </script>
+</head>
+<body id='indexfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+ <p class='legend'>Hot-keys on this page</p>
+ <div>
+ <p class='keyhelp'>
+ <span class='key'>n</span>
+ <span class='key'>s</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+
+ <span class='key'>c</span> &nbsp; change column sorting
+ </p>
+ </div>
+</div>
+
+<div id='index'>
+ <table class='index'>
+ <thead>
+
+ <tr class='tablehead' title='Click to sort'>
+ <th class='name left headerSortDown shortkey_n'>Module</th>
+ <th class='shortkey_s'>statements</th>
+ <th class='shortkey_m'>missing</th>
+ <th class='shortkey_x'>excluded</th>
+
+ <th class='right shortkey_c'>coverage</th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr class='total'>
+ <td class='name left'>Total</td>
+ <td>1</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr class='file'>
+ <td class='name left'><a href='unicode.html'>unicode</a></td>
+ <td>1</td>
+ <td>0</td>
+ <td>0</td>
+
+ <td class='right'>100%</td>
+ </tr>
+
+ </tbody>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5.1a0'>coverage.py v3.5.1a0</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_unicode/unicode.html b/test/farm/html/gold_unicode/unicode.html
new file mode 100644
index 00000000..518a59a1
--- /dev/null
+++ b/test/farm/html/gold_unicode/unicode.html
@@ -0,0 +1,91 @@
+<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+
+
+ <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <title>Coverage for unicode: 100%</title>
+ <link rel='stylesheet' href='style.css' type='text/css'>
+ <script type='text/javascript' src='jquery-1.4.3.min.js'></script>
+ <script type='text/javascript' src='jquery.hotkeys.js'></script>
+ <script type='text/javascript' src='jquery.isonscreen.js'></script>
+ <script type='text/javascript' src='coverage_html.js'></script>
+ <script type='text/javascript' charset='utf-8'>
+ jQuery(document).ready(coverage.pyfile_ready);
+ </script>
+</head>
+<body id='pyfile'>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage for <b>unicode</b> :
+ <span class='pc_cov'>100%</span>
+ </h1>
+ <img id='keyboard_icon' src='keybd_closed.png'>
+ <h2 class='stats'>
+ 1 statements
+ <span class='run hide_run shortkey_r' onclick='coverage.toggle_lines(this, "run")'>1 run</span>
+ <span class='mis shortkey_m' onclick='coverage.toggle_lines(this, "mis")'>0 missing</span>
+ <span class='exc shortkey_x' onclick='coverage.toggle_lines(this, "exc")'>0 excluded</span>
+
+ </h2>
+ </div>
+</div>
+
+<div class='help_panel'>
+ <img id='panel_icon' src='keybd_open.png'>
+<p class='legend'>Hot-keys on this page</p>
+ <div>
+<p class='keyhelp'>
+ <span class='key'>r</span>
+ <span class='key'>m</span>
+ <span class='key'>x</span>
+ <span class='key'>p</span> &nbsp; toggle line displays
+ </p>
+<p class='keyhelp'>
+ <span class='key'>j</span>
+ <span class='key'>k</span> &nbsp; next/prev highlighted chunk
+ </p>
+<p class='keyhelp'>
+ <span class='key'>0</span> &nbsp; (zero) top of page
+ </p>
+<p class='keyhelp'>
+ <span class='key'>1</span> &nbsp; (one) first highlighted chunk
+ </p>
+ </div>
+</div>
+
+<div id='source'>
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+<p id='n1' class='pln'><a href='#n1'>1</a></p>
+<p id='n2' class='pln'><a href='#n2'>2</a></p>
+<p id='n3' class='pln'><a href='#n3'>3</a></p>
+<p id='n4' class='stm run hide_run'><a href='#n4'>4</a></p>
+<p id='n5' class='pln'><a href='#n5'>5</a></p>
+
+ </td>
+ <td class='text' valign='top'>
+<p id='t1' class='pln'><span class='com'># A python source file with exotic characters</span><span class='strut'>&nbsp;</span></p>
+<p id='t2' class='pln'><span class='com'># -*- coding: utf-8 -*-</span><span class='strut'>&nbsp;</span></p>
+<p id='t3' class='pln'><span class='strut'>&nbsp;</span></p>
+<p id='t4' class='stm run hide_run'><span class='nam'>upside_down</span> <span class='op'>=</span> <span class='str'>&quot;&#654;d&#729;&#477;b&#592;&#633;&#477;&#652;o&#596;&quot;</span><span class='strut'>&nbsp;</span></p>
+<p id='t5' class='stm run hide_run'><span class='nam'>surrogate</span> <span class='op'>=</span> <span class='str'>&quot;db40,dd00: x&#56128;&#56576; &#917760;&quot;</span><span class='strut'>&nbsp;</span></p>
+
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='index.html'>&#xab; index</a> &nbsp; &nbsp; <a class='nav' href='http://nedbatchelder.com/code/coverage/3.5.1a0'>coverage.py v3.5.1a0</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/test/farm/html/gold_x_xml/coverage.xml b/test/farm/html/gold_x_xml/coverage.xml
index d558f5d7..912112f2 100644
--- a/test/farm/html/gold_x_xml/coverage.xml
+++ b/test/farm/html/gold_x_xml/coverage.xml
@@ -4,7 +4,7 @@
<coverage branch-rate="0" line-rate="0.6667" timestamp="1253972570431" version="3.1b1">
<!-- Generated by coverage.py: http://nedbatchelder.com/code/coverage/VER -->
<packages>
- <package branch-rate="0" complexity="0" line-rate="0.6667" name=".">
+ <package branch-rate="0" complexity="0" line-rate="0.6667" name="">
<classes>
<class branch-rate="0" complexity="0" filename="a.py" line-rate="0.6667" name="a">
<methods/>
diff --git a/test/farm/html/gold_y_xml_branch/coverage.xml b/test/farm/html/gold_y_xml_branch/coverage.xml
index f7bf0b89..ecbe0073 100644
--- a/test/farm/html/gold_y_xml_branch/coverage.xml
+++ b/test/farm/html/gold_y_xml_branch/coverage.xml
@@ -4,7 +4,7 @@
<coverage branch-rate="0.5" line-rate="0.8" timestamp="1259288252325" version="3.2b4">
<!-- Generated by coverage.py: http://nedbatchelder.com/code/coverage/VER -->
<packages>
- <package branch-rate="0.5" complexity="0" line-rate="0.8" name=".">
+ <package branch-rate="0.5" complexity="0" line-rate="0.8" name="">
<classes>
<class branch-rate="0.5" complexity="0" filename="y.py" line-rate="0.8" name="y">
<methods/>
diff --git a/test/farm/html/run_b_branch.py b/test/farm/html/run_b_branch.py
index f129e436..761d9662 100644
--- a/test/farm/html/run_b_branch.py
+++ b/test/farm/html/run_b_branch.py
@@ -1,5 +1,5 @@
def html_it():
- """Run coverage with branches and make an HTML report for a."""
+ """Run coverage with branches and make an HTML report for b."""
import coverage
cov = coverage.coverage(branch=True)
cov.start()
@@ -15,14 +15,14 @@ compare("gold_b_branch", "html_b_branch", size_within=10, file_pattern="*.html")
contains("html_b_branch/b.html",
"<span class='key'>if</span> <span class='nam'>x</span> <span class='op'>&lt;</span> <span class='num'>2</span>",
"&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span>",
- "<span class='pc_cov'>76%</span>",
+ "<span class='pc_cov'>70%</span>",
"<span class='annotate' title='no jump to this line number'>8</span>",
"<span class='annotate' title='no jump to this line number'>exit</span>",
- "<span class='annotate' title='no jumps to these line numbers'>25&nbsp;&nbsp; 26</span>",
+ "<span class='annotate' title='no jumps to these line numbers'>23&nbsp;&nbsp; 25</span>",
)
contains("html_b_branch/index.html",
"<a href='b.html'>b</a>",
- "<span class='pc_cov'>76%</span>"
+ "<span class='pc_cov'>70%</span>"
)
clean("html_b_branch")
diff --git a/test/farm/html/run_bom.py b/test/farm/html/run_bom.py
new file mode 100644
index 00000000..918ad784
--- /dev/null
+++ b/test/farm/html/run_bom.py
@@ -0,0 +1,21 @@
+import sys
+
+def html_it():
+ """Run coverage and make an HTML report for bom.py."""
+ import coverage
+ cov = coverage.coverage()
+ cov.start()
+ import bom
+ cov.stop()
+ cov.html_report(bom, directory="../html_bom")
+
+runfunc(html_it, rundir="src")
+
+# HTML files will change often. Check that the sizes are reasonable,
+# and check that certain key strings are in the output.
+compare("gold_bom", "html_bom", size_within=10, file_pattern="*.html")
+contains("html_bom/bom.html",
+ "<span class='str'>&quot;3&#215;4 = 12, &#247;2 = 6&#177;0&quot;</span>",
+ )
+
+clean("html_bom")
diff --git a/test/farm/html/run_isolatin1.py b/test/farm/html/run_isolatin1.py
new file mode 100644
index 00000000..9f4b8690
--- /dev/null
+++ b/test/farm/html/run_isolatin1.py
@@ -0,0 +1,21 @@
+import sys
+
+def html_it():
+ """Run coverage and make an HTML report for isolatin1.py."""
+ import coverage
+ cov = coverage.coverage()
+ cov.start()
+ import isolatin1
+ cov.stop()
+ cov.html_report(isolatin1, directory="../html_isolatin1")
+
+runfunc(html_it, rundir="src")
+
+# HTML files will change often. Check that the sizes are reasonable,
+# and check that certain key strings are in the output.
+compare("gold_isolatin1", "html_isolatin1", size_within=10, file_pattern="*.html")
+contains("html_isolatin1/isolatin1.html",
+ "<span class='str'>&quot;3&#215;4 = 12, &#247;2 = 6&#177;0&quot;</span>",
+ )
+
+clean("html_isolatin1")
diff --git a/test/farm/html/run_partial.py b/test/farm/html/run_partial.py
new file mode 100644
index 00000000..0ef8589c
--- /dev/null
+++ b/test/farm/html/run_partial.py
@@ -0,0 +1,32 @@
+import sys
+
+def html_it():
+ """Run coverage and make an HTML report for partial."""
+ import coverage
+ cov = coverage.coverage(branch=True)
+ cov.start()
+ import partial
+ cov.stop()
+ cov.html_report(partial, directory="../html_partial")
+
+runfunc(html_it, rundir="src")
+
+# HTML files will change often. Check that the sizes are reasonable,
+# and check that certain key strings are in the output.
+compare("gold_partial", "html_partial", size_within=10, file_pattern="*.html")
+contains("html_partial/partial.html",
+ "<p id='t5' class='stm run hide_run'>",
+ "<p id='t8' class='stm run hide_run'>",
+ "<p id='t11' class='stm run hide_run'>",
+ # The "if 0" and "if 1" statements are optimized away.
+ "<p id='t14' class='pln'>",
+ )
+contains("html_partial/index.html",
+ "<a href='partial.html'>partial</a>",
+ )
+if sys.version_info >= (2, 4):
+ contains("html_partial/index.html",
+ "<span class='pc_cov'>100%</span>"
+ )
+
+clean("html_partial")
diff --git a/test/farm/html/run_styled.py b/test/farm/html/run_styled.py
new file mode 100644
index 00000000..3a212957
--- /dev/null
+++ b/test/farm/html/run_styled.py
@@ -0,0 +1,28 @@
+def html_it():
+ """Run coverage and make an HTML report for a."""
+ import coverage
+ cov = coverage.coverage()
+ cov.start()
+ import a
+ cov.stop()
+ cov.html_report(a, directory="../html_styled", extra_css="extra.css")
+
+runfunc(html_it, rundir="src")
+
+# HTML files will change often. Check that the sizes are reasonable,
+# and check that certain key strings are in the output.
+compare("gold_styled", "html_styled", size_within=10, file_pattern="*.html")
+compare("gold_styled", "html_styled", size_within=10, file_pattern="*.css")
+contains("html_styled/a.html",
+ "<link rel='stylesheet' href='extra.css' type='text/css'>",
+ "<span class='key'>if</span> <span class='num'>1</span> <span class='op'>&lt;</span> <span class='num'>2</span>",
+ "&nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span>",
+ "<span class='pc_cov'>67%</span>"
+ )
+contains("html_styled/index.html",
+ "<link rel='stylesheet' href='extra.css' type='text/css'>",
+ "<a href='a.html'>a</a>",
+ "<span class='pc_cov'>67%</span>"
+ )
+
+clean("html_styled")
diff --git a/test/farm/html/run_unicode.py b/test/farm/html/run_unicode.py
new file mode 100644
index 00000000..6ed44660
--- /dev/null
+++ b/test/farm/html/run_unicode.py
@@ -0,0 +1,30 @@
+import sys
+
+def html_it():
+ """Run coverage and make an HTML report for unicode.py."""
+ import coverage
+ cov = coverage.coverage()
+ cov.start()
+ import unicode
+ cov.stop()
+ cov.html_report(unicode, directory="../html_unicode")
+
+runfunc(html_it, rundir="src")
+
+# HTML files will change often. Check that the sizes are reasonable,
+# and check that certain key strings are in the output.
+compare("gold_unicode", "html_unicode", size_within=10, file_pattern="*.html")
+contains("html_unicode/unicode.html",
+ "<span class='str'>&quot;&#654;d&#729;&#477;b&#592;&#633;&#477;&#652;o&#596;&quot;</span>",
+ )
+
+if sys.maxunicode == 65535:
+ contains("html_unicode/unicode.html",
+ "<span class='str'>&quot;db40,dd00: x&#56128;&#56576;&quot;</span>",
+ )
+else:
+ contains("html_unicode/unicode.html",
+ "<span class='str'>&quot;db40,dd00: x&#917760;&quot;</span>",
+ )
+
+clean("html_unicode")
diff --git a/test/farm/html/src/b.py b/test/farm/html/src/b.py
index dffdd50f..3bf73a9f 100644
--- a/test/farm/html/src/b.py
+++ b/test/farm/html/src/b.py
@@ -16,13 +16,14 @@ def two(x):
two(1)
-def three_way():
- # for-else can be a three-way branch.
- for i in range(10):
- if i == 3:
- break
- else:
- return 23
- return 17
+def three():
+ try:
+ # This if has two branches, *neither* one taken.
+ if name_error_this_variable_doesnt_exist:
+ a = 1
+ else:
+ a = 2
+ except:
+ pass
-three_way()
+three()
diff --git a/test/farm/html/src/bom.py b/test/farm/html/src/bom.py
new file mode 100644
index 00000000..2db8b717
--- /dev/null
+++ b/test/farm/html/src/bom.py
@@ -0,0 +1,11 @@
+# A python source file in utf-8, with BOM
+math = "3×4 = 12, ÷2 = 6±0"
+
+import sys
+
+if sys.version_info >= (3, 0):
+ assert len(math) == 18
+ assert len(math.encode('utf-8')) == 21
+else:
+ assert len(math) == 21
+ assert len(math.decode('utf-8')) == 18
diff --git a/test/farm/html/src/coverage.xml b/test/farm/html/src/coverage.xml
index bc517328..128cf750 100644
--- a/test/farm/html/src/coverage.xml
+++ b/test/farm/html/src/coverage.xml
@@ -4,7 +4,7 @@
<coverage branch-rate="0.0" line-rate="0.666666666667" timestamp="1263087779313" version="3.3a1">
<!-- Generated by coverage.py: http://nedbatchelder.com/code/coverage -->
<packages>
- <package branch-rate="0.0" complexity="0.0" line-rate="0.666666666667" name=".">
+ <package branch-rate="0.0" complexity="0.0" line-rate="0.666666666667" name="">
<classes>
<class branch-rate="0.0" complexity="0.0" filename="a.py" line-rate="0.666666666667" name="a">
<methods/>
diff --git a/test/farm/html/src/extra.css b/test/farm/html/src/extra.css
new file mode 100644
index 00000000..46c41fcd
--- /dev/null
+++ b/test/farm/html/src/extra.css
@@ -0,0 +1 @@
+/* Doesn't matter what goes in here, it gets copied. */
diff --git a/test/farm/html/src/isolatin1.py b/test/farm/html/src/isolatin1.py
new file mode 100644
index 00000000..057c097b
--- /dev/null
+++ b/test/farm/html/src/isolatin1.py
@@ -0,0 +1,5 @@
+# A python source file in another encoding.
+# -*- coding: iso8859-1 -*-
+
+math = "34 = 12, 2 = 60"
+assert len(math) == 18
diff --git a/test/farm/html/src/partial.py b/test/farm/html/src/partial.py
new file mode 100644
index 00000000..8d62f5c5
--- /dev/null
+++ b/test/farm/html/src/partial.py
@@ -0,0 +1,18 @@
+# partial branches
+
+a = 3
+
+while True:
+ break
+
+while 1:
+ break
+
+while a: # pragma: no branch
+ break
+
+if 0:
+ never_happen()
+
+if 1:
+ a = 13
diff --git a/test/farm/html/src/tabbed.py b/test/farm/html/src/tabbed.py
index 4c39cafe..2035852f 100644
--- a/test/farm/html/src/tabbed.py
+++ b/test/farm/html/src/tabbed.py
@@ -5,4 +5,3 @@ if x:
if x: # look nice
b = "No spaces" # when they
c = "Done" # line up.
-
diff --git a/test/farm/html/src/unicode.py b/test/farm/html/src/unicode.py
new file mode 100644
index 00000000..f6a9a052
--- /dev/null
+++ b/test/farm/html/src/unicode.py
@@ -0,0 +1,5 @@
+# A python source file with exotic characters
+# -*- coding: utf-8 -*-
+
+upside_down = "ʎd˙ǝbɐɹǝʌoɔ"
+surrogate = "db40,dd00: x󠄀"
diff --git a/test/farm/run/run_timid.py b/test/farm/run/run_timid.py
index 3810e6db..b4f5134f 100644
--- a/test/farm/run/run_timid.py
+++ b/test/farm/run/run_timid.py
@@ -20,9 +20,8 @@ contains("out/showtraceout.txt", "timid PyTracer")
if os.environ.get('COVERAGE_TEST_TRACER', 'c') == 'c':
# If the C trace function is being tested, then regular running should have
- # the C function (shown as None in f_trace since it isn't a Python
- # function).
- contains("out/showtraceout.txt", "regular None")
+ # the C function, which registers itself as f_trace.
+ contains("out/showtraceout.txt", "regular CTracer")
else:
# If the Python trace function is being tested, then regular running will
# also show the Python function.
diff --git a/test/farm/run/src/chdir.py b/test/farm/run/src/chdir.py
index d8287ed7..6d834924 100644
--- a/test/farm/run/src/chdir.py
+++ b/test/farm/run/src/chdir.py
@@ -2,4 +2,3 @@ import os
print("Line One")
os.chdir("subdir")
print("Line Two")
-
diff --git a/test/farm/run/src/showtrace.py b/test/farm/run/src/showtrace.py
index c3b4356c..e97412e0 100644
--- a/test/farm/run/src/showtrace.py
+++ b/test/farm/run/src/showtrace.py
@@ -4,7 +4,7 @@
import sys
# Show what the trace function is. If a C-based function is used, then f_trace
-# is None.
+# may be None.
trace_fn = sys._getframe(0).f_trace
if trace_fn is None:
trace_name = "None"
@@ -13,6 +13,11 @@ else:
try:
trace_name = trace_fn.im_class.__name__
except AttributeError:
- trace_name = trace_fn.__self__.__class__.__name__
+ try:
+ trace_name = trace_fn.__self__.__class__.__name__
+ except AttributeError:
+ # A C-based function could also manifest as an f_trace value
+ # which doesn't have im_class or __self__.
+ trace_name = trace_fn.__class__.__name__
print("%s %s" % (sys.argv[1], trace_name))
diff --git a/test/js/index.html b/test/js/index.html
new file mode 100644
index 00000000..60bdb30a
--- /dev/null
+++ b/test/js/index.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Coverage.py Javascript Test Suite</title>
+ <link rel="stylesheet" href="../qunit/qunit.css" type="text/css" media="screen">
+ <script type="text/javascript" src="../../coverage/htmlfiles/jquery-1.4.3.min.js"></script>
+ <script type='text/javascript' src="../../coverage/htmlfiles/jquery.isonscreen.js"></script>
+ <script type="text/javascript" src="../../coverage/htmlfiles/coverage_html.js"></script>
+ <script type="text/javascript" src="../qunit/qunit.js"></script>
+ <script type="text/javascript" src="../qunit/jquery.tmpl.min.js"></script>
+
+ <style>
+ .r { background-color: red; }
+ .w { }
+ .b { background-color: blue; }
+ </style>
+
+ <!-- Templates for the coverage report output -->
+ <script id="fixture-template" type="text/x-jquery-tmpl">
+ <table cellspacing='0' cellpadding='0'>
+ <tr>
+ <td class='linenos' valign='top'>
+ <!-- #lineno-template goes here -->
+ </td>
+ <td class='text' valign='top'>
+ <!-- #text-template goes here -->
+ </td>
+ </tr>
+ </table>
+ </script>
+
+ <script id="lineno-template" type="text/x-jquery-tmpl">
+ <p id='n${number}' class='${klass}'><a href='#n${number}'>${number}</a></p>
+ </script>
+
+ <script id="text-template" type="text/x-jquery-tmpl">
+ <p id='t${number}' class='${klass}'>Hello, world!</p>
+ </script>
+
+ <!-- Pull in the tests -->
+ <script type="text/javascript" src="tests.js"></script>
+
+</head>
+<body>
+ <h1 id="qunit-header">Coverage.py Javascript Test Suite</h1>
+ <h2 id="qunit-banner"></h2>
+ <div id="qunit-testrunner-toolbar"></div>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests"></ol>
+ <div id="qunit-fixture"></div>
+</body>
+</html>
diff --git a/test/js/tests.js b/test/js/tests.js
new file mode 100644
index 00000000..73b4ce2b
--- /dev/null
+++ b/test/js/tests.js
@@ -0,0 +1,204 @@
+// Tests of coverage.py HTML report chunk navigation.
+/*global coverage, test, module, equals, jQuery, $ */
+
+// Test helpers
+
+function selection_is(sel) {
+ raw_selection_is(sel, true);
+}
+
+function raw_selection_is(sel, check_highlight) {
+ var beg = sel[0], end = sel[1];
+ equals(coverage.sel_begin, beg);
+ equals(coverage.sel_end, end);
+ if (check_highlight) {
+ equals(coverage.code_container().find(".highlight").length, end-beg);
+ }
+}
+
+function build_fixture(spec) {
+ var i, data;
+ $("#fixture-template").tmpl().appendTo("#qunit-fixture");
+ for (i = 0; i < spec.length; i++) {
+ data = {number: i+1, klass: spec.substr(i, 1)};
+ $("#lineno-template").tmpl(data).appendTo("#qunit-fixture .linenos");
+ $("#text-template").tmpl(data).appendTo("#qunit-fixture .text");
+ }
+ coverage.pyfile_ready(jQuery);
+}
+
+// Tests
+
+// Zero-chunk tests
+
+module("Zero-chunk navigation", {
+ setup: function () {
+ build_fixture("wwww");
+ }
+});
+
+test("set_sel defaults", function () {
+ coverage.set_sel(2);
+ equals(coverage.sel_begin, 2);
+ equals(coverage.sel_end, 3);
+});
+
+test("No first chunk to select", function () {
+ coverage.to_first_chunk();
+});
+
+// One-chunk tests
+
+$.each([
+ ['rrrrr', [1,6]],
+ ['r', [1,2]],
+ ['wwrrrr', [3,7]],
+ ['wwrrrrww', [3,7]],
+ ['rrrrww', [1,5]]
+], function (i, params) {
+
+ // Each of these tests uses a fixture with one highlighted chunks.
+ var id = params[0];
+ var c1 = params[1];
+
+ module("One-chunk navigation - " + id, {
+ setup: function () {
+ build_fixture(id);
+ }
+ });
+
+ test("First chunk", function () {
+ coverage.to_first_chunk();
+ selection_is(c1);
+ });
+
+ test("Next chunk is first chunk", function () {
+ coverage.to_next_chunk();
+ selection_is(c1);
+ });
+
+ test("There is no next chunk", function () {
+ coverage.to_first_chunk();
+ coverage.to_next_chunk();
+ selection_is(c1);
+ });
+
+ test("There is no prev chunk", function () {
+ coverage.to_first_chunk();
+ coverage.to_prev_chunk();
+ selection_is(c1);
+ });
+});
+
+// Two-chunk tests
+
+$.each([
+ ['rrwwrrrr', [1,3], [5,9]],
+ ['rb', [1,2], [2,3]],
+ ['rbbbbbbbbbb', [1,2], [2,12]],
+ ['rrrrrrrrrrb', [1,11], [11,12]],
+ ['wrrwrrrrw', [2,4], [5,9]],
+ ['rrrbbb', [1,4], [4,7]]
+], function (i, params) {
+
+ // Each of these tests uses a fixture with two highlighted chunks.
+ var id = params[0];
+ var c1 = params[1];
+ var c2 = params[2];
+
+ module("Two-chunk navigation - " + id, {
+ setup: function () {
+ build_fixture(id);
+ }
+ });
+
+ test("First chunk", function () {
+ coverage.to_first_chunk();
+ selection_is(c1);
+ });
+
+ test("Next chunk is first chunk", function () {
+ coverage.to_next_chunk();
+ selection_is(c1);
+ });
+
+ test("Move to next chunk", function () {
+ coverage.to_first_chunk();
+ coverage.to_next_chunk();
+ selection_is(c2);
+ });
+
+ test("Move to first chunk", function () {
+ coverage.to_first_chunk();
+ coverage.to_next_chunk();
+ coverage.to_first_chunk();
+ selection_is(c1);
+ });
+
+ test("Move to previous chunk", function () {
+ coverage.to_first_chunk();
+ coverage.to_next_chunk();
+ coverage.to_prev_chunk();
+ selection_is(c1);
+ });
+
+ test("Next doesn't move after last chunk", function () {
+ coverage.to_first_chunk();
+ coverage.to_next_chunk();
+ coverage.to_next_chunk();
+ selection_is(c2);
+ });
+
+ test("Prev doesn't move before first chunk", function () {
+ coverage.to_first_chunk();
+ coverage.to_next_chunk();
+ coverage.to_prev_chunk();
+ coverage.to_prev_chunk();
+ selection_is(c1);
+ });
+
+});
+
+module("Miscellaneous");
+
+test("Jump from a line selected", function () {
+ build_fixture("rrwwrr");
+ coverage.set_sel(3);
+ coverage.to_next_chunk();
+ selection_is([5,7]);
+});
+
+// Tests of select_line_or_chunk.
+
+$.each([
+ // The data for each test: a spec for the fixture to build, and an array
+ // of the selection that will be selected by select_line_or_chunk for
+ // each line in the fixture.
+ ['rrwwrr', [[1,3], [1,3], [3,4], [4,5], [5,7], [5,7]]],
+ ['rb', [[1,2], [2,3]]],
+ ['r', [[1,2]]],
+ ['w', [[1,2]]],
+ ['www', [[1,2], [2,3], [3,4]]],
+ ['wwwrrr', [[1,2], [2,3], [3,4], [4,7], [4,7], [4,7]]],
+ ['rrrwww', [[1,4], [1,4], [1,4], [4,5], [5,6], [6,7]]],
+ ['rrrbbb', [[1,4], [1,4], [1,4], [4,7], [4,7], [4,7]]]
+], function (i, params) {
+
+ // Each of these tests uses a fixture with two highlighted chunks.
+ var id = params[0];
+ var sels = params[1];
+
+ module("Select line or chunk - " + id, {
+ setup: function () {
+ build_fixture(id);
+ }
+ });
+
+ $.each(sels, function (i, sel) {
+ i++;
+ test("Select line " + i, function () {
+ coverage.select_line_or_chunk(i);
+ raw_selection_is(sel);
+ });
+ });
+});
diff --git a/test/meta_coverage.py b/test/meta_coverage.py
index 1c71abf0..ef0292ae 100644
--- a/test/meta_coverage.py
+++ b/test/meta_coverage.py
@@ -45,7 +45,7 @@ def run_tests_with_coverage():
if hasattr(mod, '__file__') and mod.__file__.startswith(covdir):
covmods[name] = mod
del sys.modules[name]
- import coverage # don't warn about re-import: pylint: disable-msg=W0404
+ import coverage # don't warn about re-import: pylint: disable=W0404
#sys.modules.update(covmods)
# Run nosetests, with the arguments from our command line.
diff --git a/test/modules/pkg1/__main__.py b/test/modules/pkg1/__main__.py
new file mode 100644
index 00000000..66ce5956
--- /dev/null
+++ b/test/modules/pkg1/__main__.py
@@ -0,0 +1,3 @@
+# Used in the tests for run_python_module
+import sys
+print("pkg1.__main__: passed %s" % sys.argv[1])
diff --git a/test/modules/pkg1/runmod2.py b/test/modules/pkg1/runmod2.py
new file mode 100644
index 00000000..b52964cb
--- /dev/null
+++ b/test/modules/pkg1/runmod2.py
@@ -0,0 +1,3 @@
+# Used in the tests for run_python_module
+import sys
+print("runmod2: passed %s" % sys.argv[1])
diff --git a/test/modules/pkg1/sub/__main__.py b/test/modules/pkg1/sub/__main__.py
new file mode 100644
index 00000000..b5be9f1c
--- /dev/null
+++ b/test/modules/pkg1/sub/__main__.py
@@ -0,0 +1,3 @@
+# Used in the tests for run_python_module
+import sys
+print("pkg1.sub.__main__: passed %s" % sys.argv[1])
diff --git a/test/modules/pkg1/sub/runmod3.py b/test/modules/pkg1/sub/runmod3.py
new file mode 100644
index 00000000..3a1ad155
--- /dev/null
+++ b/test/modules/pkg1/sub/runmod3.py
@@ -0,0 +1,3 @@
+# Used in the tests for run_python_module
+import sys
+print("runmod3: passed %s" % sys.argv[1])
diff --git a/test/modules/runmod1.py b/test/modules/runmod1.py
new file mode 100644
index 00000000..671d81ef
--- /dev/null
+++ b/test/modules/runmod1.py
@@ -0,0 +1,3 @@
+# Used in the tests for run_python_module
+import sys
+print("runmod1: passed %s" % sys.argv[1])
diff --git a/test/modules/usepkgs.py b/test/modules/usepkgs.py
index 208e3f30..93c7d904 100644
--- a/test/modules/usepkgs.py
+++ b/test/modules/usepkgs.py
@@ -1,2 +1,4 @@
import pkg1.p1a, pkg1.p1b
import pkg2.p2a, pkg2.p2b
+import othermods.othera, othermods.otherb
+import othermods.sub.osa, othermods.sub.osb
diff --git a/test/moremodules/othermods/__init__.py b/test/moremodules/othermods/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/moremodules/othermods/__init__.py
diff --git a/test/moremodules/othermods/othera.py b/test/moremodules/othermods/othera.py
new file mode 100644
index 00000000..78896928
--- /dev/null
+++ b/test/moremodules/othermods/othera.py
@@ -0,0 +1,2 @@
+o = 1
+p = 2
diff --git a/test/moremodules/othermods/otherb.py b/test/moremodules/othermods/otherb.py
new file mode 100644
index 00000000..2bd8a441
--- /dev/null
+++ b/test/moremodules/othermods/otherb.py
@@ -0,0 +1,2 @@
+q = 3
+r = 4
diff --git a/test/moremodules/othermods/sub/__init__.py b/test/moremodules/othermods/sub/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/moremodules/othermods/sub/__init__.py
diff --git a/test/moremodules/othermods/sub/osa.py b/test/moremodules/othermods/sub/osa.py
new file mode 100644
index 00000000..0139d28b
--- /dev/null
+++ b/test/moremodules/othermods/sub/osa.py
@@ -0,0 +1,2 @@
+s = 5
+t = 6
diff --git a/test/moremodules/othermods/sub/osb.py b/test/moremodules/othermods/sub/osb.py
new file mode 100644
index 00000000..b024b148
--- /dev/null
+++ b/test/moremodules/othermods/sub/osb.py
@@ -0,0 +1,2 @@
+u = 7
+v = 8
diff --git a/test/osinfo.py b/test/osinfo.py
index 04855fe6..25c3a7c6 100644
--- a/test/osinfo.py
+++ b/test/osinfo.py
@@ -45,8 +45,10 @@ elif sys.platform == 'linux2':
try:
# get pseudo file /proc/<pid>/status
t = open('/proc/%d/status' % os.getpid())
- v = t.read()
- t.close()
+ try:
+ v = t.read()
+ finally:
+ t.close()
except IOError:
return 0 # non-Linux?
# get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
diff --git a/test/qunit/jquery.tmpl.min.js b/test/qunit/jquery.tmpl.min.js
new file mode 100644
index 00000000..7438b2ca
--- /dev/null
+++ b/test/qunit/jquery.tmpl.min.js
@@ -0,0 +1,10 @@
+/*
+ * jQuery Templates Plugin 1.0.0pre
+ * http://github.com/jquery/jquery-tmpl
+ * Requires jQuery 1.4.2
+ *
+ * Copyright Software Freedom Conservancy, Inc.
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+(function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h<m;h++){c=h;k=(h>0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i<j&&!(f=a.data(h[i++],"tmplItem")));if(f&&c)g[2]=function(b){a.tmpl.afterManip(this,b,k)};r.apply(this,g)}else r.apply(this,arguments);c=0;!e&&a.tmpl.complete(b);return this}});a.extend({tmpl:function(d,h,e,c){var i,k=!c;if(k){c=p;d=a.template[d]||a.template(null,d);f={}}else if(!d){d=c.tmpl;b[c.key]=c;c.nodes=[];c.wrapped&&n(c,c.wrapped);return a(j(c,null,c.tmpl(a,c)))}if(!d)return[];if(typeof h==="function")h=h.call(c||{});e&&e.wrapped&&n(e,e.wrapped);i=a.isArray(h)?a.map(h,function(a){return a?g(e,c,d,a):null}):[g(e,c,d,h)];return k?a(j(c,null,i)):i},tmplItem:function(b){var c;if(b instanceof a)b=b[0];while(b&&b.nodeType===1&&!(c=a.data(b,"tmplItem"))&&(b=b.parentNode));return c||p},template:function(c,b){if(b){if(typeof b==="string")b=o(b);else if(b instanceof a)b=b[0]||{};if(b.nodeType)b=a.data(b,"tmpl")||a.data(b,"tmpl",o(b.innerHTML));return typeof c==="string"?(a.template[c]=b):b}return c?typeof c!=="string"?a.template(null,c):a.template[c]||a.template(null,q.test(c)?c:a(c)):null},encode:function(a){return(""+a).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(__,$1,$2);__=[];",close:"call=$item.calls();__=call._.concat($item.wrap(call,__));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else f=e=i.$1||"null";g=h(g);return"');"+j[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(f).split("$1").join(e).split("$2").join(g||i.$2||"")+"__.push('"})+"');}return __;")}function n(c,b){c._wrap=j(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function h(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,h;for(e=0,p=o.length;e<p;e++){if((k=o[e]).nodeType!==1)continue;j=k.getElementsByTagName("*");for(h=j.length-1;h>=0;h--)m(j[h]);m(k)}function m(j){var p,h=j,k,e,m;if(m=j.getAttribute(d)){while(h.parentNode&&(h=h.parentNode).nodeType===1&&!(p=h.getAttribute(d)));if(p!==m){h=h.parentNode?h.nodeType===11?0:h.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[h]||f[h]);e.key=++i;b[i]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;h=a.data(j.parentNode,"tmplItem");h=h?h.key:0}if(e){k=e;while(k&&k.key!=h){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery); \ No newline at end of file
diff --git a/test/qunit/qunit.css b/test/qunit/qunit.css
new file mode 100644
index 00000000..b3c6db52
--- /dev/null
+++ b/test/qunit/qunit.css
@@ -0,0 +1,225 @@
+/**
+ * QUnit - A JavaScript Unit Testing Framework
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2011 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * or GPL (GPL-LICENSE.txt) licenses.
+ */
+
+/** Font Family and Sizes */
+
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
+}
+
+#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
+#qunit-tests { font-size: smaller; }
+
+
+/** Resets */
+
+#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
+ margin: 0;
+ padding: 0;
+}
+
+
+/** Header */
+
+#qunit-header {
+ padding: 0.5em 0 0.5em 1em;
+
+ color: #8699a4;
+ background-color: #0d3349;
+
+ font-size: 1.5em;
+ line-height: 1em;
+ font-weight: normal;
+
+ border-radius: 15px 15px 0 0;
+ -moz-border-radius: 15px 15px 0 0;
+ -webkit-border-top-right-radius: 15px;
+ -webkit-border-top-left-radius: 15px;
+}
+
+#qunit-header a {
+ text-decoration: none;
+ color: #c2ccd1;
+}
+
+#qunit-header a:hover,
+#qunit-header a:focus {
+ color: #fff;
+}
+
+#qunit-banner {
+ height: 5px;
+}
+
+#qunit-testrunner-toolbar {
+ padding: 0.5em 0 0.5em 2em;
+ color: #5E740B;
+ background-color: #eee;
+}
+
+#qunit-userAgent {
+ padding: 0.5em 0 0.5em 2.5em;
+ background-color: #2b81af;
+ color: #fff;
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+
+
+/** Tests: Pass/Fail */
+
+#qunit-tests {
+ list-style-position: inside;
+}
+
+#qunit-tests li {
+ padding: 0.4em 0.5em 0.4em 2.5em;
+ border-bottom: 1px solid #fff;
+ list-style-position: inside;
+}
+
+#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
+ display: none;
+}
+
+#qunit-tests li strong {
+ cursor: pointer;
+}
+
+#qunit-tests li a {
+ padding: 0.5em;
+ color: #c2ccd1;
+ text-decoration: none;
+}
+#qunit-tests li a:hover,
+#qunit-tests li a:focus {
+ color: #000;
+}
+
+#qunit-tests ol {
+ margin-top: 0.5em;
+ padding: 0.5em;
+
+ background-color: #fff;
+
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+
+ box-shadow: inset 0px 2px 13px #999;
+ -moz-box-shadow: inset 0px 2px 13px #999;
+ -webkit-box-shadow: inset 0px 2px 13px #999;
+}
+
+#qunit-tests table {
+ border-collapse: collapse;
+ margin-top: .2em;
+}
+
+#qunit-tests th {
+ text-align: right;
+ vertical-align: top;
+ padding: 0 .5em 0 0;
+}
+
+#qunit-tests td {
+ vertical-align: top;
+}
+
+#qunit-tests pre {
+ margin: 0;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+#qunit-tests del {
+ background-color: #e0f2be;
+ color: #374e0c;
+ text-decoration: none;
+}
+
+#qunit-tests ins {
+ background-color: #ffcaca;
+ color: #500;
+ text-decoration: none;
+}
+
+/*** Test Counts */
+
+#qunit-tests b.counts { color: black; }
+#qunit-tests b.passed { color: #5E740B; }
+#qunit-tests b.failed { color: #710909; }
+
+#qunit-tests li li {
+ margin: 0.5em;
+ padding: 0.4em 0.5em 0.4em 0.5em;
+ background-color: #fff;
+ border-bottom: none;
+ list-style-position: inside;
+}
+
+/*** Passing Styles */
+
+#qunit-tests li li.pass {
+ color: #5E740B;
+ background-color: #fff;
+ border-left: 26px solid #C6E746;
+}
+
+#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
+#qunit-tests .pass .test-name { color: #366097; }
+
+#qunit-tests .pass .test-actual,
+#qunit-tests .pass .test-expected { color: #999999; }
+
+#qunit-banner.qunit-pass { background-color: #C6E746; }
+
+/*** Failing Styles */
+
+#qunit-tests li li.fail {
+ color: #710909;
+ background-color: #fff;
+ border-left: 26px solid #EE5757;
+}
+
+#qunit-tests > li:last-child {
+ border-radius: 0 0 15px 15px;
+ -moz-border-radius: 0 0 15px 15px;
+ -webkit-border-bottom-right-radius: 15px;
+ -webkit-border-bottom-left-radius: 15px;
+}
+
+#qunit-tests .fail { color: #000000; background-color: #EE5757; }
+#qunit-tests .fail .test-name,
+#qunit-tests .fail .module-name { color: #000000; }
+
+#qunit-tests .fail .test-actual { color: #EE5757; }
+#qunit-tests .fail .test-expected { color: green; }
+
+#qunit-banner.qunit-fail { background-color: #EE5757; }
+
+
+/** Result */
+
+#qunit-testresult {
+ padding: 0.5em 0.5em 0.5em 2.5em;
+
+ color: #2b81af;
+ background-color: #D2E0E6;
+
+ border-bottom: 1px solid white;
+}
+
+/** Fixture */
+
+#qunit-fixture {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+}
diff --git a/test/qunit/qunit.js b/test/qunit/qunit.js
new file mode 100644
index 00000000..e00cca90
--- /dev/null
+++ b/test/qunit/qunit.js
@@ -0,0 +1,1448 @@
+/**
+ * QUnit - A JavaScript Unit Testing Framework
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2011 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * or GPL (GPL-LICENSE.txt) licenses.
+ */
+
+(function(window) {
+
+var defined = {
+ setTimeout: typeof window.setTimeout !== "undefined",
+ sessionStorage: (function() {
+ try {
+ return !!sessionStorage.getItem;
+ } catch(e){
+ return false;
+ }
+ })()
+};
+
+var testId = 0;
+
+var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
+ this.name = name;
+ this.testName = testName;
+ this.expected = expected;
+ this.testEnvironmentArg = testEnvironmentArg;
+ this.async = async;
+ this.callback = callback;
+ this.assertions = [];
+};
+Test.prototype = {
+ init: function() {
+ var tests = id("qunit-tests");
+ if (tests) {
+ var b = document.createElement("strong");
+ b.innerHTML = "Running " + this.name;
+ var li = document.createElement("li");
+ li.appendChild( b );
+ li.className = "running";
+ li.id = this.id = "test-output" + testId++;
+ tests.appendChild( li );
+ }
+ },
+ setup: function() {
+ if (this.module != config.previousModule) {
+ if ( config.previousModule ) {
+ QUnit.moduleDone( {
+ name: config.previousModule,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all
+ } );
+ }
+ config.previousModule = this.module;
+ config.moduleStats = { all: 0, bad: 0 };
+ QUnit.moduleStart( {
+ name: this.module
+ } );
+ }
+
+ config.current = this;
+ this.testEnvironment = extend({
+ setup: function() {},
+ teardown: function() {}
+ }, this.moduleTestEnvironment);
+ if (this.testEnvironmentArg) {
+ extend(this.testEnvironment, this.testEnvironmentArg);
+ }
+
+ QUnit.testStart( {
+ name: this.testName
+ } );
+
+ // allow utility functions to access the current test environment
+ // TODO why??
+ QUnit.current_testEnvironment = this.testEnvironment;
+
+ try {
+ if ( !config.pollution ) {
+ saveGlobal();
+ }
+
+ this.testEnvironment.setup.call(this.testEnvironment);
+ } catch(e) {
+ QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
+ }
+ },
+ run: function() {
+ if ( this.async ) {
+ QUnit.stop();
+ }
+
+ if ( config.notrycatch ) {
+ this.callback.call(this.testEnvironment);
+ return;
+ }
+ try {
+ this.callback.call(this.testEnvironment);
+ } catch(e) {
+ fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
+ QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
+ // else next test will carry the responsibility
+ saveGlobal();
+
+ // Restart the tests if they're blocking
+ if ( config.blocking ) {
+ start();
+ }
+ }
+ },
+ teardown: function() {
+ try {
+ this.testEnvironment.teardown.call(this.testEnvironment);
+ checkPollution();
+ } catch(e) {
+ QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
+ }
+ },
+ finish: function() {
+ if ( this.expected && this.expected != this.assertions.length ) {
+ QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
+ }
+
+ var good = 0, bad = 0,
+ tests = id("qunit-tests");
+
+ config.stats.all += this.assertions.length;
+ config.moduleStats.all += this.assertions.length;
+
+ if ( tests ) {
+ var ol = document.createElement("ol");
+
+ for ( var i = 0; i < this.assertions.length; i++ ) {
+ var assertion = this.assertions[i];
+
+ var li = document.createElement("li");
+ li.className = assertion.result ? "pass" : "fail";
+ li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
+ ol.appendChild( li );
+
+ if ( assertion.result ) {
+ good++;
+ } else {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+
+ // store result when possible
+ if ( QUnit.config.reorder && defined.sessionStorage ) {
+ if (bad) {
+ sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
+ } else {
+ sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
+ }
+ }
+
+ if (bad == 0) {
+ ol.style.display = "none";
+ }
+
+ var b = document.createElement("strong");
+ b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
+
+ var a = document.createElement("a");
+ a.innerHTML = "Rerun";
+ a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
+
+ addEvent(b, "click", function() {
+ var next = b.nextSibling.nextSibling,
+ display = next.style.display;
+ next.style.display = display === "none" ? "block" : "none";
+ });
+
+ addEvent(b, "dblclick", function(e) {
+ var target = e && e.target ? e.target : window.event.srcElement;
+ if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
+ target = target.parentNode;
+ }
+ if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
+ window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
+ }
+ });
+
+ var li = id(this.id);
+ li.className = bad ? "fail" : "pass";
+ li.removeChild( li.firstChild );
+ li.appendChild( b );
+ li.appendChild( a );
+ li.appendChild( ol );
+
+ } else {
+ for ( var i = 0; i < this.assertions.length; i++ ) {
+ if ( !this.assertions[i].result ) {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+ }
+
+ try {
+ QUnit.reset();
+ } catch(e) {
+ fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
+ }
+
+ QUnit.testDone( {
+ name: this.testName,
+ failed: bad,
+ passed: this.assertions.length - bad,
+ total: this.assertions.length
+ } );
+ },
+
+ queue: function() {
+ var test = this;
+ synchronize(function() {
+ test.init();
+ });
+ function run() {
+ // each of these can by async
+ synchronize(function() {
+ test.setup();
+ });
+ synchronize(function() {
+ test.run();
+ });
+ synchronize(function() {
+ test.teardown();
+ });
+ synchronize(function() {
+ test.finish();
+ });
+ }
+ // defer when previous test run passed, if storage is available
+ var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
+ if (bad) {
+ run();
+ } else {
+ synchronize(run);
+ };
+ }
+
+};
+
+var QUnit = {
+
+ // call on start of module test to prepend name to all tests
+ module: function(name, testEnvironment) {
+ config.currentModule = name;
+ config.currentModuleTestEnviroment = testEnvironment;
+ },
+
+ asyncTest: function(testName, expected, callback) {
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = 0;
+ }
+
+ QUnit.test(testName, expected, callback, true);
+ },
+
+ test: function(testName, expected, callback, async) {
+ var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
+
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = null;
+ }
+ // is 2nd argument a testEnvironment?
+ if ( expected && typeof expected === 'object') {
+ testEnvironmentArg = expected;
+ expected = null;
+ }
+
+ if ( config.currentModule ) {
+ name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
+ }
+
+ if ( !validTest(config.currentModule + ": " + testName) ) {
+ return;
+ }
+
+ var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
+ test.module = config.currentModule;
+ test.moduleTestEnvironment = config.currentModuleTestEnviroment;
+ test.queue();
+ },
+
+ /**
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
+ */
+ expect: function(asserts) {
+ config.current.expected = asserts;
+ },
+
+ /**
+ * Asserts true.
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
+ */
+ ok: function(a, msg) {
+ a = !!a;
+ var details = {
+ result: a,
+ message: msg
+ };
+ msg = escapeHtml(msg);
+ QUnit.log(details);
+ config.current.assertions.push({
+ result: a,
+ message: msg
+ });
+ },
+
+ /**
+ * Checks that the first two arguments are equal, with an optional message.
+ * Prints out both actual and expected values.
+ *
+ * Prefered to ok( actual == expected, message )
+ *
+ * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
+ *
+ * @param Object actual
+ * @param Object expected
+ * @param String message (optional)
+ */
+ equal: function(actual, expected, message) {
+ QUnit.push(expected == actual, actual, expected, message);
+ },
+
+ notEqual: function(actual, expected, message) {
+ QUnit.push(expected != actual, actual, expected, message);
+ },
+
+ deepEqual: function(actual, expected, message) {
+ QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
+ },
+
+ notDeepEqual: function(actual, expected, message) {
+ QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
+ },
+
+ strictEqual: function(actual, expected, message) {
+ QUnit.push(expected === actual, actual, expected, message);
+ },
+
+ notStrictEqual: function(actual, expected, message) {
+ QUnit.push(expected !== actual, actual, expected, message);
+ },
+
+ raises: function(block, expected, message) {
+ var actual, ok = false;
+
+ if (typeof expected === 'string') {
+ message = expected;
+ expected = null;
+ }
+
+ try {
+ block();
+ } catch (e) {
+ actual = e;
+ }
+
+ if (actual) {
+ // we don't want to validate thrown error
+ if (!expected) {
+ ok = true;
+ // expected is a regexp
+ } else if (QUnit.objectType(expected) === "regexp") {
+ ok = expected.test(actual);
+ // expected is a constructor
+ } else if (actual instanceof expected) {
+ ok = true;
+ // expected is a validation function which returns true is validation passed
+ } else if (expected.call({}, actual) === true) {
+ ok = true;
+ }
+ }
+
+ QUnit.ok(ok, message);
+ },
+
+ start: function() {
+ config.semaphore--;
+ if (config.semaphore > 0) {
+ // don't start until equal number of stop-calls
+ return;
+ }
+ if (config.semaphore < 0) {
+ // ignore if start is called more often then stop
+ config.semaphore = 0;
+ }
+ // A slight delay, to avoid any current callbacks
+ if ( defined.setTimeout ) {
+ window.setTimeout(function() {
+ if ( config.timeout ) {
+ clearTimeout(config.timeout);
+ }
+
+ config.blocking = false;
+ process();
+ }, 13);
+ } else {
+ config.blocking = false;
+ process();
+ }
+ },
+
+ stop: function(timeout) {
+ config.semaphore++;
+ config.blocking = true;
+
+ if ( timeout && defined.setTimeout ) {
+ clearTimeout(config.timeout);
+ config.timeout = window.setTimeout(function() {
+ QUnit.ok( false, "Test timed out" );
+ QUnit.start();
+ }, timeout);
+ }
+ }
+};
+
+// Backwards compatibility, deprecated
+QUnit.equals = QUnit.equal;
+QUnit.same = QUnit.deepEqual;
+
+// Maintain internal state
+var config = {
+ // The queue of tests to run
+ queue: [],
+
+ // block until document ready
+ blocking: true,
+
+ // by default, run previously failed tests first
+ // very useful in combination with "Hide passed tests" checked
+ reorder: true,
+
+ noglobals: false,
+ notrycatch: false
+};
+
+// Load paramaters
+(function() {
+ var location = window.location || { search: "", protocol: "file:" },
+ params = location.search.slice( 1 ).split( "&" ),
+ length = params.length,
+ urlParams = {},
+ current;
+
+ if ( params[ 0 ] ) {
+ for ( var i = 0; i < length; i++ ) {
+ current = params[ i ].split( "=" );
+ current[ 0 ] = decodeURIComponent( current[ 0 ] );
+ // allow just a key to turn on a flag, e.g., test.html?noglobals
+ current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
+ urlParams[ current[ 0 ] ] = current[ 1 ];
+ if ( current[ 0 ] in config ) {
+ config[ current[ 0 ] ] = current[ 1 ];
+ }
+ }
+ }
+
+ QUnit.urlParams = urlParams;
+ config.filter = urlParams.filter;
+
+ // Figure out if we're running the tests from a server or not
+ QUnit.isLocal = !!(location.protocol === 'file:');
+})();
+
+// Expose the API as global variables, unless an 'exports'
+// object exists, in that case we assume we're in CommonJS
+if ( typeof exports === "undefined" || typeof require === "undefined" ) {
+ extend(window, QUnit);
+ window.QUnit = QUnit;
+} else {
+ extend(exports, QUnit);
+ exports.QUnit = QUnit;
+}
+
+// define these after exposing globals to keep them in these QUnit namespace only
+extend(QUnit, {
+ config: config,
+
+ // Initialize the configuration options
+ init: function() {
+ extend(config, {
+ stats: { all: 0, bad: 0 },
+ moduleStats: { all: 0, bad: 0 },
+ started: +new Date,
+ updateRate: 1000,
+ blocking: false,
+ autostart: true,
+ autorun: false,
+ filter: "",
+ queue: [],
+ semaphore: 0
+ });
+
+ var tests = id( "qunit-tests" ),
+ banner = id( "qunit-banner" ),
+ result = id( "qunit-testresult" );
+
+ if ( tests ) {
+ tests.innerHTML = "";
+ }
+
+ if ( banner ) {
+ banner.className = "";
+ }
+
+ if ( result ) {
+ result.parentNode.removeChild( result );
+ }
+
+ if ( tests ) {
+ result = document.createElement( "p" );
+ result.id = "qunit-testresult";
+ result.className = "result";
+ tests.parentNode.insertBefore( result, tests );
+ result.innerHTML = 'Running...<br/>&nbsp;';
+ }
+ },
+
+ /**
+ * Resets the test setup. Useful for tests that modify the DOM.
+ *
+ * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
+ */
+ reset: function() {
+ if ( window.jQuery ) {
+ jQuery( "#qunit-fixture" ).html( config.fixture );
+ } else {
+ var main = id( 'qunit-fixture' );
+ if ( main ) {
+ main.innerHTML = config.fixture;
+ }
+ }
+ },
+
+ /**
+ * Trigger an event on an element.
+ *
+ * @example triggerEvent( document.body, "click" );
+ *
+ * @param DOMElement elem
+ * @param String type
+ */
+ triggerEvent: function( elem, type, event ) {
+ if ( document.createEvent ) {
+ event = document.createEvent("MouseEvents");
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ elem.dispatchEvent( event );
+
+ } else if ( elem.fireEvent ) {
+ elem.fireEvent("on"+type);
+ }
+ },
+
+ // Safe object type checking
+ is: function( type, obj ) {
+ return QUnit.objectType( obj ) == type;
+ },
+
+ objectType: function( obj ) {
+ if (typeof obj === "undefined") {
+ return "undefined";
+
+ // consider: typeof null === object
+ }
+ if (obj === null) {
+ return "null";
+ }
+
+ var type = Object.prototype.toString.call( obj )
+ .match(/^\[object\s(.*)\]$/)[1] || '';
+
+ switch (type) {
+ case 'Number':
+ if (isNaN(obj)) {
+ return "nan";
+ } else {
+ return "number";
+ }
+ case 'String':
+ case 'Boolean':
+ case 'Array':
+ case 'Date':
+ case 'RegExp':
+ case 'Function':
+ return type.toLowerCase();
+ }
+ if (typeof obj === "object") {
+ return "object";
+ }
+ return undefined;
+ },
+
+ push: function(result, actual, expected, message) {
+ var details = {
+ result: result,
+ message: message,
+ actual: actual,
+ expected: expected
+ };
+
+ message = escapeHtml(message) || (result ? "okay" : "failed");
+ message = '<span class="test-message">' + message + "</span>";
+ expected = escapeHtml(QUnit.jsDump.parse(expected));
+ actual = escapeHtml(QUnit.jsDump.parse(actual));
+ var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
+ if (actual != expected) {
+ output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
+ output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
+ }
+ if (!result) {
+ var source = sourceFromStacktrace();
+ if (source) {
+ details.source = source;
+ output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeHtml(source) + '</pre></td></tr>';
+ }
+ }
+ output += "</table>";
+
+ QUnit.log(details);
+
+ config.current.assertions.push({
+ result: !!result,
+ message: output
+ });
+ },
+
+ url: function( params ) {
+ params = extend( extend( {}, QUnit.urlParams ), params );
+ var querystring = "?",
+ key;
+ for ( key in params ) {
+ querystring += encodeURIComponent( key ) + "=" +
+ encodeURIComponent( params[ key ] ) + "&";
+ }
+ return window.location.pathname + querystring.slice( 0, -1 );
+ },
+
+ // Logging callbacks; all receive a single argument with the listed properties
+ // run test/logs.html for any related changes
+ begin: function() {},
+ // done: { failed, passed, total, runtime }
+ done: function() {},
+ // log: { result, actual, expected, message }
+ log: function() {},
+ // testStart: { name }
+ testStart: function() {},
+ // testDone: { name, failed, passed, total }
+ testDone: function() {},
+ // moduleStart: { name }
+ moduleStart: function() {},
+ // moduleDone: { name, failed, passed, total }
+ moduleDone: function() {}
+});
+
+if ( typeof document === "undefined" || document.readyState === "complete" ) {
+ config.autorun = true;
+}
+
+addEvent(window, "load", function() {
+ QUnit.begin({});
+
+ // Initialize the config, saving the execution queue
+ var oldconfig = extend({}, config);
+ QUnit.init();
+ extend(config, oldconfig);
+
+ config.blocking = false;
+
+ var userAgent = id("qunit-userAgent");
+ if ( userAgent ) {
+ userAgent.innerHTML = navigator.userAgent;
+ }
+ var banner = id("qunit-header");
+ if ( banner ) {
+ banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' +
+ '<label><input name="noglobals" type="checkbox"' + ( config.noglobals ? ' checked="checked"' : '' ) + '>noglobals</label>' +
+ '<label><input name="notrycatch" type="checkbox"' + ( config.notrycatch ? ' checked="checked"' : '' ) + '>notrycatch</label>';
+ addEvent( banner, "change", function( event ) {
+ var params = {};
+ params[ event.target.name ] = event.target.checked ? true : undefined;
+ window.location = QUnit.url( params );
+ });
+ }
+
+ var toolbar = id("qunit-testrunner-toolbar");
+ if ( toolbar ) {
+ var filter = document.createElement("input");
+ filter.type = "checkbox";
+ filter.id = "qunit-filter-pass";
+ addEvent( filter, "click", function() {
+ var ol = document.getElementById("qunit-tests");
+ if ( filter.checked ) {
+ ol.className = ol.className + " hidepass";
+ } else {
+ var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
+ ol.className = tmp.replace(/ hidepass /, " ");
+ }
+ if ( defined.sessionStorage ) {
+ if (filter.checked) {
+ sessionStorage.setItem("qunit-filter-passed-tests", "true");
+ } else {
+ sessionStorage.removeItem("qunit-filter-passed-tests");
+ }
+ }
+ });
+ if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
+ filter.checked = true;
+ var ol = document.getElementById("qunit-tests");
+ ol.className = ol.className + " hidepass";
+ }
+ toolbar.appendChild( filter );
+
+ var label = document.createElement("label");
+ label.setAttribute("for", "qunit-filter-pass");
+ label.innerHTML = "Hide passed tests";
+ toolbar.appendChild( label );
+ }
+
+ var main = id('qunit-fixture');
+ if ( main ) {
+ config.fixture = main.innerHTML;
+ }
+
+ if (config.autostart) {
+ QUnit.start();
+ }
+});
+
+function done() {
+ config.autorun = true;
+
+ // Log the last module results
+ if ( config.currentModule ) {
+ QUnit.moduleDone( {
+ name: config.currentModule,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all
+ } );
+ }
+
+ var banner = id("qunit-banner"),
+ tests = id("qunit-tests"),
+ runtime = +new Date - config.started,
+ passed = config.stats.all - config.stats.bad,
+ html = [
+ 'Tests completed in ',
+ runtime,
+ ' milliseconds.<br/>',
+ '<span class="passed">',
+ passed,
+ '</span> tests of <span class="total">',
+ config.stats.all,
+ '</span> passed, <span class="failed">',
+ config.stats.bad,
+ '</span> failed.'
+ ].join('');
+
+ if ( banner ) {
+ banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
+ }
+
+ if ( tests ) {
+ id( "qunit-testresult" ).innerHTML = html;
+ }
+
+ if ( typeof document !== "undefined" && document.title ) {
+ // show ✖ for good, ✔ for bad suite result in title
+ // use escape sequences in case file gets loaded with non-utf-8-charset
+ document.title = (config.stats.bad ? "\u2716" : "\u2714") + " " + document.title;
+ }
+
+ QUnit.done( {
+ failed: config.stats.bad,
+ passed: passed,
+ total: config.stats.all,
+ runtime: runtime
+ } );
+}
+
+function validTest( name ) {
+ var filter = config.filter,
+ run = false;
+
+ if ( !filter ) {
+ return true;
+ }
+
+ var not = filter.charAt( 0 ) === "!";
+ if ( not ) {
+ filter = filter.slice( 1 );
+ }
+
+ if ( name.indexOf( filter ) !== -1 ) {
+ return !not;
+ }
+
+ if ( not ) {
+ run = true;
+ }
+
+ return run;
+}
+
+// so far supports only Firefox, Chrome and Opera (buggy)
+// could be extended in the future to use something like https://github.com/csnover/TraceKit
+function sourceFromStacktrace() {
+ try {
+ throw new Error();
+ } catch ( e ) {
+ if (e.stacktrace) {
+ // Opera
+ return e.stacktrace.split("\n")[6];
+ } else if (e.stack) {
+ // Firefox, Chrome
+ return e.stack.split("\n")[4];
+ }
+ }
+}
+
+function escapeHtml(s) {
+ if (!s) {
+ return "";
+ }
+ s = s + "";
+ return s.replace(/[\&"<>\\]/g, function(s) {
+ switch(s) {
+ case "&": return "&amp;";
+ case "\\": return "\\\\";
+ case '"': return '\"';
+ case "<": return "&lt;";
+ case ">": return "&gt;";
+ default: return s;
+ }
+ });
+}
+
+function synchronize( callback ) {
+ config.queue.push( callback );
+
+ if ( config.autorun && !config.blocking ) {
+ process();
+ }
+}
+
+function process() {
+ var start = (new Date()).getTime();
+
+ while ( config.queue.length && !config.blocking ) {
+ if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
+ config.queue.shift()();
+ } else {
+ window.setTimeout( process, 13 );
+ break;
+ }
+ }
+ if (!config.blocking && !config.queue.length) {
+ done();
+ }
+}
+
+function saveGlobal() {
+ config.pollution = [];
+
+ if ( config.noglobals ) {
+ for ( var key in window ) {
+ config.pollution.push( key );
+ }
+ }
+}
+
+function checkPollution( name ) {
+ var old = config.pollution;
+ saveGlobal();
+
+ var newGlobals = diff( config.pollution, old );
+ if ( newGlobals.length > 0 ) {
+ ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
+ }
+
+ var deletedGlobals = diff( old, config.pollution );
+ if ( deletedGlobals.length > 0 ) {
+ ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
+ }
+}
+
+// returns a new Array with the elements that are in a but not in b
+function diff( a, b ) {
+ var result = a.slice();
+ for ( var i = 0; i < result.length; i++ ) {
+ for ( var j = 0; j < b.length; j++ ) {
+ if ( result[i] === b[j] ) {
+ result.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+function fail(message, exception, callback) {
+ if ( typeof console !== "undefined" && console.error && console.warn ) {
+ console.error(message);
+ console.error(exception);
+ console.warn(callback.toString());
+
+ } else if ( window.opera && opera.postError ) {
+ opera.postError(message, exception, callback.toString);
+ }
+}
+
+function extend(a, b) {
+ for ( var prop in b ) {
+ if ( b[prop] === undefined ) {
+ delete a[prop];
+ } else {
+ a[prop] = b[prop];
+ }
+ }
+
+ return a;
+}
+
+function addEvent(elem, type, fn) {
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, fn, false );
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, fn );
+ } else {
+ fn();
+ }
+}
+
+function id(name) {
+ return !!(typeof document !== "undefined" && document && document.getElementById) &&
+ document.getElementById( name );
+}
+
+// Test for equality any JavaScript type.
+// Discussions and reference: http://philrathe.com/articles/equiv
+// Test suites: http://philrathe.com/tests/equiv
+// Author: Philippe Rathé <prathe@gmail.com>
+QUnit.equiv = function () {
+
+ var innerEquiv; // the real equiv function
+ var callers = []; // stack to decide between skip/abort functions
+ var parents = []; // stack to avoiding loops from circular referencing
+
+ // Call the o related callback with the given arguments.
+ function bindCallbacks(o, callbacks, args) {
+ var prop = QUnit.objectType(o);
+ if (prop) {
+ if (QUnit.objectType(callbacks[prop]) === "function") {
+ return callbacks[prop].apply(callbacks, args);
+ } else {
+ return callbacks[prop]; // or undefined
+ }
+ }
+ }
+
+ var callbacks = function () {
+
+ // for string, boolean, number and null
+ function useStrictEquality(b, a) {
+ if (b instanceof a.constructor || a instanceof b.constructor) {
+ // to catch short annotaion VS 'new' annotation of a declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ return a == b;
+ } else {
+ return a === b;
+ }
+ }
+
+ return {
+ "string": useStrictEquality,
+ "boolean": useStrictEquality,
+ "number": useStrictEquality,
+ "null": useStrictEquality,
+ "undefined": useStrictEquality,
+
+ "nan": function (b) {
+ return isNaN(b);
+ },
+
+ "date": function (b, a) {
+ return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
+ },
+
+ "regexp": function (b, a) {
+ return QUnit.objectType(b) === "regexp" &&
+ a.source === b.source && // the regex itself
+ a.global === b.global && // and its modifers (gmi) ...
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline;
+ },
+
+ // - skip when the property is a method of an instance (OOP)
+ // - abort otherwise,
+ // initial === would have catch identical references anyway
+ "function": function () {
+ var caller = callers[callers.length - 1];
+ return caller !== Object &&
+ typeof caller !== "undefined";
+ },
+
+ "array": function (b, a) {
+ var i, j, loop;
+ var len;
+
+ // b could be an object literal here
+ if ( ! (QUnit.objectType(b) === "array")) {
+ return false;
+ }
+
+ len = a.length;
+ if (len !== b.length) { // safe and faster
+ return false;
+ }
+
+ //track reference to avoid circular references
+ parents.push(a);
+ for (i = 0; i < len; i++) {
+ loop = false;
+ for(j=0;j<parents.length;j++){
+ if(parents[j] === a[i]){
+ loop = true;//dont rewalk array
+ }
+ }
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ parents.pop();
+ return false;
+ }
+ }
+ parents.pop();
+ return true;
+ },
+
+ "object": function (b, a) {
+ var i, j, loop;
+ var eq = true; // unless we can proove it
+ var aProperties = [], bProperties = []; // collection of strings
+
+ // comparing constructors is more strict than using instanceof
+ if ( a.constructor !== b.constructor) {
+ return false;
+ }
+
+ // stack constructor before traversing properties
+ callers.push(a.constructor);
+ //track reference to avoid circular references
+ parents.push(a);
+
+ for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
+ loop = false;
+ for(j=0;j<parents.length;j++){
+ if(parents[j] === a[i])
+ loop = true; //don't go down the same path twice
+ }
+ aProperties.push(i); // collect a's properties
+
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ eq = false;
+ break;
+ }
+ }
+
+ callers.pop(); // unstack, we are done
+ parents.pop();
+
+ for (i in b) {
+ bProperties.push(i); // collect b's properties
+ }
+
+ // Ensures identical properties name
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
+ }
+ };
+ }();
+
+ innerEquiv = function () { // can take multiple arguments
+ var args = Array.prototype.slice.apply(arguments);
+ if (args.length < 2) {
+ return true; // end transition
+ }
+
+ return (function (a, b) {
+ if (a === b) {
+ return true; // catch the most you can
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) {
+ return false; // don't lose time with error prone cases
+ } else {
+ return bindCallbacks(a, callbacks, [b, a]);
+ }
+
+ // apply transition with (1..n) arguments
+ })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
+ };
+
+ return innerEquiv;
+
+}();
+
+/**
+ * jsDump
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
+ * Date: 5/15/2008
+ * @projectDescription Advanced and extensible data dumping for Javascript.
+ * @version 1.0.0
+ * @author Ariel Flesler
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
+ */
+QUnit.jsDump = (function() {
+ function quote( str ) {
+ return '"' + str.toString().replace(/"/g, '\\"') + '"';
+ };
+ function literal( o ) {
+ return o + '';
+ };
+ function join( pre, arr, post ) {
+ var s = jsDump.separator(),
+ base = jsDump.indent(),
+ inner = jsDump.indent(1);
+ if ( arr.join )
+ arr = arr.join( ',' + s + inner );
+ if ( !arr )
+ return pre + post;
+ return [ pre, inner + arr, base + post ].join(s);
+ };
+ function array( arr ) {
+ var i = arr.length, ret = Array(i);
+ this.up();
+ while ( i-- )
+ ret[i] = this.parse( arr[i] );
+ this.down();
+ return join( '[', ret, ']' );
+ };
+
+ var reName = /^function (\w+)/;
+
+ var jsDump = {
+ parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
+ var parser = this.parsers[ type || this.typeOf(obj) ];
+ type = typeof parser;
+
+ return type == 'function' ? parser.call( this, obj ) :
+ type == 'string' ? parser :
+ this.parsers.error;
+ },
+ typeOf:function( obj ) {
+ var type;
+ if ( obj === null ) {
+ type = "null";
+ } else if (typeof obj === "undefined") {
+ type = "undefined";
+ } else if (QUnit.is("RegExp", obj)) {
+ type = "regexp";
+ } else if (QUnit.is("Date", obj)) {
+ type = "date";
+ } else if (QUnit.is("Function", obj)) {
+ type = "function";
+ } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
+ type = "window";
+ } else if (obj.nodeType === 9) {
+ type = "document";
+ } else if (obj.nodeType) {
+ type = "node";
+ } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
+ type = "array";
+ } else {
+ type = typeof obj;
+ }
+ return type;
+ },
+ separator:function() {
+ return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
+ },
+ indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
+ if ( !this.multiline )
+ return '';
+ var chr = this.indentChar;
+ if ( this.HTML )
+ chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
+ return Array( this._depth_ + (extra||0) ).join(chr);
+ },
+ up:function( a ) {
+ this._depth_ += a || 1;
+ },
+ down:function( a ) {
+ this._depth_ -= a || 1;
+ },
+ setParser:function( name, parser ) {
+ this.parsers[name] = parser;
+ },
+ // The next 3 are exposed so you can use them
+ quote:quote,
+ literal:literal,
+ join:join,
+ //
+ _depth_: 1,
+ // This is the list of parsers, to modify them, use jsDump.setParser
+ parsers:{
+ window: '[Window]',
+ document: '[Document]',
+ error:'[ERROR]', //when no parser is found, shouldn't happen
+ unknown: '[Unknown]',
+ 'null':'null',
+ 'undefined':'undefined',
+ 'function':function( fn ) {
+ var ret = 'function',
+ name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
+ if ( name )
+ ret += ' ' + name;
+ ret += '(';
+
+ ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
+ return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
+ },
+ array: array,
+ nodelist: array,
+ arguments: array,
+ object:function( map ) {
+ var ret = [ ];
+ QUnit.jsDump.up();
+ for ( var key in map )
+ ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) );
+ QUnit.jsDump.down();
+ return join( '{', ret, '}' );
+ },
+ node:function( node ) {
+ var open = QUnit.jsDump.HTML ? '&lt;' : '<',
+ close = QUnit.jsDump.HTML ? '&gt;' : '>';
+
+ var tag = node.nodeName.toLowerCase(),
+ ret = open + tag;
+
+ for ( var a in QUnit.jsDump.DOMAttrs ) {
+ var val = node[QUnit.jsDump.DOMAttrs[a]];
+ if ( val )
+ ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
+ }
+ return ret + close + open + '/' + tag + close;
+ },
+ functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
+ var l = fn.length;
+ if ( !l ) return '';
+
+ var args = Array(l);
+ while ( l-- )
+ args[l] = String.fromCharCode(97+l);//97 is 'a'
+ return ' ' + args.join(', ') + ' ';
+ },
+ key:quote, //object calls it internally, the key part of an item in a map
+ functionCode:'[code]', //function calls it internally, it's the content of the function
+ attribute:quote, //node calls it internally, it's an html attribute value
+ string:quote,
+ date:quote,
+ regexp:literal, //regex
+ number:literal,
+ 'boolean':literal
+ },
+ DOMAttrs:{//attributes to dump from nodes, name=>realName
+ id:'id',
+ name:'name',
+ 'class':'className'
+ },
+ HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
+ indentChar:' ',//indentation unit
+ multiline:true //if true, items in a collection, are separated by a \n, else just a space.
+ };
+
+ return jsDump;
+})();
+
+// from Sizzle.js
+function getText( elems ) {
+ var ret = "", elem;
+
+ for ( var i = 0; elems[i]; i++ ) {
+ elem = elems[i];
+
+ // Get the text from text nodes and CDATA nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+ ret += elem.nodeValue;
+
+ // Traverse everything else, except comment nodes
+ } else if ( elem.nodeType !== 8 ) {
+ ret += getText( elem.childNodes );
+ }
+ }
+
+ return ret;
+};
+
+/*
+ * Javascript Diff Algorithm
+ * By John Resig (http://ejohn.org/)
+ * Modified by Chu Alan "sprite"
+ *
+ * Released under the MIT license.
+ *
+ * More Info:
+ * http://ejohn.org/projects/javascript-diff-algorithm/
+ *
+ * Usage: QUnit.diff(expected, actual)
+ *
+ * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
+ */
+QUnit.diff = (function() {
+ function diff(o, n){
+ var ns = new Object();
+ var os = new Object();
+
+ for (var i = 0; i < n.length; i++) {
+ if (ns[n[i]] == null)
+ ns[n[i]] = {
+ rows: new Array(),
+ o: null
+ };
+ ns[n[i]].rows.push(i);
+ }
+
+ for (var i = 0; i < o.length; i++) {
+ if (os[o[i]] == null)
+ os[o[i]] = {
+ rows: new Array(),
+ n: null
+ };
+ os[o[i]].rows.push(i);
+ }
+
+ for (var i in ns) {
+ if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
+ n[ns[i].rows[0]] = {
+ text: n[ns[i].rows[0]],
+ row: os[i].rows[0]
+ };
+ o[os[i].rows[0]] = {
+ text: o[os[i].rows[0]],
+ row: ns[i].rows[0]
+ };
+ }
+ }
+
+ for (var i = 0; i < n.length - 1; i++) {
+ if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
+ n[i + 1] == o[n[i].row + 1]) {
+ n[i + 1] = {
+ text: n[i + 1],
+ row: n[i].row + 1
+ };
+ o[n[i].row + 1] = {
+ text: o[n[i].row + 1],
+ row: i + 1
+ };
+ }
+ }
+
+ for (var i = n.length - 1; i > 0; i--) {
+ if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
+ n[i - 1] == o[n[i].row - 1]) {
+ n[i - 1] = {
+ text: n[i - 1],
+ row: n[i].row - 1
+ };
+ o[n[i].row - 1] = {
+ text: o[n[i].row - 1],
+ row: i - 1
+ };
+ }
+ }
+
+ return {
+ o: o,
+ n: n
+ };
+ }
+
+ return function(o, n){
+ o = o.replace(/\s+$/, '');
+ n = n.replace(/\s+$/, '');
+ var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
+
+ var str = "";
+
+ var oSpace = o.match(/\s+/g);
+ if (oSpace == null) {
+ oSpace = [" "];
+ }
+ else {
+ oSpace.push(" ");
+ }
+ var nSpace = n.match(/\s+/g);
+ if (nSpace == null) {
+ nSpace = [" "];
+ }
+ else {
+ nSpace.push(" ");
+ }
+
+ if (out.n.length == 0) {
+ for (var i = 0; i < out.o.length; i++) {
+ str += '<del>' + out.o[i] + oSpace[i] + "</del>";
+ }
+ }
+ else {
+ if (out.n[0].text == null) {
+ for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
+ str += '<del>' + out.o[n] + oSpace[n] + "</del>";
+ }
+ }
+
+ for (var i = 0; i < out.n.length; i++) {
+ if (out.n[i].text == null) {
+ str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
+ }
+ else {
+ var pre = "";
+
+ for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
+ pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
+ }
+ str += " " + out.n[i].text + nSpace[i] + pre;
+ }
+ }
+ }
+
+ return str;
+ };
+})();
+
+})(this);
diff --git a/test/test_api.py b/test/test_api.py
index 5952dfe7..c15db5ed 100644
--- a/test/test_api.py
+++ b/test/test_api.py
@@ -84,13 +84,13 @@ class SingletonApiTest(CoverageTest):
self.do_report_work("mycode4")
coverage.report()
rpt = re.sub(r"\s+", " ", self.stdout())
- self.assertTrue("mycode4 7 3 57% 4-6" in rpt)
+ self.assertIn("mycode4 7 3 57% 4-6", rpt)
class ApiTest(CoverageTest):
"""Api-oriented tests for Coverage."""
- def clean_files(self, files, *pats):
+ def clean_files(self, files, pats):
"""Remove names matching `pats` from `files`, a list of filenames."""
good = []
for f in files:
@@ -101,10 +101,11 @@ class ApiTest(CoverageTest):
good.append(f)
return good
- def listdir(self, where):
- """Like os.listdir, but exclude files we don't care about."""
- files = os.listdir(where)
- return self.clean_files(files, "*.pyc", "__pycache__")
+ def assertFiles(self, files):
+ """Assert that the files here are `files`, ignoring the usual junk."""
+ here = os.listdir(".")
+ here = self.clean_files(here, ["*.pyc", "__pycache__"])
+ self.assertSameElements(here, files)
def test_unexecuted_file(self):
cov = coverage.coverage()
@@ -176,15 +177,11 @@ class ApiTest(CoverageTest):
def test_ignore_stdlib(self):
self.make_file("mymain.py", """\
- import mymod, colorsys
+ import colorsys
a = 1
hls = colorsys.rgb_to_hls(1.0, 0.5, 0.0)
""")
- self.make_file("mymod.py", """\
- fooey = 17
- """)
-
# Measure without the stdlib.
cov1 = coverage.coverage()
self.assertEqual(cov1.config.cover_pylib, False)
@@ -212,6 +209,27 @@ class ApiTest(CoverageTest):
_, statements, missing, _ = cov2.analysis("colorsys.py")
self.assertNotEqual(statements, missing)
+ def test_include_can_measure_stdlib(self):
+ self.make_file("mymain.py", """\
+ import colorsys, random
+ a = 1
+ r, g, b = [random.random() for _ in range(3)]
+ hls = colorsys.rgb_to_hls(r, g, b)
+ """)
+
+ # Measure without the stdlib, but include colorsys.
+ cov1 = coverage.coverage(cover_pylib=False, include=["*/colorsys.py"])
+ cov1.start()
+ self.import_local_file("mymain") # pragma: recursive coverage
+ cov1.stop() # pragma: recursive coverage
+
+ # some statements were marked executed in colorsys.py
+ _, statements, missing, _ = cov1.analysis("colorsys.py")
+ self.assertNotEqual(statements, missing)
+ # but none were in random.py
+ _, statements, missing, _ = cov1.analysis("random.py")
+ self.assertEqual(statements, missing)
+
def test_exclude_list(self):
cov = coverage.coverage()
cov.clear_exclude()
@@ -220,24 +238,56 @@ class ApiTest(CoverageTest):
self.assertEqual(cov.get_exclude_list(), ["foo"])
cov.exclude("bar")
self.assertEqual(cov.get_exclude_list(), ["foo", "bar"])
- self.assertEqual(cov.exclude_re, "(foo)|(bar)")
+ self.assertEqual(cov._exclude_regex('exclude'), "(foo)|(bar)")
cov.clear_exclude()
self.assertEqual(cov.get_exclude_list(), [])
+ def test_exclude_partial_list(self):
+ cov = coverage.coverage()
+ cov.clear_exclude(which='partial')
+ self.assertEqual(cov.get_exclude_list(which='partial'), [])
+ cov.exclude("foo", which='partial')
+ self.assertEqual(cov.get_exclude_list(which='partial'), ["foo"])
+ cov.exclude("bar", which='partial')
+ self.assertEqual(cov.get_exclude_list(which='partial'), ["foo", "bar"])
+ self.assertEqual(cov._exclude_regex(which='partial'), "(foo)|(bar)")
+ cov.clear_exclude(which='partial')
+ self.assertEqual(cov.get_exclude_list(which='partial'), [])
+
+ def test_exclude_and_partial_are_separate_lists(self):
+ cov = coverage.coverage()
+ cov.clear_exclude(which='partial')
+ cov.clear_exclude(which='exclude')
+ cov.exclude("foo", which='partial')
+ self.assertEqual(cov.get_exclude_list(which='partial'), ['foo'])
+ self.assertEqual(cov.get_exclude_list(which='exclude'), [])
+ cov.exclude("bar", which='exclude')
+ self.assertEqual(cov.get_exclude_list(which='partial'), ['foo'])
+ self.assertEqual(cov.get_exclude_list(which='exclude'), ['bar'])
+ cov.exclude("p2", which='partial')
+ cov.exclude("e2", which='exclude')
+ self.assertEqual(cov.get_exclude_list(which='partial'), ['foo', 'p2'])
+ self.assertEqual(cov.get_exclude_list(which='exclude'), ['bar', 'e2'])
+ cov.clear_exclude(which='partial')
+ self.assertEqual(cov.get_exclude_list(which='partial'), [])
+ self.assertEqual(cov.get_exclude_list(which='exclude'), ['bar', 'e2'])
+ cov.clear_exclude(which='exclude')
+ self.assertEqual(cov.get_exclude_list(which='partial'), [])
+ self.assertEqual(cov.get_exclude_list(which='exclude'), [])
+
def test_datafile_default(self):
# Default data file behavior: it's .coverage
self.make_file("datatest1.py", """\
fooey = 17
""")
- self.assertSameElements(self.listdir("."), ["datatest1.py"])
+ self.assertFiles(["datatest1.py"])
cov = coverage.coverage()
cov.start()
self.import_local_file("datatest1") # pragma: recursive coverage
cov.stop() # pragma: recursive coverage
cov.save()
- self.assertSameElements(self.listdir("."),
- ["datatest1.py", ".coverage"])
+ self.assertFiles(["datatest1.py", ".coverage"])
def test_datafile_specified(self):
# You can specify the data file name.
@@ -245,14 +295,13 @@ class ApiTest(CoverageTest):
fooey = 17
""")
- self.assertSameElements(self.listdir("."), ["datatest2.py"])
+ self.assertFiles(["datatest2.py"])
cov = coverage.coverage(data_file="cov.data")
cov.start()
self.import_local_file("datatest2") # pragma: recursive coverage
cov.stop() # pragma: recursive coverage
cov.save()
- self.assertSameElements(self.listdir("."),
- ["datatest2.py", "cov.data"])
+ self.assertFiles(["datatest2.py", "cov.data"])
def test_datafile_and_suffix_specified(self):
# You can specify the data file name and suffix.
@@ -260,14 +309,13 @@ class ApiTest(CoverageTest):
fooey = 17
""")
- self.assertSameElements(self.listdir("."), ["datatest3.py"])
+ self.assertFiles(["datatest3.py"])
cov = coverage.coverage(data_file="cov.data", data_suffix="14")
cov.start()
self.import_local_file("datatest3") # pragma: recursive coverage
cov.stop() # pragma: recursive coverage
cov.save()
- self.assertSameElements(self.listdir("."),
- ["datatest3.py", "cov.data.14"])
+ self.assertFiles(["datatest3.py", "cov.data.14"])
def test_datafile_from_rcfile(self):
# You can specify the data file name in the .coveragerc file
@@ -279,15 +327,13 @@ class ApiTest(CoverageTest):
data_file = mydata.dat
""")
- self.assertSameElements(self.listdir("."),
- ["datatest4.py", ".coveragerc"])
+ self.assertFiles(["datatest4.py", ".coveragerc"])
cov = coverage.coverage()
cov.start()
self.import_local_file("datatest4") # pragma: recursive coverage
cov.stop() # pragma: recursive coverage
cov.save()
- self.assertSameElements(self.listdir("."),
- ["datatest4.py", ".coveragerc", "mydata.dat"])
+ self.assertFiles(["datatest4.py", ".coveragerc", "mydata.dat"])
def test_empty_reporting(self):
# Used to be you'd get an exception reporting on nothing...
@@ -296,17 +342,84 @@ class ApiTest(CoverageTest):
cov.report()
-class SourceOmitIncludeTest(CoverageTest):
- """Test using `source`, `omit` and `include` when measuring code."""
+class UsingModulesMixin(object):
+ """A mixin for importing modules from test/modules and test/moremodules."""
run_in_temp_dir = False
def setUp(self):
- super(SourceOmitIncludeTest, self).setUp()
+ super(UsingModulesMixin, self).setUp()
# Parent class saves and restores sys.path, we can just modify it.
- sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules'))
+ self.old_dir = os.getcwd()
+ os.chdir(self.nice_file(os.path.dirname(__file__), 'modules'))
+ sys.path.append(".")
+ sys.path.append("../moremodules")
+
+ def tearDown(self):
+ os.chdir(self.old_dir)
+ super(UsingModulesMixin, self).tearDown()
+
+
+class OmitIncludeTestsMixin(UsingModulesMixin):
+ """Test methods for coverage methods taking include and omit."""
+
+ def filenames_in(self, summary, filenames):
+ """Assert the `filenames` are in the keys of `summary`."""
+ for filename in filenames.split():
+ self.assertIn(filename, summary)
+
+ def filenames_not_in(self, summary, filenames):
+ """Assert the `filenames` are not in the keys of `summary`."""
+ for filename in filenames.split():
+ self.assertNotIn(filename, summary)
+
+ def test_nothing_specified(self):
+ result = self.coverage_usepkgs()
+ self.filenames_in(result, "p1a p1b p2a p2b othera otherb osa osb")
+ self.filenames_not_in(result, "p1c")
+ # Because there was no source= specified, we don't search for
+ # unexecuted files.
+
+ def test_include(self):
+ result = self.coverage_usepkgs(include=["*/p1a.py"])
+ self.filenames_in(result, "p1a")
+ self.filenames_not_in(result, "p1b p1c p2a p2b othera otherb osa osb")
+
+ def test_include_2(self):
+ result = self.coverage_usepkgs(include=["*a.py"])
+ self.filenames_in(result, "p1a p2a othera osa")
+ self.filenames_not_in(result, "p1b p1c p2b otherb osb")
+
+ def test_include_as_string(self):
+ result = self.coverage_usepkgs(include="*a.py")
+ self.filenames_in(result, "p1a p2a othera osa")
+ self.filenames_not_in(result, "p1b p1c p2b otherb osb")
+
+ def test_omit(self):
+ result = self.coverage_usepkgs(omit=["*/p1a.py"])
+ self.filenames_in(result, "p1b p2a p2b")
+ self.filenames_not_in(result, "p1a p1c")
+
+ def test_omit_2(self):
+ result = self.coverage_usepkgs(omit=["*a.py"])
+ self.filenames_in(result, "p1b p2b otherb osb")
+ self.filenames_not_in(result, "p1a p1c p2a othera osa")
- def coverage_usepkgs_summary(self, **kwargs):
+ def test_omit_as_string(self):
+ result = self.coverage_usepkgs(omit="*a.py")
+ self.filenames_in(result, "p1b p2b otherb osb")
+ self.filenames_not_in(result, "p1a p1c p2a othera osa")
+
+ def test_omit_and_include(self):
+ result = self.coverage_usepkgs( include=["*/p1*"], omit=["*/p1a.py"])
+ self.filenames_in(result, "p1b")
+ self.filenames_not_in(result, "p1a p1c p2a p2b")
+
+
+class SourceOmitIncludeTest(OmitIncludeTestsMixin, CoverageTest):
+ """Test using `source`, `omit` and `include` when measuring code."""
+
+ def coverage_usepkgs(self, **kwargs):
"""Run coverage on usepkgs and return the line summary.
Arguments are passed to the `coverage.coverage` constructor.
@@ -314,56 +427,89 @@ class SourceOmitIncludeTest(CoverageTest):
"""
cov = coverage.coverage(**kwargs)
cov.start()
- import usepkgs # pylint: disable-msg=F0401,W0612
+ import usepkgs # pylint: disable=F0401,W0612
cov.stop()
- return cov.data.summary()
-
- def test_nothing_specified(self):
- lines = self.coverage_usepkgs_summary()
- self.assertEqual(lines['p1a.py'], 3)
- self.assertEqual(lines['p1b.py'], 3)
- self.assertEqual(lines['p2a.py'], 3)
- self.assertEqual(lines['p2b.py'], 3)
- # Because there was no source= specified, we don't search for
- # unexecuted files.
- self.assert_('p1c.py' not in lines)
+ cov._harvest_data() # private! sshhh...
+ summary = cov.data.summary()
+ for k, v in list(summary.items()):
+ assert k.endswith(".py")
+ summary[k[:-3]] = v
+ return summary
def test_source_package(self):
- lines = self.coverage_usepkgs_summary(source=["pkg1"])
- self.assertEqual(lines['p1a.py'], 3)
- self.assertEqual(lines['p1b.py'], 3)
- self.assert_('p2a.py' not in lines)
- self.assert_('p2b.py' not in lines)
+ lines = self.coverage_usepkgs(source=["pkg1"])
+ self.filenames_in(lines, "p1a p1b")
+ self.filenames_not_in(lines, "p2a p2b othera otherb osa osb")
# Because source= was specified, we do search for unexecuted files.
- self.assertEqual(lines['p1c.py'], 0)
+ self.assertEqual(lines['p1c'], 0)
def test_source_package_dotted(self):
- lines = self.coverage_usepkgs_summary(source=["pkg1.p1b"])
- self.assert_('p1a.py' not in lines)
- self.assertEqual(lines['p1b.py'], 3)
- self.assert_('p2a.py' not in lines)
- self.assert_('p2b.py' not in lines)
- self.assert_('p1c.py' not in lines)
+ lines = self.coverage_usepkgs(source=["pkg1.p1b"])
+ self.filenames_in(lines, "p1b")
+ self.filenames_not_in(lines, "p1a p1c p2a p2b othera otherb osa osb")
- def test_include(self):
- lines = self.coverage_usepkgs_summary(include=["*/p1a.py"])
- self.assertEqual(lines['p1a.py'], 3)
- self.assert_('p1b.py' not in lines)
- self.assert_('p2a.py' not in lines)
- self.assert_('p2b.py' not in lines)
- def test_omit(self):
- lines = self.coverage_usepkgs_summary(omit=["*/p1a.py"])
- self.assert_('p1a.py' not in lines)
- self.assertEqual(lines['p1b.py'], 3)
- self.assertEqual(lines['p2a.py'], 3)
- self.assertEqual(lines['p2b.py'], 3)
+class ReportIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest):
+ """Tests of the report include/omit functionality."""
- def test_omit_and_include(self):
- lines = self.coverage_usepkgs_summary(
- include=["*/p1*"], omit=["*/p1a.py"]
- )
- self.assert_('p1a.py' not in lines)
- self.assertEqual(lines['p1b.py'], 3)
- self.assert_('p2a.py' not in lines)
- self.assert_('p2b.py' not in lines)
+ def coverage_usepkgs(self, **kwargs):
+ """Try coverage.report()."""
+ cov = coverage.coverage()
+ cov.start()
+ import usepkgs # pylint: disable=F0401,W0612
+ cov.stop()
+ report = StringIO()
+ cov.report(file=report, **kwargs)
+ return report.getvalue()
+
+
+class XmlIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest):
+ """Tests of the xml include/omit functionality.
+
+ This also takes care of the HTML and annotate include/omit, by virtue
+ of the structure of the code.
+
+ """
+
+ def coverage_usepkgs(self, **kwargs):
+ """Try coverage.xml_report()."""
+ cov = coverage.coverage()
+ cov.start()
+ import usepkgs # pylint: disable=F0401,W0612
+ cov.stop()
+ cov.xml_report(outfile="-", **kwargs)
+ return self.stdout()
+
+
+class AnalysisTest(CoverageTest):
+ """Test the numerical analysis of results."""
+ def test_many_missing_branches(self):
+ cov = coverage.coverage(branch=True)
+
+ self.make_file("missing.py", """\
+ def fun1(x):
+ if x == 1:
+ print("one")
+ else:
+ print("not one")
+ print("done") # pragma: nocover
+
+ def fun2(x):
+ print("x")
+
+ fun2(3)
+ """)
+
+ # Import the python file, executing it.
+ cov.start()
+ self.import_local_file("missing") # pragma: recursive coverage
+ cov.stop() # pragma: recursive coverage
+
+ nums = cov._analyze("missing.py").numbers
+ self.assertEqual(nums.n_files, 1)
+ self.assertEqual(nums.n_statements, 7)
+ self.assertEqual(nums.n_excluded, 1)
+ self.assertEqual(nums.n_missing, 3)
+ self.assertEqual(nums.n_branches, 2)
+ self.assertEqual(nums.n_partial_branches, 0)
+ self.assertEqual(nums.n_missing_branches, 2)
diff --git a/test/test_arcs.py b/test/test_arcs.py
index dafe0fbb..a9f7470b 100644
--- a/test/test_arcs.py
+++ b/test/test_arcs.py
@@ -143,6 +143,23 @@ class SimpleArcTest(CoverageTest):
)
+if sys.version_info >= (2, 6):
+ class WithTest(CoverageTest):
+ """Arc-measuring tests involving context managers."""
+
+ def test_with(self):
+ self.check_coverage("""\
+ def example():
+ with open("test", "w") as f: # exit
+ f.write("")
+ return 1
+
+ example()
+ """,
+ arcz=".1 .2 23 34 4. 16 6."
+ )
+
+
class LoopArcTest(CoverageTest):
"""Arc-measuring tests involving loops."""
@@ -213,15 +230,14 @@ class LoopArcTest(CoverageTest):
i += 1
assert a == 4 and i == 3
""",
- arcz=".1 12 23 34 45 36 63 57 27 7.",
- arcz_missing="27" # while loop never exits naturally.
+ arcz=".1 12 23 34 45 36 63 57 7.",
)
# With "while True", 2.x thinks it's computation, 3.x thinks it's
# constant.
if sys.version_info >= (3, 0):
- arcz = ".1 12 23 34 45 36 63 57 27 7."
+ arcz = ".1 12 23 34 45 36 63 57 7."
else:
- arcz = ".1 12 23 34 45 36 62 57 27 7."
+ arcz = ".1 12 23 27 34 45 36 62 57 7."
self.check_coverage("""\
a, i = 1, 0
while True:
@@ -232,7 +248,6 @@ class LoopArcTest(CoverageTest):
assert a == 4 and i == 3
""",
arcz=arcz,
- arcz_missing="27" # while loop never exits naturally.
)
def test_for_if_else_for(self):
@@ -262,6 +277,21 @@ class LoopArcTest(CoverageTest):
arcz_missing="26 6."
)
+ def test_for_else(self):
+ self.check_coverage("""\
+ def forelse(seq):
+ for n in seq:
+ if n > 5:
+ break
+ else:
+ print('None of the values were greater than 5')
+ print('Done')
+ forelse([1,2])
+ forelse([1,6])
+ """,
+ arcz=".1 .2 23 32 34 47 26 67 7. 18 89 9."
+ )
+
class ExceptionArcTest(CoverageTest):
"""Arc-measuring tests involving exception handling."""
@@ -420,18 +450,19 @@ class ExceptionArcTest(CoverageTest):
arcz=".1 12 23 34 3D 45 56 67 68 7A 8A A3 AB AD BC CD D.",
arcz_missing="3D AB BC CD", arcz_unpredicted="")
- def xxx_xest_finally_in_loop_2(self):
- self.check_coverage("""\
- for i in range(5):
- try:
- j = 3
- finally:
- f = 5
- g = 6
- h = 7
- """,
- arcz=".1 12 23 35 56 61 17 7.",
- arcz_missing="", arcz_unpredicted="")
+ if 0:
+ def test_finally_in_loop_2(self):
+ self.check_coverage("""\
+ for i in range(5):
+ try:
+ j = 3
+ finally:
+ f = 5
+ g = 6
+ h = 7
+ """,
+ arcz=".1 12 23 35 56 61 17 7.",
+ arcz_missing="", arcz_unpredicted="")
if sys.version_info >= (2, 5):
# Try-except-finally was new in 2.5
@@ -481,3 +512,33 @@ class MiscArcTest(CoverageTest):
assert d
""",
arcz=".1 19 9.")
+
+
+class ExcludeTest(CoverageTest):
+ """Tests of exclusions to indicate known partial branches."""
+
+ def test_default(self):
+ # A number of forms of pragma comment are accepted.
+ self.check_coverage("""\
+ a = 1
+ if a: #pragma: no branch
+ b = 3
+ c = 4
+ if c: # pragma NOBRANCH
+ d = 6
+ e = 7
+ """,
+ [1,2,3,4,5,6,7],
+ arcz=".1 12 23 24 34 45 56 57 67 7.", arcz_missing="")
+
+ def test_custom_pragmas(self):
+ self.check_coverage("""\
+ a = 1
+ while a: # [only some]
+ c = 3
+ break
+ assert c == 5-2
+ """,
+ [1,2,3,4,5],
+ partials=["only some"],
+ arcz=".1 12 23 34 45 25 5.", arcz_missing="")
diff --git a/test/test_cmdline.py b/test/test_cmdline.py
index aa72b340..eb7fe0f5 100644
--- a/test/test_cmdline.py
+++ b/test/test_cmdline.py
@@ -33,7 +33,8 @@ class CmdLineTest(CoverageTest):
"""
m = self.model_object()
ret = coverage.CoverageScript(
- _covpkg=m, _run_python_file=m.run_python_file, _help_fn=m.help_fn
+ _covpkg=m, _run_python_file=m.run_python_file,
+ _run_python_module=m.run_python_module, _help_fn=m.help_fn
).command_line(shlex.split(args))
return m, ret
@@ -250,35 +251,35 @@ class ClassicCmdLineTest(CmdLineTest):
def test_html_report(self):
# coverage -b -d DIR [-i] [-o DIR,...] [FILE1 FILE2 ...]
self.cmd_executes("-b", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-b -d dir1", self.INIT_LOAD + """\
- .html_report(directory="dir1", ignore_errors=None,
+ .html_report(directory="dir1", ignore_errors=None, title=None,
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-b -i", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=True,
+ .html_report(directory=None, ignore_errors=True, title=None,
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-b -o fooey", """\
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=["fooey"], include=None, morfs=[])
""")
self.cmd_executes("-b -o fooey,booey", """\
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=["fooey", "booey"], include=None, morfs=[])
""")
self.cmd_executes("-b mod1", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=None, include=None, morfs=["mod1"])
""")
self.cmd_executes("-b mod1 mod2 mod3", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=None, include=None, morfs=["mod1", "mod2", "mod3"])
""")
@@ -372,7 +373,7 @@ class FakeCoverageForDebugData(object):
"""Fake coverage().data.has_arcs()"""
return False
- def summary(self, fullpath): # pylint: disable-msg=W0613
+ def summary(self, fullpath): # pylint: disable=W0613
"""Fake coverage().data.summary()"""
return self._summary
@@ -446,6 +447,14 @@ class NewCmdLineTest(CmdLineTest):
self.cmd_executes_same("html --omit f,b", "-b --omit f,b")
self.cmd_executes_same("html m1", "-b m1")
self.cmd_executes_same("html m1 m2 m3", "-b m1 m2 m3")
+ self.cmd_executes("html", self.INIT_LOAD + """\
+ .html_report(ignore_errors=None, omit=None, include=None, morfs=[],
+ directory=None, title=None)
+ """)
+ self.cmd_executes("html --title=Hello_there", self.INIT_LOAD + """\
+ .html_report(ignore_errors=None, omit=None, include=None, morfs=[],
+ directory=None, title='Hello_there')
+ """)
def test_report(self):
self.cmd_executes_same("report", "-r")
@@ -521,15 +530,42 @@ class NewCmdLineTest(CmdLineTest):
.save()
""")
+ def test_run_module(self):
+ self.cmd_executes("run -m mymodule", """\
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
+ .erase()
+ .start()
+ .run_python_module('mymodule', ['mymodule'])
+ .stop()
+ .save()
+ """)
+ self.cmd_executes("run -m mymodule -qq arg1 arg2", """\
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
+ .erase()
+ .start()
+ .run_python_module('mymodule', ['mymodule', '-qq', 'arg1', 'arg2'])
+ .stop()
+ .save()
+ """)
+ self.cmd_executes("run --branch -m mymodule", """\
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=True, config_file=True, source=None, include=None, omit=None)
+ .erase()
+ .start()
+ .run_python_module('mymodule', ['mymodule'])
+ .stop()
+ .save()
+ """)
+ self.cmd_executes_same("run -m mymodule", "run --module mymodule")
+
def test_xml(self):
# coverage xml [-i] [--omit DIR,...] [FILE1 FILE2 ...]
self.cmd_executes("xml", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None, morfs=[],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml -i", self.INIT_LOAD + """\
.xml_report(ignore_errors=True, omit=None, include=None, morfs=[],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml -o myxml.foo", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None, morfs=[],
@@ -543,21 +579,21 @@ class NewCmdLineTest(CmdLineTest):
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
.xml_report(ignore_errors=None, omit=["fooey"], include=None, morfs=[],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml --omit fooey,booey", """\
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
.xml_report(ignore_errors=None, omit=["fooey", "booey"], include=None,
- morfs=[], outfile="coverage.xml")
+ morfs=[], outfile=None)
""")
self.cmd_executes("xml mod1", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None, morfs=["mod1"],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml mod1 mod2 mod3", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None,
- morfs=["mod1", "mod2", "mod3"], outfile="coverage.xml")
+ morfs=["mod1", "mod2", "mod3"], outfile=None)
""")
def test_no_arguments_at_all(self):
@@ -576,6 +612,12 @@ class CmdLineStdoutTest(CmdLineTest):
assert "Code coverage for Python." in out
assert out.count("\n") < 4
+ def test_version(self):
+ self.command_line("--version")
+ out = self.stdout()
+ assert "ersion " in out
+ assert out.count("\n") < 4
+
def test_help(self):
self.command_line("help")
out = self.stdout()
diff --git a/test/test_codeunit.py b/test/test_codeunit.py
index 7903d153..b543949c 100644
--- a/test/test_codeunit.py
+++ b/test/test_codeunit.py
@@ -8,7 +8,7 @@ from coverage.files import FileLocator
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
-# pylint: disable-msg=F0401
+# pylint: disable=F0401
# Unable to import 'aa' (No module named aa)
class CodeUnitTest(CoverageTest):
diff --git a/test/test_config.py b/test/test_config.py
index d5290584..19e37ab9 100644
--- a/test/test_config.py
+++ b/test/test_config.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
"""Test the config file handling for coverage.py"""
import os, sys
@@ -127,13 +128,29 @@ class ConfigFileTest(CoverageTest):
yet_more
precision = 3
+ partial_branches =
+ pragma:?\\s+no branch
+ partial_branches_always =
+ if 0:
+ while True:
+
+ show_missing= TruE
+
[html]
directory = c:\\tricky\\dir.somewhere
-
+ extra_css=something/extra.css
+ title = Title & nums # nums!
[xml]
output=mycov.xml
+ [paths]
+ source =
+ .
+ /home/ned/src/
+
+ other = other, /home/ned/other, c:\\Ned\\etc
+
""")
cov = coverage.coverage()
@@ -144,7 +161,7 @@ class ConfigFileTest(CoverageTest):
self.assertTrue(cov.config.parallel)
self.assertEqual(cov.get_exclude_list(),
- ["if 0:", "pragma:?\s+no cover", "another_tab"]
+ ["if 0:", r"pragma:?\s+no cover", "another_tab"]
)
self.assertTrue(cov.config.ignore_errors)
self.assertEqual(cov.config.include, ["a/", "b/"])
@@ -153,6 +170,33 @@ class ConfigFileTest(CoverageTest):
)
self.assertEqual(cov.config.precision, 3)
+ self.assertEqual(cov.config.partial_list,
+ [r"pragma:?\s+no branch"]
+ )
+ self.assertEqual(cov.config.partial_always_list,
+ ["if 0:", "while True:"]
+ )
+ self.assertTrue(cov.config.show_missing)
self.assertEqual(cov.config.html_dir, r"c:\tricky\dir.somewhere")
+ self.assertEqual(cov.config.extra_css, "something/extra.css")
+ self.assertEqual(cov.config.html_title, "Title & nums # nums!")
self.assertEqual(cov.config.xml_output, "mycov.xml")
+
+ self.assertEqual(cov.config.paths, {
+ 'source': ['.', '/home/ned/src/'],
+ 'other': ['other', '/home/ned/other', 'c:\\Ned\\etc']
+ })
+
+ if sys.version_info[:2] != (3,1):
+ def test_one(self):
+ # This sample file tries to use lots of variation of syntax...
+ self.make_file(".coveragerc", """\
+ [html]
+ title = tabblo & «ταБЬℓσ» # numbers
+ """)
+ cov = coverage.coverage()
+
+ self.assertEqual(cov.config.html_title,
+ "tabblo & «ταБЬℓσ» # numbers"
+ )
diff --git a/test/test_coverage.py b/test/test_coverage.py
index 31f3aa17..5da9cb16 100644
--- a/test/test_coverage.py
+++ b/test/test_coverage.py
@@ -140,12 +140,33 @@ class SimpleStatementTest(CoverageTest):
"""Testing simple single-line statements."""
def test_expression(self):
+ # Bare expressions as statements are tricky: some implementations
+ # optimize some of them away. All implementations seem to count
+ # the implicit return at the end as executable.
+ self.check_coverage("""\
+ 12
+ 23
+ """,
+ ([1,2],[2]), "")
+ self.check_coverage("""\
+ 12
+ 23
+ a = 3
+ """,
+ ([1,2,3],[3]), "")
self.check_coverage("""\
1 + 2
1 + \\
2
""",
- [1,2], "")
+ ([1,2], [2]), "")
+ self.check_coverage("""\
+ 1 + 2
+ 1 + \\
+ 2
+ a = 4
+ """,
+ ([1,2,4], [4]), "")
def test_assert(self):
self.check_coverage("""\
@@ -560,7 +581,7 @@ class SimpleStatementTest(CoverageTest):
c = 6
assert (a,b,c) == (1,3,6)
""",
- ([1,3,5,6,7], [1,3,4,5,6,7]), "")
+ ([1,3,6,7], [1,3,5,6,7], [1,3,4,5,6,7]), "")
class CompoundStatementTest(CoverageTest):
@@ -821,6 +842,16 @@ class CompoundStatementTest(CoverageTest):
""",
[1,2,4,5,7,9,10], "4, 7")
+ if sys.version_info >= (2, 4):
+ # In 2.4 and up, constant if's were compiled away.
+ def test_constant_if(self):
+ self.check_coverage("""\
+ if 1:
+ a = 2
+ assert a == 2
+ """,
+ [2,3], "")
+
def test_while(self):
self.check_coverage("""\
a = 3; b = 0
@@ -1134,7 +1165,7 @@ class ExcludeTest(CoverageTest):
if 0:
a = 4 # -cc
""",
- [1,3], "", ['-cc'])
+ [1,3], "", excludes=['-cc'])
def test_two_excludes(self):
self.check_coverage("""\
@@ -1146,7 +1177,7 @@ class ExcludeTest(CoverageTest):
c = 6 # -xx
assert a == 1 and b == 2
""",
- [1,3,5,7], "5", ['-cc', '-xx'])
+ [1,3,5,7], "5", excludes=['-cc', '-xx'])
def test_excluding_if_suite(self):
self.check_coverage("""\
@@ -1158,7 +1189,7 @@ class ExcludeTest(CoverageTest):
c = 6
assert a == 1 and b == 2
""",
- [1,7], "", ['if 0:'])
+ [1,7], "", excludes=['if 0:'])
def test_excluding_if_but_not_else_suite(self):
self.check_coverage("""\
@@ -1173,7 +1204,7 @@ class ExcludeTest(CoverageTest):
b = 9
assert a == 8 and b == 9
""",
- [1,8,9,10], "", ['if 0:'])
+ [1,8,9,10], "", excludes=['if 0:'])
def test_excluding_else_suite(self):
self.check_coverage("""\
@@ -1188,7 +1219,7 @@ class ExcludeTest(CoverageTest):
b = 9
assert a == 4 and b == 5 and c == 6
""",
- [1,3,4,5,6,10], "", ['#pragma: NO COVER'])
+ [1,3,4,5,6,10], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 1; b = 2
@@ -1208,7 +1239,7 @@ class ExcludeTest(CoverageTest):
b = 9
assert a == 4 and b == 5 and c == 6
""",
- [1,3,4,5,6,17], "", ['#pragma: NO COVER'])
+ [1,3,4,5,6,17], "", excludes=['#pragma: NO COVER'])
def test_excluding_elif_suites(self):
self.check_coverage("""\
@@ -1226,7 +1257,7 @@ class ExcludeTest(CoverageTest):
b = 12
assert a == 4 and b == 5 and c == 6
""",
- [1,3,4,5,6,11,12,13], "11-12", ['#pragma: NO COVER'])
+ [1,3,4,5,6,11,12,13], "11-12", excludes=['#pragma: NO COVER'])
def test_excluding_oneline_if(self):
self.check_coverage("""\
@@ -1237,7 +1268,7 @@ class ExcludeTest(CoverageTest):
foo()
""",
- [1,2,4,6], "", ["no cover"])
+ [1,2,4,6], "", excludes=["no cover"])
def test_excluding_a_colon_not_a_suite(self):
self.check_coverage("""\
@@ -1248,7 +1279,7 @@ class ExcludeTest(CoverageTest):
foo()
""",
- [1,2,4,6], "", ["no cover"])
+ [1,2,4,6], "", excludes=["no cover"])
def test_excluding_for_suite(self):
self.check_coverage("""\
@@ -1257,7 +1288,7 @@ class ExcludeTest(CoverageTest):
a += i
assert a == 15
""",
- [1,4], "", ['#pragma: NO COVER'])
+ [1,4], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
for i in [1,
@@ -1266,7 +1297,7 @@ class ExcludeTest(CoverageTest):
a += i
assert a == 15
""",
- [1,6], "", ['#pragma: NO COVER'])
+ [1,6], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
for i in [1,2,3,4,5
@@ -1276,7 +1307,7 @@ class ExcludeTest(CoverageTest):
a = 99
assert a == 1
""",
- [1,7], "", ['#pragma: NO COVER'])
+ [1,7], "", excludes=['#pragma: NO COVER'])
def test_excluding_for_else(self):
self.check_coverage("""\
@@ -1289,7 +1320,7 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 1
""",
- [1,2,3,4,5,8], "5", ['#pragma: NO COVER'])
+ [1,2,3,4,5,8], "5", excludes=['#pragma: NO COVER'])
def test_excluding_while(self):
self.check_coverage("""\
@@ -1300,7 +1331,7 @@ class ExcludeTest(CoverageTest):
b = 99
assert a == 3 and b == 0
""",
- [1,6], "", ['#pragma: NO COVER'])
+ [1,6], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 3; b = 0
while (
@@ -1311,7 +1342,7 @@ class ExcludeTest(CoverageTest):
b = 99
assert a == 3 and b == 0
""",
- [1,8], "", ['#pragma: NO COVER'])
+ [1,8], "", excludes=['#pragma: NO COVER'])
def test_excluding_while_else(self):
self.check_coverage("""\
@@ -1324,7 +1355,7 @@ class ExcludeTest(CoverageTest):
b = 123
assert a == 3 and b == 1
""",
- [1,2,3,4,5,8], "5", ['#pragma: NO COVER'])
+ [1,2,3,4,5,8], "5", excludes=['#pragma: NO COVER'])
def test_excluding_try_except(self):
self.check_coverage("""\
@@ -1335,7 +1366,7 @@ class ExcludeTest(CoverageTest):
a = 99
assert a == 1
""",
- [1,2,3,6], "", ['#pragma: NO COVER'])
+ [1,2,3,6], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
try:
@@ -1345,7 +1376,7 @@ class ExcludeTest(CoverageTest):
a = 99
assert a == 99
""",
- [1,2,3,4,5,6,7], "", ['#pragma: NO COVER'])
+ [1,2,3,4,5,6,7], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
try:
@@ -1357,7 +1388,7 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 123
""",
- [1,2,3,4,7,8,9], "", ['#pragma: NO COVER'])
+ [1,2,3,4,7,8,9], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
try:
@@ -1368,7 +1399,7 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 123
""",
- [1,2,3,7,8], "", ['#pragma: NO COVER'])
+ [1,2,3,7,8], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
try:
@@ -1380,7 +1411,7 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 99
""",
- [1,2,3,4,5,6,9], "", ['#pragma: NO COVER'])
+ [1,2,3,4,5,6,9], "", excludes=['#pragma: NO COVER'])
def test_excluding_try_except_pass(self):
self.check_coverage("""\
@@ -1391,7 +1422,7 @@ class ExcludeTest(CoverageTest):
x = 2
assert a == 1
""",
- [1,2,3,6], "", ['#pragma: NO COVER'])
+ [1,2,3,6], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
try:
@@ -1403,7 +1434,7 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 123
""",
- [1,2,3,4,7,8,9], "", ['#pragma: NO COVER'])
+ [1,2,3,4,7,8,9], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
try:
@@ -1414,7 +1445,7 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 123
""",
- [1,2,3,7,8], "", ['#pragma: NO COVER'])
+ [1,2,3,7,8], "", excludes=['#pragma: NO COVER'])
self.check_coverage("""\
a = 0
try:
@@ -1426,7 +1457,7 @@ class ExcludeTest(CoverageTest):
x = 2
assert a == 99
""",
- [1,2,3,4,5,6,9], "", ['#pragma: NO COVER'])
+ [1,2,3,4,5,6,9], "", excludes=['#pragma: NO COVER'])
def test_excluding_if_pass(self):
# From a comment on the coverage page by Michael McNeil Forbes:
@@ -1439,7 +1470,7 @@ class ExcludeTest(CoverageTest):
f()
""",
- [1,7], "", ["no cover"])
+ [1,7], "", excludes=["no cover"])
def test_excluding_function(self):
self.check_coverage("""\
@@ -1451,7 +1482,7 @@ class ExcludeTest(CoverageTest):
x = 1
assert x == 1
""",
- [6,7], "", ['#pragma: NO COVER'])
+ [6,7], "", excludes=['#pragma: NO COVER'])
def test_excluding_method(self):
self.check_coverage("""\
@@ -1465,7 +1496,7 @@ class ExcludeTest(CoverageTest):
x = Fooey()
assert x.a == 1
""",
- [1,2,3,8,9], "", ['#pragma: NO COVER'])
+ [1,2,3,8,9], "", excludes=['#pragma: NO COVER'])
def test_excluding_class(self):
self.check_coverage("""\
@@ -1479,7 +1510,7 @@ class ExcludeTest(CoverageTest):
x = 1
assert x == 1
""",
- [8,9], "", ['#pragma: NO COVER'])
+ [8,9], "", excludes=['#pragma: NO COVER'])
if sys.version_info >= (2, 4):
@@ -1683,7 +1714,7 @@ class ReportingTest(CoverageTest):
CoverageException, "No data to report.",
self.command_line, "annotate -d ann"
)
- self.assertFalse(os.path.exists("ann"))
+ self.assert_doesnt_exist("ann")
def test_no_data_to_report_on_html(self):
# Reporting with no data produces a nice message and no output dir.
@@ -1691,7 +1722,7 @@ class ReportingTest(CoverageTest):
CoverageException, "No data to report.",
self.command_line, "html -d htmlcov"
)
- self.assertFalse(os.path.exists("htmlcov"))
+ self.assert_doesnt_exist("htmlcov")
def test_no_data_to_report_on_xml(self):
# Reporting with no data produces a nice message.
diff --git a/test/test_data.py b/test/test_data.py
index 298078a2..5ad2f440 100644
--- a/test/test_data.py
+++ b/test/test_data.py
@@ -4,6 +4,7 @@ import os, sys
from coverage.backward import pickle
from coverage.data import CoverageData
+from coverage.files import PathAliases
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
@@ -23,12 +24,13 @@ ARC_DATA_3 = { 'x.py': {(1,2):None, (2,3):None}, 'y.py': {(17,23):None} }
X_PY_ARCS_3 = [(1,2), (2,3)]
Y_PY_ARCS_3 = [(17,23)]
+
class DataTest(CoverageTest):
"""Test cases for coverage.data."""
- def assert_summary(self, covdata, summary):
+ def assert_summary(self, covdata, summary, fullpath=False):
"""Check that the summary of `covdata` is `summary`."""
- self.assertEqual(covdata.summary(), summary)
+ self.assertEqual(covdata.summary(fullpath), summary)
def assert_measured_files(self, covdata, measured):
"""Check that `covdata`'s measured files are `measured`."""
@@ -120,3 +122,28 @@ class DataTest(CoverageTest):
arcs = data['arcs']
self.assertSameElements(arcs['x.py'], X_PY_ARCS_3)
self.assertSameElements(arcs['y.py'], Y_PY_ARCS_3)
+
+ def test_combining_with_aliases(self):
+ covdata1 = CoverageData()
+ covdata1.add_line_data({
+ '/home/ned/proj/src/a.py': {1:None, 2:None},
+ '/home/ned/proj/src/sub/b.py': {3:None},
+ })
+ covdata1.write(suffix='1')
+
+ covdata2 = CoverageData()
+ covdata2.add_line_data({
+ r'c:\ned\test\a.py': {4:None, 5:None},
+ r'c:\ned\test\sub\b.py': {6:None},
+ })
+ covdata2.write(suffix='2')
+
+ covdata3 = CoverageData()
+ aliases = PathAliases()
+ aliases.add("/home/ned/proj/src/", "./")
+ aliases.add(r"c:\ned\test", "./")
+ covdata3.combine_parallel_data(aliases=aliases)
+ self.assert_summary(
+ covdata3, { './a.py':4, './sub/b.py':2 }, fullpath=True
+ )
+ self.assert_measured_files(covdata3, [ './a.py', './sub/b.py' ])
diff --git a/test/test_execfile.py b/test/test_execfile.py
index 2f28a069..1c5b8024 100644
--- a/test/test_execfile.py
+++ b/test/test_execfile.py
@@ -2,7 +2,7 @@
import os, sys
-from coverage.execfile import run_python_file
+from coverage.execfile import run_python_file, run_python_module
from coverage.misc import NoSource
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
@@ -10,7 +10,7 @@ from coveragetest import CoverageTest
here = os.path.dirname(__file__)
-class RunTest(CoverageTest):
+class RunFileTest(CoverageTest):
"""Test cases for `run_python_file`."""
def test_run_python_file(self):
@@ -55,8 +55,10 @@ class RunTest(CoverageTest):
pylines = """# try newlines|print('Hello, world!')|""".split('|')
for nl in ('\n', '\r\n', '\r'):
fpy = open('nl.py', 'wb')
- fpy.write(nl.join(pylines).encode('utf-8'))
- fpy.close()
+ try:
+ fpy.write(nl.join(pylines).encode('utf-8'))
+ finally:
+ fpy.close()
run_python_file('nl.py', ['nl.py'])
self.assertEqual(self.stdout(), "Hello, world!\n"*3)
@@ -74,3 +76,42 @@ class RunTest(CoverageTest):
def test_no_such_file(self):
self.assertRaises(NoSource, run_python_file, "xyzzy.py", [])
+
+
+class RunModuleTest(CoverageTest):
+ """Test run_python_module."""
+
+ run_in_temp_dir = False
+
+ def setUp(self):
+ super(RunModuleTest, self).setUp()
+ # Parent class saves and restores sys.path, we can just modify it.
+ sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules'))
+
+ def test_runmod1(self):
+ run_python_module("runmod1", ["runmod1", "hello"])
+ self.assertEqual(self.stdout(), "runmod1: passed hello\n")
+
+ def test_runmod2(self):
+ run_python_module("pkg1.runmod2", ["runmod2", "hello"])
+ self.assertEqual(self.stdout(), "runmod2: passed hello\n")
+
+ def test_runmod3(self):
+ run_python_module("pkg1.sub.runmod3", ["runmod3", "hello"])
+ self.assertEqual(self.stdout(), "runmod3: passed hello\n")
+
+ def test_pkg1_main(self):
+ run_python_module("pkg1", ["pkg1", "hello"])
+ self.assertEqual(self.stdout(), "pkg1.__main__: passed hello\n")
+
+ def test_pkg1_sub_main(self):
+ run_python_module("pkg1.sub", ["pkg1.sub", "hello"])
+ self.assertEqual(self.stdout(), "pkg1.sub.__main__: passed hello\n")
+
+ def test_no_such_module(self):
+ self.assertRaises(NoSource, run_python_module, "i_dont_exist", [])
+ self.assertRaises(NoSource, run_python_module, "i.dont_exist", [])
+ self.assertRaises(NoSource, run_python_module, "i.dont.exist", [])
+
+ def test_no_main(self):
+ self.assertRaises(NoSource, run_python_module, "pkg2", ["pkg2", "hi"])
diff --git a/test/test_farm.py b/test/test_farm.py
index 79b345a6..f06158e4 100644
--- a/test/test_farm.py
+++ b/test/test_farm.py
@@ -3,7 +3,7 @@
import difflib, filecmp, fnmatch, glob, os, re, shutil, sys
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
-from backtest import run_command, execfile # pylint: disable-msg=W0622
+from backtest import run_command, execfile # pylint: disable=W0622
def test_farm(clean_only=False):
@@ -52,7 +52,8 @@ class FarmTestCase(object):
def addtopath(self, directory):
"""Add `directory` to the path, and return the old path."""
oldpath = sys.path[:]
- sys.path.insert(0, directory)
+ if directory is not None:
+ sys.path.insert(0, directory)
return oldpath
def restorepath(self, path):
@@ -144,6 +145,8 @@ class FarmTestCase(object):
"""
cwd = self.cd(rundir)
+ if outfile:
+ fout = open(outfile, "a+")
try:
for cmd in cmds.split("\n"):
cmd = cmd.strip()
@@ -152,10 +155,12 @@ class FarmTestCase(object):
retcode, output = run_command(cmd)
print(output.rstrip())
if outfile:
- open(outfile, "a+").write(output)
+ fout.write(output)
if retcode:
raise Exception("command exited abnormally")
finally:
+ if outfile:
+ fout.close()
self.cd(cwd)
def runfunc(self, fn, rundir="src", addtopath=None):
@@ -321,7 +326,12 @@ def main(): # pragma: no cover
clean - Clean all the output for all tests.
"""
- op = sys.argv[1]
+ op = 'help'
+ try:
+ op = sys.argv[1]
+ except IndexError:
+ pass
+
if op == 'run':
# Run the test for real.
case = FarmTestCase(sys.argv[2])
@@ -335,7 +345,7 @@ def main(): # pragma: no cover
for test in test_farm(clean_only=True):
test[0].run_fully()
else:
- print("Need an operation: run, out, clean")
+ print(main.__doc__)
# So that we can run just one farm run.py at a time.
if __name__ == '__main__':
diff --git a/test/test_files.py b/test/test_files.py
index 4ffc6ca2..5692699c 100644
--- a/test/test_files.py
+++ b/test/test_files.py
@@ -3,8 +3,9 @@
import os, sys
from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher
-from coverage.files import find_python_files
-from coverage.backward import set # pylint: disable-msg=W0622
+from coverage.files import PathAliases, find_python_files, abs_file
+from coverage.backward import set # pylint: disable=W0622
+from coverage.misc import CoverageException
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
@@ -36,6 +37,17 @@ class FileLocatorTest(CoverageTest):
self.assertEqual(fl.relative_filename(a1), "file1.py")
self.assertEqual(fl.relative_filename(a2), a2)
+ def test_filepath_contains_absolute_prefix_twice(self):
+ # https://bitbucket.org/ned/coveragepy/issue/194
+ # Build a path that has two pieces matching the absolute path prefix.
+ # Technically, this test doesn't do that on Windows, but drive
+ # letters make that impractical to acheive.
+ fl = FileLocator()
+ d = abs_file(os.curdir)
+ trick = os.path.splitdrive(d)[1].lstrip(os.path.sep)
+ rel = os.path.join('sub', trick, 'file1.py')
+ self.assertEqual(fl.relative_filename(abs_file(rel)), rel)
+
class MatcherTest(CoverageTest):
"""Tests of file matchers."""
@@ -72,20 +84,87 @@ class MatcherTest(CoverageTest):
self.assertFalse(fnm.match(fl.canonical_filename(file5)))
+class PathAliasesTest(CoverageTest):
+ """Tests for coverage/files.py:PathAliases"""
+
+ def test_noop(self):
+ aliases = PathAliases()
+ self.assertEqual(aliases.map('/ned/home/a.py'), '/ned/home/a.py')
+
+ def test_nomatch(self):
+ aliases = PathAliases()
+ aliases.add('/home/*/src', './mysrc')
+ self.assertEqual(aliases.map('/home/foo/a.py'), '/home/foo/a.py')
+
+ def test_wildcard(self):
+ aliases = PathAliases()
+ aliases.add('/ned/home/*/src', './mysrc')
+ self.assertEqual(aliases.map('/ned/home/foo/src/a.py'), './mysrc/a.py')
+ aliases = PathAliases()
+ aliases.add('/ned/home/*/src/', './mysrc')
+ self.assertEqual(aliases.map('/ned/home/foo/src/a.py'), './mysrc/a.py')
+
+ def test_no_accidental_match(self):
+ aliases = PathAliases()
+ aliases.add('/home/*/src', './mysrc')
+ self.assertEqual(aliases.map('/home/foo/srcetc'), '/home/foo/srcetc')
+
+ def test_multiple_patterns(self):
+ aliases = PathAliases()
+ aliases.add('/home/*/src', './mysrc')
+ aliases.add('/lib/*/libsrc', './mylib')
+ self.assertEqual(aliases.map('/home/foo/src/a.py'), './mysrc/a.py')
+ self.assertEqual(aliases.map('/lib/foo/libsrc/a.py'), './mylib/a.py')
+
+ def test_cant_have_wildcard_at_end(self):
+ aliases = PathAliases()
+ self.assertRaisesRegexp(
+ CoverageException, "Pattern must not end with wildcards.",
+ aliases.add, "/ned/home/*", "fooey"
+ )
+ self.assertRaisesRegexp(
+ CoverageException, "Pattern must not end with wildcards.",
+ aliases.add, "/ned/home/*/", "fooey"
+ )
+ self.assertRaisesRegexp(
+ CoverageException, "Pattern must not end with wildcards.",
+ aliases.add, "/ned/home/*/*/", "fooey"
+ )
+
+ def test_no_accidental_munging(self):
+ aliases = PathAliases()
+ aliases.add(r'c:\Zoo\boo', 'src/')
+ aliases.add('/home/ned$', 'src/')
+ self.assertEqual(aliases.map(r'c:\Zoo\boo\foo.py'), 'src/foo.py')
+ self.assertEqual(aliases.map(r'/home/ned$/foo.py'), 'src/foo.py')
+
+ def test_paths_are_os_corrected(self):
+ aliases = PathAliases()
+ aliases.add('/home/ned/*/src', './mysrc')
+ aliases.add(r'c:\ned\src', './mysrc')
+ mapped = aliases.map(r'C:\Ned\src\sub\a.py')
+ self.assertEqual(mapped, './mysrc/sub/a.py')
+
+ aliases = PathAliases()
+ aliases.add('/home/ned/*/src', r'.\mysrc')
+ aliases.add(r'c:\ned\src', r'.\mysrc')
+ mapped = aliases.map(r'/home/ned/foo/src/sub/a.py')
+ self.assertEqual(mapped, r'.\mysrc\sub\a.py')
+
+
class FindPythonFilesTest(CoverageTest):
"""Tests of `find_python_files`."""
def test_find_python_files(self):
self.make_file("sub/a.py")
self.make_file("sub/b.py")
- self.make_file("sub/__init__.py")
self.make_file("sub/x.c") # nope: not .py
self.make_file("sub/ssub/__init__.py")
self.make_file("sub/ssub/s.py")
+ self.make_file("sub/ssub/~s.py") # nope: editor effluvia
self.make_file("sub/lab/exp.py") # nope: no __init__.py
py_files = set(find_python_files("sub"))
self.assert_same_files(py_files, [
- "sub/__init__.py", "sub/a.py", "sub/b.py",
+ "sub/a.py", "sub/b.py",
"sub/ssub/__init__.py", "sub/ssub/s.py",
])
-
diff --git a/test/test_html.py b/test/test_html.py
new file mode 100644
index 00000000..29106562
--- /dev/null
+++ b/test/test_html.py
@@ -0,0 +1,289 @@
+# -*- coding: utf-8 -*-
+"""Tests that HTML generation is awesome."""
+
+import os.path, sys
+import coverage
+from coverage.misc import NotPython
+
+sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
+from coveragetest import CoverageTest
+
+class HtmlTestHelpers(CoverageTest):
+ """Methods that help with HTML tests."""
+
+ def create_initial_files(self):
+ """Create the source files we need to run these tests."""
+ self.make_file("main_file.py", """\
+ import helper1, helper2
+ helper1.func1(12)
+ helper2.func2(12)
+ """)
+ self.make_file("helper1.py", """\
+ def func1(x):
+ if x % 2:
+ print("odd")
+ """)
+ self.make_file("helper2.py", """\
+ def func2(x):
+ print("x is %d" % x)
+ """)
+
+ def run_coverage(self, covargs=None, htmlargs=None):
+ """Run coverage on main_file.py, and create an HTML report."""
+ self.clean_local_file_imports()
+ cov = coverage.coverage(**(covargs or {}))
+ cov.start()
+ self.import_local_file("main_file")
+ cov.stop()
+ cov.html_report(**(htmlargs or {}))
+
+ def remove_html_files(self):
+ """Remove the HTML files created as part of the HTML report."""
+ os.remove("htmlcov/index.html")
+ os.remove("htmlcov/main_file.html")
+ os.remove("htmlcov/helper1.html")
+ os.remove("htmlcov/helper2.html")
+
+
+class HtmlDeltaTest(HtmlTestHelpers, CoverageTest):
+ """Tests of the HTML delta speed-ups."""
+
+ def setUp(self):
+ super(HtmlDeltaTest, self).setUp()
+
+ # At least one of our tests monkey-patches the version of coverage,
+ # so grab it here to restore it later.
+ self.real_coverage_version = coverage.__version__
+
+ self.maxDiff = None
+
+ def tearDown(self):
+ coverage.__version__ = self.real_coverage_version
+ super(HtmlDeltaTest, self).tearDown()
+
+ def test_html_created(self):
+ # Test basic HTML generation: files should be created.
+ self.create_initial_files()
+ self.run_coverage()
+
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/main_file.html")
+ self.assert_exists("htmlcov/helper1.html")
+ self.assert_exists("htmlcov/helper2.html")
+ self.assert_exists("htmlcov/style.css")
+ self.assert_exists("htmlcov/coverage_html.js")
+
+ def test_html_delta_from_source_change(self):
+ # HTML generation can create only the files that have changed.
+ # In this case, helper1 changes because its source is different.
+ self.create_initial_files()
+ self.run_coverage()
+ index1 = open("htmlcov/index.html").read()
+ self.remove_html_files()
+
+ # Now change a file and do it again
+ self.make_file("helper1.py", """\
+ def func1(x): # A nice function
+ if x % 2:
+ print("odd")
+ """)
+
+ self.run_coverage()
+
+ # Only the changed files should have been created.
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/helper1.html")
+ self.assert_doesnt_exist("htmlcov/main_file.html")
+ self.assert_doesnt_exist("htmlcov/helper2.html")
+ index2 = open("htmlcov/index.html").read()
+ self.assertMultiLineEqual(index1, index2)
+
+ def test_html_delta_from_coverage_change(self):
+ # HTML generation can create only the files that have changed.
+ # In this case, helper1 changes because its coverage is different.
+ self.create_initial_files()
+ self.run_coverage()
+ self.remove_html_files()
+
+ # Now change a file and do it again
+ self.make_file("main_file.py", """\
+ import helper1, helper2
+ helper1.func1(23)
+ helper2.func2(23)
+ """)
+
+ self.run_coverage()
+
+ # Only the changed files should have been created.
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/helper1.html")
+ self.assert_exists("htmlcov/main_file.html")
+ self.assert_doesnt_exist("htmlcov/helper2.html")
+
+ def test_html_delta_from_settings_change(self):
+ # HTML generation can create only the files that have changed.
+ # In this case, everything changes because the coverage settings have
+ # changed.
+ self.create_initial_files()
+ self.run_coverage(covargs=dict(timid=False))
+ index1 = open("htmlcov/index.html").read()
+ self.remove_html_files()
+
+ self.run_coverage(covargs=dict(timid=True))
+
+ # All the files have been reported again.
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/helper1.html")
+ self.assert_exists("htmlcov/main_file.html")
+ self.assert_exists("htmlcov/helper2.html")
+ index2 = open("htmlcov/index.html").read()
+ self.assertMultiLineEqual(index1, index2)
+
+ def test_html_delta_from_coverage_version_change(self):
+ # HTML generation can create only the files that have changed.
+ # In this case, everything changes because the coverage version has
+ # changed.
+ self.create_initial_files()
+ self.run_coverage()
+ index1 = open("htmlcov/index.html").read()
+ self.remove_html_files()
+
+ # "Upgrade" coverage.py!
+ coverage.__version__ = "XYZZY"
+
+ self.run_coverage()
+
+ # All the files have been reported again.
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/helper1.html")
+ self.assert_exists("htmlcov/main_file.html")
+ self.assert_exists("htmlcov/helper2.html")
+ index2 = open("htmlcov/index.html").read()
+ fixed_index2 = index2.replace("XYZZY", self.real_coverage_version)
+ self.assertMultiLineEqual(index1, fixed_index2)
+
+
+class HtmlTitleTests(HtmlTestHelpers, CoverageTest):
+ """Tests of the HTML title support."""
+
+ def test_default_title(self):
+ self.create_initial_files()
+ self.run_coverage()
+ index = open("htmlcov/index.html").read()
+ self.assertIn("<title>Coverage report</title>", index)
+ self.assertIn("<h1>Coverage report:", index)
+
+ def test_title_set_in_config_file(self):
+ self.create_initial_files()
+ self.make_file(".coveragerc", "[html]\ntitle = Metrics & stuff!\n")
+ self.run_coverage()
+ index = open("htmlcov/index.html").read()
+ self.assertIn("<title>Metrics &amp; stuff!</title>", index)
+ self.assertIn("<h1>Metrics &amp; stuff!:", index)
+
+ if sys.version_info[:2] != (3,1):
+ def test_non_ascii_title_set_in_config_file(self):
+ self.create_initial_files()
+ self.make_file(".coveragerc",
+ "[html]\ntitle = «ταБЬℓσ» numbers"
+ )
+ self.run_coverage()
+ index = open("htmlcov/index.html").read()
+ self.assertIn(
+ "<title>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " numbers", index
+ )
+ self.assertIn(
+ "<h1>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " numbers", index
+ )
+
+ def test_title_set_in_args(self):
+ self.create_initial_files()
+ self.make_file(".coveragerc", "[html]\ntitle = Good title\n")
+ self.run_coverage(htmlargs=dict(title="«ταБЬℓσ» & stüff!"))
+ index = open("htmlcov/index.html").read()
+ self.assertIn(
+ "<title>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " &amp; st&#252;ff!</title>", index
+ )
+ self.assertIn(
+ "<h1>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " &amp; st&#252;ff!:", index
+ )
+
+
+class HtmlWithUnparsableFilesTest(CoverageTest):
+ """Test the behavior when measuring unparsable files."""
+
+ def test_dotpy_not_python(self):
+ self.make_file("innocuous.py", "a = 1")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("innocuous")
+ cov.stop()
+ self.make_file("innocuous.py", "<h1>This isn't python!</h1>")
+ self.assertRaisesRegexp(
+ NotPython,
+ "Couldn't parse '.*innocuous.py' as Python source: '.*' at line 1",
+ cov.html_report
+ )
+
+ def test_dotpy_not_python_ignored(self):
+ self.make_file("innocuous.py", "a = 2")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("innocuous")
+ cov.stop()
+ self.make_file("innocuous.py", "<h1>This isn't python!</h1>")
+ cov.html_report(ignore_errors=True)
+ self.assert_exists("htmlcov/index.html")
+ # this would be better as a glob, if the html layout changes:
+ self.assert_doesnt_exist("htmlcov/innocuous.html")
+
+ def test_dothtml_not_python(self):
+ # We run a .html file, and when reporting, we can't parse it as
+ # Python. Since it wasn't .py, no error is reported.
+
+ # Run an "html" file
+ self.make_file("innocuous.html", "a = 3")
+ self.run_command("coverage run innocuous.html")
+ # Before reporting, change it to be an HTML file.
+ self.make_file("innocuous.html", "<h1>This isn't python at all!</h1>")
+ output = self.run_command("coverage html")
+ self.assertEqual(output.strip(), "No data to report.")
+
+ def test_execed_liar_ignored(self):
+ # Jinja2 sets __file__ to be a non-Python file, and then execs code.
+ # If that file contains non-Python code, a TokenError shouldn't
+ # have been raised when writing the HTML report.
+ if sys.version_info < (3, 0):
+ source = "exec compile('','','exec') in {'__file__': 'liar.html'}"
+ else:
+ source = "exec(compile('','','exec'), {'__file__': 'liar.html'})"
+ self.make_file("liar.py", source)
+ self.make_file("liar.html", "{# Whoops, not python code #}")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("liar")
+ cov.stop()
+ cov.html_report()
+ self.assert_exists("htmlcov/index.html")
+
+ def test_execed_liar_ignored_indentation_error(self):
+ # Jinja2 sets __file__ to be a non-Python file, and then execs code.
+ # If that file contains untokenizable code, we shouldn't get an
+ # exception.
+ if sys.version_info < (3, 0):
+ source = "exec compile('','','exec') in {'__file__': 'liar.html'}"
+ else:
+ source = "exec(compile('','','exec'), {'__file__': 'liar.html'})"
+ self.make_file("liar.py", source)
+ # Tokenize will raise an IndentationError if it can't dedent.
+ self.make_file("liar.html", "0\n 2\n 1\n")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("liar")
+ cov.stop()
+ cov.html_report()
+ self.assert_exists("htmlcov/index.html")
diff --git a/test/test_misc.py b/test/test_misc.py
new file mode 100644
index 00000000..ac53cddb
--- /dev/null
+++ b/test/test_misc.py
@@ -0,0 +1,76 @@
+"""Tests of miscellaneous stuff."""
+
+import os, sys
+
+from coverage.misc import Hasher, file_be_gone
+from coverage import __version__, __url__
+sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
+from coveragetest import CoverageTest
+
+class HasherTest(CoverageTest):
+ """Test our wrapper of md5 hashing."""
+
+ def test_string_hashing(self):
+ h1 = Hasher()
+ h1.update("Hello, world!")
+ h2 = Hasher()
+ h2.update("Goodbye!")
+ h3 = Hasher()
+ h3.update("Hello, world!")
+ self.assertNotEqual(h1.digest(), h2.digest())
+ self.assertEqual(h1.digest(), h3.digest())
+
+ def test_dict_hashing(self):
+ h1 = Hasher()
+ h1.update({'a': 17, 'b': 23})
+ h2 = Hasher()
+ h2.update({'b': 23, 'a': 17})
+ self.assertEqual(h1.digest(), h2.digest())
+
+
+class RemoveFileTest(CoverageTest):
+ """Tests of misc.file_be_gone."""
+
+ def test_remove_nonexistent_file(self):
+ # it's ok to try to remove a file that doesn't exist.
+ file_be_gone("not_here.txt")
+
+ def test_remove_actual_file(self):
+ # it really does remove a file that does exist.
+ self.make_file("here.txt", "We are here, we are here, we are here!")
+ file_be_gone("here.txt")
+ self.assert_doesnt_exist("here.txt")
+
+ def test_actual_errors(self):
+ # Errors can still happen.
+ # ". is a directory" on Unix, or "Access denied" on Windows
+ self.assertRaises(OSError, file_be_gone, ".")
+
+
+class SetupPyTest(CoverageTest):
+ """Tests of setup.py"""
+
+ run_in_temp_dir = False
+
+ def test_metadata(self):
+ status, output = self.run_command_status(
+ "python setup.py --description --version --url --author"
+ )
+ self.assertEqual(status, 0)
+ out = output.splitlines()
+ self.assertIn("measurement", out[0])
+ self.assertEqual(out[1], __version__)
+ self.assertEqual(out[2], __url__)
+ self.assertIn("Ned Batchelder", out[3])
+
+ def test_more_metadata(self):
+ from setup import setup_args
+
+ classifiers = setup_args['classifiers']
+ self.assertGreater(len(classifiers), 7)
+ self.assertTrue(classifiers[-1].startswith("Development Status ::"))
+
+ long_description = setup_args['long_description'].splitlines()
+ self.assertGreater(len(long_description), 7)
+ self.assertNotEqual(long_description[0].strip(), "")
+ self.assertNotEqual(long_description[-1].strip(), "")
diff --git a/test/test_oddball.py b/test/test_oddball.py
index e94e2bad..a8c243de 100644
--- a/test/test_oddball.py
+++ b/test/test_oddball.py
@@ -129,7 +129,13 @@ class RecursionTest(CoverageTest):
class MemoryLeakTest(CoverageTest):
- """Attempt the impossible: test that memory doesn't leak."""
+ """Attempt the impossible: test that memory doesn't leak.
+
+ Note: this test is truly unusual, and may fail unexpectedly.
+ In particular, it is known to fail on PyPy if test_oddball.py is run in
+ isolation: https://bitbucket.org/ned/coveragepy/issue/186
+
+ """
def test_for_leaks(self):
lines = list(range(301, 315))
@@ -301,6 +307,7 @@ class ExceptionTest(CoverageTest):
# Clean the line data and compare to expected results.
# The filenames are absolute, so keep just the base.
+ cov._harvest_data() # private! sshhh...
lines = cov.data.line_data()
clean_lines = {}
for f, llist in lines.items():
@@ -348,3 +355,37 @@ if sys.version_info >= (2, 5):
doctest.testmod(sys.modules[__name__]) # we're not __main__ :(
''',
[1,11,12,14,16,17], "")
+
+
+if hasattr(sys, 'gettrace'):
+ class GettraceTest(CoverageTest):
+ """Tests that we work properly with `sys.gettrace()`."""
+ def test_round_trip(self):
+ self.check_coverage('''\
+ import sys
+ def foo(n):
+ return 3*n
+ def bar(n):
+ return 5*n
+ a = foo(6)
+ sys.settrace(sys.gettrace())
+ a = bar(8)
+ ''',
+ [1,2,3,4,5,6,7,8], "")
+
+ def test_multi_layers(self):
+ self.check_coverage('''\
+ import sys
+ def level1():
+ a = 3
+ level2()
+ b = 5
+ def level2():
+ c = 7
+ sys.settrace(sys.gettrace())
+ d = 9
+ e = 10
+ level1()
+ f = 12
+ ''',
+ [1,2,3,4,5,6,7,8,9,10,11,12], "")
diff --git a/test/test_parser.py b/test/test_parser.py
index b398044d..220db17e 100644
--- a/test/test_parser.py
+++ b/test/test_parser.py
@@ -16,7 +16,7 @@ class ParserTest(CoverageTest):
def parse_source(self, text):
"""Parse `text` as source, and return the `CodeParser` used."""
text = textwrap.dedent(text)
- cp = CodeParser(text, exclude="nocover")
+ cp = CodeParser(text=text, exclude="nocover")
cp.parse_source()
return cp
@@ -94,3 +94,41 @@ class ParserTest(CoverageTest):
b = 6
""")
self.assertEqual(cp.exit_counts(), { 1:1, 2:1, 3:1, 6:1 })
+
+
+class ParserFileTest(CoverageTest):
+ """Tests for Coverage.py's code parsing from files."""
+
+ def parse_file(self, filename):
+ """Parse `text` as source, and return the `CodeParser` used."""
+ cp = CodeParser(filename=filename, exclude="nocover")
+ cp.parse_source()
+ return cp
+
+ def test_line_endings(self):
+ text = """\
+ # check some basic branch counting
+ class Foo:
+ def foo(self, a):
+ if a:
+ return 5
+ else:
+ return 7
+
+ class Bar:
+ pass
+ """
+ counts = { 2:1, 3:1, 4:2, 5:1, 7:1, 9:1, 10:1 }
+ name_endings = (("unix", "\n"), ("dos", "\r\n"), ("mac", "\r"))
+ for fname, newline in name_endings:
+ fname = fname + ".py"
+ self.make_file(fname, text, newline=newline)
+ cp = self.parse_file(fname)
+ self.assertEqual(cp.exit_counts(), counts)
+
+ def test_encoding(self):
+ self.make_file("encoded.py", """\
+ coverage = "\xe7\xf6v\xear\xe3g\xe9"
+ """)
+ cp = self.parse_file("encoded.py")
+ cp.exit_counts()
diff --git a/test/test_phystokens.py b/test/test_phystokens.py
index 0e778510..d4e417e8 100644
--- a/test/test_phystokens.py
+++ b/test/test_phystokens.py
@@ -37,8 +37,8 @@ class PhysTokensTest(CoverageTest):
# source_token_lines doesn't preserve trailing spaces, so trim all that
# before comparing.
source = source.replace('\r\n', '\n')
- source = re.sub("(?m)[ \t]+$", "", source)
- tokenized = re.sub("(?m)[ \t]+$", "", tokenized)
+ source = re.sub(r"(?m)[ \t]+$", "", source)
+ tokenized = re.sub(r"(?m)[ \t]+$", "", tokenized)
self.assertMultiLineEqual(source, tokenized)
def check_file_tokenization(self, fname):
diff --git a/test/test_process.py b/test/test_process.py
index 89804c16..2d926038 100644
--- a/test/test_process.py
+++ b/test/test_process.py
@@ -6,6 +6,7 @@ import coverage
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
+here = os.path.dirname(__file__)
class ProcessTest(CoverageTest):
"""Tests of the per-process behavior of coverage.py."""
@@ -24,9 +25,9 @@ class ProcessTest(CoverageTest):
w = "world"
""")
- self.assertFalse(os.path.exists(".coverage"))
+ self.assert_doesnt_exist(".coverage")
self.run_command("coverage -x mycode.py")
- self.assertTrue(os.path.exists(".coverage"))
+ self.assert_exists(".coverage")
def test_environment(self):
# Checks that we can import modules from the test directory at all!
@@ -37,9 +38,9 @@ class ProcessTest(CoverageTest):
print ('done')
""")
- self.assertFalse(os.path.exists(".coverage"))
+ self.assert_doesnt_exist(".coverage")
out = self.run_command("coverage -x mycode.py")
- self.assertTrue(os.path.exists(".coverage"))
+ self.assert_exists(".coverage")
self.assertEqual(out, 'done\n')
def test_combine_parallel_data(self):
@@ -56,18 +57,18 @@ class ProcessTest(CoverageTest):
out = self.run_command("coverage -x -p b_or_c.py b")
self.assertEqual(out, 'done\n')
- self.assertFalse(os.path.exists(".coverage"))
+ self.assert_doesnt_exist(".coverage")
out = self.run_command("coverage -x -p b_or_c.py c")
self.assertEqual(out, 'done\n')
- self.assertFalse(os.path.exists(".coverage"))
+ self.assert_doesnt_exist(".coverage")
# After two -p runs, there should be two .coverage.machine.123 files.
self.assertEqual(self.number_of_data_files(), 2)
# Combine the parallel coverage data files into .coverage .
self.run_command("coverage -c")
- self.assertTrue(os.path.exists(".coverage"))
+ self.assert_exists(".coverage")
# After combining, there should be only the .coverage file.
self.assertEqual(self.number_of_data_files(), 1)
@@ -97,19 +98,19 @@ class ProcessTest(CoverageTest):
out = self.run_command("coverage run b_or_c.py b")
self.assertEqual(out, 'done\n')
- self.assertFalse(os.path.exists(".coverage"))
+ self.assert_doesnt_exist(".coverage")
out = self.run_command("coverage run b_or_c.py c")
self.assertEqual(out, 'done\n')
- self.assertFalse(os.path.exists(".coverage"))
+ self.assert_doesnt_exist(".coverage")
# After two runs, there should be two .coverage.machine.123 files.
self.assertEqual(self.number_of_data_files(), 2)
# Combine the parallel coverage data files into .coverage .
self.run_command("coverage combine")
- self.assertTrue(os.path.exists(".coverage"))
- self.assertTrue(os.path.exists(".coveragerc"))
+ self.assert_exists(".coverage")
+ self.assert_exists(".coveragerc")
# After combining, there should be only the .coverage file.
self.assertEqual(self.number_of_data_files(), 1)
@@ -128,6 +129,57 @@ class ProcessTest(CoverageTest):
b_or_c 7 0 100%
"""))
+ def test_combine_with_aliases(self):
+ self.make_file("d1/x.py", """\
+ a = 1
+ b = 2
+ print("%s %s" % (a, b))
+ """)
+
+ self.make_file("d2/x.py", """\
+ # 1
+ # 2
+ # 3
+ c = 4
+ d = 5
+ print("%s %s" % (c, d))
+ """)
+
+ self.make_file(".coveragerc", """\
+ [run]
+ parallel = True
+
+ [paths]
+ source =
+ src
+ */d1
+ */d2
+ """)
+
+ out = self.run_command("coverage run " + os.path.normpath("d1/x.py"))
+ self.assertEqual(out, '1 2\n')
+ out = self.run_command("coverage run " + os.path.normpath("d2/x.py"))
+ self.assertEqual(out, '4 5\n')
+
+ self.assertEqual(self.number_of_data_files(), 2)
+
+ self.run_command("coverage combine")
+ self.assert_exists(".coverage")
+
+ # After combining, there should be only the .coverage file.
+ self.assertEqual(self.number_of_data_files(), 1)
+
+ # Read the coverage data file and see that the two different x.py
+ # files have been combined together.
+ data = coverage.CoverageData()
+ data.read_file(".coverage")
+ summary = data.summary(fullpath=True)
+ self.assertEqual(len(summary), 1)
+ actual = os.path.normcase(os.path.abspath(list(summary.keys())[0]))
+ expected = os.path.normcase(os.path.abspath('src/x.py'))
+ self.assertEqual(actual, expected)
+ self.assertEqual(list(summary.values())[0], 6)
+
def test_missing_source_file(self):
# Check what happens if the source is missing when reporting happens.
self.make_file("fleeting.py", """\
@@ -138,7 +190,7 @@ class ProcessTest(CoverageTest):
os.remove("fleeting.py")
out = self.run_command("coverage html -d htmlcov")
self.assertRegexpMatches(out, "No source for code: '.*fleeting.py'")
- self.assertFalse("Traceback" in out)
+ self.assertNotIn("Traceback", out)
# It happens that the code paths are different for *.py and other
# files, so try again with no extension.
@@ -150,13 +202,13 @@ class ProcessTest(CoverageTest):
os.remove("fleeting")
status, out = self.run_command_status("coverage html -d htmlcov", 1)
self.assertRegexpMatches(out, "No source for code: '.*fleeting'")
- self.assertFalse("Traceback" in out)
+ self.assertNotIn("Traceback", out)
self.assertEqual(status, 1)
def test_running_missing_file(self):
status, out = self.run_command_status("coverage run xyzzy.py", 1)
self.assertRegexpMatches(out, "No file to run: .*xyzzy.py")
- self.assertFalse("Traceback" in out)
+ self.assertNotIn("Traceback", out)
self.assertEqual(status, 1)
def test_code_throws(self):
@@ -174,12 +226,16 @@ class ProcessTest(CoverageTest):
# same traceback.
status, out = self.run_command_status("coverage run throw.py", 1)
out2 = self.run_command("python throw.py")
+ if '__pypy__' in sys.builtin_module_names:
+ # Pypy has an extra frame in the traceback for some reason
+ lines2 = out2.splitlines()
+ out2 = "".join([l+"\n" for l in lines2 if "toplevel" not in l])
self.assertMultiLineEqual(out, out2)
# But also make sure that the output is what we expect.
- self.assertTrue('File "throw.py", line 5, in f2' in out)
- self.assertTrue('raise Exception("hey!")' in out)
- self.assertFalse('coverage' in out)
+ self.assertIn('File "throw.py", line 5, in f2', out)
+ self.assertIn('raise Exception("hey!")', out)
+ self.assertNotIn('coverage', out)
self.assertEqual(status, 1)
def test_code_exits(self):
@@ -220,6 +276,28 @@ class ProcessTest(CoverageTest):
self.assertEqual(status, status2)
self.assertEqual(status, 0)
+ def test_coverage_run_is_like_python(self):
+ tryfile = os.path.join(here, "try_execfile.py")
+ self.make_file("run_me.py", open(tryfile).read())
+ out = self.run_command("coverage run run_me.py")
+ out2 = self.run_command("python run_me.py")
+ self.assertMultiLineEqual(out, out2)
+
+ if sys.version_info >= (2, 6): # Doesn't work in 2.5, and I don't care!
+ def test_coverage_run_dashm_is_like_python_dashm(self):
+ # These -m commands assume the coverage tree is on the path.
+ out = self.run_command("coverage run -m test.try_execfile")
+ out2 = self.run_command("python -m test.try_execfile")
+ self.assertMultiLineEqual(out, out2)
+
+ if 0:
+ # For https://bitbucket.org/ned/coveragepy/issue/207
+ def test_coverage_run_dashm_is_like_python_dashm_with__main__(self):
+ self.make_file("package/__init__.py") # empty
+ self.make_file("package/__main__.py", "#\n") # empty
+ out = self.run_command("coverage run -m package")
+ out2 = self.run_command("python -m package")
+ self.assertMultiLineEqual(out, out2)
if hasattr(os, 'fork'):
def test_fork(self):
@@ -242,7 +320,7 @@ class ProcessTest(CoverageTest):
out = self.run_command("coverage run -p fork.py")
self.assertEqual(out, 'Child!\n')
- self.assertFalse(os.path.exists(".coverage"))
+ self.assert_doesnt_exist(".coverage")
# After running the forking program, there should be two
# .coverage.machine.123 files.
@@ -250,7 +328,7 @@ class ProcessTest(CoverageTest):
# Combine the parallel coverage data files into .coverage .
self.run_command("coverage -c")
- self.assertTrue(os.path.exists(".coverage"))
+ self.assert_exists(".coverage")
# After combining, there should be only the .coverage file.
self.assertEqual(self.number_of_data_files(), 1)
@@ -268,10 +346,106 @@ class ProcessTest(CoverageTest):
""")
out = self.run_command("coverage run --source=sys,xyzzy,quux hello.py")
- self.assertTrue("Hello\n" in out)
- self.assertTrue(textwrap.dedent("""\
- Coverage.py warning: Module sys has no python source.
- Coverage.py warning: Source module xyzzy was never encountered.
- Coverage.py warning: Source module quux was never encountered.
+ self.assertIn("Hello\n", out)
+ self.assertIn(textwrap.dedent("""\
+ Coverage.py warning: Module sys has no Python source.
+ Coverage.py warning: Module xyzzy was never imported.
+ Coverage.py warning: Module quux was never imported.
Coverage.py warning: No data was collected.
- """) in out)
+ """), out)
+
+ def test_warnings_if_never_run(self):
+ out = self.run_command("coverage run i_dont_exist.py")
+ self.assertIn("No file to run: 'i_dont_exist.py'", out)
+ self.assertNotIn("warning", out)
+ self.assertNotIn("Exception", out)
+
+ out = self.run_command("coverage run -m no_such_module")
+ self.assertTrue(
+ ("No module named no_such_module" in out) or
+ ("No module named 'no_such_module'" in out)
+ )
+ self.assertNotIn("warning", out)
+ self.assertNotIn("Exception", out)
+
+ if sys.version_info >= (3, 0): # This only works on 3.x for now.
+ # It only works with the C tracer.
+ if os.getenv('COVERAGE_TEST_TRACER', 'c') == 'c':
+ def test_fullcoverage(self):
+ # fullcoverage is a trick to get stdlib modules measured from
+ # the very beginning of the process. Here we import os and
+ # then check how many lines are measured.
+ self.make_file("getenv.py", """\
+ import os
+ print("FOOEY == %s" % os.getenv("FOOEY"))
+ """)
+
+ fullcov = os.path.join(
+ os.path.dirname(coverage.__file__), "fullcoverage"
+ )
+ self.set_environ("FOOEY", "BOO")
+ self.set_environ("PYTHONPATH", fullcov)
+ out = self.run_command("python -m coverage run -L getenv.py")
+ self.assertEqual(out, "FOOEY == BOO\n")
+ data = coverage.CoverageData()
+ data.read_file(".coverage")
+ # The actual number of executed lines in os.py when it's
+ # imported is 120 or so. Just running os.getenv executes
+ # about 5.
+ self.assertGreater(data.summary()['os.py'], 50)
+
+
+class AliasedCommandTests(CoverageTest):
+ """Tests of the version-specific command aliases."""
+
+ def test__major_version_works(self):
+ # "coverage2" works on py2
+ cmd = "coverage%d" % sys.version_info[0]
+ out = self.run_command(cmd)
+ self.assertIn("Code coverage for Python", out)
+
+ def test_wrong_alias_doesnt_work(self):
+ # "coverage3" doesn't work on py2
+ badcmd = "coverage%d" % (5 - sys.version_info[0])
+ out = self.run_command(badcmd)
+ self.assertNotIn("Code coverage for Python", out)
+
+ def test_specific_alias_works(self):
+ # "coverage-2.7" works on py2.7
+ cmd = "coverage-%d.%d" % sys.version_info[:2]
+ out = self.run_command(cmd)
+ self.assertIn("Code coverage for Python", out)
+
+
+class FailUnderTest(CoverageTest):
+ """Tests of the --fail-under switch."""
+
+ def setUp(self):
+ super(FailUnderTest, self).setUp()
+ self.make_file("fifty.py", """\
+ # I have 50% coverage!
+ a = 1
+ if a > 2:
+ b = 3
+ c = 4
+ """)
+ st, _ = self.run_command_status("coverage run fifty.py", 0)
+ self.assertEqual(st, 0)
+
+ def test_report(self):
+ st, _ = self.run_command_status("coverage report --fail-under=50", 0)
+ self.assertEqual(st, 0)
+ st, _ = self.run_command_status("coverage report --fail-under=51", 2)
+ self.assertEqual(st, 2)
+
+ def test_html_report(self):
+ st, _ = self.run_command_status("coverage html --fail-under=50", 0)
+ self.assertEqual(st, 0)
+ st, _ = self.run_command_status("coverage html --fail-under=51", 2)
+ self.assertEqual(st, 2)
+
+ def test_xml_report(self):
+ st, _ = self.run_command_status("coverage xml --fail-under=50", 0)
+ self.assertEqual(st, 0)
+ st, _ = self.run_command_status("coverage xml --fail-under=51", 2)
+ self.assertEqual(st, 2)
diff --git a/test/test_results.py b/test/test_results.py
index d6919fa2..3da92e4c 100644
--- a/test/test_results.py
+++ b/test/test_results.py
@@ -62,4 +62,3 @@ class NumbersTest(CoverageTest):
self.assertEqual(n9999.pc_covered_str, "0.1")
self.assertEqual(n10000.pc_covered_str, "0.0")
Numbers.set_precision(0)
-
diff --git a/test/test_summary.py b/test/test_summary.py
index fcc26125..b460c2dc 100644
--- a/test/test_summary.py
+++ b/test/test_summary.py
@@ -1,6 +1,6 @@
"""Test text-based summary reporting for coverage.py"""
-import os, re, sys, textwrap
+import os, re, sys
import coverage
from coverage.backward import StringIO
@@ -25,7 +25,7 @@ class SummaryTest(CoverageTest):
def report_from_command(self, cmd):
"""Return the report from the `cmd`, with some convenience added."""
report = self.run_command(cmd).replace('\\', '/')
- self.assertFalse("error" in report.lower())
+ self.assertNotIn("error", report.lower())
return report
def line_count(self, report):
@@ -51,10 +51,10 @@ class SummaryTest(CoverageTest):
# ---------------------------------------------------------------------
# TOTAL 8 0 100%
- self.assertFalse("/coverage/__init__/" in report)
- self.assertTrue("/test/modules/covmod1 " in report)
- self.assertTrue("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/__init__/", report)
+ self.assertIn("/test/modules/covmod1 ", report)
+ self.assertIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "TOTAL 8 0 100%")
def test_report_just_one(self):
@@ -67,10 +67,10 @@ class SummaryTest(CoverageTest):
# mycode 4 0 100%
self.assertEqual(self.line_count(report), 3)
- self.assertFalse("/coverage/" in report)
- self.assertFalse("/test/modules/covmod1 " in report)
- self.assertFalse("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/", report)
+ self.assertNotIn("/test/modules/covmod1 ", report)
+ self.assertNotIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "mycode 4 0 100%")
def test_report_omitting(self):
@@ -84,10 +84,10 @@ class SummaryTest(CoverageTest):
# mycode 4 0 100%
self.assertEqual(self.line_count(report), 3)
- self.assertFalse("/coverage/" in report)
- self.assertFalse("/test/modules/covmod1 " in report)
- self.assertFalse("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/", report)
+ self.assertNotIn("/test/modules/covmod1 ", report)
+ self.assertNotIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "mycode 4 0 100%")
def test_report_including(self):
@@ -100,10 +100,10 @@ class SummaryTest(CoverageTest):
# mycode 4 0 100%
self.assertEqual(self.line_count(report), 3)
- self.assertFalse("/coverage/" in report)
- self.assertFalse("/test/modules/covmod1 " in report)
- self.assertFalse("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/", report)
+ self.assertNotIn("/test/modules/covmod1 ", report)
+ self.assertNotIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "mycode 4 0 100%")
def test_report_branches(self):
@@ -118,15 +118,120 @@ class SummaryTest(CoverageTest):
self.assertEqual(out, 'x\n')
report = self.report_from_command("coverage report")
- # Name Stmts Miss Branch BrPart Cover
+ # Name Stmts Miss Branch BrMiss Cover
# --------------------------------------------
# mybranch 5 0 2 1 85%
self.assertEqual(self.line_count(report), 3)
- self.assertTrue("mybranch " in report)
+ self.assertIn("mybranch ", report)
self.assertEqual(self.last_line_squeezed(report),
"mybranch 5 0 2 1 86%")
+ def test_dotpy_not_python(self):
+ # We run a .py file, and when reporting, we can't parse it as Python.
+ # We should get an error message in the report.
+
+ self.run_command("coverage run mycode.py")
+ self.make_file("mycode.py", "This isn't python at all!")
+ report = self.report_from_command("coverage -r mycode.py")
+
+ # pylint: disable=C0301
+ # Name Stmts Miss Cover
+ # ----------------------------
+ # mycode NotPython: Couldn't parse '/tmp/test_cover/63354509363/mycode.py' as Python source: 'invalid syntax' at line 1
+
+ last = self.last_line_squeezed(report)
+ # The actual file name varies run to run.
+ last = re.sub(r"parse '.*mycode.py", "parse 'mycode.py", last)
+ # The actual error message varies version to version
+ last = re.sub(r": '.*' at", ": 'error' at", last)
+ self.assertEqual(last,
+ "mycode NotPython: "
+ "Couldn't parse 'mycode.py' as Python source: "
+ "'error' at line 1"
+ )
+
+ def test_dotpy_not_python_ignored(self):
+ # We run a .py file, and when reporting, we can't parse it as Python,
+ # but we've said to ignore errors, so there's no error reported.
+ self.run_command("coverage run mycode.py")
+ self.make_file("mycode.py", "This isn't python at all!")
+ report = self.report_from_command("coverage -r -i mycode.py")
+
+ # Name Stmts Miss Cover
+ # ----------------------------
+
+ self.assertEqual(self.line_count(report), 2)
+
+ def test_dothtml_not_python(self):
+ # We run a .html file, and when reporting, we can't parse it as
+ # Python. Since it wasn't .py, no error is reported.
+
+ # Run an "html" file
+ self.make_file("mycode.html", "a = 1")
+ self.run_command("coverage run mycode.html")
+ # Before reporting, change it to be an HTML file.
+ self.make_file("mycode.html", "<h1>This isn't python at all!</h1>")
+ report = self.report_from_command("coverage -r mycode.html")
+
+ # Name Stmts Miss Cover
+ # ----------------------------
+
+ self.assertEqual(self.line_count(report), 2)
+
+ def get_report(self, cov):
+ """Get the report from `cov`, and canonicalize it."""
+ repout = StringIO()
+ cov.report(file=repout, show_missing=False)
+ report = repout.getvalue().replace('\\', '/')
+ report = re.sub(r" +", " ", report)
+ return report
+
+ def test_bug_156_file_not_run_should_be_zero(self):
+ # https://bitbucket.org/ned/coveragepy/issue/156
+ self.make_file("mybranch.py", """\
+ def branch(x):
+ if x:
+ print("x")
+ return x
+ branch(1)
+ """)
+ self.make_file("main.py", """\
+ print("y")
+ """)
+ cov = coverage.coverage(branch=True, source=["."])
+ cov.start()
+ import main # pylint: disable=F0401,W0612
+ cov.stop()
+ report = self.get_report(cov).splitlines()
+ self.assertIn("mybranch 5 5 2 2 0%", report)
+
+ def run_TheCode_and_report_it(self):
+ """A helper for the next few tests."""
+ cov = coverage.coverage()
+ cov.start()
+ import TheCode # pylint: disable=F0401,W0612
+ cov.stop()
+ return self.get_report(cov)
+
+ def test_bug_203_mixed_case_listed_twice_with_rc(self):
+ self.make_file("TheCode.py", "a = 1\n")
+ self.make_file(".coveragerc", "[run]\nsource = .\n")
+
+ report = self.run_TheCode_and_report_it()
+
+ self.assertIn("TheCode", report)
+ self.assertNotIn("thecode", report)
+
+ def test_bug_203_mixed_case_listed_twice(self):
+ self.make_file("TheCode.py", "a = 1\n")
+
+ report = self.run_TheCode_and_report_it()
+
+ self.assertIn("TheCode", report)
+ self.assertNotIn("thecode", report)
+
+
class SummaryTest2(CoverageTest):
"""Another bunch of summary tests."""
# This class exists because tests naturally clump into classes based on the
@@ -138,28 +243,59 @@ class SummaryTest2(CoverageTest):
def setUp(self):
super(SummaryTest2, self).setUp()
# Parent class saves and restores sys.path, we can just modify it.
- sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules'))
+ this_dir = os.path.dirname(__file__)
+ sys.path.append(self.nice_file(this_dir, 'modules'))
+ sys.path.append(self.nice_file(this_dir, 'moremodules'))
def test_empty_files(self):
+ # Shows that empty files like __init__.py are listed as having zero
+ # statements, not one statement.
cov = coverage.coverage()
cov.start()
- import usepkgs # pylint: disable-msg=F0401,W0612
+ import usepkgs # pylint: disable=F0401,W0612
cov.stop()
repout = StringIO()
cov.report(file=repout, show_missing=False)
report = repout.getvalue().replace('\\', '/')
- self.assertMultiLineEqual(report, textwrap.dedent("""\
- Name Stmts Miss Cover
- ------------------------------------------------
- test/modules/pkg1/__init__ 1 0 100%
- test/modules/pkg1/p1a 3 0 100%
- test/modules/pkg1/p1b 3 0 100%
- test/modules/pkg2/__init__ 0 0 100%
- test/modules/pkg2/p2a 3 0 100%
- test/modules/pkg2/p2b 3 0 100%
- test/modules/usepkgs 2 0 100%
- ------------------------------------------------
- TOTAL 15 0 100%
- """))
+ report = re.sub(r"\s+", " ", report)
+ self.assertIn("test/modules/pkg1/__init__ 1 0 100%", report)
+ self.assertIn("test/modules/pkg2/__init__ 0 0 100%", report)
+
+
+class ReportingReturnValue(CoverageTest):
+ """Tests of reporting functions returning values."""
+
+ def run_coverage(self):
+ """Run coverage on doit.py and return the coverage object."""
+ self.make_file("doit.py", """\
+ a = 1
+ b = 2
+ c = 3
+ d = 4
+ if a > 10:
+ f = 6
+ g = 7
+ """)
+
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("doit")
+ cov.stop()
+ return cov
+
+ def test_report(self):
+ cov = self.run_coverage()
+ val = cov.report(include="*/doit.py")
+ self.assertAlmostEqual(val, 85.7, 1)
+
+ def test_html(self):
+ cov = self.run_coverage()
+ val = cov.html_report(include="*/doit.py")
+ self.assertAlmostEqual(val, 85.7, 1)
+
+ def test_xml(self):
+ cov = self.run_coverage()
+ val = cov.xml_report(include="*/doit.py")
+ self.assertAlmostEqual(val, 85.7, 1)
diff --git a/test/test_templite.py b/test/test_templite.py
index 93e9183d..0435c545 100644
--- a/test/test_templite.py
+++ b/test/test_templite.py
@@ -3,7 +3,7 @@
from coverage.templite import Templite
import unittest
-# pylint: disable-msg=W0612,E1101
+# pylint: disable=W0612,E1101
# Disable W0612 (Unused variable) and
# E1101 (Instance of 'foo' has no 'bar' member)
diff --git a/test/test_testing.py b/test/test_testing.py
index 1cae9310..9943b65c 100644
--- a/test/test_testing.py
+++ b/test/test_testing.py
@@ -1,11 +1,13 @@
+# -*- coding: utf-8 -*-
"""Tests that our test infrastructure is really working!"""
import os, sys
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
+from coverage.backward import to_bytes
from backunittest import TestCase
from coveragetest import CoverageTest
-from coverage.backward import set # pylint: disable-msg=W0622
+from coverage.backward import set # pylint: disable=W0622
class TestingTest(TestCase):
"""Tests of helper methods on `backunittest.TestCase`."""
@@ -92,10 +94,42 @@ class TestingTest(TestCase):
self.assertFalse(False)
self.assertRaises(AssertionError, self.assertFalse, True)
+ def test_assert_in(self):
+ self.assertIn("abc", "hello abc")
+ self.assertIn("abc", ["xyz", "abc", "foo"])
+ self.assertIn("abc", {'abc': 1, 'xyz': 2})
+ self.assertRaises(AssertionError, self.assertIn, "abc", "xyz")
+ self.assertRaises(AssertionError, self.assertIn, "abc", ["x", "xabc"])
+ self.assertRaises(AssertionError, self.assertIn, "abc", {'x':'abc'})
+
+ def test_assert_not_in(self):
+ self.assertRaises(AssertionError, self.assertNotIn, "abc", "hello abc")
+ self.assertRaises(AssertionError,
+ self.assertNotIn, "abc", ["xyz", "abc", "foo"]
+ )
+ self.assertRaises(AssertionError,
+ self.assertNotIn, "abc", {'abc': 1, 'xyz': 2}
+ )
+ self.assertNotIn("abc", "xyz")
+ self.assertNotIn("abc", ["x", "xabc"])
+ self.assertNotIn("abc", {'x':'abc'})
+
+ def test_assert_greater(self):
+ self.assertGreater(10, 9)
+ self.assertGreater("xyz", "abc")
+ self.assertRaises(AssertionError, self.assertGreater, 9, 10)
+ self.assertRaises(AssertionError, self.assertGreater, 10, 10)
+ self.assertRaises(AssertionError, self.assertGreater, "abc", "xyz")
+ self.assertRaises(AssertionError, self.assertGreater, "xyz", "xyz")
+
class CoverageTestTest(CoverageTest):
"""Test the methods in `CoverageTest`."""
+ def file_text(self, fname):
+ """Return the text read from a file."""
+ return open(fname, "rb").read().decode('ascii')
+
def test_make_file(self):
# A simple file.
self.make_file("fooey.boo", "Hello there")
@@ -109,3 +143,27 @@ class CoverageTestTest(CoverageTest):
# A deeper directory
self.make_file("sub/deeper/evenmore/third.txt")
self.assertEqual(open("sub/deeper/evenmore/third.txt").read(), "")
+
+ def test_make_file_newline(self):
+ self.make_file("unix.txt", "Hello\n")
+ self.assertEqual(self.file_text("unix.txt"), "Hello\n")
+ self.make_file("dos.txt", "Hello\n", newline="\r\n")
+ self.assertEqual(self.file_text("dos.txt"), "Hello\r\n")
+ self.make_file("mac.txt", "Hello\n", newline="\r")
+ self.assertEqual(self.file_text("mac.txt"), "Hello\r")
+
+ def test_make_file_non_ascii(self):
+ self.make_file("unicode.txt", "tabblo: «ταБЬℓσ»")
+ self.assertEqual(
+ open("unicode.txt", "rb").read(),
+ to_bytes("tabblo: «ταБЬℓσ»")
+ )
+
+ def test_file_exists(self):
+ self.make_file("whoville.txt", "We are here!")
+ self.assert_exists("whoville.txt")
+ self.assert_doesnt_exist("shadow.txt")
+ self.assertRaises(
+ AssertionError, self.assert_doesnt_exist, "whoville.txt"
+ )
+ self.assertRaises(AssertionError, self.assert_exists, "shadow.txt")
diff --git a/test/test_xml.py b/test/test_xml.py
new file mode 100644
index 00000000..dda03e09
--- /dev/null
+++ b/test/test_xml.py
@@ -0,0 +1,89 @@
+"""Tests for XML reports from coverage.py."""
+
+import os, re, sys
+import coverage
+
+sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
+from coveragetest import CoverageTest
+
+class XmlReportTest(CoverageTest):
+ """Tests of the XML reports from coverage.py."""
+
+ def run_mycode(self):
+ """Run mycode.py, so we can report on it."""
+ self.make_file("mycode.py", "print('hello')\n")
+ self.run_command("coverage run mycode.py")
+
+ def test_default_file_placement(self):
+ self.run_mycode()
+ self.run_command("coverage xml")
+ self.assert_exists("coverage.xml")
+
+ def test_argument_affects_xml_placement(self):
+ self.run_mycode()
+ self.run_command("coverage xml -o put_it_there.xml")
+ self.assert_doesnt_exist("coverage.xml")
+ self.assert_exists("put_it_there.xml")
+
+ def test_config_affects_xml_placement(self):
+ self.run_mycode()
+ self.make_file(".coveragerc", "[xml]\noutput = xml.out\n")
+ self.run_command("coverage xml")
+ self.assert_doesnt_exist("coverage.xml")
+ self.assert_exists("xml.out")
+
+ def test_no_data(self):
+ # https://bitbucket.org/ned/coveragepy/issue/210
+ self.run_command("coverage xml")
+ self.assert_doesnt_exist("coverage.xml")
+
+ def test_no_source(self):
+ # Written while investigating a bug, might as well keep it.
+ # https://bitbucket.org/ned/coveragepy/issue/208
+ self.make_file("innocuous.py", "a = 4")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("innocuous")
+ cov.stop()
+ os.remove("innocuous.py")
+ cov.xml_report(ignore_errors=True)
+ self.assert_exists("coverage.xml")
+
+ def run_doit(self):
+ """Construct a simple sub-package."""
+ self.make_file("sub/__init__.py")
+ self.make_file("sub/doit.py", "print('doit!')")
+ self.make_file("main.py", "import sub.doit")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("main")
+ cov.stop()
+ return cov
+
+ def test_filename_format_showing_everything(self):
+ cov = self.run_doit()
+ cov.xml_report(outfile="-")
+ xml = self.stdout()
+ doit_line = re_line(xml, "class.*doit")
+ self.assertIn('filename="sub/doit.py"', doit_line)
+
+ def test_filename_format_including_filename(self):
+ cov = self.run_doit()
+ cov.xml_report(["sub/doit.py"], outfile="-")
+ xml = self.stdout()
+ doit_line = re_line(xml, "class.*doit")
+ self.assertIn('filename="sub/doit.py"', doit_line)
+
+ def test_filename_format_including_module(self):
+ cov = self.run_doit()
+ import sub.doit # pylint: disable=F0401
+ cov.xml_report([sub.doit], outfile="-")
+ xml = self.stdout()
+ doit_line = re_line(xml, "class.*doit")
+ self.assertIn('filename="sub/doit.py"', doit_line)
+
+
+def re_line(text, pat):
+ """Return the one line in `text` that matches regex `pat`."""
+ lines = [l for l in text.splitlines() if re.search(pat, l)]
+ return lines[0]
diff --git a/test/try_execfile.py b/test/try_execfile.py
index d7ea4398..9bbabd1a 100644
--- a/test/try_execfile.py
+++ b/test/try_execfile.py
@@ -1,6 +1,6 @@
"""Test file for run_python_file."""
-import pprint, sys
+import os, pprint, sys
DATA = "xyzzy"
@@ -12,17 +12,23 @@ def my_function(a):
FN_VAL = my_function("fooey")
+try:
+ pkg = __package__
+except NameError:
+ pkg = "*No __package__*"
+
globals_to_check = {
'__name__': __name__,
'__file__': __file__,
'__doc__': __doc__,
'__builtins__.has_open': hasattr(__builtins__, 'open'),
'__builtins__.dir': dir(__builtins__),
+ '__package__': pkg,
'DATA': DATA,
'FN_VAL': FN_VAL,
'__main__.DATA': getattr(__main__, "DATA", "nothing"),
'argv': sys.argv,
- 'path0': sys.path[0],
+ 'path': [os.path.normcase(p) for p in sys.path],
}
pprint.pprint(globals_to_check)