summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/__init__.py5
-rw-r--r--tests/backtest.py3
-rw-r--r--tests/coveragetest.py203
-rw-r--r--tests/covmodzip1.py3
-rw-r--r--tests/eggsrc/egg1/egg1.py3
-rw-r--r--tests/eggsrc/setup.py3
-rw-r--r--tests/farm/annotate/annotate_dir.py3
-rw-r--r--tests/farm/annotate/gold/white.py,cover3
-rw-r--r--tests/farm/annotate/gold_anno_dir/a_a.py,cover3
-rw-r--r--tests/farm/annotate/gold_anno_dir/b_b.py,cover3
-rw-r--r--tests/farm/annotate/gold_anno_dir/multi.py,cover3
-rw-r--r--tests/farm/annotate/gold_encodings/utf8.py,cover3
-rw-r--r--tests/farm/annotate/gold_multi/a/a.py,cover3
-rw-r--r--tests/farm/annotate/gold_multi/b/b.py,cover3
-rw-r--r--tests/farm/annotate/gold_multi/multi.py,cover3
-rw-r--r--tests/farm/annotate/gold_v24/white.py,cover33
-rw-r--r--tests/farm/annotate/run.py3
-rw-r--r--tests/farm/annotate/run_encodings.py3
-rw-r--r--tests/farm/annotate/run_multi.py3
-rw-r--r--tests/farm/annotate/src/a/a.py3
-rw-r--r--tests/farm/annotate/src/b/b.py3
-rw-r--r--tests/farm/annotate/src/multi.py3
-rw-r--r--tests/farm/annotate/src/utf8.py3
-rw-r--r--tests/farm/annotate/src/white.py3
-rw-r--r--tests/farm/html/gold_a/a_py.html118
-rw-r--r--tests/farm/html/gold_a/index.html82
-rw-r--r--tests/farm/html/gold_b_branch/b_py.html208
-rw-r--r--tests/farm/html/gold_b_branch/index.html86
-rw-r--r--tests/farm/html/gold_bom/bom_py.html120
-rw-r--r--tests/farm/html/gold_bom/index.html78
-rw-r--r--tests/farm/html/gold_isolatin1/index.html82
-rw-r--r--tests/farm/html/gold_isolatin1/isolatin1_py.html110
-rw-r--r--tests/farm/html/gold_omit_1/index.html100
-rw-r--r--tests/farm/html/gold_omit_1/m1_py.html98
-rw-r--r--tests/farm/html/gold_omit_1/m2_py.html98
-rw-r--r--tests/farm/html/gold_omit_1/m3_py.html98
-rw-r--r--tests/farm/html/gold_omit_1/main_py.html130
-rw-r--r--tests/farm/html/gold_omit_2/index.html94
-rw-r--r--tests/farm/html/gold_omit_2/m2_py.html98
-rw-r--r--tests/farm/html/gold_omit_2/m3_py.html98
-rw-r--r--tests/farm/html/gold_omit_2/main_py.html130
-rw-r--r--tests/farm/html/gold_omit_3/index.html88
-rw-r--r--tests/farm/html/gold_omit_3/m3_py.html98
-rw-r--r--tests/farm/html/gold_omit_3/main_py.html130
-rw-r--r--tests/farm/html/gold_omit_4/index.html94
-rw-r--r--tests/farm/html/gold_omit_4/m1_py.html98
-rw-r--r--tests/farm/html/gold_omit_4/m3_py.html98
-rw-r--r--tests/farm/html/gold_omit_4/main_py.html130
-rw-r--r--tests/farm/html/gold_omit_5/index.html88
-rw-r--r--tests/farm/html/gold_omit_5/m1_py.html98
-rw-r--r--tests/farm/html/gold_omit_5/main_py.html130
-rw-r--r--tests/farm/html/gold_other/blah_blah_other_py.html106
-rw-r--r--tests/farm/html/gold_other/here_py.html122
-rw-r--r--tests/farm/html/gold_other/index.html88
-rw-r--r--tests/farm/html/gold_partial/index.html90
-rw-r--r--tests/farm/html/gold_partial/partial_py.html164
-rw-r--r--tests/farm/html/gold_styled/a_py.html120
-rw-r--r--tests/farm/html/gold_styled/index.html84
-rw-r--r--tests/farm/html/gold_styled/style.css60
-rw-r--r--tests/farm/html/gold_unicode/index.html82
-rw-r--r--tests/farm/html/gold_unicode/unicode_py.html110
-rw-r--r--tests/farm/html/gold_x_xml/coverage.xml45
-rw-r--r--tests/farm/html/gold_y_xml_branch/coverage.xml49
-rw-r--r--tests/farm/html/othersrc/other.py3
-rw-r--r--tests/farm/html/run_a.py26
-rw-r--r--tests/farm/html/run_a_xml_1.py26
-rw-r--r--tests/farm/html/run_a_xml_2.py26
-rw-r--r--tests/farm/html/run_b_branch.py29
-rw-r--r--tests/farm/html/run_bom.py21
-rw-r--r--tests/farm/html/run_isolatin1.py21
-rw-r--r--tests/farm/html/run_omit_1.py12
-rw-r--r--tests/farm/html/run_omit_2.py12
-rw-r--r--tests/farm/html/run_omit_3.py12
-rw-r--r--tests/farm/html/run_omit_4.py12
-rw-r--r--tests/farm/html/run_omit_5.py12
-rw-r--r--tests/farm/html/run_other.py26
-rw-r--r--tests/farm/html/run_partial.py31
-rw-r--r--tests/farm/html/run_styled.py28
-rw-r--r--tests/farm/html/run_tabbed.py24
-rw-r--r--tests/farm/html/run_unicode.py24
-rw-r--r--tests/farm/html/run_y_xml_branch.py26
-rw-r--r--tests/farm/html/src/a.py5
-rw-r--r--tests/farm/html/src/b.py5
-rw-r--r--tests/farm/html/src/bom.py23
-rw-r--r--tests/farm/html/src/coverage.xml23
-rw-r--r--tests/farm/html/src/here.py5
-rw-r--r--tests/farm/html/src/isolatin1.py5
-rw-r--r--tests/farm/html/src/m1.py3
-rw-r--r--tests/farm/html/src/m2.py3
-rw-r--r--tests/farm/html/src/m3.py3
-rw-r--r--tests/farm/html/src/main.py3
-rw-r--r--tests/farm/html/src/omit4.ini3
-rw-r--r--tests/farm/html/src/omit5.ini5
-rw-r--r--tests/farm/html/src/partial.ini9
-rw-r--r--tests/farm/html/src/partial.py12
-rw-r--r--tests/farm/html/src/run_a_xml_2.ini5
-rw-r--r--tests/farm/html/src/tabbed.py3
-rw-r--r--tests/farm/html/src/unicode.py5
-rw-r--r--tests/farm/html/src/y.py5
-rw-r--r--tests/farm/run/run_chdir.py3
-rw-r--r--tests/farm/run/run_timid.py3
-rw-r--r--tests/farm/run/run_xxx.py3
-rw-r--r--tests/farm/run/src/chdir.py3
-rw-r--r--tests/farm/run/src/showtrace.py3
-rw-r--r--tests/farm/run/src/xxx3
-rw-r--r--tests/goldtest.py42
-rw-r--r--tests/helpers.py32
-rw-r--r--tests/js/index.html17
-rw-r--r--tests/js/tests.js96
-rw-r--r--tests/modules/covmod1.py3
-rw-r--r--tests/modules/pkg1/__init__.py1
-rw-r--r--tests/modules/pkg1/p1a.py3
-rw-r--r--tests/modules/pkg1/p1b.py3
-rw-r--r--tests/modules/pkg1/p1c.py3
-rw-r--r--tests/modules/pkg1/runmod2.py3
-rw-r--r--tests/modules/pkg1/sub/ps1a.py3
-rw-r--r--tests/modules/pkg1/sub/runmod3.py3
-rw-r--r--tests/modules/pkg2/p2a.py3
-rw-r--r--tests/modules/pkg2/p2b.py3
-rw-r--r--tests/modules/plugins/a_plugin.py2
-rw-r--r--tests/modules/plugins/another.py5
-rw-r--r--tests/modules/process_test/__init__.py0
-rw-r--r--tests/modules/process_test/try_execfile.py (renamed from tests/try_execfile.py)3
-rw-r--r--tests/modules/runmod1.py3
-rw-r--r--tests/modules/usepkgs.py3
-rw-r--r--tests/moremodules/othermods/othera.py3
-rw-r--r--tests/moremodules/othermods/otherb.py3
-rw-r--r--tests/moremodules/othermods/sub/osa.py3
-rw-r--r--tests/moremodules/othermods/sub/osb.py3
-rw-r--r--tests/osinfo.py55
-rw-r--r--tests/plugin1.py12
-rw-r--r--tests/plugin2.py9
-rw-r--r--tests/qunit/qunit.css225
-rw-r--r--tests/qunit/qunit.js1448
-rw-r--r--tests/stress_phystoken.tok3
-rw-r--r--tests/stress_phystoken_dos.tok3
-rw-r--r--tests/test_api.py211
-rw-r--r--tests/test_arcs.py856
-rw-r--r--tests/test_backward.py6
-rw-r--r--tests/test_cmdline.py258
-rw-r--r--tests/test_collector.py5
-rw-r--r--tests/test_concurrency.py459
-rw-r--r--tests/test_config.py244
-rw-r--r--tests/test_coverage.py223
-rw-r--r--tests/test_data.py719
-rw-r--r--tests/test_debug.py58
-rw-r--r--tests/test_execfile.py54
-rw-r--r--tests/test_farm.py524
-rw-r--r--tests/test_filereporter.py17
-rw-r--r--tests/test_files.py24
-rw-r--r--tests/test_html.py474
-rw-r--r--tests/test_misc.py48
-rw-r--r--tests/test_oddball.py106
-rw-r--r--tests/test_parser.py251
-rw-r--r--tests/test_phystokens.py188
-rw-r--r--tests/test_pickle2json.py55
-rw-r--r--tests/test_plugins.py190
-rw-r--r--tests/test_process.py549
-rw-r--r--tests/test_python.py5
-rw-r--r--tests/test_results.py11
-rw-r--r--tests/test_summary.py339
-rw-r--r--tests/test_templite.py25
-rw-r--r--tests/test_testing.py97
-rw-r--r--tests/test_xml.py140
164 files changed, 7544 insertions, 5408 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
index 5a0e30f4..1ff1e1be 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1 +1,4 @@
-"""Automated tests. Run with nosetests."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Automated tests. Run with pytest."""
diff --git a/tests/backtest.py b/tests/backtest.py
index 50834721..827e891f 100644
--- a/tests/backtest.py
+++ b/tests/backtest.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Add things to old Pythons so I can pretend they are newer, for tests."""
# pylint: disable=redefined-builtin
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index 1623ef99..dacb9b63 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -1,5 +1,9 @@
-"""Base test case class for coverage testing."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+"""Base test case class for coverage.py testing."""
+
+import contextlib
import datetime
import glob
import os
@@ -9,15 +13,17 @@ import shlex
import shutil
import sys
-import coverage
-from coverage.backunittest import TestCase
-from coverage.backward import StringIO, import_local_file, string_class
-from coverage.control import _TEST_NAME_FILE
-from coverage.test_helpers import (
+from unittest_mixins import (
EnvironmentAwareMixin, StdStreamCapturingMixin, TempDirMixin,
+ DelayedAssertionMixin,
)
-from nose.plugins.skip import SkipTest
+import coverage
+from coverage.backunittest import TestCase
+from coverage.backward import StringIO, import_local_file, string_class, shlex_quote
+from coverage.backward import invalidate_import_caches
+from coverage.cmdline import CoverageScript
+from coverage.debug import _TEST_NAME_FILE, DebugControl
from tests.helpers import run_command
@@ -30,9 +36,10 @@ class CoverageTest(
EnvironmentAwareMixin,
StdStreamCapturingMixin,
TempDirMixin,
+ DelayedAssertionMixin,
TestCase
):
- """A base class for Coverage test cases."""
+ """A base class for coverage.py test cases."""
# Standard unittest setting: show me diffs even if they are very long.
maxDiff = None
@@ -43,17 +50,17 @@ class CoverageTest(
def setUp(self):
super(CoverageTest, self).setUp()
+ # Attributes for getting info about what happened.
+ self.last_command_status = None
+ self.last_command_output = None
+ self.last_module_name = None
+
if _TEST_NAME_FILE: # pragma: debugging
with open(_TEST_NAME_FILE, "w") as f:
f.write("%s_%s" % (
self.__class__.__name__, self._testMethodName,
))
- def skip(self, reason):
- """Skip this test, and give a reason."""
- self.class_behavior().skipped += 1
- raise SkipTest(reason)
-
def clean_local_file_imports(self):
"""Clean up the results of calls to `import_local_file`.
@@ -71,20 +78,24 @@ class CoverageTest(
if os.path.exists("__pycache__"):
shutil.rmtree("__pycache__")
- def import_local_file(self, modname):
+ invalidate_import_caches()
+
+ def import_local_file(self, modname, modfile=None):
"""Import a local file as a module.
Opens a file in the current directory named `modname`.py, imports it
- as `modname`, and returns the module object.
+ as `modname`, and returns the module object. `modfile` is the file to
+ import if it isn't in the current directory.
"""
- return import_local_file(modname)
+ return import_local_file(modname, modfile)
- def start_import_stop(self, cov, modname):
+ def start_import_stop(self, cov, modname, modfile=None):
"""Start coverage, import a file, then stop coverage.
`cov` is started and stopped, with an `import_local_file` of
- `modname` in the middle.
+ `modname` in the middle. `modfile` is the file to import as `modname`
+ if it isn't in the current directory.
The imported module is returned.
@@ -92,21 +103,22 @@ class CoverageTest(
cov.start()
try: # pragma: nested
# Import the Python file, executing it.
- mod = self.import_local_file(modname)
+ mod = self.import_local_file(modname, modfile)
finally: # pragma: nested
- # Stop Coverage.
+ # Stop coverage.py.
cov.stop()
return mod
def get_module_name(self):
- """Return the module name to use for this test run."""
- return 'coverage_test_' + str(random.random())[2:]
+ """Return a random module name to use for this test run."""
+ self.last_module_name = 'coverage_test_' + str(random.random())[2:]
+ return self.last_module_name
# Map chars to numbers for arcz_to_arcs
_arcz_map = {'.': -1}
- _arcz_map.update(dict((c, ord(c)-ord('0')) for c in '123456789'))
+ _arcz_map.update(dict((c, ord(c) - ord('0')) for c in '123456789'))
_arcz_map.update(dict(
- (c, 10+ord(c)-ord('A')) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ (c, 10 + ord(c) - ord('A')) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
))
def arcz_to_arcs(self, arcz):
@@ -137,7 +149,7 @@ class CoverageTest(
assert pair[1] == '-'
a, _, b = pair
bsgn = -1
- arcs.append((asgn*self._arcz_map[a], bsgn*self._arcz_map[b]))
+ arcs.append((asgn * self._arcz_map[a], bsgn * self._arcz_map[b]))
return sorted(arcs)
def assert_equal_args(self, a1, a2, msg=None):
@@ -150,7 +162,7 @@ class CoverageTest(
def check_coverage(
self, text, lines=None, missing="", report="",
excludes=None, partials="",
- arcz=None, arcz_missing=None, arcz_unpredicted=None,
+ arcz=None, arcz_missing="", arcz_unpredicted="",
arcs=None, arcs_missing=None, arcs_unpredicted=None,
):
"""Check the coverage measurement of `text`.
@@ -162,29 +174,30 @@ class CoverageTest(
of the measurement report.
For arc measurement, `arcz` is a string that can be decoded into arcs
- in the code (see `arcz_to_arcs` for the encoding scheme),
+ in the code (see `arcz_to_arcs` for the encoding scheme).
`arcz_missing` are the arcs that are not executed, and
- `arcs_unpredicted` are the arcs executed in the code, but not deducible
- from the code.
+ `arcz_unpredicted` are the arcs executed in the code, but not deducible
+ from the code. These last two default to "", meaning we explicitly
+ check that there are no missing or unpredicted arcs.
Returns the Coverage object, in case you want to poke at it some more.
"""
# We write the code into a file so that we can import it.
- # Coverage wants to deal with things as modules with file names.
+ # Coverage.py wants to deal with things as modules with file names.
modname = self.get_module_name()
- self.make_file(modname+".py", text)
+ self.make_file(modname + ".py", text)
if arcs is None and arcz is not None:
arcs = self.arcz_to_arcs(arcz)
- if arcs_missing is None and arcz_missing is not None:
+ if arcs_missing is None:
arcs_missing = self.arcz_to_arcs(arcz_missing)
- if arcs_unpredicted is None and arcz_unpredicted is not None:
+ if arcs_unpredicted is None:
arcs_unpredicted = self.arcz_to_arcs(arcz_unpredicted)
- # Start up Coverage.
- cov = coverage.coverage(branch=(arcs_missing is not None))
+ # Start up coverage.py.
+ cov = coverage.Coverage(branch=True)
cov.erase()
for exc in excludes or []:
cov.exclude(exc)
@@ -211,9 +224,7 @@ class CoverageTest(
if statements == line_list:
break
else:
- self.fail(
- "None of the lines choices matched %r" % statements
- )
+ self.fail("None of the lines choices matched %r" % statements)
missing_formatted = analysis.missing_formatted()
if isinstance(missing, string_class):
@@ -223,38 +234,59 @@ class CoverageTest(
if missing_formatted == missing_list:
break
else:
- self.fail(
- "None of the missing choices matched %r" %
- missing_formatted
- )
+ self.fail("None of the missing choices matched %r" % missing_formatted)
if arcs is not None:
- self.assert_equal_args(
- analysis.arc_possibilities(), arcs, "Possible arcs differ"
+ with self.delayed_assertions():
+ self.assert_equal_args(
+ analysis.arc_possibilities(), arcs,
+ "Possible arcs differ",
)
- if arcs_missing is not None:
self.assert_equal_args(
analysis.arcs_missing(), arcs_missing,
"Missing arcs differ"
- )
+ )
- if arcs_unpredicted is not None:
self.assert_equal_args(
analysis.arcs_unpredicted(), arcs_unpredicted,
"Unpredicted arcs differ"
- )
+ )
if report:
frep = StringIO()
- cov.report(mod, file=frep)
+ cov.report(mod, file=frep, show_missing=True)
rep = " ".join(frep.getvalue().split("\n")[2].split()[1:])
self.assertEqual(report, rep)
return cov
+ @contextlib.contextmanager
+ def assert_warnings(self, cov, warnings):
+ """A context manager to check that particular warnings happened in `cov`."""
+ saved_warnings = []
+ def capture_warning(msg):
+ """A fake implementation of Coverage._warn, to capture warnings."""
+ saved_warnings.append(msg)
+
+ original_warn = cov._warn
+ cov._warn = capture_warning
+
+ try:
+ yield
+ except:
+ raise
+ else:
+ for warning_regex in warnings:
+ for saved in saved_warnings:
+ if re.search(warning_regex, saved):
+ break
+ else:
+ self.fail("Didn't find warning %r in %r" % (warning_regex, saved_warnings))
+ cov._warn = original_warn
+
def nice_file(self, *fparts):
- """Canonicalize the filename composed of the parts in `fparts`."""
+ """Canonicalize the file name composed of the parts in `fparts`."""
fname = os.path.join(*fparts)
return os.path.normcase(os.path.abspath(os.path.realpath(fname)))
@@ -299,28 +331,26 @@ class CoverageTest(
Returns None.
"""
- script = coverage.CoverageScript(_covpkg=_covpkg)
+ script = CoverageScript(_covpkg=_covpkg)
ret_actual = script.command_line(shlex.split(args))
self.assertEqual(ret_actual, ret)
+ coverage_command = "coverage"
+
def run_command(self, cmd):
- """Run the command-line `cmd` in a sub-process, and print its output.
+ """Run the command-line `cmd` in a sub-process.
+
+ `cmd` is the command line to invoke in a sub-process. Returns the
+ combined content of `stdout` and `stderr` output streams from the
+ sub-process.
+
+ See `run_command_status` for complete semantics.
Use this when you need to test the process behavior of coverage.
Compare with `command_line`.
- Returns the process' stdout text.
-
"""
- # Running Python sub-processes can be tricky. Use the real name of our
- # own executable. So "python foo.py" might get executed as
- # "python3.3 foo.py". This is important because Python 3.x doesn't
- # install as "python", so you might get a Python 2 executable instead
- # if you don't use the executable's basename.
- if cmd.startswith("python "):
- cmd = os.path.basename(sys.executable) + cmd[6:]
-
_, output = self.run_command_status(cmd)
return output
@@ -331,9 +361,40 @@ class CoverageTest(
Compare with `command_line`.
- Returns a pair: the process' exit status and stdout text.
+ Handles the following command names specially:
+
+ * "python" is replaced with the command name of the current
+ Python interpreter.
+
+ * "coverage" is replaced with the command name for the main
+ Coverage.py program.
+
+ Returns a pair: the process' exit status and its stdout/stderr text,
+ which are also stored as `self.last_command_status` and
+ `self.last_command_output`.
"""
+ # Make sure "python" and "coverage" mean specifically what we want
+ # them to mean.
+ split_commandline = cmd.split(" ", 1)
+ command_name = split_commandline[0]
+ command_args = split_commandline[1:]
+
+ if command_name == "python":
+ # Running a Python interpreter in a sub-processes can be tricky.
+ # Use the real name of our own executable. So "python foo.py" might
+ # get executed as "python3.3 foo.py". This is important because
+ # Python 3.x doesn't install as "python", so you might get a Python
+ # 2 executable instead if you don't use the executable's basename.
+ command_name = os.path.basename(sys.executable)
+
+ if command_name == "coverage":
+ # The invocation requests the Coverage.py program. Substitute the
+ # actual Coverage.py main command name.
+ command_name = self.coverage_command
+
+ cmd = " ".join([shlex_quote(command_name)] + command_args)
+
# Add our test modules directory to PYTHONPATH. I'm sure there's too
# much path munging here, but...
here = os.path.dirname(self.nice_file(coverage.__file__, ".."))
@@ -345,9 +406,9 @@ class CoverageTest(
pypath += testmods + os.pathsep + zipfile
self.set_environ('PYTHONPATH', pypath)
- status, output = run_command(cmd)
- print(output)
- return status, output
+ self.last_command_status, self.last_command_output = run_command(cmd)
+ print(self.last_command_output)
+ return self.last_command_status, self.last_command_output
def report_from_command(self, cmd):
"""Return the report from the `cmd`, with some convenience added."""
@@ -373,3 +434,13 @@ class CoverageTest(
def last_line_squeezed(self, report):
"""Return the last line of `report` with the spaces squeezed down."""
return self.squeezed_lines(report)[-1]
+
+
+class DebugControlString(DebugControl):
+ """A `DebugControl` that writes to a StringIO, for testing."""
+ def __init__(self, options):
+ super(DebugControlString, self).__init__(options, StringIO())
+
+ def get_output(self):
+ """Get the output text from the `DebugControl`."""
+ return self.output.getvalue()
diff --git a/tests/covmodzip1.py b/tests/covmodzip1.py
index 3ec4cdc4..6f135dd6 100644
--- a/tests/covmodzip1.py
+++ b/tests/covmodzip1.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""covmodzip.py: for putting into a zip file."""
j = 1
j += 1
diff --git a/tests/eggsrc/egg1/egg1.py b/tests/eggsrc/egg1/egg1.py
index 3fadde33..72600808 100644
--- a/tests/eggsrc/egg1/egg1.py
+++ b/tests/eggsrc/egg1/egg1.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# My egg file!
walrus = "Eggman"
diff --git a/tests/eggsrc/setup.py b/tests/eggsrc/setup.py
index f9b8b9d0..c935798d 100644
--- a/tests/eggsrc/setup.py
+++ b/tests/eggsrc/setup.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
from setuptools import setup
setup(
diff --git a/tests/farm/annotate/annotate_dir.py b/tests/farm/annotate/annotate_dir.py
index 86c18cab..3bb2dbe7 100644
--- a/tests/farm/annotate/annotate_dir.py
+++ b/tests/farm/annotate/annotate_dir.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
copy("src", "run")
run("""
coverage run multi.py
diff --git a/tests/farm/annotate/gold/white.py,cover b/tests/farm/annotate/gold/white.py,cover
index 36b0b993..fc163226 100644
--- a/tests/farm/annotate/gold/white.py,cover
+++ b/tests/farm/annotate/gold/white.py,cover
@@ -1,3 +1,6 @@
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# A test case sent to me by Steve White
> def f(self):
diff --git a/tests/farm/annotate/gold_anno_dir/a_a.py,cover b/tests/farm/annotate/gold_anno_dir/a_a.py,cover
index d0ff3c0c..4729cfbb 100644
--- a/tests/farm/annotate/gold_anno_dir/a_a.py,cover
+++ b/tests/farm/annotate/gold_anno_dir/a_a.py,cover
@@ -1,3 +1,6 @@
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
> def a(x):
> if x == 1:
> print("x is 1")
diff --git a/tests/farm/annotate/gold_anno_dir/b_b.py,cover b/tests/farm/annotate/gold_anno_dir/b_b.py,cover
index 90d076f1..228715f0 100644
--- a/tests/farm/annotate/gold_anno_dir/b_b.py,cover
+++ b/tests/farm/annotate/gold_anno_dir/b_b.py,cover
@@ -1,3 +1,6 @@
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
> def b(x):
> msg = "x is %s" % x
> print(msg)
diff --git a/tests/farm/annotate/gold_anno_dir/multi.py,cover b/tests/farm/annotate/gold_anno_dir/multi.py,cover
index 2a5c59ce..90a13c91 100644
--- a/tests/farm/annotate/gold_anno_dir/multi.py,cover
+++ b/tests/farm/annotate/gold_anno_dir/multi.py,cover
@@ -1,3 +1,6 @@
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
> import a.a
> import b.b
diff --git a/tests/farm/annotate/gold_encodings/utf8.py,cover b/tests/farm/annotate/gold_encodings/utf8.py,cover
index 6dbf7e0d..3ef31e0f 100644
--- a/tests/farm/annotate/gold_encodings/utf8.py,cover
+++ b/tests/farm/annotate/gold_encodings/utf8.py,cover
@@ -1,4 +1,7 @@
# -*- coding: utf-8 -*-
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# This comment has an accent: é
> print("spam eggs")
diff --git a/tests/farm/annotate/gold_multi/a/a.py,cover b/tests/farm/annotate/gold_multi/a/a.py,cover
index fb3f5435..e5e97226 100644
--- a/tests/farm/annotate/gold_multi/a/a.py,cover
+++ b/tests/farm/annotate/gold_multi/a/a.py,cover
@@ -1,3 +1,6 @@
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
> def a(x):
> if x == 1:
> print "x is 1"
diff --git a/tests/farm/annotate/gold_multi/b/b.py,cover b/tests/farm/annotate/gold_multi/b/b.py,cover
index a3f5daec..26b25548 100644
--- a/tests/farm/annotate/gold_multi/b/b.py,cover
+++ b/tests/farm/annotate/gold_multi/b/b.py,cover
@@ -1,2 +1,5 @@
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
> def b(x):
> print "x is %s" % x
diff --git a/tests/farm/annotate/gold_multi/multi.py,cover b/tests/farm/annotate/gold_multi/multi.py,cover
index 2a5c59ce..90a13c91 100644
--- a/tests/farm/annotate/gold_multi/multi.py,cover
+++ b/tests/farm/annotate/gold_multi/multi.py,cover
@@ -1,3 +1,6 @@
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+ # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
> import a.a
> import b.b
diff --git a/tests/farm/annotate/gold_v24/white.py,cover b/tests/farm/annotate/gold_v24/white.py,cover
deleted file mode 100644
index bbd8d428..00000000
--- a/tests/farm/annotate/gold_v24/white.py,cover
+++ /dev/null
@@ -1,33 +0,0 @@
- # A test case sent to me by Steve White
-
-> def f(self):
-! if self==1:
-! pass
-! elif self.m('fred'):
-! pass
-! elif (g==1) and (b==2):
-! pass
-! elif self.m('fred')==True:
-! pass
-! elif ((g==1) and (b==2))==True:
-! pass
-> else:
-! pass
-
-> def g(x):
-> if x == 1:
-> a = 1
-! else:
-! a = 2
-
-> g(1)
-
-> def h(x):
-- if 0: #pragma: no cover
-- pass
-> if x == 1:
-! a = 1
-> else:
-> a = 2
-
-> h(2)
diff --git a/tests/farm/annotate/run.py b/tests/farm/annotate/run.py
index 236f401f..33e5f671 100644
--- a/tests/farm/annotate/run.py
+++ b/tests/farm/annotate/run.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
copy("src", "out")
run("""
coverage run white.py
diff --git a/tests/farm/annotate/run_encodings.py b/tests/farm/annotate/run_encodings.py
index eb1a3a9a..527cd88f 100644
--- a/tests/farm/annotate/run_encodings.py
+++ b/tests/farm/annotate/run_encodings.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
copy("src", "out")
run("""
coverage run utf8.py
diff --git a/tests/farm/annotate/run_multi.py b/tests/farm/annotate/run_multi.py
index ef1e8238..4646293e 100644
--- a/tests/farm/annotate/run_multi.py
+++ b/tests/farm/annotate/run_multi.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
copy("src", "out_multi")
run("""
coverage run multi.py
diff --git a/tests/farm/annotate/src/a/a.py b/tests/farm/annotate/src/a/a.py
index c2583d1e..e3e6631d 100644
--- a/tests/farm/annotate/src/a/a.py
+++ b/tests/farm/annotate/src/a/a.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
def a(x):
if x == 1:
print("x is 1")
diff --git a/tests/farm/annotate/src/b/b.py b/tests/farm/annotate/src/b/b.py
index 625a5490..b31d8c95 100644
--- a/tests/farm/annotate/src/b/b.py
+++ b/tests/farm/annotate/src/b/b.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
def b(x):
msg = "x is %s" % x
print(msg)
diff --git a/tests/farm/annotate/src/multi.py b/tests/farm/annotate/src/multi.py
index 19a6200c..bf8cfd5f 100644
--- a/tests/farm/annotate/src/multi.py
+++ b/tests/farm/annotate/src/multi.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
import a.a
import b.b
diff --git a/tests/farm/annotate/src/utf8.py b/tests/farm/annotate/src/utf8.py
index 27342d87..fd43b2ab 100644
--- a/tests/farm/annotate/src/utf8.py
+++ b/tests/farm/annotate/src/utf8.py
@@ -1,4 +1,7 @@
# -*- coding: utf-8 -*-
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# This comment has an accent: é
print("spam eggs")
diff --git a/tests/farm/annotate/src/white.py b/tests/farm/annotate/src/white.py
index ecbbd25a..21e8a627 100644
--- a/tests/farm/annotate/src/white.py
+++ b/tests/farm/annotate/src/white.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# A test case sent to me by Steve White
def f(self):
diff --git a/tests/farm/html/gold_a/a_py.html b/tests/farm/html/gold_a/a_py.html
index 03c1fc95..00ab529d 100644
--- a/tests/farm/html/gold_a/a_py.html
+++ b/tests/farm/html/gold_a/a_py.html
@@ -1,96 +1,106 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for a.py: 67%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>a</b> :
- <span class='pc_cov'>67%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>a.py</b> :
+ <span class="pc_cov">67%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
3 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>1 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">1 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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="pln"><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="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="pln"><a href="#n9">9</a></p>
+<p id="n10" class="stm mis"><a href="#n10">10</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</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="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="t7" class="pln">&nbsp; &nbsp; <span class="com"># Needed a &lt; to look at HTML entities.</span><span class="strut">&nbsp;</span></p>
+<p id="t8" 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="t9" class="pln"><span class="key">else</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t10" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_a/index.html b/tests/farm/html/gold_a/index.html
index 4a79fc57..35507b6f 100644
--- a/tests/farm/html/gold_a/index.html
+++ b/tests/farm/html/gold_a/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>67%</span>
+ <span class="pc_cov">67%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,54 +33,54 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>3</td>
<td>1</td>
<td>0</td>
- <td class='right' data-ratio='2 3'>67%</td>
+ <td class="right" data-ratio="2 3">67%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='a.html'>a</a></td>
+ <tr class="file">
+ <td class="name left"><a href="a_py.html">a.py</a></td>
<td>3</td>
<td>1</td>
<td>0</td>
- <td class='right' data-ratio='2 3'>67%</td>
+ <td class="right" data-ratio="2 3">67%</td>
</tr>
</tbody>
@@ -88,10 +91,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_b_branch/b_py.html b/tests/farm/html/gold_b_branch/b_py.html
index 15b06661..4a876500 100644
--- a/tests/farm/html/gold_b_branch/b_py.html
+++ b/tests/farm/html/gold_b_branch/b_py.html
@@ -1,142 +1,152 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for b: 70%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for b.py: 70%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>b</b> :
- <span class='pc_cov'>70%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>b.py</b> :
+ <span class="pc_cov">70%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
17 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>14 run</span>
- <span class='mis shortkey_m button_toggle_mis'>3 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">14 run</span>
+ <span class="mis shortkey_m button_toggle_mis">3 missing</span>
+ <span class="exc shortkey_x button_toggle_exc">0 excluded</span>
- <span class='par run hide_run shortkey_p button_toggle_par'>4 partial</span>
+ <span class="par run hide_run shortkey_p button_toggle_par">4 partial</span>
</h2>
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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='stm run hide_run'><a href='#n20'>20</a></p>
-<p id='n21' class='pln'><a href='#n21'>21</a></p>
-<p id='n22' class='stm par run hide_run'><a href='#n22'>22</a></p>
-<p id='n23' class='stm mis'><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='stm run hide_run'><a href='#n27'>27</a></p>
-<p id='n28' class='pln'><a href='#n28'>28</a></p>
-<p id='n29' class='stm run hide_run'><a href='#n29'>29</a></p>
+ <td class="linenos">
+<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="pln"><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="pln"><a href="#n7">7</a></p>
+<p id="n8" class="stm par 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 mis"><a href="#n11">11</a></p>
+<p id="n12" class="pln"><a href="#n12">12</a></p>
+<p id="n13" class="stm run hide_run"><a href="#n13">13</a></p>
+<p id="n14" class="pln"><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 par run hide_run"><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>
+<p id="n20" class="stm run hide_run"><a href="#n20">20</a></p>
+<p id="n21" class="pln"><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 par run hide_run"><a href="#n25">25</a></p>
+<p id="n26" class="stm mis"><a href="#n26">26</a></p>
+<p id="n27" class="pln"><a href="#n27">27</a></p>
+<p id="n28" class="stm mis"><a href="#n28">28</a></p>
+<p id="n29" class="stm run hide_run"><a href="#n29">29</a></p>
+<p id="n30" class="stm run hide_run"><a href="#n30">30</a></p>
+<p id="n31" class="pln"><a href="#n31">31</a></p>
+<p id="n32" class="stm run hide_run"><a href="#n32">32</a></p>
</td>
- <td class='text'>
-<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</span><span class='op'>(</span><span class='op'>)</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t20' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>try</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t21' class='pln'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='com'># This if has two branches, *neither* one taken.</span><span class='strut'>&nbsp;</span></p>
-<p id='t22' class='stm par run hide_run'><span class='annotate' title='no jumps to these line numbers'>23&nbsp;&nbsp; 25</span>&nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>if</span> <span class='nam'>name_error_this_variable_doesnt_exist</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t23' class='stm mis'>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'>&nbsp;</span></p>
-<p id='t24' class='pln'>&nbsp; &nbsp; &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; &nbsp; &nbsp; <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'>&nbsp;</span></p>
-<p id='t26' class='stm run hide_run'>&nbsp; &nbsp; <span class='key'>except</span><span class='op'>:</span><span class='strut'>&nbsp;</span></p>
-<p id='t27' class='stm run hide_run'>&nbsp; &nbsp; &nbsp; &nbsp; <span class='key'>pass</span><span class='strut'>&nbsp;</span></p>
-<p id='t28' class='pln'><span class='strut'>&nbsp;</span></p>
-<p id='t29' class='stm run hide_run'><span class='nam'>three</span><span class='op'>(</span><span class='op'>)</span><span class='strut'>&nbsp;</span></p>
+ <td class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</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">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="t7" 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="t8" class="stm par run hide_run"><span class="annotate" title="no jump to this line number">11</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="t9" 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="t10" class="pln">&nbsp; &nbsp; <span class="key">else</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t11" 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="t12" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t13" 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="t14" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t15" 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="t16" 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="t17" 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="t18" 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="t19" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t20" 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="t21" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t22" class="stm run hide_run"><span class="key">def</span> <span class="nam">three</span><span class="op">(</span><span class="op">)</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t23" class="stm run hide_run">&nbsp; &nbsp; <span class="key">try</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t24" class="pln">&nbsp; &nbsp; &nbsp; &nbsp; <span class="com"># This if has two branches, *neither* one taken.</span><span class="strut">&nbsp;</span></p>
+<p id="t25" class="stm par run hide_run"><span class="annotate" title="no jumps to these line numbers">26&nbsp;&nbsp; 28</span>&nbsp; &nbsp; &nbsp; &nbsp; <span class="key">if</span> <span class="nam">name_error_this_variable_doesnt_exist</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t26" class="stm mis">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nam">a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t27" class="pln">&nbsp; &nbsp; &nbsp; &nbsp; <span class="key">else</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t28" class="stm mis">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nam">a</span> <span class="op">=</span> <span class="num">2</span><span class="strut">&nbsp;</span></p>
+<p id="t29" class="stm run hide_run">&nbsp; &nbsp; <span class="key">except</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t30" class="stm run hide_run">&nbsp; &nbsp; &nbsp; &nbsp; <span class="key">pass</span><span class="strut">&nbsp;</span></p>
+<p id="t31" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t32" class="stm run hide_run"><span class="nam">three</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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_b_branch/index.html b/tests/farm/html/gold_b_branch/index.html
index be4adc89..ebc3a106 100644
--- a/tests/farm/html/gold_b_branch/index.html
+++ b/tests/farm/html/gold_b_branch/index.html
@@ -1,28 +1,28 @@
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>70%</span>
+ <span class="pc_cov">70%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,44 +30,44 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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">b</span>
+ <span class="key">p</span>
- <span class='key'>c</span> &nbsp; change column sorting
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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="shortkey_b">branches</th>
+ <th class="shortkey_p">partial</th>
- <th class='right shortkey_c'>coverage</th>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>17</td>
<td>3</td>
<td>0</td>
@@ -75,13 +75,13 @@
<td>6</td>
<td>4</td>
- <td class='right' data-ratio='16 23'>70%</td>
+ <td class="right" data-ratio="16 23">70%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='b.html'>b</a></td>
+ <tr class="file">
+ <td class="name left"><a href="b.html">b</a></td>
<td>17</td>
<td>3</td>
<td>0</td>
@@ -89,7 +89,7 @@
<td>6</td>
<td>4</td>
- <td class='right' data-ratio='16 23'>70%</td>
+ <td class="right" data-ratio="16 23">70%</td>
</tr>
</tbody>
@@ -100,10 +100,10 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="http://nedbatchelder.com/code/coverage/4.0a1">coverage.py v4.0a1</a>
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_bom/bom_py.html b/tests/farm/html/gold_bom/bom_py.html
index 40c64bdb..127f2f45 100644
--- a/tests/farm/html/gold_bom/bom_py.html
+++ b/tests/farm/html/gold_bom/bom_py.html
@@ -1,104 +1,104 @@
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
<title>Coverage for bom: 71%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage for <b>bom</b> :
- <span class='pc_cov'>71%</span>
+ <span class="pc_cov">71%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <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>
+ <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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<p id='t1' class='pln'><span class='err'>&#65533;</span><span class='err'>&#65533;</span><span class='err'>&#65533;</span><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 class="text">
+<p id="t1" class="pln"><span class="err">&#65533;</span><span class="err">&#65533;</span><span class="err">&#65533;</span><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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="http://nedbatchelder.com/code/coverage/4.0a1">coverage.py v4.0a1</a>
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_bom/index.html b/tests/farm/html/gold_bom/index.html
index 525e7778..77696727 100644
--- a/tests/farm/html/gold_bom/index.html
+++ b/tests/farm/html/gold_bom/index.html
@@ -1,28 +1,28 @@
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>71%</span>
+ <span class="pc_cov">71%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,54 +30,54 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>7</td>
<td>2</td>
<td>0</td>
- <td class='right' data-ratio='5 7'>71%</td>
+ <td class="right" data-ratio="5 7">71%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='bom.html'>bom</a></td>
+ <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' data-ratio='5 7'>71%</td>
+ <td class="right" data-ratio="5 7">71%</td>
</tr>
</tbody>
@@ -88,10 +88,10 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="http://nedbatchelder.com/code/coverage/4.0a1">coverage.py v4.0a1</a>
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_isolatin1/index.html b/tests/farm/html/gold_isolatin1/index.html
index b111b86f..ee49cc5e 100644
--- a/tests/farm/html/gold_isolatin1/index.html
+++ b/tests/farm/html/gold_isolatin1/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,54 +33,54 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='isolatin1.html'>isolatin1</a></td>
+ <tr class="file">
+ <td class="name left"><a href="isolatin1_py.html">isolatin1.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
</tbody>
@@ -88,10 +91,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_isolatin1/isolatin1_py.html b/tests/farm/html/gold_isolatin1/isolatin1_py.html
index 0e4ac95a..bad0d78d 100644
--- a/tests/farm/html/gold_isolatin1/isolatin1_py.html
+++ b/tests/farm/html/gold_isolatin1/isolatin1_py.html
@@ -1,92 +1,102 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for isolatin1.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>isolatin1</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>isolatin1.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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="pln"><a href="#n4">4</a></p>
+<p id="n5" class="pln"><a href="#n5">5</a></p>
+<p id="n6" class="pln"><a href="#n6">6</a></p>
+<p id="n7" class="stm run hide_run"><a href="#n7">7</a></p>
+<p id="n8" class="stm run hide_run"><a href="#n8">8</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># -*- coding: iso8859-1 -*-</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t4" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t5" class="pln"><span class="com"># A Python source file in another encoding.</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t7" 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="t8" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_1/index.html b/tests/farm/html/gold_omit_1/index.html
index 7cacebbd..404d6b6a 100644
--- a/tests/farm/html/gold_omit_1/index.html
+++ b/tests/farm/html/gold_omit_1/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,81 +33,81 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>14</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='14 14'>100%</td>
+ <td class="right" data-ratio="14 14">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='m1.html'>m1</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m1_py.html">m1.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='m2.html'>m2</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m2_py.html">m2.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m3_py.html">m3.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
+ <tr class="file">
+ <td class="name left"><a href="main_py.html">main.py</a></td>
<td>8</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='8 8'>100%</td>
+ <td class="right" data-ratio="8 8">100%</td>
</tr>
</tbody>
@@ -115,10 +118,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_1/m1_py.html b/tests/farm/html/gold_omit_1/m1_py.html
index de44f789..44d73e49 100644
--- a/tests/farm/html/gold_omit_1/m1_py.html
+++ b/tests/farm/html/gold_omit_1/m1_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m1.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m1</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m1.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_1/m2_py.html b/tests/farm/html/gold_omit_1/m2_py.html
index c775e6bb..ff75cbe9 100644
--- a/tests/farm/html/gold_omit_1/m2_py.html
+++ b/tests/farm/html/gold_omit_1/m2_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m2.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m2</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m2.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m2a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_1/m3_py.html b/tests/farm/html/gold_omit_1/m3_py.html
index 67354c48..4cdcc088 100644
--- a/tests/farm/html/gold_omit_1/m3_py.html
+++ b/tests/farm/html/gold_omit_1/m3_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m3.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m3.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m3a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_1/main_py.html b/tests/farm/html/gold_omit_1/main_py.html
index a71b10e4..d33dfedc 100644
--- a/tests/farm/html/gold_omit_1/main_py.html
+++ b/tests/farm/html/gold_omit_1/main_py.html
@@ -1,102 +1,112 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for main.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>main.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
8 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>8 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">8 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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>
+<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="stm run hide_run"><a href="#n13">13</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</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="nam">a</span> <span class="op">=</span> <span class="num">5</span><span class="strut">&nbsp;</span></p>
+<p id="t9" 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="t10" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t11" 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="t12" 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="t13" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_2/index.html b/tests/farm/html/gold_omit_2/index.html
index b6d495c8..01c13e31 100644
--- a/tests/farm/html/gold_omit_2/index.html
+++ b/tests/farm/html/gold_omit_2/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,72 +33,72 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>12</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='12 12'>100%</td>
+ <td class="right" data-ratio="12 12">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='m2.html'>m2</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m2_py.html">m2.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m3_py.html">m3.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
+ <tr class="file">
+ <td class="name left"><a href="main_py.html">main.py</a></td>
<td>8</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='8 8'>100%</td>
+ <td class="right" data-ratio="8 8">100%</td>
</tr>
</tbody>
@@ -106,10 +109,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_2/m2_py.html b/tests/farm/html/gold_omit_2/m2_py.html
index c775e6bb..ff75cbe9 100644
--- a/tests/farm/html/gold_omit_2/m2_py.html
+++ b/tests/farm/html/gold_omit_2/m2_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m2.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m2</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m2.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m2a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_2/m3_py.html b/tests/farm/html/gold_omit_2/m3_py.html
index 67354c48..4cdcc088 100644
--- a/tests/farm/html/gold_omit_2/m3_py.html
+++ b/tests/farm/html/gold_omit_2/m3_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m3.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m3.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m3a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_2/main_py.html b/tests/farm/html/gold_omit_2/main_py.html
index a71b10e4..d33dfedc 100644
--- a/tests/farm/html/gold_omit_2/main_py.html
+++ b/tests/farm/html/gold_omit_2/main_py.html
@@ -1,102 +1,112 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for main.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>main.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
8 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>8 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">8 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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>
+<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="stm run hide_run"><a href="#n13">13</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</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="nam">a</span> <span class="op">=</span> <span class="num">5</span><span class="strut">&nbsp;</span></p>
+<p id="t9" 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="t10" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t11" 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="t12" 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="t13" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_3/index.html b/tests/farm/html/gold_omit_3/index.html
index db0ad581..79192911 100644
--- a/tests/farm/html/gold_omit_3/index.html
+++ b/tests/farm/html/gold_omit_3/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,63 +33,63 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>10</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='10 10'>100%</td>
+ <td class="right" data-ratio="10 10">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m3_py.html">m3.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
+ <tr class="file">
+ <td class="name left"><a href="main_py.html">main.py</a></td>
<td>8</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='8 8'>100%</td>
+ <td class="right" data-ratio="8 8">100%</td>
</tr>
</tbody>
@@ -97,10 +100,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_3/m3_py.html b/tests/farm/html/gold_omit_3/m3_py.html
index 67354c48..4cdcc088 100644
--- a/tests/farm/html/gold_omit_3/m3_py.html
+++ b/tests/farm/html/gold_omit_3/m3_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m3.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m3.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m3a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_3/main_py.html b/tests/farm/html/gold_omit_3/main_py.html
index a71b10e4..d33dfedc 100644
--- a/tests/farm/html/gold_omit_3/main_py.html
+++ b/tests/farm/html/gold_omit_3/main_py.html
@@ -1,102 +1,112 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for main.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>main.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
8 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>8 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">8 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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>
+<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="stm run hide_run"><a href="#n13">13</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</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="nam">a</span> <span class="op">=</span> <span class="num">5</span><span class="strut">&nbsp;</span></p>
+<p id="t9" 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="t10" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t11" 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="t12" 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="t13" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_4/index.html b/tests/farm/html/gold_omit_4/index.html
index 130e2993..0e52f497 100644
--- a/tests/farm/html/gold_omit_4/index.html
+++ b/tests/farm/html/gold_omit_4/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,72 +33,72 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>12</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='12 12'>100%</td>
+ <td class="right" data-ratio="12 12">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='m1.html'>m1</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m1_py.html">m1.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='m3.html'>m3</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m3_py.html">m3.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
+ <tr class="file">
+ <td class="name left"><a href="main_py.html">main.py</a></td>
<td>8</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='8 8'>100%</td>
+ <td class="right" data-ratio="8 8">100%</td>
</tr>
</tbody>
@@ -106,10 +109,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_4/m1_py.html b/tests/farm/html/gold_omit_4/m1_py.html
index de44f789..44d73e49 100644
--- a/tests/farm/html/gold_omit_4/m1_py.html
+++ b/tests/farm/html/gold_omit_4/m1_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m1.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m1</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m1.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_4/m3_py.html b/tests/farm/html/gold_omit_4/m3_py.html
index 67354c48..4cdcc088 100644
--- a/tests/farm/html/gold_omit_4/m3_py.html
+++ b/tests/farm/html/gold_omit_4/m3_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m3.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m3</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m3.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m3a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_4/main_py.html b/tests/farm/html/gold_omit_4/main_py.html
index a71b10e4..d33dfedc 100644
--- a/tests/farm/html/gold_omit_4/main_py.html
+++ b/tests/farm/html/gold_omit_4/main_py.html
@@ -1,102 +1,112 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for main.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>main.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
8 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>8 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">8 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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>
+<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="stm run hide_run"><a href="#n13">13</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</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="nam">a</span> <span class="op">=</span> <span class="num">5</span><span class="strut">&nbsp;</span></p>
+<p id="t9" 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="t10" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t11" 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="t12" 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="t13" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_5/index.html b/tests/farm/html/gold_omit_5/index.html
index 66306a29..509e7900 100644
--- a/tests/farm/html/gold_omit_5/index.html
+++ b/tests/farm/html/gold_omit_5/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,63 +33,63 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>10</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='10 10'>100%</td>
+ <td class="right" data-ratio="10 10">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='m1.html'>m1</a></td>
+ <tr class="file">
+ <td class="name left"><a href="m1_py.html">m1.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='main.html'>main</a></td>
+ <tr class="file">
+ <td class="name left"><a href="main_py.html">main.py</a></td>
<td>8</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='8 8'>100%</td>
+ <td class="right" data-ratio="8 8">100%</td>
</tr>
</tbody>
@@ -97,10 +100,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_5/m1_py.html b/tests/farm/html/gold_omit_5/m1_py.html
index de44f789..44d73e49 100644
--- a/tests/farm/html/gold_omit_5/m1_py.html
+++ b/tests/farm/html/gold_omit_5/m1_py.html
@@ -1,86 +1,96 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for m1.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>m1</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>m1.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1a</span> <span class="op">=</span> <span class="num">1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_omit_5/main_py.html b/tests/farm/html/gold_omit_5/main_py.html
index a71b10e4..d33dfedc 100644
--- a/tests/farm/html/gold_omit_5/main_py.html
+++ b/tests/farm/html/gold_omit_5/main_py.html
@@ -1,102 +1,112 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for main.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>main</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>main.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
8 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>8 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">8 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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>
+<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="stm run hide_run"><a href="#n13">13</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</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">m1</span><span class="strut">&nbsp;</span></p>
+<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</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="nam">a</span> <span class="op">=</span> <span class="num">5</span><span class="strut">&nbsp;</span></p>
+<p id="t9" 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="t10" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t11" 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="t12" 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="t13" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_other/blah_blah_other_py.html b/tests/farm/html/gold_other/blah_blah_other_py.html
index f070f3ef..54861c23 100644
--- a/tests/farm/html/gold_other/blah_blah_other_py.html
+++ b/tests/farm/html/gold_other/blah_blah_other_py.html
@@ -1,90 +1,100 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <meta http-equiv='X-UA-Compatible' content='IE=emulateIE7' />
- <title>Coverage for /Users/ned/coverage/trunk/tests/farm/html/othersrc/other: 100%</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for /Users/ned/coverage/trunk/tests/farm/html/othersrc/other.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>/Users/ned/coverage/trunk/tests/farm/html/othersrc/other</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>/Users/ned/coverage/trunk/tests/farm/html/othersrc/other.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
1 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>1 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">1 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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="pln"><a href="#n4">4</a></p>
+<p id="n5" class="pln"><a href="#n5">5</a></p>
+<p id="n6" class="pln"><a href="#n6">6</a></p>
+<p id="n7" class="stm run hide_run"><a href="#n7">7</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t4" 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="t5" class="pln"><span class="com"># HTML report.</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t7" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_other/here_py.html b/tests/farm/html/gold_other/here_py.html
index e091395a..82aa70a2 100644
--- a/tests/farm/html/gold_other/here_py.html
+++ b/tests/farm/html/gold_other/here_py.html
@@ -1,98 +1,108 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for here.py: 75%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>here</b> :
- <span class='pc_cov'>75%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>here.py</b> :
+ <span class="pc_cov">75%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
4 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>3 run</span>
- <span class='mis shortkey_m button_toggle_mis'>1 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">3 run</span>
+ <span class="mis shortkey_m button_toggle_mis">1 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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="pln"><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="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 mis"><a href="#n11">11</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</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">import</span> <span class="nam">other</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">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="t9" 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="t10" class="pln"><span class="key">else</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t11" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_other/index.html b/tests/farm/html/gold_other/index.html
index a27295c4..9a8d72de 100644
--- a/tests/farm/html/gold_other/index.html
+++ b/tests/farm/html/gold_other/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>80%</span>
+ <span class="pc_cov">80%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,63 +33,63 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>5</td>
<td>1</td>
<td>0</td>
- <td class='right' data-ratio='4 5'>80%</td>
+ <td class="right" data-ratio="4 5">80%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='_Users_ned_coverage_trunk_tests_farm_html_othersrc_other.html'>/Users/ned/coverage/trunk/tests/farm/html/othersrc/other</a></td>
+ <tr class="file">
+ <td class="name left"><a href="_Users_ned_coverage_trunk_tests_farm_html_othersrc_other_py.html">/Users/ned/coverage/trunk/tests/farm/html/othersrc/other.py</a></td>
<td>1</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='1 1'>100%</td>
+ <td class="right" data-ratio="1 1">100%</td>
</tr>
- <tr class='file'>
- <td class='name left'><a href='here.html'>here</a></td>
+ <tr class="file">
+ <td class="name left"><a href="here_py.html">here.py</a></td>
<td>4</td>
<td>1</td>
<td>0</td>
- <td class='right' data-ratio='3 4'>75%</td>
+ <td class="right" data-ratio="3 4">75%</td>
</tr>
</tbody>
@@ -97,10 +100,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_partial/index.html b/tests/farm/html/gold_partial/index.html
index 5445d769..40ffcc4c 100644
--- a/tests/farm/html/gold_partial/index.html
+++ b/tests/farm/html/gold_partial/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,44 +33,44 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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">b</span>
+ <span class="key">p</span>
- <span class='key'>c</span> &nbsp; change column sorting
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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="shortkey_b">branches</th>
+ <th class="shortkey_p">partial</th>
- <th class='right shortkey_c'>coverage</th>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>8</td>
<td>0</td>
<td>0</td>
@@ -75,13 +78,13 @@
<td>4</td>
<td>0</td>
- <td class='right' data-ratio='12 12'>100%</td>
+ <td class="right" data-ratio="12 12">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='partial.html'>partial</a></td>
+ <tr class="file">
+ <td class="name left"><a href="partial_py.html">partial.py</a></td>
<td>8</td>
<td>0</td>
<td>0</td>
@@ -89,7 +92,7 @@
<td>4</td>
<td>0</td>
- <td class='right' data-ratio='12 12'>100%</td>
+ <td class="right" data-ratio="12 12">100%</td>
</tr>
</tbody>
@@ -100,10 +103,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_partial/partial_py.html b/tests/farm/html/gold_partial/partial_py.html
index 64dfacfa..796153f1 100644
--- a/tests/farm/html/gold_partial/partial_py.html
+++ b/tests/farm/html/gold_partial/partial_py.html
@@ -1,120 +1,130 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for partial.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>partial</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>partial.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
8 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>8 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">8 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 missing</span>
+ <span class="exc shortkey_x button_toggle_exc">0 excluded</span>
- <span class='par run hide_run shortkey_p button_toggle_par'>0 partial</span>
+ <span class="par run hide_run shortkey_p button_toggle_par">0 partial</span>
</h2>
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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>
+ <td class="linenos">
+<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="pln"><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="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="stm 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="pln"><a href="#n17">17</a></p>
+<p id="n18" class="pln"><a href="#n18">18</a></p>
+<p id="n19" class="pln"><a href="#n19">19</a></p>
+<p id="n20" class="pln"><a href="#n20">20</a></p>
+<p id="n21" class="stm run hide_run"><a href="#n21">21</a></p>
</td>
- <td class='text'>
-<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>
+ <td class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t4" class="pln"><span class="com"># partial branches</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="nam">a</span> <span class="op">=</span> <span class="num">3</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="nam">True</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="num">1</span><span class="op">:</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="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="t15" class="stm run hide_run">&nbsp; &nbsp; <span class="key">break</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">0</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t18" 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="t19" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t20" class="pln"><span class="key">if</span> <span class="num">1</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t21" 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>
</td>
</tr>
</table>
</div>
-<div id='footer'>
- <div class='content'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_styled/a_py.html b/tests/farm/html/gold_styled/a_py.html
index 9fdaee17..c8221753 100644
--- a/tests/farm/html/gold_styled/a_py.html
+++ b/tests/farm/html/gold_styled/a_py.html
@@ -1,98 +1,108 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for a.py: 67%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <link rel='stylesheet' href='extra.css' type='text/css'>
+ <link rel="stylesheet" href="extra.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>a</b> :
- <span class='pc_cov'>67%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>a.py</b> :
+ <span class="pc_cov">67%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
3 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>1 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">1 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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="pln"><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="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="pln"><a href="#n9">9</a></p>
+<p id="n10" class="stm mis"><a href="#n10">10</a></p>
</td>
- <td class='text'>
-<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 class="text">
+<p id="t1" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</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="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="t7" class="pln">&nbsp; &nbsp; <span class="com"># Needed a &lt; to look at HTML entities.</span><span class="strut">&nbsp;</span></p>
+<p id="t8" 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="t9" class="pln"><span class="key">else</span><span class="op">:</span><span class="strut">&nbsp;</span></p>
+<p id="t10" 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'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_styled/index.html b/tests/farm/html/gold_styled/index.html
index 87a8c3db..05a8fe21 100644
--- a/tests/farm/html/gold_styled/index.html
+++ b/tests/farm/html/gold_styled/index.html
@@ -1,30 +1,33 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <link rel='stylesheet' href='extra.css' type='text/css'>
+ <link rel="stylesheet" href="extra.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>67%</span>
+ <span class="pc_cov">67%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -32,54 +35,54 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>3</td>
<td>1</td>
<td>0</td>
- <td class='right' data-ratio='2 3'>67%</td>
+ <td class="right" data-ratio="2 3">67%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='a.html'>a</a></td>
+ <tr class="file">
+ <td class="name left"><a href="a_py.html">a.py</a></td>
<td>3</td>
<td>1</td>
<td>0</td>
- <td class='right' data-ratio='2 3'>67%</td>
+ <td class="right" data-ratio="2 3">67%</td>
</tr>
</tbody>
@@ -90,10 +93,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_styled/style.css b/tests/farm/html/gold_styled/style.css
index 038335c1..c3767eef 100644
--- a/tests/farm/html/gold_styled/style.css
+++ b/tests/farm/html/gold_styled/style.css
@@ -1,4 +1,7 @@
-/* CSS styles for Coverage. */
+/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
+/* For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt */
+
+/* CSS styles for coverage.py. */
/* Page-wide styles */
html, body, h1, h2, h3, p, table, td, th {
margin: 0;
@@ -61,7 +64,7 @@ a.nav:hover {
#source {
padding: 1em;
- font-family: "courier new", monospace;
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.indexfile #footer {
@@ -157,7 +160,7 @@ h2.stats {
.help_panel {
position: absolute;
- background: #ffc;
+ background: #ffffcc;
padding: .5em;
border: 1px solid #883;
display: none;
@@ -223,7 +226,8 @@ td.text {
margin: 0;
padding: 0 0 0 .5em;
border-left: 2px solid #ffffff;
- white-space: nowrap;
+ white-space: pre;
+ position: relative;
}
.text p.mis {
@@ -249,7 +253,6 @@ td.text {
.text span.annotate {
font-family: georgia;
- font-style: italic;
color: #666;
float: right;
padding-right: .5em;
@@ -257,6 +260,27 @@ td.text {
.text p.hide_par span.annotate {
display: none;
}
+.text span.annotate.long {
+ display: none;
+ }
+.text p:hover span.annotate.long {
+ display: block;
+ max-width: 50%;
+ white-space: normal;
+ float: right;
+ position: absolute;
+ top: 1.75em;
+ right: 1em;
+ width: 30em;
+ height: auto;
+ color: #333;
+ background: #ffffcc;
+ border: 1px solid #888;
+ padding: .25em .5em;
+ z-index: 999;
+ border-radius: .2em;
+ box-shadow: #cccccc .2em .2em .2em;
+ }
/* Syntax coloring */
.text .com {
@@ -306,10 +330,6 @@ td.text {
text-decoration: none;
color: #000;
}
-#index td.name a:hover {
- text-decoration: underline;
- color: #000;
- }
#index tr.total,
#index tr.total_dynamic {
}
@@ -322,3 +342,25 @@ td.text {
#index tr.file:hover {
background: #eeeeee;
}
+#index tr.file:hover td.name {
+ text-decoration: underline;
+ color: #000;
+ }
+
+/* scroll marker styles */
+#scroll_marker {
+ position: fixed;
+ right: 0;
+ top: 0;
+ width: 16px;
+ height: 100%;
+ background: white;
+ border-left: 1px solid #eee;
+ }
+
+#scroll_marker .marker {
+ background: #ffdddd;
+ position: absolute;
+ min-height: 3px;
+ width: 100%;
+ }
diff --git a/tests/farm/html/gold_unicode/index.html b/tests/farm/html/gold_unicode/index.html
index dae53ea0..6d8268d8 100644
--- a/tests/farm/html/gold_unicode/index.html
+++ b/tests/farm/html/gold_unicode/index.html
@@ -1,28 +1,31 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
- <link rel='stylesheet' href='style.css' type='text/css'>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.min.js'></script>
- <script type='text/javascript' src='jquery.debounce.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'>
+ <script type="text/javascript" src="jquery.min.js"></script>
+ <script type="text/javascript" src="jquery.debounce.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">
jQuery(document).ready(coverage.index_ready);
</script>
</head>
-<body class='indexfile'>
+<body class="indexfile">
-<div id='header'>
- <div class='content'>
+<div id="header">
+ <div class="content">
<h1>Coverage report:
- <span class='pc_cov'>100%</span>
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter..." />
@@ -30,54 +33,54 @@
</div>
</div>
-<div class='help_panel'>
- <img id='panel_icon' src='keybd_open.png' alt='Hide keyboard shortcuts' />
- <p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+ <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>
+ <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
+ <span class="key">c</span> &nbsp; change column sorting
</p>
</div>
</div>
-<div id='index'>
- <table class='index'>
+<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>
+ <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>
+ <th class="right shortkey_c">coverage</th>
</tr>
</thead>
<tfoot>
- <tr class='total'>
- <td class='name left'>Total</td>
+ <tr class="total">
+ <td class="name left">Total</td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
</tfoot>
<tbody>
- <tr class='file'>
- <td class='name left'><a href='unicode.html'>unicode</a></td>
+ <tr class="file">
+ <td class="name left"><a href="unicode_py.html">unicode.py</a></td>
<td>2</td>
<td>0</td>
<td>0</td>
- <td class='right' data-ratio='2 2'>100%</td>
+ <td class="right" data-ratio="2 2">100%</td>
</tr>
</tbody>
@@ -88,10 +91,11 @@
</p>
</div>
-<div id='footer'>
- <div class='content'>
+<div id="footer">
+ <div class="content">
<p>
- <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:31
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_unicode/unicode_py.html b/tests/farm/html/gold_unicode/unicode_py.html
index d67af56d..83b0f382 100644
--- a/tests/farm/html/gold_unicode/unicode_py.html
+++ b/tests/farm/html/gold_unicode/unicode_py.html
@@ -1,92 +1,102 @@
+
+
+
<!DOCTYPE html>
<html>
<head>
- <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <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'>
+ <meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
+ <title>Coverage for unicode.py: 100%</title>
+ <link rel="stylesheet" href="style.css" type="text/css">
- <script type='text/javascript' src='jquery.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'>
+ <script type="text/javascript" src="jquery.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">
jQuery(document).ready(coverage.pyfile_ready);
</script>
</head>
-<body class='pyfile'>
+<body class="pyfile">
-<div id='header'>
- <div class='content'>
- <h1>Coverage for <b>unicode</b> :
- <span class='pc_cov'>100%</span>
+<div id="header">
+ <div class="content">
+ <h1>Coverage for <b>unicode.py</b> :
+ <span class="pc_cov">100%</span>
</h1>
- <img id='keyboard_icon' src='keybd_closed.png' alt='Show keyboard shortcuts' />
+ <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
- <h2 class='stats'>
+ <h2 class="stats">
2 statements &nbsp;
- <span class='run hide_run shortkey_r button_toggle_run'>2 run</span>
- <span class='mis shortkey_m button_toggle_mis'>0 missing</span>
- <span class='exc shortkey_x button_toggle_exc'>0 excluded</span>
+ <span class="run hide_run shortkey_r button_toggle_run">2 run</span>
+ <span class="mis shortkey_m button_toggle_mis">0 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' alt='Hide keyboard shortcuts' />
-<p class='legend'>Hot-keys on this page</p>
+<div class="help_panel">
+ <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
+<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 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 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 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 class="keyhelp">
+ <span class="key">1</span> &nbsp; (one) first highlighted chunk
</p>
</div>
</div>
-<div id='source'>
+<div id="source">
<table>
<tr>
- <td class='linenos'>
-<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 class="linenos">
+<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="pln"><a href="#n4">4</a></p>
+<p id="n5" class="pln"><a href="#n5">5</a></p>
+<p id="n6" class="pln"><a href="#n6">6</a></p>
+<p id="n7" class="stm run hide_run"><a href="#n7">7</a></p>
+<p id="n8" class="stm run hide_run"><a href="#n8">8</a></p>
</td>
- <td class='text'>
-<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&#917760;&quot;</span><span class='strut'>&nbsp;</span></p>
+ <td class="text">
+<p id="t1" class="pln"><span class="com"># -*- coding: utf-8 -*-</span><span class="strut">&nbsp;</span></p>
+<p id="t2" class="pln"><span class="com"># Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0</span><span class="strut">&nbsp;</span></p>
+<p id="t3" class="pln"><span class="com"># For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt</span><span class="strut">&nbsp;</span></p>
+<p id="t4" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t5" class="pln"><span class="com"># A Python source file with exotic characters.</span><span class="strut">&nbsp;</span></p>
+<p id="t6" class="pln"><span class="strut">&nbsp;</span></p>
+<p id="t7" 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="t8" class="stm run hide_run"><span class="nam">surrogate</span> <span class="op">=</span> <span class="str">&quot;db40,dd00: x&#917760;&quot;</span><span class="strut">&nbsp;</span></p>
</td>
</tr>
</table>
</div>
-<div id='footer'>
- <div class='content'>
+<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/4.0a1'>coverage.py v4.0a1</a>
+ <a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/coverage-4.0a7">coverage.py v4.0a7</a>,
+ created at 2015-07-24 09:04
</p>
</div>
</div>
diff --git a/tests/farm/html/gold_x_xml/coverage.xml b/tests/farm/html/gold_x_xml/coverage.xml
index 1511ae89..b3e9854f 100644
--- a/tests/farm/html/gold_x_xml/coverage.xml
+++ b/tests/farm/html/gold_x_xml/coverage.xml
@@ -1,23 +1,22 @@
-<?xml version="1.0" ?>
-<!DOCTYPE coverage
- SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'>
-<coverage branch-rate="0" line-rate="0.6667" timestamp="1253972570431" version="3.1b1">
- <!-- Generated by coverage.py: https://coverage.readthedocs.org/VER -->
- <sources>
- <source></source>
- </sources>
- <packages>
- <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.py">
- <methods/>
- <lines>
- <line hits="1" number="3"/>
- <line hits="1" number="5"/>
- <line hits="0" number="7"/>
- </lines>
- </class>
- </classes>
- </package>
- </packages>
-</coverage>
+<?xml version="1.0" ?>
+<coverage branch-rate="0" line-rate="0.6667" timestamp="1437745880639" version="4.0a7">
+ <!-- Generated by coverage.py: https://coverage.readthedocs.io/en/coverage-4.0a7 -->
+ <!-- Based on https://raw.githubusercontent.com/cobertura/web/f0366e5e2cf18f111cbd61fc34ef720a6584ba02/htdocs/xml/coverage-03.dtd -->
+ <sources>
+ <source>/Users/ned/coverage/trunk/tests/farm/html/src</source>
+ </sources>
+ <packages>
+ <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.py">
+ <methods/>
+ <lines>
+ <line hits="1" number="6"/>
+ <line hits="1" number="8"/>
+ <line hits="0" number="10"/>
+ </lines>
+ </class>
+ </classes>
+ </package>
+ </packages>
+</coverage>
diff --git a/tests/farm/html/gold_y_xml_branch/coverage.xml b/tests/farm/html/gold_y_xml_branch/coverage.xml
index 8e098fe8..d8ff0bb7 100644
--- a/tests/farm/html/gold_y_xml_branch/coverage.xml
+++ b/tests/farm/html/gold_y_xml_branch/coverage.xml
@@ -1,25 +1,24 @@
-<?xml version="1.0" ?>
-<!DOCTYPE coverage
- SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'>
-<coverage branch-rate="0.5" line-rate="0.8" timestamp="1259288252325" version="3.2b4">
- <!-- Generated by coverage.py: https://coverage.readthedocs.org/VER -->
- <sources>
- <source></source>
- </sources>
- <packages>
- <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.py">
- <methods/>
- <lines>
- <line hits="1" number="3"/>
- <line branch="true" condition-coverage="50% (1/2)" hits="1" number="4"/>
- <line hits="1" number="5"/>
- <line hits="0" number="7"/>
- <line hits="1" number="9"/>
- </lines>
- </class>
- </classes>
- </package>
- </packages>
-</coverage>
+<?xml version="1.0" ?>
+<coverage branch-rate="0.5" line-rate="0.8" timestamp="1437745880882" version="4.0a7">
+ <!-- Generated by coverage.py: https://coverage.readthedocs.io/en/coverage-4.0a7 -->
+ <!-- Based on https://raw.githubusercontent.com/cobertura/web/f0366e5e2cf18f111cbd61fc34ef720a6584ba02/htdocs/xml/coverage-03.dtd -->
+ <sources>
+ <source>/Users/ned/coverage/trunk/tests/farm/html/src</source>
+ </sources>
+ <packages>
+ <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.py">
+ <methods/>
+ <lines>
+ <line hits="1" number="6"/>
+ <line branch="true" condition-coverage="50% (1/2)" hits="1" missing-branches="10" number="7"/>
+ <line hits="1" number="8"/>
+ <line hits="0" number="10"/>
+ <line hits="1" number="12"/>
+ </lines>
+ </class>
+ </classes>
+ </package>
+ </packages>
+</coverage>
diff --git a/tests/farm/html/othersrc/other.py b/tests/farm/html/othersrc/other.py
index 6d3f86e7..bf0304d2 100644
--- a/tests/farm/html/othersrc/other.py
+++ b/tests/farm/html/othersrc/other.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# A file in another directory. We're checking that it ends up in the
# HTML report.
diff --git a/tests/farm/html/run_a.py b/tests/farm/html/run_a.py
deleted file mode 100644
index f510e117..00000000
--- a/tests/farm/html/run_a.py
+++ /dev/null
@@ -1,26 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for a."""
- import coverage
- cov = coverage.coverage()
- cov.start()
- import a # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(a, directory="../html_a")
-
-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_a", "html_a", size_within=10, file_pattern="*.html")
-contains("html_a/a_py.html",
- '<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_a/index.html",
- '<a href="a_py.html">a.py</a>',
- '<span class="pc_cov">67%</span>',
- '<td class="right" data-ratio="2 3">67%</td>',
- )
-
-clean("html_a")
diff --git a/tests/farm/html/run_a_xml_1.py b/tests/farm/html/run_a_xml_1.py
deleted file mode 100644
index eec66174..00000000
--- a/tests/farm/html/run_a_xml_1.py
+++ /dev/null
@@ -1,26 +0,0 @@
-source_path = None
-
-def html_it():
- """Run coverage and make an XML report for a."""
- import coverage, coverage.files
- cov = coverage.coverage()
- cov.start()
- import a # pragma: nested
- cov.stop() # pragma: nested
- cov.xml_report(a, outfile="../xml_1/coverage.xml")
- global source_path
- source_path = coverage.files.relative_directory().rstrip('/')
-
-import os
-if not os.path.exists("xml_1"):
- os.makedirs("xml_1")
-
-runfunc(html_it, rundir="src")
-
-compare("gold_x_xml", "xml_1", scrubs=[
- (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
- (r' version="[-.\w]+"', ' version="VERSION"'),
- (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
- (r'/coverage.readthedocs.org/?[-.\w/]*', '/coverage.readthedocs.org/VER'),
- ])
-clean("xml_1")
diff --git a/tests/farm/html/run_a_xml_2.py b/tests/farm/html/run_a_xml_2.py
deleted file mode 100644
index 081c8aa3..00000000
--- a/tests/farm/html/run_a_xml_2.py
+++ /dev/null
@@ -1,26 +0,0 @@
-source_path = None
-
-def html_it():
- """Run coverage and make an XML report for a."""
- import coverage, coverage.files
- cov = coverage.coverage(config_file="run_a_xml_2.ini")
- cov.start()
- import a # pragma: nested
- cov.stop() # pragma: nested
- cov.xml_report(a)
- global source_path
- source_path = coverage.files.relative_directory().rstrip('/')
-
-import os
-if not os.path.exists("xml_2"):
- os.makedirs("xml_2")
-
-runfunc(html_it, rundir="src")
-
-compare("gold_x_xml", "xml_2", scrubs=[
- (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
- (r' version="[-.\w]+"', ' version="VERSION"'),
- (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
- (r'/coverage.readthedocs.org/?[-.\w/]*', '/coverage.readthedocs.org/VER'),
- ])
-clean("xml_2")
diff --git a/tests/farm/html/run_b_branch.py b/tests/farm/html/run_b_branch.py
deleted file mode 100644
index 388b5c5e..00000000
--- a/tests/farm/html/run_b_branch.py
+++ /dev/null
@@ -1,29 +0,0 @@
-def html_it():
- """Run coverage with branches and make an HTML report for b."""
- import coverage
- cov = coverage.coverage(branch=True)
- cov.start()
- import b # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(b, directory="../html_b_branch")
-
-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_b_branch", "html_b_branch", size_within=10, file_pattern="*.html")
-contains("html_b_branch/b_py.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">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">23&nbsp;&nbsp; 25</span>',
- )
-contains("html_b_branch/index.html",
- '<a href="b_py.html">b.py</a>',
- '<span class="pc_cov">70%</span>',
- '<td class="right" data-ratio="16 23">70%</td>',
- )
-
-clean("html_b_branch")
diff --git a/tests/farm/html/run_bom.py b/tests/farm/html/run_bom.py
deleted file mode 100644
index a6e6d8b8..00000000
--- a/tests/farm/html/run_bom.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import sys
-
-def html_it():
- """Run coverage and make an HTML report for bom.py."""
- import coverage
- cov = coverage.coverage()
- cov.start()
- import bom # pragma: nested
- cov.stop() # pragma: nested
- 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_py.html",
- '<span class="str">&quot;3&#215;4 = 12, &#247;2 = 6&#177;0&quot;</span>',
- )
-
-clean("html_bom")
diff --git a/tests/farm/html/run_isolatin1.py b/tests/farm/html/run_isolatin1.py
deleted file mode 100644
index b03cd25c..00000000
--- a/tests/farm/html/run_isolatin1.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import sys
-
-def html_it():
- """Run coverage and make an HTML report for isolatin1.py."""
- import coverage
- cov = coverage.coverage()
- cov.start()
- import isolatin1 # pragma: nested
- cov.stop() # pragma: nested
- 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_py.html",
- '<span class="str">&quot;3&#215;4 = 12, &#247;2 = 6&#177;0&quot;</span>',
- )
-
-clean("html_isolatin1")
diff --git a/tests/farm/html/run_omit_1.py b/tests/farm/html/run_omit_1.py
deleted file mode 100644
index 102aeb2a..00000000
--- a/tests/farm/html/run_omit_1.py
+++ /dev/null
@@ -1,12 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for main."""
- import coverage
- cov = coverage.coverage(include=["./*"])
- cov.start()
- import main # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(directory="../html_omit_1")
-
-runfunc(html_it, rundir="src")
-compare("gold_omit_1", "html_omit_1", size_within=10, file_pattern="*.html")
-clean("html_omit_1")
diff --git a/tests/farm/html/run_omit_2.py b/tests/farm/html/run_omit_2.py
deleted file mode 100644
index a149c518..00000000
--- a/tests/farm/html/run_omit_2.py
+++ /dev/null
@@ -1,12 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for main."""
- import coverage
- cov = coverage.coverage(include=["./*"])
- cov.start()
- import main # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(directory="../html_omit_2", omit=["m1.py"])
-
-runfunc(html_it, rundir="src")
-compare("gold_omit_2", "html_omit_2", size_within=10, file_pattern="*.html")
-clean("html_omit_2")
diff --git a/tests/farm/html/run_omit_3.py b/tests/farm/html/run_omit_3.py
deleted file mode 100644
index 07b38a8a..00000000
--- a/tests/farm/html/run_omit_3.py
+++ /dev/null
@@ -1,12 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for main."""
- import coverage
- cov = coverage.coverage(include=["./*"])
- cov.start()
- import main # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(directory="../html_omit_3", omit=["m1.py", "m2.py"])
-
-runfunc(html_it, rundir="src")
-compare("gold_omit_3", "html_omit_3", size_within=10, file_pattern="*.html")
-clean("html_omit_3")
diff --git a/tests/farm/html/run_omit_4.py b/tests/farm/html/run_omit_4.py
deleted file mode 100644
index 8c0c789c..00000000
--- a/tests/farm/html/run_omit_4.py
+++ /dev/null
@@ -1,12 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for main."""
- import coverage
- cov = coverage.coverage(config_file="omit4.ini", include=["./*"])
- cov.start()
- import main # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(directory="../html_omit_4")
-
-runfunc(html_it, rundir="src")
-compare("gold_omit_4", "html_omit_4", size_within=10, file_pattern="*.html")
-clean("html_omit_4")
diff --git a/tests/farm/html/run_omit_5.py b/tests/farm/html/run_omit_5.py
deleted file mode 100644
index 4ba5e50c..00000000
--- a/tests/farm/html/run_omit_5.py
+++ /dev/null
@@ -1,12 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for main."""
- import coverage
- cov = coverage.coverage(config_file="omit5.ini", include=["./*"])
- cov.start()
- import main # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report()
-
-runfunc(html_it, rundir="src")
-compare("gold_omit_5", "html_omit_5", size_within=10, file_pattern="*.html")
-clean("html_omit_5")
diff --git a/tests/farm/html/run_other.py b/tests/farm/html/run_other.py
deleted file mode 100644
index 7c7f344a..00000000
--- a/tests/farm/html/run_other.py
+++ /dev/null
@@ -1,26 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for everything."""
- import coverage
- cov = coverage.coverage(include=["./*", "../othersrc/*"])
- cov.start()
- import here # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(directory="../html_other")
-
-runfunc(html_it, rundir="src", addtopath="../othersrc")
-
-# Different platforms will name the "other" file differently. Rename it
-import os, glob
-
-for p in glob.glob("html_other/*_other_py.html"):
- os.rename(p, "html_other/blah_blah_other_py.html")
-
-# HTML files will change often. Check that the sizes are reasonable,
-# and check that certain key strings are in the output.
-compare("gold_other", "html_other", size_within=10, file_pattern="*.html")
-contains("html_other/index.html",
- '<a href="here_py.html">here.py</a>',
- 'other_py.html">', 'other.py</a>',
- )
-
-clean("html_other")
diff --git a/tests/farm/html/run_partial.py b/tests/farm/html/run_partial.py
deleted file mode 100644
index 7330bb27..00000000
--- a/tests/farm/html/run_partial.py
+++ /dev/null
@@ -1,31 +0,0 @@
-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 # pragma: nested
- cov.stop() # pragma: nested
- 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_py.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_py.html">partial.py</a>',
- )
-contains("html_partial/index.html",
- '<span class="pc_cov">100%</span>'
- )
-
-clean("html_partial")
diff --git a/tests/farm/html/run_styled.py b/tests/farm/html/run_styled.py
deleted file mode 100644
index ebfbf3bc..00000000
--- a/tests/farm/html/run_styled.py
+++ /dev/null
@@ -1,28 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for a."""
- import coverage
- cov = coverage.coverage()
- cov.start()
- import a # pragma: nested
- cov.stop() # pragma: nested
- 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_py.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_py.html">a.py</a>',
- '<span class="pc_cov">67%</span>'
- )
-
-clean("html_styled")
diff --git a/tests/farm/html/run_tabbed.py b/tests/farm/html/run_tabbed.py
deleted file mode 100644
index 3e8a900f..00000000
--- a/tests/farm/html/run_tabbed.py
+++ /dev/null
@@ -1,24 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for tabbed."""
- import coverage
- cov = coverage.coverage()
- cov.start()
- import tabbed # pragma: nested
- cov.stop() # pragma: nested
- cov.html_report(tabbed, directory="../html_tabbed")
-
-runfunc(html_it, rundir="src")
-
-# Editors like to change things, make sure our source file still has tabs.
-contains("src/tabbed.py", "\tif x:\t\t\t\t\t# look nice")
-
-contains("html_tabbed/tabbed_py.html",
- '>&nbsp; &nbsp; &nbsp; &nbsp; <span class="key">if</span> '
- '<span class="nam">x</span><span class="op">:</span>'
- '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '
- '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; '
- '<span class="com"># look nice</span>'
- )
-
-doesnt_contain("html_tabbed/tabbed_py.html", "\t")
-clean("html_tabbed")
diff --git a/tests/farm/html/run_unicode.py b/tests/farm/html/run_unicode.py
deleted file mode 100644
index 455d0168..00000000
--- a/tests/farm/html/run_unicode.py
+++ /dev/null
@@ -1,24 +0,0 @@
-def html_it():
- """Run coverage and make an HTML report for unicode.py."""
- import coverage
- cov = coverage.coverage()
- cov.start()
- import unicode # pragma: nested
- cov.stop() # pragma: nested
- 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_py.html",
- '<span class="str">&quot;&#654;d&#729;&#477;b&#592;&#633;&#477;&#652;o&#596;&quot;</span>',
- )
-
-contains_any("html_unicode/unicode_py.html",
- '<span class="str">&quot;db40,dd00: x&#56128;&#56576;&quot;</span>',
- '<span class="str">&quot;db40,dd00: x&#917760;&quot;</span>',
- )
-
-clean("html_unicode")
diff --git a/tests/farm/html/run_y_xml_branch.py b/tests/farm/html/run_y_xml_branch.py
deleted file mode 100644
index b26f3af8..00000000
--- a/tests/farm/html/run_y_xml_branch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-source_path = None
-
-def xml_it():
- """Run coverage and make an XML report for y."""
- import coverage, coverage.files
- cov = coverage.coverage(branch=True)
- cov.start()
- import y # pragma: nested
- cov.stop() # pragma: nested
- cov.xml_report(y, outfile="../xml_branch/coverage.xml")
- global source_path
- source_path = coverage.files.relative_directory().rstrip('/')
-
-import os
-if not os.path.exists("xml_branch"):
- os.makedirs("xml_branch")
-
-runfunc(xml_it, rundir="src")
-
-compare("gold_y_xml_branch", "xml_branch", scrubs=[
- (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
- (r' version="[-.\w]+"', ' version="VERSION"'),
- (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
- (r'/coverage.readthedocs.org/?[-.\w/]*', '/coverage.readthedocs.org/VER'),
- ])
-clean("xml_branch")
diff --git a/tests/farm/html/src/a.py b/tests/farm/html/src/a.py
index 9e71aebd..85764e21 100644
--- a/tests/farm/html/src/a.py
+++ b/tests/farm/html/src/a.py
@@ -1,4 +1,7 @@
-# A test file for HTML reporting by coverage.
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+# A test file for HTML reporting by coverage.py.
if 1 < 2:
# Needed a < to look at HTML entities.
diff --git a/tests/farm/html/src/b.py b/tests/farm/html/src/b.py
index 3bf73a9f..cb673c22 100644
--- a/tests/farm/html/src/b.py
+++ b/tests/farm/html/src/b.py
@@ -1,4 +1,7 @@
-# A test file for HTML reporting by coverage.
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+# A test file for HTML reporting by coverage.py.
def one(x):
# This will be a branch that misses the else.
diff --git a/tests/farm/html/src/bom.py b/tests/farm/html/src/bom.py
index 1aff5d52..21d26ca2 100644
--- a/tests/farm/html/src/bom.py
+++ b/tests/farm/html/src/bom.py
@@ -1,11 +1,14 @@
-# A Python source file in utf-8, with BOM.
-math = "3×4 = 12, ÷2 = 6±0"
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
-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
+# 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/tests/farm/html/src/coverage.xml b/tests/farm/html/src/coverage.xml
deleted file mode 100644
index e20cdaec..00000000
--- a/tests/farm/html/src/coverage.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE coverage
- SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'>
-<coverage branch-rate="0.0" line-rate="0.666666666667" timestamp="1263087779313" version="3.3a1">
- <!-- Generated by coverage.py: http://nedbatchelder.com/code/coverage -->
- <sources>
- <source></source>
- </sources>
- <packages>
- <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/>
- <lines>
- <line hits="1" number="3"/>
- <line hits="1" number="5"/>
- <line hits="0" number="7"/>
- </lines>
- </class>
- </classes>
- </package>
- </packages>
-</coverage>
diff --git a/tests/farm/html/src/here.py b/tests/farm/html/src/here.py
index d0d26ea7..fee9960d 100644
--- a/tests/farm/html/src/here.py
+++ b/tests/farm/html/src/here.py
@@ -1,4 +1,7 @@
-# A test file for HTML reporting by coverage.
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+# A test file for HTML reporting by coverage.py.
import other
diff --git a/tests/farm/html/src/isolatin1.py b/tests/farm/html/src/isolatin1.py
index 7a49b07d..55a6f7de 100644
--- a/tests/farm/html/src/isolatin1.py
+++ b/tests/farm/html/src/isolatin1.py
@@ -1,5 +1,8 @@
-# A Python source file in another encoding.
# -*- coding: iso8859-1 -*-
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+# A Python source file in another encoding.
math = "34 = 12, 2 = 60"
assert len(math) == 18
diff --git a/tests/farm/html/src/m1.py b/tests/farm/html/src/m1.py
index 927e1f6b..524fb0aa 100644
--- a/tests/farm/html/src/m1.py
+++ b/tests/farm/html/src/m1.py
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
m1a = 1
m1b = 2
diff --git a/tests/farm/html/src/m2.py b/tests/farm/html/src/m2.py
index ffddf6cf..2d13bfe2 100644
--- a/tests/farm/html/src/m2.py
+++ b/tests/farm/html/src/m2.py
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
m2a = 1
m2b = 2
diff --git a/tests/farm/html/src/m3.py b/tests/farm/html/src/m3.py
index 395d7d25..96e8b992 100644
--- a/tests/farm/html/src/m3.py
+++ b/tests/farm/html/src/m3.py
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
m3a = 1
m3b = 2
diff --git a/tests/farm/html/src/main.py b/tests/farm/html/src/main.py
index ce894465..238d0b58 100644
--- a/tests/farm/html/src/main.py
+++ b/tests/farm/html/src/main.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
import m1
import m2
import m3
diff --git a/tests/farm/html/src/omit4.ini b/tests/farm/html/src/omit4.ini
index 6821ecda..b792e703 100644
--- a/tests/farm/html/src/omit4.ini
+++ b/tests/farm/html/src/omit4.ini
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
[report]
omit = m2.py
diff --git a/tests/farm/html/src/omit5.ini b/tests/farm/html/src/omit5.ini
index 7e32b414..3b6add29 100644
--- a/tests/farm/html/src/omit5.ini
+++ b/tests/farm/html/src/omit5.ini
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
[report]
omit =
fooey
@@ -5,4 +8,4 @@ omit =
helloworld
[html]
-directory = ../html_omit_5
+directory = ../out/omit_5
diff --git a/tests/farm/html/src/partial.ini b/tests/farm/html/src/partial.ini
new file mode 100644
index 00000000..cdb241b5
--- /dev/null
+++ b/tests/farm/html/src/partial.ini
@@ -0,0 +1,9 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+[run]
+branch = True
+
+[report]
+exclude_lines =
+ raise AssertionError
diff --git a/tests/farm/html/src/partial.py b/tests/farm/html/src/partial.py
index 8d62f5c5..0f8fbe3c 100644
--- a/tests/farm/html/src/partial.py
+++ b/tests/farm/html/src/partial.py
@@ -1,6 +1,9 @@
-# partial branches
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
-a = 3
+# partial branches and excluded lines
+
+a = 6
while True:
break
@@ -15,4 +18,7 @@ if 0:
never_happen()
if 1:
- a = 13
+ a = 21
+
+if a == 23:
+ raise AssertionError("Can't")
diff --git a/tests/farm/html/src/run_a_xml_2.ini b/tests/farm/html/src/run_a_xml_2.ini
index 8d28f97b..f632bd09 100644
--- a/tests/farm/html/src/run_a_xml_2.ini
+++ b/tests/farm/html/src/run_a_xml_2.ini
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Put all the XML output in xml_2
[xml]
-output = ../xml_2/coverage.xml
+output = ../out/xml_2/coverage.xml
diff --git a/tests/farm/html/src/tabbed.py b/tests/farm/html/src/tabbed.py
index 2035852f..e897e9fa 100644
--- a/tests/farm/html/src/tabbed.py
+++ b/tests/farm/html/src/tabbed.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# This file should have tabs.
x = 1
if x:
diff --git a/tests/farm/html/src/unicode.py b/tests/farm/html/src/unicode.py
index 08e1b540..37c5533a 100644
--- a/tests/farm/html/src/unicode.py
+++ b/tests/farm/html/src/unicode.py
@@ -1,5 +1,8 @@
-# A Python source file with exotic characters.
# -*- coding: utf-8 -*-
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+# A Python source file with exotic characters.
upside_down = "ʎd˙ǝbɐɹǝʌoɔ"
surrogate = "db40,dd00: x󠄀"
diff --git a/tests/farm/html/src/y.py b/tests/farm/html/src/y.py
index af7c9689..a50bb629 100644
--- a/tests/farm/html/src/y.py
+++ b/tests/farm/html/src/y.py
@@ -1,4 +1,7 @@
-# A test file for XML reporting by coverage.
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+# A test file for XML reporting by coverage.py.
def choice(x):
if x < 2:
diff --git a/tests/farm/run/run_chdir.py b/tests/farm/run/run_chdir.py
index 367cd0ad..9e3c7515 100644
--- a/tests/farm/run/run_chdir.py
+++ b/tests/farm/run/run_chdir.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
copy("src", "out")
run("""
coverage run chdir.py
diff --git a/tests/farm/run/run_timid.py b/tests/farm/run/run_timid.py
index 99155b85..a632cea3 100644
--- a/tests/farm/run/run_timid.py
+++ b/tests/farm/run/run_timid.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Test that the --timid command line argument properly swaps the tracer
# function for a simpler one.
#
diff --git a/tests/farm/run/run_xxx.py b/tests/farm/run/run_xxx.py
index 6fedc934..62a862e5 100644
--- a/tests/farm/run/run_xxx.py
+++ b/tests/farm/run/run_xxx.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
copy("src", "out")
run("""
coverage run xxx
diff --git a/tests/farm/run/src/chdir.py b/tests/farm/run/src/chdir.py
index 6d834924..35cfcc81 100644
--- a/tests/farm/run/src/chdir.py
+++ b/tests/farm/run/src/chdir.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
import os
print("Line One")
os.chdir("subdir")
diff --git a/tests/farm/run/src/showtrace.py b/tests/farm/run/src/showtrace.py
index e97412e0..3a2750a6 100644
--- a/tests/farm/run/src/showtrace.py
+++ b/tests/farm/run/src/showtrace.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Show the current frame's trace function, so that we can test what the
# command-line options do to the trace function used.
diff --git a/tests/farm/run/src/xxx b/tests/farm/run/src/xxx
index 8f727f08..864da457 100644
--- a/tests/farm/run/src/xxx
+++ b/tests/farm/run/src/xxx
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# This is a python file though it doesn't look like it, like a main script.
a = b = c = d = 0
a = 3
diff --git a/tests/goldtest.py b/tests/goldtest.py
new file mode 100644
index 00000000..baaa8f01
--- /dev/null
+++ b/tests/goldtest.py
@@ -0,0 +1,42 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""A test base class for tests based on gold file comparison."""
+
+import os
+import sys
+
+from unittest_mixins import change_dir # pylint: disable=unused-import
+
+from tests.coveragetest import CoverageTest
+from tests.test_farm import clean
+# Import helpers, eventually test_farm.py will go away.
+from tests.test_farm import ( # pylint: disable=unused-import
+ compare, contains, doesnt_contain, contains_any,
+)
+
+
+class CoverageGoldTest(CoverageTest):
+ """A test based on gold files."""
+
+ run_in_temp_dir = False
+
+ def setUp(self):
+ super(CoverageGoldTest, self).setUp()
+ self.chdir(self.root_dir)
+ # Modules should be importable from the current directory.
+ sys.path.insert(0, '')
+
+ def output_dir(self, the_dir):
+ """Declare where the output directory is.
+
+ The output directory is deleted at the end of the test, unless the
+ COVERAGE_KEEP_OUTPUT environment variable is set.
+
+ """
+ # To make sure tests are isolated, we always clean the directory at the
+ # beginning of the test.
+ clean(the_dir)
+
+ if not os.environ.get("COVERAGE_KEEP_OUTPUT"): # pragma: part covered
+ self.addCleanup(clean, the_dir)
diff --git a/tests/helpers.py b/tests/helpers.py
index c26f4859..ebc15cd1 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -1,18 +1,38 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Helpers for coverage.py tests."""
+import os
import subprocess
+import sys
+
+from coverage import env
+from coverage.backward import unicode_class
+from coverage.misc import output_encoding
-# This isn't really a backward compatibility thing, should be moved into a
-# helpers file or something.
def run_command(cmd):
"""Run a command in a sub-process.
Returns the exit status code and the combined stdout and stderr.
"""
+ if env.PY2 and isinstance(cmd, unicode_class):
+ cmd = cmd.encode(sys.getfilesystemencoding())
+
+ # In some strange cases (PyPy3 in a virtualenv!?) the stdout encoding of
+ # the subprocess is set incorrectly to ascii. Use an environment variable
+ # to force the encoding to be the same as ours.
+ sub_env = dict(os.environ)
+ encoding = output_encoding()
+ if encoding:
+ sub_env['PYTHONIOENCODING'] = encoding
+
proc = subprocess.Popen(
- cmd, shell=True,
+ cmd,
+ shell=True,
+ env=sub_env,
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT
)
@@ -21,14 +41,14 @@ def run_command(cmd):
# Get the output, and canonicalize it to strings with newlines.
if not isinstance(output, str):
- output = output.decode('utf-8')
+ output = output.decode(output_encoding())
output = output.replace('\r', '')
return status, output
class CheckUniqueFilenames(object):
- """Asserts the uniqueness of filenames passed to a function."""
+ """Asserts the uniqueness of file names passed to a function."""
def __init__(self, wrapped):
self.filenames = set()
self.wrapped = wrapped
@@ -44,7 +64,7 @@ class CheckUniqueFilenames(object):
def wrapper(self, filename, *args, **kwargs):
"""The replacement method. Check that we don't have dupes."""
assert filename not in self.filenames, (
- "Filename %r passed to %r twice" % (filename, self.wrapped)
+ "File name %r passed to %r twice" % (filename, self.wrapped)
)
self.filenames.add(filename)
ret = self.wrapped(filename, *args, **kwargs)
diff --git a/tests/js/index.html b/tests/js/index.html
index 5edfced9..744014bc 100644
--- a/tests/js/index.html
+++ b/tests/js/index.html
@@ -2,11 +2,12 @@
<html>
<head>
<title>Coverage.py Javascript Test Suite</title>
- <link rel="stylesheet" href="../qunit/qunit.css" type="text/css" media="screen">
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.0.1.css">
<script type="text/javascript" src="../../coverage/htmlfiles/jquery.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>
@@ -37,16 +38,12 @@
<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"></div>
<div id="qunit-fixture"></div>
+ <script src="https://code.jquery.com/qunit/qunit-2.0.1.js"></script>
+ <!-- pull in our tests -->
+ <script src="tests.js"></script>
</body>
</html>
diff --git a/tests/js/tests.js b/tests/js/tests.js
index 73b4ce2b..bf2ca734 100644
--- a/tests/js/tests.js
+++ b/tests/js/tests.js
@@ -1,18 +1,21 @@
+/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
+/* For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt */
+
// Tests of coverage.py HTML report chunk navigation.
-/*global coverage, test, module, equals, jQuery, $ */
+/*global coverage, jQuery, $ */
// Test helpers
-function selection_is(sel) {
- raw_selection_is(sel, true);
+function selection_is(assert, sel) {
+ raw_selection_is(assert, sel, true);
}
-function raw_selection_is(sel, check_highlight) {
+function raw_selection_is(assert, sel, check_highlight) {
var beg = sel[0], end = sel[1];
- equals(coverage.sel_begin, beg);
- equals(coverage.sel_end, end);
+ assert.equal(coverage.sel_begin, beg);
+ assert.equal(coverage.sel_end, end);
if (check_highlight) {
- equals(coverage.code_container().find(".highlight").length, end-beg);
+ assert.equal(coverage.code_container().find(".highlight").length, end-beg);
}
}
@@ -31,20 +34,21 @@ function build_fixture(spec) {
// Zero-chunk tests
-module("Zero-chunk navigation", {
- setup: function () {
+QUnit.module("Zero-chunk navigation", {
+ beforeEach: function () {
build_fixture("wwww");
}
});
-test("set_sel defaults", function () {
+QUnit.test("set_sel defaults", function (assert) {
coverage.set_sel(2);
- equals(coverage.sel_begin, 2);
- equals(coverage.sel_end, 3);
+ assert.equal(coverage.sel_begin, 2);
+ assert.equal(coverage.sel_end, 3);
});
-test("No first chunk to select", function () {
+QUnit.test("No first chunk to select", function (assert) {
coverage.to_first_chunk();
+ assert.expect(0);
});
// One-chunk tests
@@ -61,32 +65,32 @@ $.each([
var id = params[0];
var c1 = params[1];
- module("One-chunk navigation - " + id, {
- setup: function () {
+ QUnit.module("One-chunk navigation - " + id, {
+ beforeEach: function () {
build_fixture(id);
}
});
- test("First chunk", function () {
+ QUnit.test("First chunk", function (assert) {
coverage.to_first_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
- test("Next chunk is first chunk", function () {
+ QUnit.test("Next chunk is first chunk", function (assert) {
coverage.to_next_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
- test("There is no next chunk", function () {
+ QUnit.test("There is no next chunk", function (assert) {
coverage.to_first_chunk();
coverage.to_next_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
- test("There is no prev chunk", function () {
+ QUnit.test("There is no prev chunk", function (assert) {
coverage.to_first_chunk();
coverage.to_prev_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
});
@@ -106,66 +110,66 @@ $.each([
var c1 = params[1];
var c2 = params[2];
- module("Two-chunk navigation - " + id, {
- setup: function () {
+ QUnit.module("Two-chunk navigation - " + id, {
+ beforeEach: function () {
build_fixture(id);
}
});
- test("First chunk", function () {
+ QUnit.test("First chunk", function (assert) {
coverage.to_first_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
- test("Next chunk is first chunk", function () {
+ QUnit.test("Next chunk is first chunk", function (assert) {
coverage.to_next_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
- test("Move to next chunk", function () {
+ QUnit.test("Move to next chunk", function (assert) {
coverage.to_first_chunk();
coverage.to_next_chunk();
- selection_is(c2);
+ selection_is(assert, c2);
});
- test("Move to first chunk", function () {
+ QUnit.test("Move to first chunk", function (assert) {
coverage.to_first_chunk();
coverage.to_next_chunk();
coverage.to_first_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
- test("Move to previous chunk", function () {
+ QUnit.test("Move to previous chunk", function (assert) {
coverage.to_first_chunk();
coverage.to_next_chunk();
coverage.to_prev_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
- test("Next doesn't move after last chunk", function () {
+ QUnit.test("Next doesn't move after last chunk", function (assert) {
coverage.to_first_chunk();
coverage.to_next_chunk();
coverage.to_next_chunk();
- selection_is(c2);
+ selection_is(assert, c2);
});
- test("Prev doesn't move before first chunk", function () {
+ QUnit.test("Prev doesn't move before first chunk", function (assert) {
coverage.to_first_chunk();
coverage.to_next_chunk();
coverage.to_prev_chunk();
coverage.to_prev_chunk();
- selection_is(c1);
+ selection_is(assert, c1);
});
});
-module("Miscellaneous");
+QUnit.module("Miscellaneous");
-test("Jump from a line selected", function () {
+QUnit.test("Jump from a line selected", function (assert) {
build_fixture("rrwwrr");
coverage.set_sel(3);
coverage.to_next_chunk();
- selection_is([5,7]);
+ selection_is(assert, [5,7]);
});
// Tests of select_line_or_chunk.
@@ -188,17 +192,17 @@ $.each([
var id = params[0];
var sels = params[1];
- module("Select line or chunk - " + id, {
- setup: function () {
+ QUnit.module("Select line or chunk - " + id, {
+ beforeEach: function () {
build_fixture(id);
}
});
$.each(sels, function (i, sel) {
i++;
- test("Select line " + i, function () {
+ QUnit.test("Select line " + i, function (assert) {
coverage.select_line_or_chunk(i);
- raw_selection_is(sel);
+ raw_selection_is(assert, sel);
});
});
});
diff --git a/tests/modules/covmod1.py b/tests/modules/covmod1.py
index b3f5e5f2..0f9638b8 100644
--- a/tests/modules/covmod1.py
+++ b/tests/modules/covmod1.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# covmod1.py: Simplest module for testing.
i = 1
i += 1
diff --git a/tests/modules/pkg1/__init__.py b/tests/modules/pkg1/__init__.py
index 2dfeb9c1..e2e4af5f 100644
--- a/tests/modules/pkg1/__init__.py
+++ b/tests/modules/pkg1/__init__.py
@@ -1,3 +1,4 @@
# This __init__.py has a module-level docstring, which is counted as a
# statement.
"""A simple package for testing with."""
+print("pkg1.__init__: %s" % (__name__,))
diff --git a/tests/modules/pkg1/p1a.py b/tests/modules/pkg1/p1a.py
index 337add49..5d81b1fa 100644
--- a/tests/modules/pkg1/p1a.py
+++ b/tests/modules/pkg1/p1a.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
import os, sys
# Invoke functions in os and sys so we can see if we measure code there.
diff --git a/tests/modules/pkg1/p1b.py b/tests/modules/pkg1/p1b.py
index 59d6fb54..53505cef 100644
--- a/tests/modules/pkg1/p1b.py
+++ b/tests/modules/pkg1/p1b.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
x = 1
y = 2
z = 3
diff --git a/tests/modules/pkg1/p1c.py b/tests/modules/pkg1/p1c.py
index a9aeef04..98f319e8 100644
--- a/tests/modules/pkg1/p1c.py
+++ b/tests/modules/pkg1/p1c.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
a = 1
b = 2
c = 3
diff --git a/tests/modules/pkg1/runmod2.py b/tests/modules/pkg1/runmod2.py
index b52964cb..5911db7b 100644
--- a/tests/modules/pkg1/runmod2.py
+++ b/tests/modules/pkg1/runmod2.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Used in the tests for run_python_module
import sys
print("runmod2: passed %s" % sys.argv[1])
diff --git a/tests/modules/pkg1/sub/ps1a.py b/tests/modules/pkg1/sub/ps1a.py
index 4b6a15cc..44d3b274 100644
--- a/tests/modules/pkg1/sub/ps1a.py
+++ b/tests/modules/pkg1/sub/ps1a.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
d = 1
e = 2
f = 3
diff --git a/tests/modules/pkg1/sub/runmod3.py b/tests/modules/pkg1/sub/runmod3.py
index 3a1ad155..1f5ce27e 100644
--- a/tests/modules/pkg1/sub/runmod3.py
+++ b/tests/modules/pkg1/sub/runmod3.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Used in the tests for run_python_module
import sys
print("runmod3: passed %s" % sys.argv[1])
diff --git a/tests/modules/pkg2/p2a.py b/tests/modules/pkg2/p2a.py
index b606711d..62caae22 100644
--- a/tests/modules/pkg2/p2a.py
+++ b/tests/modules/pkg2/p2a.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
q = 1
r = 1
s = 1
diff --git a/tests/modules/pkg2/p2b.py b/tests/modules/pkg2/p2b.py
index 7a34e2c6..73716eb4 100644
--- a/tests/modules/pkg2/p2b.py
+++ b/tests/modules/pkg2/p2b.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
t = 1
u = 1
v = 1
diff --git a/tests/modules/plugins/a_plugin.py b/tests/modules/plugins/a_plugin.py
index 2a9910d0..0cc96e5a 100644
--- a/tests/modules/plugins/a_plugin.py
+++ b/tests/modules/plugins/a_plugin.py
@@ -2,8 +2,10 @@
from coverage import CoveragePlugin
+
class Plugin(CoveragePlugin):
pass
+
def coverage_init(reg, options):
reg.add_file_tracer(Plugin())
diff --git a/tests/modules/plugins/another.py b/tests/modules/plugins/another.py
index 2a9910d0..80902d34 100644
--- a/tests/modules/plugins/another.py
+++ b/tests/modules/plugins/another.py
@@ -1,9 +1,14 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""A plugin for tests to reference."""
from coverage import CoveragePlugin
+
class Plugin(CoveragePlugin):
pass
+
def coverage_init(reg, options):
reg.add_file_tracer(Plugin())
diff --git a/tests/modules/process_test/__init__.py b/tests/modules/process_test/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/modules/process_test/__init__.py
diff --git a/tests/try_execfile.py b/tests/modules/process_test/try_execfile.py
index e0b79b48..70905071 100644
--- a/tests/try_execfile.py
+++ b/tests/modules/process_test/try_execfile.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Test file for run_python_file.
This file is executed two ways::
diff --git a/tests/modules/runmod1.py b/tests/modules/runmod1.py
index 671d81ef..b43b299a 100644
--- a/tests/modules/runmod1.py
+++ b/tests/modules/runmod1.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Used in the tests for run_python_module
import sys
print("runmod1: passed %s" % sys.argv[1])
diff --git a/tests/modules/usepkgs.py b/tests/modules/usepkgs.py
index 93c7d904..4e94acaa 100644
--- a/tests/modules/usepkgs.py
+++ b/tests/modules/usepkgs.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
import pkg1.p1a, pkg1.p1b
import pkg2.p2a, pkg2.p2b
import othermods.othera, othermods.otherb
diff --git a/tests/moremodules/othermods/othera.py b/tests/moremodules/othermods/othera.py
index 78896928..b3ee9c04 100644
--- a/tests/moremodules/othermods/othera.py
+++ b/tests/moremodules/othermods/othera.py
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
o = 1
p = 2
diff --git a/tests/moremodules/othermods/otherb.py b/tests/moremodules/othermods/otherb.py
index 2bd8a441..334fdc4a 100644
--- a/tests/moremodules/othermods/otherb.py
+++ b/tests/moremodules/othermods/otherb.py
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
q = 3
r = 4
diff --git a/tests/moremodules/othermods/sub/osa.py b/tests/moremodules/othermods/sub/osa.py
index 0139d28b..4005640e 100644
--- a/tests/moremodules/othermods/sub/osa.py
+++ b/tests/moremodules/othermods/sub/osa.py
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
s = 5
t = 6
diff --git a/tests/moremodules/othermods/sub/osb.py b/tests/moremodules/othermods/sub/osb.py
index b024b148..7d96fb79 100644
--- a/tests/moremodules/othermods/sub/osb.py
+++ b/tests/moremodules/othermods/sub/osb.py
@@ -1,2 +1,5 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
u = 7
v = 8
diff --git a/tests/osinfo.py b/tests/osinfo.py
index 0b86ef54..a7ebd2ef 100644
--- a/tests/osinfo.py
+++ b/tests/osinfo.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""OS information for testing."""
from coverage import env
@@ -8,29 +11,29 @@ if env.WINDOWS:
def process_ram():
"""How much RAM is this process using? (Windows)"""
import ctypes
- # lifted from:
- # lists.ubuntu.com/archives/bazaar-commits/2009-February/011990.html
+ # From: http://lists.ubuntu.com/archives/bazaar-commits/2009-February/011990.html
class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
"""Used by GetProcessMemoryInfo"""
- _fields_ = [('cb', ctypes.c_ulong),
- ('PageFaultCount', ctypes.c_ulong),
- ('PeakWorkingSetSize', ctypes.c_size_t),
- ('WorkingSetSize', ctypes.c_size_t),
- ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
- ('QuotaPagedPoolUsage', ctypes.c_size_t),
- ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
- ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
- ('PagefileUsage', ctypes.c_size_t),
- ('PeakPagefileUsage', ctypes.c_size_t),
- ('PrivateUsage', ctypes.c_size_t),
- ]
+ _fields_ = [
+ ('cb', ctypes.c_ulong),
+ ('PageFaultCount', ctypes.c_ulong),
+ ('PeakWorkingSetSize', ctypes.c_size_t),
+ ('WorkingSetSize', ctypes.c_size_t),
+ ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
+ ('QuotaPagedPoolUsage', ctypes.c_size_t),
+ ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
+ ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
+ ('PagefileUsage', ctypes.c_size_t),
+ ('PeakPagefileUsage', ctypes.c_size_t),
+ ('PrivateUsage', ctypes.c_size_t),
+ ]
mem_struct = PROCESS_MEMORY_COUNTERS_EX()
ret = ctypes.windll.psapi.GetProcessMemoryInfo(
- ctypes.windll.kernel32.GetCurrentProcess(),
- ctypes.byref(mem_struct),
- ctypes.sizeof(mem_struct)
- )
+ ctypes.windll.kernel32.GetCurrentProcess(),
+ ctypes.byref(mem_struct),
+ ctypes.sizeof(mem_struct)
+ )
if not ret:
return 0
return mem_struct.PrivateUsage
@@ -44,26 +47,26 @@ elif env.LINUX:
def _VmB(key):
"""Read the /proc/PID/status file to find memory use."""
try:
- # get pseudo file /proc/<pid>/status
+ # Get pseudo file /proc/<pid>/status
with open('/proc/%d/status' % os.getpid()) as t:
v = t.read()
except IOError:
return 0 # non-Linux?
- # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
+ # Get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
i = v.index(key)
v = v[i:].split(None, 3)
if len(v) < 3:
- return 0 # invalid format?
- # convert Vm value to bytes
+ return 0 # Invalid format?
+ # Convert Vm value to bytes.
return int(float(v[1]) * _scale[v[2].lower()])
def process_ram():
"""How much RAM is this process using? (Linux implementation)"""
return _VmB('VmRSS')
-
else:
- # Don't have an implementation, at least satisfy the interface.
+ # Generic implementation.
def process_ram():
- """How much RAM is this process using? (placebo implementation)"""
- return 0
+ """How much RAM is this process using? (stdlib implementation)"""
+ import resource
+ return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
diff --git a/tests/plugin1.py b/tests/plugin1.py
index 0ba09d93..af4dfc52 100644
--- a/tests/plugin1.py
+++ b/tests/plugin1.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""A plugin for test_plugins.py to import."""
import os.path
@@ -17,7 +20,7 @@ class Plugin(coverage.CoveragePlugin):
return FileReporter(filename)
-class FileTracer(coverage.plugin.FileTracer):
+class FileTracer(coverage.FileTracer):
"""A FileTracer emulating a simple static plugin."""
def __init__(self, filename):
@@ -37,14 +40,11 @@ class FileTracer(coverage.plugin.FileTracer):
return lineno*100+5, lineno*100+7
-class FileReporter(coverage.plugin.FileReporter):
+class FileReporter(coverage.FileReporter):
"""Dead-simple FileReporter."""
- def statements(self):
+ def lines(self):
return set([105, 106, 107, 205, 206, 207])
- def excluded_statements(self):
- return set([])
-
def coverage_init(reg, options): # pylint: disable=unused-argument
"""Called by coverage to initialize the plugins here."""
diff --git a/tests/plugin2.py b/tests/plugin2.py
index 6e875e5e..3bdfbdfd 100644
--- a/tests/plugin2.py
+++ b/tests/plugin2.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""A plugin for test_plugins.py to import."""
import os.path
@@ -15,7 +18,7 @@ class Plugin(coverage.CoveragePlugin):
return FileReporter(filename)
-class RenderFileTracer(coverage.plugin.FileTracer):
+class RenderFileTracer(coverage.FileTracer):
"""A FileTracer using information from the caller."""
def has_dynamic_source_filename(self):
@@ -32,9 +35,9 @@ class RenderFileTracer(coverage.plugin.FileTracer):
return lineno, lineno+1
-class FileReporter(coverage.plugin.FileReporter):
+class FileReporter(coverage.FileReporter):
"""A goofy file reporter."""
- def statements(self):
+ def lines(self):
# Goofy test arrangement: claim that the file has as many lines as the
# number in its name.
num = os.path.basename(self.filename).split(".")[0].split("_")[1]
diff --git a/tests/qunit/qunit.css b/tests/qunit/qunit.css
deleted file mode 100644
index b3c6db52..00000000
--- a/tests/qunit/qunit.css
+++ /dev/null
@@ -1,225 +0,0 @@
-/**
- * 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/tests/qunit/qunit.js b/tests/qunit/qunit.js
deleted file mode 100644
index e00cca90..00000000
--- a/tests/qunit/qunit.js
+++ /dev/null
@@ -1,1448 +0,0 @@
-/**
- * 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/tests/stress_phystoken.tok b/tests/stress_phystoken.tok
index 8d1b6bec..eb2fb669 100644
--- a/tests/stress_phystoken.tok
+++ b/tests/stress_phystoken.tok
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Here's some random Python so that test_tokenize_myself will have some
# stressful stuff to try. This file is .tok instead of .py so pylint won't
# complain about it, check_eol won't look at it, etc.
diff --git a/tests/stress_phystoken_dos.tok b/tests/stress_phystoken_dos.tok
index b08fd70e..5b016a77 100644
--- a/tests/stress_phystoken_dos.tok
+++ b/tests/stress_phystoken_dos.tok
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
# Here's some random Python so that test_tokenize_myself will have some
# stressful stuff to try. This file is .tok instead of .py so pylint won't
# complain about it, check_eol won't look at it, etc.
diff --git a/tests/test_api.py b/tests/test_api.py
index b4ae7482..6f142100 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -1,22 +1,28 @@
-"""Tests for Coverage's API."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Tests for coverage.py's API."""
import fnmatch
import os
import sys
import textwrap
+import warnings
import coverage
+from coverage import env
from coverage.backward import StringIO
from coverage.misc import CoverageException
+from coverage.report import Reporter
from tests.coveragetest import CoverageTest
class ApiTest(CoverageTest):
- """Api-oriented tests for Coverage."""
+ """Api-oriented tests for coverage.py."""
def clean_files(self, files, pats):
- """Remove names matching `pats` from `files`, a list of filenames."""
+ """Remove names matching `pats` from `files`, a list of file names."""
good = []
for f in files:
for pat in pats:
@@ -33,7 +39,7 @@ class ApiTest(CoverageTest):
self.assertCountEqual(here, files)
def test_unexecuted_file(self):
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.make_file("mycode.py", """\
a = 1
@@ -66,7 +72,7 @@ class ApiTest(CoverageTest):
""")
# Import the Python file, executing it.
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "mymain")
filename, _, _, _ = cov.analysis("mymain.py")
@@ -81,7 +87,7 @@ class ApiTest(CoverageTest):
# Import the Python file, executing it again, once it's been compiled
# already.
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "mymain")
filename, _, _, _ = cov.analysis("mymain.py")
@@ -102,7 +108,7 @@ class ApiTest(CoverageTest):
""")
# Measure without the stdlib.
- cov1 = coverage.coverage()
+ cov1 = coverage.Coverage()
self.assertEqual(cov1.config.cover_pylib, False)
self.start_import_stop(cov1, "mymain")
@@ -114,7 +120,7 @@ class ApiTest(CoverageTest):
self.assertEqual(statements, missing)
# Measure with the stdlib.
- cov2 = coverage.coverage(cover_pylib=True)
+ cov2 = coverage.Coverage(cover_pylib=True)
self.start_import_stop(cov2, "mymain")
# some statements were marked executed in mymain.py
@@ -133,7 +139,7 @@ class ApiTest(CoverageTest):
""")
# Measure without the stdlib, but include colorsys.
- cov1 = coverage.coverage(cover_pylib=False, include=["*/colorsys.py"])
+ cov1 = coverage.Coverage(cover_pylib=False, include=["*/colorsys.py"])
self.start_import_stop(cov1, "mymain")
# some statements were marked executed in colorsys.py
@@ -144,7 +150,7 @@ class ApiTest(CoverageTest):
self.assertEqual(statements, missing)
def test_exclude_list(self):
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.clear_exclude()
self.assertEqual(cov.get_exclude_list(), [])
cov.exclude("foo")
@@ -156,7 +162,7 @@ class ApiTest(CoverageTest):
self.assertEqual(cov.get_exclude_list(), [])
def test_exclude_partial_list(self):
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.clear_exclude(which='partial')
self.assertEqual(cov.get_exclude_list(which='partial'), [])
cov.exclude("foo", which='partial')
@@ -170,7 +176,7 @@ class ApiTest(CoverageTest):
self.assertEqual(cov.get_exclude_list(which='partial'), [])
def test_exclude_and_partial_are_separate_lists(self):
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.clear_exclude(which='partial')
cov.clear_exclude(which='exclude')
cov.exclude("foo", which='partial')
@@ -197,7 +203,7 @@ class ApiTest(CoverageTest):
""")
self.assertFiles(["datatest1.py"])
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "datatest1")
cov.save()
self.assertFiles(["datatest1.py", ".coverage"])
@@ -209,7 +215,7 @@ class ApiTest(CoverageTest):
""")
self.assertFiles(["datatest2.py"])
- cov = coverage.coverage(data_file="cov.data")
+ cov = coverage.Coverage(data_file="cov.data")
self.start_import_stop(cov, "datatest2")
cov.save()
self.assertFiles(["datatest2.py", "cov.data"])
@@ -221,7 +227,7 @@ class ApiTest(CoverageTest):
""")
self.assertFiles(["datatest3.py"])
- cov = coverage.coverage(data_file="cov.data", data_suffix="14")
+ cov = coverage.Coverage(data_file="cov.data", data_suffix="14")
self.start_import_stop(cov, "datatest3")
cov.save()
self.assertFiles(["datatest3.py", "cov.data.14"])
@@ -237,18 +243,19 @@ class ApiTest(CoverageTest):
""")
self.assertFiles(["datatest4.py", ".coveragerc"])
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "datatest4")
cov.save()
self.assertFiles(["datatest4.py", ".coveragerc", "mydata.dat"])
def test_empty_reporting(self):
# empty summary reports raise exception, just like the xml report
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.erase()
self.assertRaises(CoverageException, cov.report)
- def test_start_stop_start_stop(self):
+ def make_code1_code2(self):
+ """Create the code1.py and code2.py files."""
self.make_file("code1.py", """\
code1 = 1
""")
@@ -256,10 +263,9 @@ class ApiTest(CoverageTest):
code2 = 1
code2 = 2
""")
- cov = coverage.coverage()
- self.start_import_stop(cov, "code1")
- cov.save()
- self.start_import_stop(cov, "code2")
+
+ def check_code1_code2(self, cov):
+ """Check the analysis is correct for code1.py and code2.py."""
_, statements, missing, _ = cov.analysis("code1.py")
self.assertEqual(statements, [1])
self.assertEqual(missing, [])
@@ -267,30 +273,99 @@ class ApiTest(CoverageTest):
self.assertEqual(statements, [1, 2])
self.assertEqual(missing, [])
- if 0: # expected failure
- # for https://bitbucket.org/ned/coveragepy/issue/79
- def test_start_save_stop(self):
- self.make_file("code1.py", """\
- code1 = 1
- """)
- self.make_file("code2.py", """\
- code2 = 1
- code2 = 2
- """)
- cov = coverage.coverage()
- cov.start()
- self.import_local_file("code1")
- cov.save()
- self.import_local_file("code2")
- cov.stop()
-
- _, statements, missing, _ = cov.analysis("code1.py")
- self.assertEqual(statements, [1])
- self.assertEqual(missing, [])
- _, statements, missing, _ = cov.analysis("code2.py")
- self.assertEqual(statements, [1, 2])
- self.assertEqual(missing, [])
+ def test_start_stop_start_stop(self):
+ self.make_code1_code2()
+ cov = coverage.Coverage()
+ self.start_import_stop(cov, "code1")
+ cov.save()
+ self.start_import_stop(cov, "code2")
+ self.check_code1_code2(cov)
+
+ def test_start_save_stop(self):
+ self.skipTest("Expected failure: https://bitbucket.org/ned/coveragepy/issue/79")
+ self.make_code1_code2()
+ cov = coverage.Coverage()
+ cov.start()
+ self.import_local_file("code1")
+ cov.save()
+ self.import_local_file("code2")
+ cov.stop()
+
+ self.check_code1_code2(cov)
+
+ def make_good_data_files(self):
+ """Make some good data files."""
+ self.make_code1_code2()
+ cov = coverage.Coverage(data_suffix=True)
+ self.start_import_stop(cov, "code1")
+ cov.save()
+
+ cov = coverage.Coverage(data_suffix=True)
+ self.start_import_stop(cov, "code2")
+ cov.save()
+
+ def make_bad_data_file(self):
+ """Make one bad data file."""
+ self.make_file(".coverage.foo", """La la la, this isn't coverage data!""")
+
+ def test_combining_corrupt_data(self):
+ # If you combine a corrupt data file, then you will get a warning,
+ # and the file will remain.
+ self.make_good_data_files()
+ self.make_bad_data_file()
+ cov = coverage.Coverage()
+ warning_regex = (
+ r"Couldn't read data from '.*\.coverage\.foo': "
+ r"CoverageException: Doesn't seem to be a coverage\.py data file"
+ )
+ with self.assert_warnings(cov, [warning_regex]):
+ cov.combine()
+
+ # We got the results from code1 and code2 properly.
+ self.check_code1_code2(cov)
+ # The bad file still exists.
+ self.assert_exists(".coverage.foo")
+
+ def test_combining_twice(self):
+ self.make_good_data_files()
+ cov1 = coverage.Coverage()
+ cov1.combine()
+ cov1.save()
+ self.check_code1_code2(cov1)
+
+ cov2 = coverage.Coverage()
+ with self.assertRaisesRegex(CoverageException, r"No data to combine"):
+ cov2.combine(strict=True)
+
+ cov3 = coverage.Coverage()
+ cov3.combine()
+ # Now the data is empty!
+ _, statements, missing, _ = cov3.analysis("code1.py")
+ self.assertEqual(statements, [1])
+ self.assertEqual(missing, [1])
+ _, statements, missing, _ = cov3.analysis("code2.py")
+ self.assertEqual(statements, [1, 2])
+ self.assertEqual(missing, [1, 2])
+
+
+class NamespaceModuleTest(CoverageTest):
+ """Test PEP-420 namespace modules."""
+
+ def setUp(self):
+ super(NamespaceModuleTest, self).setUp()
+ if env.PYVERSION < (3, 3):
+ self.skipTest("Python before 3.3 doesn't have namespace packages")
+
+ def test_explicit_namespace_module(self):
+ self.make_file("namespace/package/module.py", "VAR = 1\n")
+ self.make_file("main.py", "import namespace\n")
+
+ cov = coverage.Coverage()
+ self.start_import_stop(cov, "main")
+
+ with self.assertRaisesRegex(CoverageException, r"Module .* has no file"):
+ cov.analysis(sys.modules['namespace'])
class UsingModulesMixin(object):
@@ -300,11 +375,12 @@ class UsingModulesMixin(object):
def setUp(self):
super(UsingModulesMixin, self).setUp()
- # Parent class saves and restores sys.path, we can just modify it.
+
old_dir = os.getcwd()
os.chdir(self.nice_file(os.path.dirname(__file__), 'modules'))
self.addCleanup(os.chdir, old_dir)
+ # Parent class saves and restores sys.path, we can just modify it.
sys.path.append(".")
sys.path.append("../moremodules")
@@ -371,15 +447,15 @@ class SourceOmitIncludeTest(OmitIncludeTestsMixin, CoverageTest):
def coverage_usepkgs(self, **kwargs):
"""Run coverage on usepkgs and return the line summary.
- Arguments are passed to the `coverage.coverage` constructor.
+ Arguments are passed to the `coverage.Coverage` constructor.
"""
- cov = coverage.coverage(**kwargs)
+ cov = coverage.Coverage(**kwargs)
cov.start()
- import usepkgs # pragma: nested # pylint: disable=import-error,unused-variable
+ import usepkgs # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
data = cov.get_data()
- summary = data.summary()
+ summary = data.line_counts()
for k, v in list(summary.items()):
assert k.endswith(".py")
summary[k[:-3]] = v
@@ -413,9 +489,9 @@ class ReportIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest):
def coverage_usepkgs(self, **kwargs):
"""Try coverage.report()."""
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.start()
- import usepkgs # pragma: nested # pylint: disable=import-error,unused-variable
+ import usepkgs # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
report = StringIO()
cov.report(file=report, **kwargs)
@@ -432,9 +508,9 @@ class XmlIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest):
def coverage_usepkgs(self, **kwargs):
"""Try coverage.xml_report()."""
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.start()
- import usepkgs # pragma: nested # pylint: disable=import-error,unused-variable
+ import usepkgs # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
cov.xml_report(outfile="-", **kwargs)
return self.stdout()
@@ -443,7 +519,7 @@ class XmlIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest):
class AnalysisTest(CoverageTest):
"""Test the numerical analysis of results."""
def test_many_missing_branches(self):
- cov = coverage.coverage(branch=True)
+ cov = coverage.Coverage(branch=True)
self.make_file("missing.py", """\
def fun1(x):
@@ -472,8 +548,8 @@ class AnalysisTest(CoverageTest):
self.assertEqual(nums.n_missing_branches, 2)
-class PluginTest(CoverageTest):
- """Test that the API works properly the way the plugins call it.
+class TestRunnerPluginTest(CoverageTest):
+ """Test that the API works properly the way various third-party plugins call it.
We don't actually use the plugins, but these tests call the API the same
way they do.
@@ -481,7 +557,7 @@ class PluginTest(CoverageTest):
"""
def pretend_to_be_nose_with_cover(self, erase):
"""This is what the nose --with-cover plugin does."""
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.make_file("no_biggie.py", """\
a = 1
@@ -497,7 +573,7 @@ class PluginTest(CoverageTest):
self.start_import_stop(cov, "no_biggie")
cov.combine()
cov.save()
- cov.report(["no_biggie.py"])
+ cov.report(["no_biggie.py"], show_missing=True)
self.assertEqual(self.stdout(), textwrap.dedent("""\
Name Stmts Miss Cover Missing
--------------------------------------------
@@ -509,3 +585,20 @@ class PluginTest(CoverageTest):
def test_nose_plugin_with_erase(self):
self.pretend_to_be_nose_with_cover(erase=True)
+
+
+class ReporterDeprecatedAttributeTest(CoverageTest):
+ """Test that Reporter.file_reporters has been deprecated."""
+
+ run_in_temp_dir = False
+
+ def test_reporter_file_reporters(self):
+ rep = Reporter(None, None)
+
+ with warnings.catch_warnings(record=True) as warns:
+ warnings.simplefilter("always")
+ # Accessing this attribute will raise a DeprecationWarning.
+ rep.file_reporters # pylint: disable=pointless-statement
+
+ self.assertEqual(len(warns), 1)
+ self.assertTrue(issubclass(warns[0].category, DeprecationWarning))
diff --git a/tests/test_arcs.py b/tests/test_arcs.py
index c84c5441..b03ac533 100644
--- a/tests/test_arcs.py
+++ b/tests/test_arcs.py
@@ -1,4 +1,7 @@
-"""Tests for Coverage.py's arc measurement."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Tests for coverage.py's arc measurement."""
from tests.coveragetest import CoverageTest
@@ -8,7 +11,7 @@ from coverage.files import abs_file
class SimpleArcTest(CoverageTest):
- """Tests for Coverage.py's arc measurement."""
+ """Tests for coverage.py's arc measurement."""
def test_simple_sequence(self):
self.check_coverage("""\
@@ -29,7 +32,7 @@ class SimpleArcTest(CoverageTest):
c = 5
""",
- arcz=".2 23 35 5-2")
+ arcz="-22 23 35 5-2")
def test_function_def(self):
self.check_coverage("""\
@@ -80,7 +83,8 @@ class SimpleArcTest(CoverageTest):
if len([]) == 0: a = 2
assert a == 2
""",
- arcz=".1 12 23 3.", arcz_missing="")
+ arcz=".1 12 23 3.",
+ )
self.check_coverage("""\
def fn(x):
if x % 2: return True
@@ -99,7 +103,8 @@ class SimpleArcTest(CoverageTest):
b = \\
6
""",
- arcz=".1 15 5-2", arcz_missing="")
+ arcz="-21 15 5-2",
+ )
def test_if_return(self):
self.check_coverage("""\
@@ -111,8 +116,8 @@ class SimpleArcTest(CoverageTest):
x = if_ret(0) + if_ret(1)
assert x == 8
""",
- arcz=".1 16 67 7. .2 23 24 3. 45 5.", arcz_missing=""
- )
+ arcz=".1 16 67 7. .2 23 24 3. 45 5.",
+ )
def test_dont_confuse_exit_and_else(self):
self.check_coverage("""\
@@ -137,15 +142,12 @@ class SimpleArcTest(CoverageTest):
arcz=".1 16 6. .2 23 3. 25 5.", arcz_missing="25 5."
)
- if 0: # expected failure
- def test_unused_lambdas_are_confusing_bug_90(self):
- self.check_coverage("""\
- a = 1
- fn = lambda x: x
- b = 3
- """,
- arcz=".1 12 .2 2-2 23 3."
- )
+ def test_what_is_the_sound_of_no_lines_clapping(self):
+ self.check_coverage("""\
+ # __init__.py
+ """,
+ arcz=".1 1.",
+ )
class WithTest(CoverageTest):
@@ -185,7 +187,8 @@ class LoopArcTest(CoverageTest):
a = i
assert a == 9
""",
- arcz=".1 12 21 13 3.", arcz_missing="")
+ arcz=".1 12 21 13 3.",
+ )
self.check_coverage("""\
a = -1
for i in range(0):
@@ -201,7 +204,8 @@ class LoopArcTest(CoverageTest):
a = i + j
assert a == 4
""",
- arcz=".1 12 23 32 21 14 4.", arcz_missing="")
+ arcz=".1 12 23 32 21 14 4.",
+ )
def test_break(self):
self.check_coverage("""\
@@ -264,7 +268,7 @@ class LoopArcTest(CoverageTest):
assert a == 4 and i == 3
""",
arcz=arcz,
- )
+ )
def test_for_if_else_for(self):
self.check_coverage("""\
@@ -289,7 +293,7 @@ class LoopArcTest(CoverageTest):
arcz=
".1 18 8G GH H. "
".2 23 34 43 26 3. 6. "
- ".9 9A 9-8 AB BC CB B9 AE E9",
+ "-89 9A 9-8 AB BC CB B9 AE E9",
arcz_missing="26 6."
)
@@ -308,10 +312,26 @@ class LoopArcTest(CoverageTest):
arcz=".1 .2 23 32 34 47 26 67 7. 18 89 9."
)
+ def test_while_else(self):
+ self.check_coverage("""\
+ def whileelse(seq):
+ while seq:
+ n = seq.pop()
+ if n > 4:
+ break
+ else:
+ n = 99
+ return n
+ assert whileelse([1, 2]) == 99
+ assert whileelse([1, 5]) == 5
+ """,
+ arcz=".1 19 9A A. .2 23 34 45 58 42 27 78 8.",
+ )
+
def test_confusing_for_loop_bug_175(self):
if env.PY3:
# Py3 counts the list comp as a separate code object.
- arcz = ".1 .2 2-2 12 23 34 45 53 3."
+ arcz = ".1 -22 2-2 12 23 34 45 53 3."
else:
arcz = ".1 12 23 34 45 53 3."
self.check_coverage("""\
@@ -321,9 +341,10 @@ class LoopArcTest(CoverageTest):
x = tup[0]
y = tup[1]
""",
- arcz=arcz, arcz_missing="", arcz_unpredicted="")
+ arcz=arcz,
+ )
if env.PY3:
- arcz = ".1 12 .2 2-2 23 34 42 2."
+ arcz = ".1 12 -22 2-2 23 34 42 2."
else:
arcz = ".1 12 23 34 42 2."
self.check_coverage("""\
@@ -332,7 +353,92 @@ class LoopArcTest(CoverageTest):
x = tup[0]
y = tup[1]
""",
- arcz=arcz, arcz_missing="", arcz_unpredicted="")
+ arcz=arcz,
+ )
+
+ def test_generator_expression(self):
+ # Generator expression:
+ self.check_coverage("""\
+ o = ((1,2), (3,4))
+ o = (a for a in o)
+ for tup in o:
+ x = tup[0]
+ y = tup[1]
+ """,
+ arcz=".1 -22 2-2 12 23 34 45 53 3.",
+ )
+
+ def test_other_comprehensions(self):
+ if env.PYVERSION < (2, 7):
+ self.skipTest("Don't have set or dict comprehensions before 2.7")
+ # Set comprehension:
+ self.check_coverage("""\
+ o = ((1,2), (3,4))
+ o = {a for a in o}
+ for tup in o:
+ x = tup[0]
+ y = tup[1]
+ """,
+ arcz=".1 -22 2-2 12 23 34 45 53 3.",
+ )
+ # Dict comprehension:
+ self.check_coverage("""\
+ o = ((1,2), (3,4))
+ o = {a:1 for a in o}
+ for tup in o:
+ x = tup[0]
+ y = tup[1]
+ """,
+ arcz=".1 -22 2-2 12 23 34 45 53 3.",
+ )
+
+ def test_multiline_dict_comp(self):
+ if env.PYVERSION < (2, 7):
+ self.skipTest("Don't have set or dict comprehensions before 2.7")
+ if env.PYVERSION < (3, 5):
+ arcz = "-42 2B B-4 2-4"
+ else:
+ arcz = "-32 2B B-3 2-3"
+ # Multiline dict comp:
+ self.check_coverage("""\
+ # comment
+ d = \\
+ {
+ i:
+ str(i)
+ for
+ i
+ in
+ range(9)
+ }
+ x = 11
+ """,
+ arcz=arcz,
+ )
+ # Multi dict comp:
+ if env.PYVERSION < (3, 5):
+ arcz = "-42 2F F-4 2-4"
+ else:
+ arcz = "-32 2F F-3 2-3"
+ self.check_coverage("""\
+ # comment
+ d = \\
+ {
+ (i, j):
+ str(i+j)
+ for
+ i
+ in
+ range(9)
+ for
+ j
+ in
+ range(13)
+ }
+ x = 15
+ """,
+ arcz=arcz,
+ )
class ExceptionArcTest(CoverageTest):
@@ -358,44 +464,48 @@ class ExceptionArcTest(CoverageTest):
b = 7
assert a == 3 and b == 7
""",
- arcz=".1 12 23 34 58 67 78 8.",
- arcz_missing="58", arcz_unpredicted="46")
+ arcz=".1 12 23 34 46 58 67 78 8.",
+ arcz_missing="58",
+ )
def test_hidden_raise(self):
self.check_coverage("""\
a, b = 1, 1
def oops(x):
- if x % 2: raise Exception("odd")
+ if x % 2:
+ raise Exception("odd")
try:
- a = 5
+ a = 6
oops(1)
- a = 7
+ a = 8
except:
- b = 9
- assert a == 5 and b == 9
+ b = 10
+ assert a == 6 and b == 10
""",
- arcz=".1 12 .3 3-2 24 45 56 67 7A 89 9A A.",
- arcz_missing="67 7A", arcz_unpredicted="68")
+ arcz=".1 12 -23 34 3-2 4-2 25 56 67 78 8B 9A AB B.",
+ arcz_missing="3-2 78 8B", arcz_unpredicted="79",
+ )
def test_except_with_type(self):
self.check_coverage("""\
a, b = 1, 1
def oops(x):
- if x % 2: raise ValueError("odd")
+ if x % 2:
+ raise ValueError("odd")
def try_it(x):
try:
- a = 6
+ a = 7
oops(x)
- a = 8
+ a = 9
except ValueError:
- b = 10
+ b = 11
return a
- assert try_it(0) == 8 # C
- assert try_it(1) == 6 # D
+ assert try_it(0) == 9 # C
+ assert try_it(1) == 7 # D
""",
- arcz=".1 12 .3 3-2 24 4C CD D. .5 56 67 78 8B 9A AB B-4",
- arcz_missing="",
- arcz_unpredicted="79")
+ arcz=".1 12 -23 34 3-2 4-2 25 5D DE E. -56 67 78 89 9C AB BC C-5",
+ arcz_unpredicted="8A",
+ )
def test_try_finally(self):
self.check_coverage("""\
@@ -406,7 +516,8 @@ class ExceptionArcTest(CoverageTest):
c = 5
assert a == 3 and c == 5
""",
- arcz=".1 12 23 35 56 6.", arcz_missing="")
+ arcz=".1 12 23 35 56 6.",
+ )
self.check_coverage("""\
a, c, d = 1, 1, 1
try:
@@ -418,8 +529,9 @@ class ExceptionArcTest(CoverageTest):
d = 8
assert a == 4 and c == 6 and d == 1 # 9
""",
- arcz=".1 12 23 34 46 67 78 89 69 9.",
- arcz_missing="67 78 89", arcz_unpredicted="")
+ arcz=".1 12 23 34 46 78 89 69 9.",
+ arcz_missing="78 89",
+ )
self.check_coverage("""\
a, c, d = 1, 1, 1
try:
@@ -433,8 +545,9 @@ class ExceptionArcTest(CoverageTest):
d = 10 # A
assert a == 4 and c == 8 and d == 10 # B
""",
- arcz=".1 12 23 34 45 68 89 8B 9A AB B.",
- arcz_missing="68 8B", arcz_unpredicted="58")
+ arcz=".1 12 23 34 45 58 68 89 8B 9A AB B.",
+ arcz_missing="68 8B",
+ )
def test_finally_in_loop(self):
self.check_coverage("""\
@@ -452,8 +565,9 @@ class ExceptionArcTest(CoverageTest):
d = 12 # C
assert a == 5 and c == 10 and d == 12 # D
""",
- arcz=".1 12 23 34 3D 45 56 67 68 8A A3 AB BC CD D.",
- arcz_missing="3D", arcz_unpredicted="7A")
+ arcz=".1 12 23 34 3D 45 56 67 68 7A 8A A3 AB BC CD D.",
+ arcz_missing="3D",
+ )
self.check_coverage("""\
a, c, d, i = 1, 1, 1, 99
try:
@@ -469,15 +583,16 @@ class ExceptionArcTest(CoverageTest):
d = 12 # C
assert a == 8 and c == 10 and d == 1 # D
""",
- arcz=".1 12 23 34 3D 45 56 67 68 8A A3 AB BC CD D.",
- arcz_missing="67 AB BC CD", arcz_unpredicted="")
+ arcz=".1 12 23 34 3D 45 56 67 68 7A 8A A3 AB BC CD D.",
+ arcz_missing="67 7A AB BC CD",
+ )
- def test_break_in_finally(self):
+ def test_break_through_finally(self):
self.check_coverage("""\
a, c, d, i = 1, 1, 1, 99
try:
- for i in range(5):
+ for i in range(3):
try:
a = 5
if i > 0:
@@ -489,8 +604,29 @@ class ExceptionArcTest(CoverageTest):
d = 12 # C
assert a == 5 and c == 10 and d == 1 # D
""",
- arcz=".1 12 23 34 3D 45 56 67 68 7A 8A A3 AB BC CD D.",
- arcz_missing="3D AB BC CD", arcz_unpredicted="AD")
+ arcz=".1 12 23 34 3D 45 56 67 68 7A 8A A3 AD BC CD D.",
+ arcz_missing="3D BC CD",
+ )
+
+ def test_continue_through_finally(self):
+ self.check_coverage("""\
+ a, b, c, d, i = 1, 1, 1, 1, 99
+ try:
+ for i in range(5):
+ try:
+ a = 5
+ if i > 0:
+ continue
+ b = 8
+ finally:
+ c = 10
+ except:
+ d = 12 # C
+ assert (a, b, c, d) == (5, 8, 10, 1) # D
+ """,
+ arcz=".1 12 23 34 3D 45 56 67 68 7A 8A A3 BC CD D.",
+ arcz_missing="BC CD",
+ )
def test_finally_in_loop_bug_92(self):
self.check_coverage("""\
@@ -503,14 +639,10 @@ class ExceptionArcTest(CoverageTest):
h = 7
""",
arcz=".1 12 23 35 56 61 17 7.",
- arcz_missing="", arcz_unpredicted="")
+ )
- # "except Exception as e" is crucial here.
def test_bug_212(self):
- # Run this test only on Py2 for now. I hope to fix it on Py3
- # eventually...
- if env.PY3:
- self.skip("This doesn't work on Python 3")
+ # "except Exception as e" is crucial here.
self.check_coverage("""\
def b(exc):
try:
@@ -527,8 +659,8 @@ class ExceptionArcTest(CoverageTest):
except:
pass
""",
- arcz=".1 .2 1A 23 34 56 67 68 8. AB BC C. DE E.",
- arcz_missing="C.", arcz_unpredicted="45 7. CD")
+ arcz=".1 .2 1A 23 34 45 56 67 68 7. 8. AB BC C. DE E.",
+ arcz_missing="C.", arcz_unpredicted="CD")
def test_except_finally(self):
self.check_coverage("""\
@@ -556,9 +688,178 @@ class ExceptionArcTest(CoverageTest):
c = 11
assert a == 5 and b == 9 and c == 11
""",
- arcz=".1 12 .3 3-2 24 45 56 67 7B 89 9B BC C.",
+ arcz=".1 12 -23 3-2 24 45 56 67 7B 89 9B BC C.",
arcz_missing="67 7B", arcz_unpredicted="68")
+ def test_multiple_except_clauses(self):
+ self.check_coverage("""\
+ a, b, c = 1, 1, 1
+ try:
+ a = 3
+ except ValueError:
+ b = 5
+ except IndexError:
+ a = 7
+ finally:
+ c = 9
+ assert a == 3 and b == 1 and c == 9
+ """,
+ arcz=".1 12 23 45 46 39 59 67 79 9A A.",
+ arcz_missing="45 59 46 67 79",
+ )
+ self.check_coverage("""\
+ a, b, c = 1, 1, 1
+ try:
+ a = int("xyz") # ValueError
+ except ValueError:
+ b = 5
+ except IndexError:
+ a = 7
+ finally:
+ c = 9
+ assert a == 1 and b == 5 and c == 9
+ """,
+ arcz=".1 12 23 45 46 39 59 67 79 9A A.",
+ arcz_missing="39 46 67 79",
+ arcz_unpredicted="34",
+ )
+ self.check_coverage("""\
+ a, b, c = 1, 1, 1
+ try:
+ a = [1][3] # IndexError
+ except ValueError:
+ b = 5
+ except IndexError:
+ a = 7
+ finally:
+ c = 9
+ assert a == 7 and b == 1 and c == 9
+ """,
+ arcz=".1 12 23 45 46 39 59 67 79 9A A.",
+ arcz_missing="39 45 59",
+ arcz_unpredicted="34",
+ )
+ self.check_coverage("""\
+ a, b, c = 1, 1, 1
+ try:
+ try:
+ a = 4/0 # ZeroDivisionError
+ except ValueError:
+ b = 6
+ except IndexError:
+ a = 8
+ finally:
+ c = 10
+ except ZeroDivisionError:
+ pass
+ assert a == 1 and b == 1 and c == 10
+ """,
+ arcz=".1 12 23 34 4A 56 6A 57 78 8A AD BC CD D.",
+ arcz_missing="4A 56 6A 78 8A AD",
+ arcz_unpredicted="45 7A AB",
+ )
+
+ def test_return_finally(self):
+ self.check_coverage("""\
+ a = [1]
+ def func():
+ try:
+ return 10
+ finally:
+ a.append(6)
+
+ assert func() == 10
+ assert a == [1, 6]
+ """,
+ arcz=".1 12 28 89 9. -23 34 46 6-2",
+ )
+
+ def test_except_jump_finally(self):
+ self.check_coverage("""\
+ def func(x):
+ a = f = g = 2
+ try:
+ for i in range(4):
+ try:
+ 6/0
+ except ZeroDivisionError:
+ if x == 'break':
+ a = 9
+ break
+ elif x == 'continue':
+ a = 12
+ continue
+ elif x == 'return':
+ a = 15 # F
+ return a, f, g, i # G
+ elif x == 'raise': # H
+ a = 18 # I
+ raise ValueError() # J
+ finally:
+ f = 21 # L
+ except ValueError: # M
+ g = 23 # N
+ return a, f, g, i # O
+
+ assert func('break') == (9, 21, 2, 0) # Q
+ assert func('continue') == (12, 21, 2, 3) # R
+ assert func('return') == (15, 2, 2, 0) # S
+ assert func('raise') == (18, 21, 23, 0) # T
+ """,
+ arcz=
+ ".1 1Q QR RS ST T. "
+ ".2 23 34 45 56 4O 6L "
+ "78 89 9A AL 8B BC CD DL BE EF FG GL EH HI IJ JL HL "
+ "LO L4 L. LM "
+ "MN NO O.",
+ arcz_missing="6L HL",
+ arcz_unpredicted="67",
+ )
+
+ def test_else_jump_finally(self):
+ self.check_coverage("""\
+ def func(x):
+ a = f = g = 2
+ try:
+ for i in range(4):
+ try:
+ b = 6
+ except ZeroDivisionError:
+ pass
+ else:
+ if x == 'break':
+ a = 11
+ break
+ elif x == 'continue':
+ a = 14
+ continue
+ elif x == 'return':
+ a = 17 # H
+ return a, f, g, i # I
+ elif x == 'raise': # J
+ a = 20 # K
+ raise ValueError() # L
+ finally:
+ f = 23 # N
+ except ValueError: # O
+ g = 25 # P
+ return a, f, g, i # Q
+
+ assert func('break') == (11, 23, 2, 0) # S
+ assert func('continue') == (14, 23, 2, 3) # T
+ assert func('return') == (17, 2, 2, 0) # U
+ assert func('raise') == (20, 23, 25, 0) # V
+ """,
+ arcz=
+ ".1 1S ST TU UV V. "
+ ".2 23 34 45 56 6A 78 8N 4Q "
+ "AB BC CN AD DE EF FN DG GH HI IN GJ JK KL LN JN "
+ "NQ N4 N. NO "
+ "OP PQ Q.",
+ arcz_missing="78 8N JN",
+ arcz_unpredicted="",
+ )
+
class YieldTest(CoverageTest):
"""Arc tests for generators."""
@@ -572,8 +873,7 @@ class YieldTest(CoverageTest):
list(gen([1,2,3]))
""",
arcz=".1 .2 23 2. 32 15 5.",
- arcz_missing="",
- arcz_unpredicted="")
+ )
def test_padded_yield_in_loop(self):
self.check_coverage("""\
@@ -588,8 +888,7 @@ class YieldTest(CoverageTest):
list(gen([1,2,3]))
""",
arcz=".1 19 9. .2 23 34 45 56 63 37 7.",
- arcz_missing="",
- arcz_unpredicted="")
+ )
def test_bug_308(self):
self.check_coverage("""\
@@ -600,9 +899,8 @@ class YieldTest(CoverageTest):
for f in run():
print(f())
""",
- arcz=".1 15 56 65 5. .2 23 32 2. .3 3-3",
- arcz_missing="",
- arcz_unpredicted="")
+ arcz=".1 15 56 65 5. .2 23 32 2. -33 3-3",
+ )
self.check_coverage("""\
def run():
@@ -613,9 +911,8 @@ class YieldTest(CoverageTest):
for f in run():
print(f())
""",
- arcz=".1 16 67 76 6. .2 23 34 43 3. 2-2 .4 4-4",
- arcz_missing="",
- arcz_unpredicted="")
+ arcz=".1 16 67 76 6. .2 23 34 43 3. -22 2-2 -44 4-4",
+ )
self.check_coverage("""\
def run():
@@ -624,9 +921,8 @@ class YieldTest(CoverageTest):
for f in run():
print(f())
""",
- arcz=".1 14 45 54 4. .2 2. 2-2",
- arcz_missing="",
- arcz_unpredicted="")
+ arcz=".1 14 45 54 4. .2 2. -22 2-2",
+ )
def test_bug_324(self):
# This code is tricky: the list() call pulls all the values from gen(),
@@ -642,14 +938,14 @@ class YieldTest(CoverageTest):
arcz=
".1 15 5. " # The module level
".2 23 32 2. " # The gen() function
- ".3 3-3", # The generator expression
- arcz_missing=".3 3-3",
- arcz_unpredicted="")
+ "-33 3-3", # The generator expression
+ arcz_missing="-33 3-3",
+ )
def test_coroutines(self):
self.check_coverage("""\
def double_inputs():
- while [1]: # avoid compiler differences
+ while len([1]): # avoid compiler differences
x = yield
x *= 2
yield x
@@ -664,9 +960,43 @@ class YieldTest(CoverageTest):
".1 17 78 89 9A AB B. "
".2 23 34 45 52 2.",
arcz_missing="2.",
- arcz_unpredicted="")
+ )
self.assertEqual(self.stdout(), "20\n12\n")
+ def test_yield_from(self):
+ if env.PYVERSION < (3, 3):
+ self.skipTest("Python before 3.3 doesn't have 'yield from'")
+ self.check_coverage("""\
+ def gen(inp):
+ i = 2
+ for n in inp:
+ i = 4
+ yield from range(3)
+ i = 6
+ i = 7
+
+ list(gen([1,2,3]))
+ """,
+ arcz=".1 19 9. .2 23 34 45 56 63 37 7.",
+ arcz_unpredicted="5.",
+ )
+
+ def test_abandoned_yield(self):
+ # https://bitbucket.org/ned/coveragepy/issue/440
+ self.check_coverage("""\
+ def gen():
+ print("yup")
+ yield "yielded"
+ print("nope")
+
+ print(next(gen()))
+ """,
+ lines=[1, 2, 3, 4, 6],
+ missing="4",
+ arcz=".1 16 6. .2 23 34 4.",
+ arcz_missing="34 4.",
+ )
+
class MiscArcTest(CoverageTest):
"""Miscellaneous arc-measuring tests."""
@@ -676,7 +1006,7 @@ class MiscArcTest(CoverageTest):
arcz = ".1 19 9."
else:
# Python 3.5 changed how dict literals are constructed.
- arcz = ".1 19 9-2"
+ arcz = "-21 19 9-2"
self.check_coverage("""\
d = {
'a': 2,
@@ -688,29 +1018,367 @@ class MiscArcTest(CoverageTest):
}
assert d
""",
- arcz=arcz)
+ arcz=arcz,
+ )
+ self.check_coverage("""\
+ d = \\
+ { 'a': 2,
+ 'b': 3,
+ 'c': {
+ 'd': 5,
+ 'e': 6,
+ }
+ }
+ assert d
+ """,
+ arcz="-21 19 9-2",
+ )
+
+ def test_unpacked_literals(self):
+ if env.PYVERSION < (3, 5):
+ self.skipTest("Don't have unpacked literals until 3.5")
+ self.check_coverage("""\
+ d = {
+ 'a': 2,
+ 'b': 3,
+ }
+ weird = {
+ **d,
+ **{'c': 7},
+ 'd': 8,
+ }
+ assert weird['b'] == 3
+ """,
+ arcz="-21 15 5A A-2"
+ )
+ self.check_coverage("""\
+ l = [
+ 2,
+ 3,
+ ]
+ weird = [
+ *l,
+ *[7],
+ 8,
+ ]
+ assert weird[1] == 3
+ """,
+ arcz="-21 15 5A A-2"
+ )
def test_pathologically_long_code_object(self):
# https://bitbucket.org/ned/coveragepy/issue/359
- # The structure of this file is such that an EXTENDED_ARG byte code is
+ # The structure of this file is such that an EXTENDED_ARG bytecode is
# needed to encode the jump at the end. We weren't interpreting those
# opcodes.
+ # Note that we no longer interpret bytecode at all, but it couldn't
+ # hurt to keep the test...
code = """\
data = [
""" + "".join("""\
- [{i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}],
+ [
+ {i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}],
""".format(i=i) for i in range(2000)
) + """\
]
- if __name__ == "__main__":
- print(len(data))
+ print(len(data))
"""
self.check_coverage(
code,
- arcs=[(-1, 1), (1, 2004), (2004, -2), (2004, 2005), (2005, -2)],
+ arcs=[(-3, 1), (1, 4004), (4004, -3)],
+ arcs_missing=[], arcs_unpredicted=[],
+ )
+
+ def test_optimized_away_lines(self):
+ self.check_coverage("""\
+ a = 1
+ if len([2]):
+ c = 3
+ if 0: # this line isn't in the compiled code.
+ if len([5]):
+ d = 6
+ e = 7
+ """,
+ lines=[1, 2, 3, 7],
+ arcz=".1 12 23 27 37 7.",
+ arcz_missing="27",
+ )
+
+ def test_partial_generators(self):
+ # https://bitbucket.org/ned/coveragepy/issues/475/generator-expression-is-marked-as-not
+ # Line 2 is executed completely.
+ # Line 3 is started but not finished, because zip ends when #2 ends.
+ # Line 4 is never started.
+ cov = self.check_coverage("""\
+ def f(a, b):
+ c = (i for i in a) # 2
+ d = (j for j in b) # 3
+ e = (k for k in b) # 4
+ return dict(zip(c, d))
+
+ f(['a', 'b'], [1, 2])
+ """,
+ arcz=".1 17 7. .2 23 34 45 5. -22 2-2 -33 3-3 -44 4-4",
+ arcz_missing="3-3 -44 4-4",
+ )
+ # ugh, unexposed methods??
+ filename = self.last_module_name + ".py"
+ fr = cov._get_file_reporter(filename)
+ arcs_executed = cov._analyze(filename).arcs_executed()
+ self.assertEqual(
+ fr.missing_arc_description(3, -3, arcs_executed),
+ "line 3 didn't finish the generator expression on line 3"
+ )
+ self.assertEqual(
+ fr.missing_arc_description(4, -4, arcs_executed),
+ "line 4 didn't run the generator expression on line 4"
+ )
+
+
+class DecoratorArcTest(CoverageTest):
+ """Tests of arcs with decorators."""
+
+ def test_function_decorator(self):
+ self.check_coverage("""\
+ def decorator(arg):
+ def _dec(f):
+ return f
+ return _dec
+
+ @decorator(6)
+ @decorator(
+ len([8]),
+ )
+ def my_function(
+ a=len([11]),
+ ):
+ x = 13
+ a = 14
+ my_function()
+ """,
+ arcz=
+ ".1 16 67 7A AE EF F. " # main line
+ ".2 24 4. -23 3-2 " # decorators
+ "-6D D-6 ", # my_function
+ )
+
+ def test_class_decorator(self):
+ self.check_coverage("""\
+ def decorator(arg):
+ def _dec(c):
+ return c
+ return _dec
+
+ @decorator(6)
+ @decorator(
+ len([8]),
+ )
+ class MyObject(
+ object
+ ):
+ X = 13
+ a = 14
+ """,
+ arcz=
+ ".1 16 67 6D 7A AE E. " # main line
+ ".2 24 4. -23 3-2 " # decorators
+ "-66 D-6 ", # MyObject
+ )
+
+ def test_bug_466(self):
+ # A bad interaction between decorators and multi-line list assignments,
+ # believe it or not...!
+ self.check_coverage("""\
+ class Parser(object):
+
+ @classmethod
+ def parse(cls):
+ formats = [ 5 ]
+
+
+ return None
+
+ Parser.parse()
+ """,
+ arcz=".1 1A A. 13 3. -35 58 8-3",
+ )
+ self.check_coverage("""\
+ class Parser(object):
+
+ @classmethod
+ def parse(cls):
+ formats = [
+ 6,
+ ]
+ return None
+
+ Parser.parse()
+ """,
+ arcz=".1 1A A. 13 3. -35 58 8-3",
+ )
+
+
+class LambdaArcTest(CoverageTest):
+ """Tests of lambdas"""
+
+ def test_multiline_lambda(self):
+ self.check_coverage("""\
+ fn = (lambda x:
+ x + 2
+ )
+ assert fn(4) == 6
+ """,
+ arcz=".1 14 4-1 1-1",
+ )
+ self.check_coverage("""\
+
+ fn = \\
+ (
+ lambda
+ x:
+ x
+ +
+ 8
+ )
+ assert fn(10) == 18
+ """,
+ arcz="-42 2A A-4 2-4",
+ )
+
+ def test_unused_lambdas_are_confusing_bug_90(self):
+ self.check_coverage("""\
+ a = 1
+ fn = lambda x: x
+ b = 3
+ """,
+ arcz=".1 12 -22 2-2 23 3.", arcz_missing="-22 2-2",
)
+ def test_raise_with_lambda_looks_like_partial_branch(self):
+ self.check_coverage("""\
+ def ouch(fn):
+ 2/0
+ a = b = c = d = 3
+ try:
+ a = ouch(lambda: 5)
+ if a:
+ b = 7
+ except ZeroDivisionError:
+ c = 9
+ d = 10
+ assert (a, b, c, d) == (3, 3, 9, 10)
+ """,
+ lines=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
+ missing="6-7",
+ arcz=".1 13 34 45 56 67 6A 7A 89 9A AB B. .2 2. -55 5-5",
+ arcz_missing="56 67 6A 7A -55 5-5",
+ arcz_unpredicted="58",
+ )
+
+ def test_lambda_in_dict(self):
+ self.check_coverage("""\
+ x = 1
+ x = 2
+ d = {
+ 4: lambda: [],
+ 5: lambda: [],
+ 6: lambda: [],
+ 7: lambda: [],
+ }
+
+ for k, v in d.items(): # 10
+ if k & 1:
+ v()
+ """,
+ arcz=".1 12 23 3A AB BC BA CA A. -43 -53 -63 -73 3-4 3-5 3-6 3-7",
+ arcz_missing="-43 3-4 -63 3-6",
+ arcz_unpredicted="",
+ )
+
+
+class AsyncTest(CoverageTest):
+ """Tests of the new async and await keywords in Python 3.5"""
+
+ def setUp(self):
+ if env.PYVERSION < (3, 5):
+ self.skipTest("Async features are new in Python 3.5")
+ super(AsyncTest, self).setUp()
+
+ def test_async(self):
+ self.check_coverage("""\
+ import asyncio
+
+ async def compute(x, y): # 3
+ print("Compute %s + %s ..." % (x, y))
+ await asyncio.sleep(0.001)
+ return x + y # 6
+
+ async def print_sum(x, y): # 8
+ result = (0 +
+ await compute(x, y) # A
+ )
+ print("%s + %s = %s" % (x, y, result))
+
+ loop = asyncio.get_event_loop() # E
+ loop.run_until_complete(print_sum(1, 2))
+ loop.close() # G
+ """,
+ arcz=
+ ".1 13 38 8E EF FG G. "
+ "-34 45 56 6-3 "
+ "-89 9C C-8",
+ arcz_unpredicted="5-3 9-8",
+ )
+ self.assertEqual(self.stdout(), "Compute 1 + 2 ...\n1 + 2 = 3\n")
+
+ def test_async_for(self):
+ self.check_coverage("""\
+ import asyncio
+
+ class AsyncIteratorWrapper: # 3
+ def __init__(self, obj): # 4
+ self._it = iter(obj)
+
+ def __aiter__(self): # 7
+ return self
+
+ async def __anext__(self): # A
+ try:
+ return next(self._it)
+ except StopIteration:
+ raise StopAsyncIteration
+
+ async def doit(): # G
+ async for letter in AsyncIteratorWrapper("abc"):
+ print(letter)
+ print(".")
+
+ loop = asyncio.get_event_loop() # L
+ loop.run_until_complete(doit())
+ loop.close()
+ """,
+ arcz=
+ ".1 13 3G GL LM MN N. " # module main line
+ "-33 34 47 7A A-3 " # class definition
+ "-GH HI IH HJ J-G " # doit
+ "-45 5-4 " # __init__
+ "-78 8-7 " # __aiter__
+ "-AB BC C-A DE E-A ", # __anext__
+ arcz_unpredicted="CD",
+ )
+ self.assertEqual(self.stdout(), "a\nb\nc\n.\n")
+
+ def test_async_with(self):
+ self.check_coverage("""\
+ async def go():
+ async with x:
+ pass
+ """,
+ arcz=".1 1. .2 23 3.",
+ arcz_missing=".2 23 3.",
+ )
+
class ExcludeTest(CoverageTest):
"""Tests of exclusions to indicate known partial branches."""
@@ -729,7 +1397,8 @@ class ExcludeTest(CoverageTest):
f = 9
""",
[1,2,3,4,5,6,7,8,9],
- arcz=".1 12 23 24 34 45 56 57 67 78 89 9. 8.", arcz_missing="")
+ arcz=".1 12 23 24 34 45 56 57 67 78 89 9. 8.",
+ )
def test_custom_pragmas(self):
self.check_coverage("""\
@@ -741,7 +1410,8 @@ class ExcludeTest(CoverageTest):
""",
[1,2,3,4,5],
partials=["only some"],
- arcz=".1 12 23 34 45 25 5.", arcz_missing="")
+ arcz=".1 12 23 34 45 25 5.",
+ )
class LineDataTest(CoverageTest):
@@ -761,5 +1431,5 @@ class LineDataTest(CoverageTest):
self.start_import_stop(cov, "fun1")
data = cov.get_data()
- fun1_lines = data.line_data(abs_file("fun1.py"))
- self.assertEqual(fun1_lines, [1, 2, 5])
+ fun1_lines = data.lines(abs_file("fun1.py"))
+ self.assertCountEqual(fun1_lines, [1, 2, 5])
diff --git a/tests/test_backward.py b/tests/test_backward.py
index 09803ba7..bbecb780 100644
--- a/tests/test_backward.py
+++ b/tests/test_backward.py
@@ -1,7 +1,10 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests that our version shims in backward.py are working."""
from coverage.backunittest import TestCase
-from coverage.backward import iitems, binary_bytes, byte_to_int, bytes_to_ints
+from coverage.backward import iitems, binary_bytes, bytes_to_ints
class BackwardTest(TestCase):
@@ -17,4 +20,3 @@ class BackwardTest(TestCase):
bb = binary_bytes(byte_values)
self.assertEqual(len(bb), len(byte_values))
self.assertEqual(byte_values, list(bytes_to_ints(bb)))
- self.assertEqual(byte_values, [byte_to_int(b) for b in bb])
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index b616ed51..3b674de7 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -1,4 +1,7 @@
-"""Test cmdline.py for coverage."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Test cmdline.py for coverage.py."""
import pprint
import re
@@ -10,8 +13,10 @@ import mock
import coverage
import coverage.cmdline
+from coverage import env
from coverage.config import CoverageConfig
-from coverage.misc import ExceptionDuringRun
+from coverage.data import CoverageData, CoverageDataFiles
+from coverage.misc import CoverageException, ExceptionDuringRun
from tests.coveragetest import CoverageTest, OK, ERR
@@ -52,35 +57,42 @@ class BaseCmdLineTest(CoverageTest):
# We'll invoke .coverage as the constructor, and then keep using the
# same object as the resulting coverage object.
mk.coverage.return_value = mk
- mk.config = CoverageConfig()
+
+ # The mock needs to get options, but shouldn't need to set them.
+ config = CoverageConfig()
+ mk.get_option = config.get_option
+
return mk
- def mock_command_line(self, args):
+ def mock_command_line(self, args, path_exists=None):
"""Run `args` through the command line, with a Mock.
Returns the Mock it used and the status code returned.
"""
m = self.model_object()
- ret = coverage.CoverageScript(
+ m.path_exists.return_value = path_exists
+
+ ret = coverage.cmdline.CoverageScript(
_covpkg=m, _run_python_file=m.run_python_file,
- _run_python_module=m.run_python_module, _help_fn=m.help_fn
+ _run_python_module=m.run_python_module, _help_fn=m.help_fn,
+ _path_exists=m.path_exists,
).command_line(shlex.split(args))
+
return m, ret
- def cmd_executes(self, args, code, ret=OK):
+ def cmd_executes(self, args, code, ret=OK, path_exists=None):
"""Assert that the `args` end up executing the sequence in `code`."""
- m1, r1 = self.mock_command_line(args)
- self.assertEqual(
- r1, ret, "Wrong status: got %s, wanted %s" % (r1, ret)
- )
+ m1, r1 = self.mock_command_line(args, path_exists=path_exists)
+ self.assertEqual(r1, ret, "Wrong status: got %r, wanted %r" % (r1, ret))
# Remove all indentation, and change ".foo()" to "m2.foo()".
code = re.sub(r"(?m)^\s+", "", code)
code = re.sub(r"(?m)^\.", "m2.", code)
m2 = self.model_object()
+ m2.path_exists.return_value = path_exists
code_obj = compile(code, "<code>", "exec")
- eval(code_obj, globals(), { 'm2': m2 }) # pylint: disable=eval-used
+ eval(code_obj, globals(), {'m2': m2}) # pylint: disable=eval-used
# Many of our functions take a lot of arguments, and cmdline.py
# calls them with many. But most of them are just the defaults, which
@@ -117,17 +129,11 @@ class BaseCmdLineTest(CoverageTest):
"""
m, r = self.mock_command_line(args)
- self.assertEqual(r, ret,
- "Wrong status: got %s, wanted %s" % (r, ret)
- )
+ self.assertEqual(r, ret, "Wrong status: got %s, wanted %s" % (r, ret))
if help_msg:
- self.assertEqual(m.method_calls[-1],
- ('help_fn', (help_msg,), {})
- )
+ self.assertEqual(m.method_calls[-1], ('help_fn', (help_msg,), {}))
else:
- self.assertEqual(m.method_calls[-1],
- ('help_fn', (), {'topic':topic})
- )
+ self.assertEqual(m.method_calls[-1], ('help_fn', (), {'topic': topic}))
class BaseCmdLineTestTest(BaseCmdLineTest):
@@ -139,38 +145,6 @@ class BaseCmdLineTestTest(BaseCmdLineTest):
self.cmd_executes_same("run", "debug")
-class FakeCoverageForDebugData(object):
- """Just enough of a fake coverage package for the 'debug data' tests."""
- def __init__(self, summary, plugin_data=None):
- self._summary = summary
- self._plugin_data = plugin_data or {}
- self.filename = "FILENAME"
- self.data = self
-
- # package members
- def coverage(self, *unused_args, **unused_kwargs):
- """The coverage class in the package."""
- return self
-
- # coverage methods
- def load(self):
- """Fake coverage().load()"""
- pass
-
- # data methods
- def has_arcs(self):
- """Fake coverage().data.has_arcs()"""
- return False
-
- def summary(self, fullpath): # pylint: disable=unused-argument
- """Fake coverage().data.summary()"""
- return self._summary
-
- def plugin_data(self):
- """Fake coverage().data.plugin_data()"""
- return self._plugin_data
-
-
class CmdLineTest(BaseCmdLineTest):
"""Tests of the coverage.py command line."""
@@ -216,58 +190,52 @@ class CmdLineTest(BaseCmdLineTest):
# coverage combine with args
self.cmd_executes("combine datadir1", """\
.coverage()
+ .combine(["datadir1"], strict=True)
+ .save()
+ """)
+ # coverage combine, appending
+ self.cmd_executes("combine --append datadir1", """\
+ .coverage()
.load()
- .combine(["datadir1"])
+ .combine(["datadir1"], strict=True)
.save()
""")
# coverage combine without args
self.cmd_executes("combine", """\
.coverage()
- .load()
- .combine(None)
+ .combine(None, strict=True)
+ .save()
+ """)
+
+ def test_combine_doesnt_confuse_options_with_args(self):
+ # https://bitbucket.org/ned/coveragepy/issues/385/coverage-combine-doesnt-work-with-rcfile
+ self.cmd_executes("combine --rcfile cov.ini", """\
+ .coverage(config_file='cov.ini')
+ .combine(None, strict=True)
+ .save()
+ """)
+ self.cmd_executes("combine --rcfile cov.ini data1 data2/more", """\
+ .coverage(config_file='cov.ini')
+ .combine(["data1", "data2/more"], strict=True)
.save()
""")
def test_debug(self):
- self.cmd_help("debug", "What information would you like: data, sys?")
+ self.cmd_help("debug", "What information would you like: config, data, sys?")
self.cmd_help("debug foo", "Don't know what you mean by 'foo'")
- def test_debug_data(self):
- fake = FakeCoverageForDebugData(
- summary={
- 'file1.py': 17, 'file2.py': 23,
- },
- plugin_data={
- 'file1.py': 'a_plugin',
- },
- )
- self.command_line("debug data", _covpkg=fake)
- self.assertMultiLineEqual(self.stdout(), textwrap.dedent("""\
- -- data ------------------------------------------------------
- path: FILENAME
- has_arcs: False
-
- 2 files:
- file1.py: 17 lines [a_plugin]
- file2.py: 23 lines
- """))
-
- def test_debug_data_with_no_data(self):
- fake = FakeCoverageForDebugData(summary={})
- self.command_line("debug data", _covpkg=fake)
- self.assertMultiLineEqual(self.stdout(), textwrap.dedent("""\
- -- data ------------------------------------------------------
- path: FILENAME
- has_arcs: False
- No data collected
- """))
-
def test_debug_sys(self):
self.command_line("debug sys")
out = self.stdout()
self.assertIn("version:", out)
self.assertIn("data_path:", out)
+ def test_debug_config(self):
+ self.command_line("debug config")
+ out = self.stdout()
+ self.assertIn("cover_pylib:", out)
+ self.assertIn("skip_covered:", out)
+
def test_erase(self):
# coverage erase
self.cmd_executes("erase", """\
@@ -288,8 +256,7 @@ class CmdLineTest(BaseCmdLineTest):
self.cmd_executes("help", ".help_fn(topic='help')")
def test_cmd_help(self):
- self.cmd_executes("run --help",
- ".help_fn(parser='<CmdOptionParser:run>')")
+ self.cmd_executes("run --help", ".help_fn(parser='<CmdOptionParser:run>')")
self.cmd_executes_same("help run", "run --help")
def test_html(self):
@@ -390,15 +357,25 @@ class CmdLineTest(BaseCmdLineTest):
.stop()
.save()
""")
- # run -a calls coverage.load first without erasing.
+ # run -a combines with an existing data file before saving.
self.cmd_executes("run -a foo.py", """\
.coverage()
- .load()
.start()
.run_python_file('foo.py', ['foo.py'])
.stop()
+ .path_exists('.coverage')
+ .combine(data_paths=['.coverage'])
.save()
- """)
+ """, path_exists=True)
+ # run -a doesn't combine anything if the data file doesn't exist.
+ self.cmd_executes("run -a foo.py", """\
+ .coverage()
+ .start()
+ .run_python_file('foo.py', ['foo.py'])
+ .stop()
+ .path_exists('.coverage')
+ .save()
+ """, path_exists=False)
# --timid sets a flag, and program arguments get passed through.
self.cmd_executes("run --timid foo.py abc 123", """\
.coverage(timid=True)
@@ -449,8 +426,7 @@ class CmdLineTest(BaseCmdLineTest):
.stop()
.save()
""")
- self.cmd_executes("run --include=pre1,pre2 --omit=opre1,opre2 foo.py",
- """\
+ self.cmd_executes("run --include=pre1,pre2 --omit=opre1,opre2 foo.py", """\
.coverage(include=["pre1", "pre2"], omit=["opre1", "opre2"])
.erase()
.start()
@@ -474,12 +450,42 @@ class CmdLineTest(BaseCmdLineTest):
.stop()
.save()
""")
+ self.cmd_executes("run --concurrency=multiprocessing foo.py", """\
+ .coverage(concurrency='multiprocessing')
+ .erase()
+ .start()
+ .run_python_file('foo.py', ['foo.py'])
+ .stop()
+ .save()
+ """)
+
+ def test_bad_run_args_with_both_source_and_include(self):
+ with self.assertRaisesRegex(CoverageException, 'mutually exclusive'):
+ self.command_line("run --include=pre1,pre2 --source=lol,wut foo.py", ret=ERR)
def test_bad_concurrency(self):
self.command_line("run --concurrency=nothing", ret=ERR)
out = self.stdout()
self.assertIn("option --concurrency: invalid choice: 'nothing'", out)
+ def test_no_multiple_concurrency(self):
+ # You can't use multiple concurrency values on the command line.
+ # I would like to have a better message about not allowing multiple
+ # values for this option, but optparse is not that flexible.
+ self.command_line("run --concurrency=multiprocessing,gevent foo.py", ret=ERR)
+ out = self.stdout()
+ self.assertIn("option --concurrency: invalid choice: 'multiprocessing,gevent'", out)
+
+ def test_multiprocessing_needs_config_file(self):
+ # You can't use command-line args to add options to multiprocessing
+ # runs, since they won't make it to the subprocesses. You need to use a
+ # config file.
+ self.command_line("run --concurrency=multiprocessing --branch foo.py", ret=ERR)
+ self.assertIn(
+ "Options affecting multiprocessing must be specified in a configuration file.",
+ self.stdout()
+ )
+
def test_run_debug(self):
self.cmd_executes("run --debug=opt1 foo.py", """\
.coverage(debug=["opt1"])
@@ -525,6 +531,14 @@ class CmdLineTest(BaseCmdLineTest):
""")
self.cmd_executes_same("run -m mymodule", "run --module mymodule")
+ def test_run_nothing(self):
+ self.command_line("run", ret=ERR)
+ self.assertIn("Nothing to do", self.stdout())
+
+ def test_cant_append_parallel(self):
+ self.command_line("run --append --parallel-mode foo.py", ret=ERR)
+ self.assertIn("Can't append to data files in parallel mode.", self.stdout())
+
def test_xml(self):
# coverage xml [-i] [--omit DIR,...] [FILE1 FILE2 ...]
self.cmd_executes("xml", """\
@@ -575,6 +589,43 @@ class CmdLineTest(BaseCmdLineTest):
self.cmd_help("xyzzy", "Unknown command: 'xyzzy'")
+class CmdLineWithFilesTest(BaseCmdLineTest):
+ """Test the command line in ways that need temp files."""
+
+ run_in_temp_dir = True
+ no_files_in_temp_dir = True
+
+ def test_debug_data(self):
+ data = CoverageData()
+ data.add_lines({
+ "file1.py": dict.fromkeys(range(1, 18)),
+ "file2.py": dict.fromkeys(range(1, 24)),
+ })
+ data.add_file_tracers({"file1.py": "a_plugin"})
+ data_files = CoverageDataFiles()
+ data_files.write(data)
+
+ self.command_line("debug data")
+ self.assertMultiLineEqual(self.stdout(), textwrap.dedent("""\
+ -- data ------------------------------------------------------
+ path: FILENAME
+ has_arcs: False
+
+ 2 files:
+ file1.py: 17 lines [a_plugin]
+ file2.py: 23 lines
+ """).replace("FILENAME", data_files.filename))
+
+ def test_debug_data_with_no_data(self):
+ data_files = CoverageDataFiles()
+ self.command_line("debug data")
+ self.assertMultiLineEqual(self.stdout(), textwrap.dedent("""\
+ -- data ------------------------------------------------------
+ path: FILENAME
+ No data collected
+ """).replace("FILENAME", data_files.filename))
+
+
class CmdLineStdoutTest(BaseCmdLineTest):
"""Test the command line with real stdout output."""
@@ -588,12 +639,16 @@ class CmdLineStdoutTest(BaseCmdLineTest):
self.command_line("--version")
out = self.stdout()
self.assertIn("ersion ", out)
+ if env.C_TRACER:
+ self.assertIn("with C extension", out)
+ else:
+ self.assertIn("without C extension", out)
self.assertLess(out.count("\n"), 4)
def test_help(self):
self.command_line("help")
out = self.stdout()
- self.assertIn("readthedocs.org", out)
+ self.assertIn("readthedocs.io", out)
self.assertGreater(out.count("\n"), 10)
def test_cmd_help(self):
@@ -603,6 +658,11 @@ class CmdLineStdoutTest(BaseCmdLineTest):
self.assertIn("--timid", out)
self.assertGreater(out.count("\n"), 10)
+ def test_unknown_topic(self):
+ # Should probably be an ERR return, but meh.
+ self.command_line("help foobar")
+ self.assertEqual(self.stdout(), "Don't know topic 'foobar'\n")
+
def test_error(self):
self.command_line("fooey kablooey", ret=ERR)
out = self.stdout()
@@ -632,17 +692,17 @@ class CmdMainTest(CoverageTest):
elif argv[0] == 'exit':
sys.exit(23)
else:
- raise AssertionError("Bad CoverageScriptStub: %r"% (argv,))
+ raise AssertionError("Bad CoverageScriptStub: %r" % (argv,))
return 0
def setUp(self):
super(CmdMainTest, self).setUp()
self.old_CoverageScript = coverage.cmdline.CoverageScript
coverage.cmdline.CoverageScript = self.CoverageScriptStub
- self.addCleanup(self.restore_coverage_script)
+ self.addCleanup(self.cleanup_coverage_script)
- def restore_coverage_script(self):
- """A cleanup"""
+ def cleanup_coverage_script(self):
+ """Restore CoverageScript when the test is done."""
coverage.cmdline.CoverageScript = self.old_CoverageScript
def test_normal(self):
diff --git a/tests/test_collector.py b/tests/test_collector.py
index 26360091..bd963415 100644
--- a/tests/test_collector.py
+++ b/tests/test_collector.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests of coverage/collector.py and other collectors."""
import os.path
@@ -35,7 +38,7 @@ class CollectorTest(CoverageTest):
# Trace one file, but not the other. CheckUniqueFilenames will assert
# that _should_trace hasn't been called twice for the same file.
- cov = coverage.coverage(include=["f1.py"])
+ cov = coverage.Coverage(include=["f1.py"])
should_trace_hook = CheckUniqueFilenames.hook(cov, '_should_trace')
# Import the Python file, executing it.
diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py
index 21048941..e36db30d 100644
--- a/tests/test_concurrency.py
+++ b/tests/test_concurrency.py
@@ -1,11 +1,14 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for concurrency libraries."""
-import os
-import os.path
+import multiprocessing
import threading
import coverage
from coverage import env
+from coverage.files import abs_file
from tests.coveragetest import CoverageTest
@@ -22,95 +25,169 @@ try:
except ImportError:
gevent = None
-try:
- import greenlet
-except ImportError:
- greenlet = None
+import greenlet
+
+
+def measurable_line(l):
+ """Is this a line of code coverage will measure?
+
+ Not blank, not a comment, and not "else"
+ """
+ l = l.strip()
+ if not l:
+ return False
+ if l.startswith('#'):
+ return False
+ if l.startswith('else:'):
+ return False
+ return True
def line_count(s):
- """How many non-blank non-comment lines are in `s`?"""
- def code_line(l):
- """Is this a code line? Not blank, and not a full-line comment."""
- return l.strip() and not l.strip().startswith('#')
- return sum(1 for l in s.splitlines() if code_line(l))
+ """How many measurable lines are in `s`?"""
+ return len(list(filter(measurable_line, s.splitlines())))
-class ConcurrencyTest(CoverageTest):
- """Tests of the concurrency support in coverage.py."""
+def print_simple_annotation(code, linenos):
+ """Print the lines in `code` with X for each line number in `linenos`."""
+ for lineno, line in enumerate(code.splitlines(), start=1):
+ print(" {0} {1}".format("X" if lineno in linenos else " ", line))
+
+
+class LineCountTest(CoverageTest):
+ """Test the helpers here."""
+
+ run_in_temp_dir = False
- LIMIT = 1000
-
- # The code common to all the concurrency models.
- COMMON = """
- class Producer(threading.Thread):
- def __init__(self, q):
- threading.Thread.__init__(self)
- self.q = q
-
- def run(self):
- for i in range({LIMIT}):
- self.q.put(i)
- self.q.put(None)
-
- class Consumer(threading.Thread):
- def __init__(self, q):
- threading.Thread.__init__(self)
- self.q = q
-
- def run(self):
- sum = 0
- while True:
- i = self.q.get()
- if i is None:
- print(sum)
- break
- sum += i
+ def test_line_count(self):
+ CODE = """
+ # Hey there!
+ x = 1
+ if x:
+ print("hello")
+ else:
+ print("bye")
+ print("done")
+ """
+
+ self.assertEqual(line_count(CODE), 5)
+
+
+# The code common to all the concurrency models.
+SUM_RANGE_Q = """
+ # Above this will be imports defining queue and threading.
+
+ class Producer(threading.Thread):
+ def __init__(self, limit, q):
+ threading.Thread.__init__(self)
+ self.limit = limit
+ self.q = q
+
+ def run(self):
+ for i in range(self.limit):
+ self.q.put(i)
+ self.q.put(None)
+
+ class Consumer(threading.Thread):
+ def __init__(self, q, qresult):
+ threading.Thread.__init__(self)
+ self.q = q
+ self.qresult = qresult
+
+ def run(self):
+ sum = 0
+ while True:
+ i = self.q.get()
+ if i is None:
+ break
+ sum += i
+ self.qresult.put(sum)
+
+ def sum_range(limit):
q = queue.Queue()
- c = Consumer(q)
- p = Producer(q)
+ qresult = queue.Queue()
+ c = Consumer(q, qresult)
+ p = Producer(limit, q)
c.start()
p.start()
p.join()
c.join()
- """.format(LIMIT=LIMIT)
-
- # Import the things to use threads.
- if env.PY2:
- THREAD = """\
- import threading
- import Queue as queue
- """ + COMMON
+ return qresult.get()
+
+ # Below this will be something using sum_range.
+ """
+
+PRINT_SUM_RANGE = """
+ print(sum_range({QLIMIT}))
+ """
+
+# Import the things to use threads.
+if env.PY2:
+ THREAD = """
+ import threading
+ import Queue as queue
+ """
+else:
+ THREAD = """
+ import threading
+ import queue
+ """
+
+# Import the things to use eventlet.
+EVENTLET = """
+ import eventlet.green.threading as threading
+ import eventlet.queue as queue
+ """
+
+# Import the things to use gevent.
+GEVENT = """
+ from gevent import monkey
+ monkey.patch_thread()
+ import threading
+ import gevent.queue as queue
+ """
+
+# Uncomplicated code that doesn't use any of the concurrency stuff, to test
+# the simple case under each of the regimes.
+SIMPLE = """
+ total = 0
+ for i in range({QLIMIT}):
+ total += i
+ print(total)
+ """
+
+
+def cant_trace_msg(concurrency, the_module):
+ """What might coverage.py say about a concurrency setting and imported module?"""
+ # In the concurrency choices, "multiprocessing" doesn't count, so remove it.
+ if "multiprocessing" in concurrency:
+ parts = concurrency.split(",")
+ parts.remove("multiprocessing")
+ concurrency = ",".join(parts)
+
+ if the_module is None:
+ # We don't even have the underlying module installed, we expect
+ # coverage to alert us to this fact.
+ expected_out = (
+ "Couldn't trace with concurrency=%s, "
+ "the module isn't installed.\n" % concurrency
+ )
+ elif env.C_TRACER or concurrency == "thread" or concurrency == "":
+ expected_out = None
else:
- THREAD = """\
- import threading
- import queue
- """ + COMMON
-
- # Import the things to use eventlet.
- EVENTLET = """\
- import eventlet.green.threading as threading
- import eventlet.queue as queue
- """ + COMMON
-
- # Import the things to use gevent.
- GEVENT = """\
- from gevent import monkey
- monkey.patch_thread()
- import threading
- import gevent.queue as queue
- """ + COMMON
-
- # Uncomplicated code that doesn't use any of the concurrency stuff, to test
- # the simple case under each of the regimes.
- SIMPLE = """\
- total = 0
- for i in range({LIMIT}):
- total += i
- print(total)
- """.format(LIMIT=LIMIT)
+ expected_out = (
+ "Can't support concurrency=%s with PyTracer, "
+ "only threads are supported\n" % concurrency
+ )
+ return expected_out
+
+
+class ConcurrencyTest(CoverageTest):
+ """Tests of the concurrency support in coverage.py."""
+
+ QLIMIT = 1000
def try_some_code(self, code, concurrency, the_module, expected_out=None):
"""Run some concurrency testing code and see that it was all covered.
@@ -127,19 +204,16 @@ class ConcurrencyTest(CoverageTest):
cmd = "coverage run --concurrency=%s try_it.py" % concurrency
out = self.run_command(cmd)
- if not the_module:
- # We don't even have the underlying module installed, we expect
- # coverage to alert us to this fact.
- expected_out = (
- "Couldn't trace with concurrency=%s, "
- "the module isn't installed.\n" % concurrency
- )
- self.assertEqual(out, expected_out)
- elif env.C_TRACER or concurrency == "thread":
+ expected_cant_trace = cant_trace_msg(concurrency, the_module)
+
+ if expected_cant_trace is not None:
+ self.assertEqual(out, expected_cant_trace)
+ else:
# We can fully measure the code if we are using the C tracer, which
# can support all the concurrency, or if we are using threads.
if expected_out is None:
- expected_out = "%d\n" % (sum(range(self.LIMIT)))
+ expected_out = "%d\n" % (sum(range(self.QLIMIT)))
+ print(code)
self.assertEqual(out, expected_out)
# Read the coverage file and see that try_it.py has all its lines
@@ -148,37 +222,37 @@ class ConcurrencyTest(CoverageTest):
data.read_file(".coverage")
# If the test fails, it's helpful to see this info:
- fname = os.path.abspath("try_it.py")
- linenos = data.line_data(fname)
+ fname = abs_file("try_it.py")
+ linenos = data.lines(fname)
print("{0}: {1}".format(len(linenos), linenos))
print_simple_annotation(code, linenos)
lines = line_count(code)
- self.assertEqual(data.summary()['try_it.py'], lines)
- else:
- expected_out = (
- "Can't support concurrency=%s with PyTracer, "
- "only threads are supported\n" % concurrency
- )
- self.assertEqual(out, expected_out)
+ self.assertEqual(data.line_counts()['try_it.py'], lines)
def test_threads(self):
- self.try_some_code(self.THREAD, "thread", threading)
+ code = (THREAD + SUM_RANGE_Q + PRINT_SUM_RANGE).format(QLIMIT=self.QLIMIT)
+ self.try_some_code(code, "thread", threading)
def test_threads_simple_code(self):
- self.try_some_code(self.SIMPLE, "thread", threading)
+ code = SIMPLE.format(QLIMIT=self.QLIMIT)
+ self.try_some_code(code, "thread", threading)
def test_eventlet(self):
- self.try_some_code(self.EVENTLET, "eventlet", eventlet)
+ code = (EVENTLET + SUM_RANGE_Q + PRINT_SUM_RANGE).format(QLIMIT=self.QLIMIT)
+ self.try_some_code(code, "eventlet", eventlet)
def test_eventlet_simple_code(self):
- self.try_some_code(self.SIMPLE, "eventlet", eventlet)
+ code = SIMPLE.format(QLIMIT=self.QLIMIT)
+ self.try_some_code(code, "eventlet", eventlet)
def test_gevent(self):
- self.try_some_code(self.GEVENT, "gevent", gevent)
+ code = (GEVENT + SUM_RANGE_Q + PRINT_SUM_RANGE).format(QLIMIT=self.QLIMIT)
+ self.try_some_code(code, "gevent", gevent)
def test_gevent_simple_code(self):
- self.try_some_code(self.SIMPLE, "gevent", gevent)
+ code = SIMPLE.format(QLIMIT=self.QLIMIT)
+ self.try_some_code(code, "gevent", gevent)
def test_greenlet(self):
GREENLET = """\
@@ -199,7 +273,8 @@ class ConcurrencyTest(CoverageTest):
self.try_some_code(GREENLET, "greenlet", greenlet, "hello world\n42\n")
def test_greenlet_simple_code(self):
- self.try_some_code(self.SIMPLE, "greenlet", greenlet)
+ code = SIMPLE.format(QLIMIT=self.QLIMIT)
+ self.try_some_code(code, "greenlet", greenlet)
def test_bug_330(self):
BUG_330 = """\
@@ -215,65 +290,147 @@ class ConcurrencyTest(CoverageTest):
eventlet.sleep(.005)
eventlet.sleep(.1)
- print len(gts)
+ print(len(gts))
"""
self.try_some_code(BUG_330, "eventlet", eventlet, "0\n")
+SQUARE_OR_CUBE_WORK = """
+ def work(x):
+ # Use different lines in different subprocesses.
+ if x % 2:
+ y = x*x
+ else:
+ y = x*x*x
+ return y
+ """
+
+SUM_RANGE_WORK = """
+ def work(x):
+ return sum_range((x+1)*100)
+ """
+
+MULTI_CODE = """
+ # Above this will be a definition of work().
+ import multiprocessing
+ import os
+ import time
+ import sys
+
+ def process_worker_main(args):
+ # Need to pause, or the tasks go too quick, and some processes
+ # in the pool don't get any work, and then don't record data.
+ time.sleep(0.02)
+ ret = work(*args)
+ return os.getpid(), ret
+
+ if __name__ == "__main__": # pragma: no branch
+ # This if is on a single line so we can get 100% coverage
+ # even if we have no arguments.
+ if len(sys.argv) > 1: multiprocessing.set_start_method(sys.argv[1])
+ pool = multiprocessing.Pool({NPROCS})
+ inputs = [(x,) for x in range({UPTO})]
+ outputs = pool.imap_unordered(process_worker_main, inputs)
+ pids = set()
+ total = 0
+ for pid, sq in outputs:
+ pids.add(pid)
+ total += sq
+ print("%d pids, total = %d" % (len(pids), total))
+ pool.close()
+ pool.join()
+ """
+
+
class MultiprocessingTest(CoverageTest):
"""Test support of the multiprocessing module."""
- def setUp(self):
- super(MultiprocessingTest, self).setUp()
- # Currently, this doesn't work on Windows, something about pickling
- # the monkey-patched Process class?
- if env.WINDOWS:
- self.skip("Multiprocessing support doesn't work on Windows")
+ def try_multiprocessing_code(
+ self, code, expected_out, the_module, concurrency="multiprocessing"
+ ):
+ """Run code using multiprocessing, it should produce `expected_out`."""
+ self.make_file("multi.py", code)
+ self.make_file(".coveragerc", """\
+ [run]
+ concurrency = %s
+ """ % concurrency)
+
+ if env.PYVERSION >= (3, 4):
+ start_methods = ['fork', 'spawn']
+ else:
+ start_methods = ['']
+
+ for start_method in start_methods:
+ if start_method and start_method not in multiprocessing.get_all_start_methods():
+ continue
+
+ out = self.run_command("coverage run multi.py %s" % (start_method,))
+ expected_cant_trace = cant_trace_msg(concurrency, the_module)
+
+ if expected_cant_trace is not None:
+ self.assertEqual(out, expected_cant_trace)
+ else:
+ self.assertEqual(out.rstrip(), expected_out)
+
+ out = self.run_command("coverage combine")
+ self.assertEqual(out, "")
+ out = self.run_command("coverage report -m")
+
+ last_line = self.squeezed_lines(out)[-1]
+ self.assertRegex(last_line, r"multi.py \d+ 0 100%")
def test_multiprocessing(self):
- self.make_file("multi.py", """\
- import multiprocessing
- import os
- import time
-
- def func(x):
- # Need to pause, or the tasks go too quick, and some processes
- # in the pool don't get any work, and then don't record data.
- time.sleep(0.02)
- # Use different lines in different subprocesses.
- if x % 2:
- y = x*x
- else:
- y = x*x*x
- return os.getpid(), y
-
- if __name__ == "__main__":
- pool = multiprocessing.Pool(3)
- inputs = range(30)
- outputs = pool.imap_unordered(func, inputs)
- pids = set()
- total = 0
- for pid, sq in outputs:
- pids.add(pid)
- total += sq
- print("%d pids, total = %d" % (len(pids), total))
- pool.close()
- pool.join()
+ nprocs = 3
+ upto = 30
+ code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
+ total = sum(x*x if x%2 else x*x*x for x in range(upto))
+ expected_out = "{nprocs} pids, total = {total}".format(nprocs=nprocs, total=total)
+ self.try_multiprocessing_code(code, expected_out, threading)
+
+ def test_multiprocessing_and_gevent(self):
+ nprocs = 3
+ upto = 30
+ code = (
+ SUM_RANGE_WORK + EVENTLET + SUM_RANGE_Q + MULTI_CODE
+ ).format(NPROCS=nprocs, UPTO=upto)
+ total = sum(sum(range((x + 1) * 100)) for x in range(upto))
+ expected_out = "{nprocs} pids, total = {total}".format(nprocs=nprocs, total=total)
+ self.try_multiprocessing_code(
+ code, expected_out, eventlet, concurrency="multiprocessing,eventlet"
+ )
+
+ def try_multiprocessing_code_with_branching(self, code, expected_out):
+ """Run code using multiprocessing, it should produce `expected_out`."""
+ self.make_file("multi.py", code)
+ self.make_file("multi.rc", """\
+ [run]
+ concurrency = multiprocessing
+ branch = True
""")
- out = self.run_command(
- "coverage run --concurrency=multiprocessing multi.py"
- )
- total = sum(x*x if x%2 else x*x*x for x in range(30))
- self.assertEqual(out.rstrip(), "3 pids, total = %d" % total)
+ if env.PYVERSION >= (3, 4):
+ start_methods = ['fork', 'spawn']
+ else:
+ start_methods = ['']
- self.run_command("coverage combine")
- out = self.run_command("coverage report -m")
- last_line = self.squeezed_lines(out)[-1]
- self.assertEqual(last_line, "multi.py 21 0 100%")
+ for start_method in start_methods:
+ if start_method and start_method not in multiprocessing.get_all_start_methods():
+ continue
+ out = self.run_command("coverage run --rcfile=multi.rc multi.py %s" % (start_method,))
+ self.assertEqual(out.rstrip(), expected_out)
-def print_simple_annotation(code, linenos):
- """Print the lines in `code` with X for each line number in `linenos`."""
- for lineno, line in enumerate(code.splitlines(), start=1):
- print(" {0} {1}".format("X" if lineno in linenos else " ", line))
+ out = self.run_command("coverage combine")
+ self.assertEqual(out, "")
+ out = self.run_command("coverage report -m")
+
+ last_line = self.squeezed_lines(out)[-1]
+ self.assertRegex(last_line, r"multi.py \d+ 0 \d+ 0 100%")
+
+ def test_multiprocessing_with_branching(self):
+ nprocs = 3
+ upto = 30
+ code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
+ total = sum(x*x if x%2 else x*x*x for x in range(upto))
+ expected_out = "{nprocs} pids, total = {total}".format(nprocs=nprocs, total=total)
+ self.try_multiprocessing_code_with_branching(code, expected_out)
diff --git a/tests/test_config.py b/tests/test_config.py
index d375830b..2aa592b9 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,4 +1,7 @@
-# -*- coding: utf-8 -*-
+# coding: utf-8
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Test the config file handling for coverage.py"""
import sys
@@ -15,17 +18,18 @@ class ConfigTest(CoverageTest):
def test_default_config(self):
# Just constructing a coverage() object gets the right defaults.
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.assertFalse(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, ".coverage")
def test_arguments(self):
# Arguments to the constructor are applied to the configuration.
- cov = coverage.coverage(timid=True, data_file="fooey.dat")
+ cov = coverage.Coverage(timid=True, data_file="fooey.dat", concurrency="multiprocessing")
self.assertTrue(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, "fooey.dat")
+ self.assertEqual(cov.config.concurrency, ["multiprocessing"])
def test_config_file(self):
# A .coveragerc file will be read into the configuration.
@@ -35,7 +39,7 @@ class ConfigTest(CoverageTest):
timid = True
data_file = .hello_kitty.data
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.assertTrue(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, ".hello_kitty.data")
@@ -48,7 +52,7 @@ class ConfigTest(CoverageTest):
; I wouldn't really use this as a data file...
data_file = delete.me
""")
- cov = coverage.coverage(config_file="my_cov.ini")
+ cov = coverage.Coverage(config_file="my_cov.ini")
self.assertTrue(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, "delete.me")
@@ -60,7 +64,7 @@ class ConfigTest(CoverageTest):
timid = True
data_file = delete.me
""")
- cov = coverage.coverage(config_file=False)
+ cov = coverage.Coverage(config_file=False)
self.assertFalse(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, ".coverage")
@@ -72,7 +76,7 @@ class ConfigTest(CoverageTest):
timid = True
data_file = weirdo.file
""")
- cov = coverage.coverage(timid=False, data_file=".mycov")
+ cov = coverage.Coverage(timid=False, data_file=".mycov")
self.assertFalse(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, ".mycov")
@@ -85,12 +89,21 @@ class ConfigTest(CoverageTest):
data_file = weirdo.file
""")
self.set_environ("COVERAGE_FILE", "fromenv.dat")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.assertEqual(cov.config.data_file, "fromenv.dat")
# But the constructor arguments override the environment variable.
- cov = coverage.coverage(data_file="fromarg.dat")
+ cov = coverage.Coverage(data_file="fromarg.dat")
self.assertEqual(cov.config.data_file, "fromarg.dat")
+ def test_debug_from_environment(self):
+ self.make_file(".coveragerc", """\
+ [run]
+ debug = dataio, pids
+ """)
+ self.set_environ("COVERAGE_DEBUG", "callers, fooey")
+ cov = coverage.Coverage()
+ self.assertEqual(cov.config.debug, ["dataio", "pids", "callers", "fooey"])
+
def test_parse_errors(self):
# Im-parsable values raise CoverageException, with details.
bad_configs_and_msgs = [
@@ -99,21 +112,21 @@ class ConfigTest(CoverageTest):
("[run\n", r"\[run"),
("[report]\nexclude_lines = foo(\n",
r"Invalid \[report\].exclude_lines value 'foo\(': "
- r"(unbalanced parenthesis|missing \))"),
+ r"(unbalanced parenthesis|missing \))"),
("[report]\npartial_branches = foo[\n",
r"Invalid \[report\].partial_branches value 'foo\[': "
- r"(unexpected end of regular expression|unterminated character set)"),
+ r"(unexpected end of regular expression|unterminated character set)"),
("[report]\npartial_branches_always = foo***\n",
r"Invalid \[report\].partial_branches_always value "
- r"'foo\*\*\*': "
- r"multiple repeat"),
- ]
+ r"'foo\*\*\*': "
+ r"multiple repeat"),
+ ]
for bad_config, msg in bad_configs_and_msgs:
print("Trying %r" % bad_config)
self.make_file(".coveragerc", bad_config)
with self.assertRaisesRegex(CoverageException, msg):
- coverage.coverage()
+ coverage.Coverage()
def test_environment_vars_in_config(self):
# Config files can have $envvars in them.
@@ -132,51 +145,79 @@ class ConfigTest(CoverageTest):
self.set_environ("DATA_FILE", "hello-world")
self.set_environ("THING", "ZZZ")
self.set_environ("OKAY", "yes")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.assertEqual(cov.config.data_file, "hello-world.fooey")
self.assertEqual(cov.config.branch, True)
- self.assertEqual(cov.config.exclude_list,
+ self.assertEqual(
+ cov.config.exclude_list,
["the_$one", "anotherZZZ", "xZZZy", "xy", "huh${X}what"]
- )
+ )
def test_tweaks_after_constructor(self):
# Arguments to the constructor are applied to the configuration.
- cov = coverage.coverage(timid=True, data_file="fooey.dat")
- cov.config["run:timid"] = False
+ cov = coverage.Coverage(timid=True, data_file="fooey.dat")
+ cov.set_option("run:timid", False)
self.assertFalse(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, "fooey.dat")
- self.assertFalse(cov.config["run:timid"])
- self.assertFalse(cov.config["run:branch"])
- self.assertEqual(cov.config["run:data_file"], "fooey.dat")
+ self.assertFalse(cov.get_option("run:timid"))
+ self.assertFalse(cov.get_option("run:branch"))
+ self.assertEqual(cov.get_option("run:data_file"), "fooey.dat")
def test_tweak_error_checking(self):
# Trying to set an unknown config value raises an error.
- cov = coverage.coverage()
+ cov = coverage.Coverage()
with self.assertRaises(CoverageException):
- cov.config["run:xyzzy"] = 12
+ cov.set_option("run:xyzzy", 12)
with self.assertRaises(CoverageException):
- cov.config["xyzzy:foo"] = 12
+ cov.set_option("xyzzy:foo", 12)
with self.assertRaises(CoverageException):
- _ = cov.config["run:xyzzy"]
+ _ = cov.get_option("run:xyzzy")
with self.assertRaises(CoverageException):
- _ = cov.config["xyzzy:foo"]
+ _ = cov.get_option("xyzzy:foo")
def test_tweak_plugin_options(self):
# Plugin options have a more flexible syntax.
- cov = coverage.coverage()
- cov.config["run:plugins"] = ["fooey.plugin", "xyzzy.coverage.plugin"]
- cov.config["fooey.plugin:xyzzy"] = 17
- cov.config["xyzzy.coverage.plugin:plugh"] = ["a", "b"]
+ cov = coverage.Coverage()
+ cov.set_option("run:plugins", ["fooey.plugin", "xyzzy.coverage.plugin"])
+ cov.set_option("fooey.plugin:xyzzy", 17)
+ cov.set_option("xyzzy.coverage.plugin:plugh", ["a", "b"])
with self.assertRaises(CoverageException):
- cov.config["no_such.plugin:foo"] = 23
+ cov.set_option("no_such.plugin:foo", 23)
- self.assertEqual(cov.config["fooey.plugin:xyzzy"], 17)
- self.assertEqual(cov.config["xyzzy.coverage.plugin:plugh"], ["a", "b"])
+ self.assertEqual(cov.get_option("fooey.plugin:xyzzy"), 17)
+ self.assertEqual(cov.get_option("xyzzy.coverage.plugin:plugh"), ["a", "b"])
with self.assertRaises(CoverageException):
- _ = cov.config["no_such.plugin:foo"]
+ _ = cov.get_option("no_such.plugin:foo")
+
+ def test_unknown_option(self):
+ self.make_file(".coveragerc", """\
+ [run]
+ xyzzy = 17
+ """)
+ msg = r"Unrecognized option '\[run\] xyzzy=' in config file .coveragerc"
+ with self.assertRaisesRegex(CoverageException, msg):
+ _ = coverage.Coverage()
+
+ def test_misplaced_option(self):
+ self.make_file(".coveragerc", """\
+ [report]
+ branch = True
+ """)
+ msg = r"Unrecognized option '\[report\] branch=' in config file .coveragerc"
+ with self.assertRaisesRegex(CoverageException, msg):
+ _ = coverage.Coverage()
+
+ def test_unknown_option_in_other_ini_file(self):
+ self.make_file("setup.cfg", """\
+ [coverage:run]
+ huh = what?
+ """)
+ msg = (r"Unrecognized option '\[coverage:run\] huh=' in config file setup.cfg")
+ with self.assertRaisesRegex(CoverageException, msg):
+ _ = coverage.Coverage()
class ConfigFileTest(CoverageTest):
@@ -198,11 +239,12 @@ class ConfigFileTest(CoverageTest):
branch = 1
cover_pylib = TRUE
parallel = on
- include = a/ , b/
concurrency = thread
+ source = myapp
plugins =
plugins.a_plugin
plugins.another
+ debug = callers, pids , dataio
[{section}report]
; these settings affect reporting.
@@ -261,34 +303,37 @@ class ConfigFileTest(CoverageTest):
examples/
"""
+ # Just some sample tox.ini text from the docs.
+ TOX_INI = """\
+ [tox]
+ envlist = py{26,27,33,34,35}-{c,py}tracer
+ skip_missing_interpreters = True
+
+ [testenv]
+ commands =
+ # Create tests/zipmods.zip, install the egg1 egg
+ python igor.py zip_mods install_egg
+ """
+
def assert_config_settings_are_correct(self, cov):
"""Check that `cov` has all the settings from LOTSA_SETTINGS."""
self.assertTrue(cov.config.timid)
self.assertEqual(cov.config.data_file, "something_or_other.dat")
self.assertTrue(cov.config.branch)
self.assertTrue(cov.config.cover_pylib)
+ self.assertEqual(cov.config.debug, ["callers", "pids", "dataio"])
self.assertTrue(cov.config.parallel)
- self.assertEqual(cov.config.concurrency, "thread")
+ self.assertEqual(cov.config.concurrency, ["thread"])
+ self.assertEqual(cov.config.source, ["myapp"])
- self.assertEqual(cov.get_exclude_list(),
- ["if 0:", r"pragma:?\s+no cover", "another_tab"]
- )
+ self.assertEqual(cov.get_exclude_list(), ["if 0:", r"pragma:?\s+no cover", "another_tab"])
self.assertTrue(cov.config.ignore_errors)
- self.assertEqual(cov.config.include, ["a/", "b/"])
- self.assertEqual(cov.config.omit,
- ["one", "another", "some_more", "yet_more"]
- )
+ self.assertEqual(cov.config.omit, ["one", "another", "some_more", "yet_more"])
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.assertEqual(cov.config.plugins,
- ["plugins.a_plugin", "plugins.another"]
- )
+ self.assertEqual(cov.config.partial_list, [r"pragma:?\s+no branch"])
+ self.assertEqual(cov.config.partial_always_list, ["if 0:", "while True:"])
+ self.assertEqual(cov.config.plugins, ["plugins.a_plugin", "plugins.another"])
self.assertTrue(cov.config.show_missing)
self.assertTrue(cov.config.skip_covered)
self.assertEqual(cov.config.html_dir, r"c:\tricky\dir.somewhere")
@@ -301,71 +346,108 @@ class ConfigFileTest(CoverageTest):
self.assertEqual(cov.config.paths, {
'source': ['.', '/home/ned/src/'],
'other': ['other', '/home/ned/other', 'c:\\Ned\\etc']
- })
+ })
self.assertEqual(cov.config.get_plugin_options("plugins.a_plugin"), {
'hello': 'world',
'names': 'Jane/John/Jenny',
- })
+ })
self.assertEqual(cov.config.get_plugin_options("plugins.another"), {})
def test_config_file_settings(self):
self.make_file(".coveragerc", self.LOTSA_SETTINGS.format(section=""))
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.assert_config_settings_are_correct(cov)
- def test_config_file_settings_in_setupcfg(self):
- # Configuration will be read from setup.cfg from sections prefixed with
- # "coverage:"
+ def check_config_file_settings_in_other_file(self, fname, contents):
+ """Check config will be read from another file, with prefixed sections."""
nested = self.LOTSA_SETTINGS.format(section="coverage:")
- self.make_file("setup.cfg", nested + "\n" + self.SETUP_CFG)
- cov = coverage.coverage()
+ fname = self.make_file(fname, nested + "\n" + contents)
+ cov = coverage.Coverage()
self.assert_config_settings_are_correct(cov)
- def test_config_file_settings_in_setupcfg_if_coveragerc_specified(self):
- # Configuration will be read from setup.cfg from sections prefixed with
- # "coverage:", even if the API said to read from a (non-existent)
- # .coveragerc file.
+ def test_config_file_settings_in_setupcfg(self):
+ self.check_config_file_settings_in_other_file("setup.cfg", self.SETUP_CFG)
+
+ def test_config_file_settings_in_toxini(self):
+ self.check_config_file_settings_in_other_file("tox.ini", self.TOX_INI)
+
+ def check_other_config_if_coveragerc_specified(self, fname, contents):
+ """Check that config `fname` is read if .coveragerc is missing, but specified."""
nested = self.LOTSA_SETTINGS.format(section="coverage:")
- self.make_file("setup.cfg", nested + "\n" + self.SETUP_CFG)
- cov = coverage.coverage(config_file=".coveragerc")
+ self.make_file(fname, nested + "\n" + contents)
+ cov = coverage.Coverage(config_file=".coveragerc")
self.assert_config_settings_are_correct(cov)
- def test_setupcfg_only_if_not_coveragerc(self):
+ def test_config_file_settings_in_setupcfg_if_coveragerc_specified(self):
+ self.check_other_config_if_coveragerc_specified("setup.cfg", self.SETUP_CFG)
+
+ def test_config_file_settings_in_tox_if_coveragerc_specified(self):
+ self.check_other_config_if_coveragerc_specified("tox.ini", self.TOX_INI)
+
+ def check_other_not_read_if_coveragerc(self, fname):
+ """Check config `fname` is not read if .coveragerc exists."""
self.make_file(".coveragerc", """\
[run]
include = foo
""")
- self.make_file("setup.cfg", """\
+ self.make_file(fname, """\
[coverage:run]
omit = bar
branch = true
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.assertEqual(cov.config.include, ["foo"])
self.assertEqual(cov.config.omit, None)
self.assertEqual(cov.config.branch, False)
- def test_setupcfg_only_if_prefixed(self):
- self.make_file("setup.cfg", """\
+ def test_setupcfg_only_if_not_coveragerc(self):
+ self.check_other_not_read_if_coveragerc("setup.cfg")
+
+ def test_toxini_only_if_not_coveragerc(self):
+ self.check_other_not_read_if_coveragerc("tox.ini")
+
+ def check_other_config_need_prefixes(self, fname):
+ """Check that `fname` sections won't be read if un-prefixed."""
+ self.make_file(fname, """\
[run]
omit = bar
branch = true
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.assertEqual(cov.config.omit, None)
self.assertEqual(cov.config.branch, False)
+ def test_setupcfg_only_if_prefixed(self):
+ self.check_other_config_need_prefixes("setup.cfg")
+
+ def test_toxini_only_if_prefixed(self):
+ self.check_other_config_need_prefixes("tox.ini")
+
+ def test_tox_ini_even_if_setup_cfg(self):
+ # There's a setup.cfg, but no coverage settings in it, so tox.ini
+ # is read.
+ nested = self.LOTSA_SETTINGS.format(section="coverage:")
+ self.make_file("tox.ini", self.TOX_INI + "\n" + nested)
+ self.make_file("setup.cfg", self.SETUP_CFG)
+ cov = coverage.Coverage()
+ self.assert_config_settings_are_correct(cov)
+
def test_non_ascii(self):
self.make_file(".coveragerc", """\
+ [report]
+ exclude_lines =
+ first
+ ✘${TOX_ENVNAME}
+ third
[html]
title = tabblo & «ταБЬℓσ» # numbers
""")
- cov = coverage.coverage()
+ self.set_environ("TOX_ENVNAME", "weirdo")
+ cov = coverage.Coverage()
- self.assertEqual(cov.config.html_title,
- "tabblo & «ταБЬℓσ» # numbers"
- )
+ self.assertEqual(cov.config.exclude_list, ["first", "✘weirdo", "third"])
+ self.assertEqual(cov.config.html_title, "tabblo & «ταБЬℓσ» # numbers")
def test_unreadable_config(self):
# If a config file is explicitly specified, then it is an error for it
@@ -373,14 +455,14 @@ class ConfigFileTest(CoverageTest):
bad_files = [
"nosuchfile.txt",
".",
- ]
+ ]
for bad_file in bad_files:
msg = "Couldn't read %r as a config file" % bad_file
with self.assertRaisesRegex(CoverageException, msg):
- coverage.coverage(config_file=bad_file)
+ coverage.Coverage(config_file=bad_file)
def test_nocoveragerc_file_when_specified(self):
- cov = coverage.coverage(config_file=".coveragerc")
+ cov = coverage.Coverage(config_file=".coveragerc")
self.assertFalse(cov.config.timid)
self.assertFalse(cov.config.branch)
self.assertEqual(cov.config.data_file, ".coverage")
diff --git a/tests/test_coverage.py b/tests/test_coverage.py
index 3de381f1..a52aced3 100644
--- a/tests/test_coverage.py
+++ b/tests/test_coverage.py
@@ -1,5 +1,8 @@
-"""Tests for Coverage."""
-# http://nedbatchelder.com/code/coverage
+# coding: utf-8
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Tests for coverage.py."""
import coverage
from coverage import env
@@ -98,7 +101,7 @@ class BasicCoverageTest(CoverageTest):
# Nothing here
d = 6
""",
- [1,2,4,6], report="4 0 100%")
+ [1,2,4,6], report="4 0 0 0 100%")
def test_indentation_wackiness(self):
# Partial final lines are OK.
@@ -106,7 +109,7 @@ class BasicCoverageTest(CoverageTest):
import sys
if not sys.path:
a = 1
- """,
+ """, # indented last line
[1,2,3], "3")
def test_multiline_initializer(self):
@@ -195,6 +198,21 @@ class SimpleStatementTest(CoverageTest):
""",
[1,2,3], "")
+ def test_more_assignments(self):
+ self.check_coverage("""\
+ x = []
+ d = {}
+ d[
+ 4 + len(x)
+ + 5
+ ] = \\
+ d[
+ 8 ** 2
+ ] = \\
+ 9
+ """,
+ [1, 2, 3], "")
+
def test_attribute_assignment(self):
# Attribute assignment
self.check_coverage("""\
@@ -308,7 +326,7 @@ class SimpleStatementTest(CoverageTest):
def test_print(self):
if env.PY3: # Print statement is gone in Py3k.
- self.skip("No more print statement in Python 3.")
+ self.skipTest("No more print statement in Python 3.")
self.check_coverage("""\
print "hello, world!"
@@ -400,35 +418,35 @@ class SimpleStatementTest(CoverageTest):
""",
[1,2,3,4,5], "4")
- if 0: # expected failure
+ def test_strange_unexecuted_continue(self):
# Peephole optimization of jumps to jumps can mean that some statements
# never hit the line tracer. The behavior is different in different
# versions of Python, so don't run this test:
- def test_strange_unexecuted_continue(self):
- self.check_coverage("""\
- a = b = c = 0
- for n in range(100):
- if n % 2:
- if n % 4:
- a += 1
- continue # <-- This line may not be hit.
- else:
- b += 1
- c += 1
- assert a == 50 and b == 50 and c == 50
-
- a = b = c = 0
- for n in range(100):
- if n % 2:
- if n % 3:
- a += 1
- continue # <-- This line is always hit.
- else:
- b += 1
- c += 1
- assert a == 33 and b == 50 and c == 50
- """,
- [1,2,3,4,5,6,8,9,10, 12,13,14,15,16,17,19,20,21], "")
+ self.skipTest("Expected failure: peephole optimization of jumps to jumps")
+ self.check_coverage("""\
+ a = b = c = 0
+ for n in range(100):
+ if n % 2:
+ if n % 4:
+ a += 1
+ continue # <-- This line may not be hit.
+ else:
+ b += 1
+ c += 1
+ assert a == 50 and b == 50 and c == 50
+
+ a = b = c = 0
+ for n in range(100):
+ if n % 2:
+ if n % 3:
+ a += 1
+ continue # <-- This line is always hit.
+ else:
+ b += 1
+ c += 1
+ assert a == 33 and b == 50 and c == 50
+ """,
+ [1,2,3,4,5,6,8,9,10, 12,13,14,15,16,17,19,20,21], "")
def test_import(self):
self.check_coverage("""\
@@ -547,6 +565,15 @@ class SimpleStatementTest(CoverageTest):
""",
([1,3,6,7], [1,3,5,6,7], [1,3,4,5,6,7]), "")
+ def test_nonascii(self):
+ self.check_coverage("""\
+ # coding: utf8
+ a = 2
+ b = 3
+ """,
+ [2, 3]
+ )
+
class CompoundStatementTest(CoverageTest):
"""Testing coverage of multi-line compound statements."""
@@ -615,7 +642,8 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert x == 3
""",
- [1,2,3,4,5,7,8], "4-7", report="7 3 57% 4-7")
+ [1,2,3,4,5,7,8], "4-7", report="7 3 4 1 45% 4-7, 2->4",
+ )
self.check_coverage("""\
a = 1; b = 2; c = 3;
if a != 1:
@@ -626,7 +654,8 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert y == 5
""",
- [1,2,3,4,5,7,8], "3, 7", report="7 2 71% 3, 7")
+ [1,2,3,4,5,7,8], "3, 7", report="7 2 4 2 64% 3, 7, 2->3, 4->7",
+ )
self.check_coverage("""\
a = 1; b = 2; c = 3;
if a != 1:
@@ -637,7 +666,8 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert z == 7
""",
- [1,2,3,4,5,7,8], "3, 5", report="7 2 71% 3, 5")
+ [1,2,3,4,5,7,8], "3, 5", report="7 2 4 2 64% 3, 5, 2->3, 4->5",
+ )
def test_elif_no_else(self):
self.check_coverage("""\
@@ -648,7 +678,8 @@ class CompoundStatementTest(CoverageTest):
y = 5
assert x == 3
""",
- [1,2,3,4,5,6], "4-5", report="6 2 67% 4-5")
+ [1,2,3,4,5,6], "4-5", report="6 2 4 1 50% 4-5, 2->4",
+ )
self.check_coverage("""\
a = 1; b = 2; c = 3;
if a != 1:
@@ -657,7 +688,8 @@ class CompoundStatementTest(CoverageTest):
y = 5
assert y == 5
""",
- [1,2,3,4,5,6], "3", report="6 1 83% 3")
+ [1,2,3,4,5,6], "3", report="6 1 4 2 70% 3, 2->3, 4->6",
+ )
def test_elif_bizarre(self):
self.check_coverage("""\
@@ -1005,7 +1037,10 @@ class CompoundStatementTest(CoverageTest):
a = 123
assert a == 123
""",
- [1,2,3,4,5,7,8], "4-5")
+ [1,2,3,4,5,7,8], "4-5",
+ arcz=".1 12 23 45 58 37 78 8.",
+ arcz_missing="45 58",
+ )
self.check_coverage("""\
a = 0
try:
@@ -1017,7 +1052,10 @@ class CompoundStatementTest(CoverageTest):
a = 123
assert a == 99
""",
- [1,2,3,4,5,6,8,9], "8")
+ [1,2,3,4,5,6,8,9], "8",
+ arcz=".1 12 23 34 45 56 69 89 9.",
+ arcz_missing="89",
+ )
def test_try_finally(self):
self.check_coverage("""\
@@ -1102,7 +1140,9 @@ class CompoundStatementTest(CoverageTest):
x = theClass().foo()
assert x == 1
""",
- [2,6,8,10,11,13,14], "")
+ [2, 6, 8, 10, 11, 13, 14], "",
+ arcz="-22 2D DE E-2 23 36 6A A-2 -68 8-6 -AB B-A",
+ )
class ExcludeTest(CoverageTest):
@@ -1126,7 +1166,7 @@ class ExcludeTest(CoverageTest):
self.check_coverage("""\
a = 1; b = 2
- if 0:
+ if len([]):
a = 4 # -cc
""",
[1,3], "", excludes=['-cc'])
@@ -1147,19 +1187,19 @@ class ExcludeTest(CoverageTest):
self.check_coverage("""\
a = 1; b = 2
- if 0:
+ if len([]): # not-here
a = 4
b = 5
c = 6
assert a == 1 and b == 2
""",
- [1,7], "", excludes=['if 0:'])
+ [1,7], "", excludes=['not-here'])
def test_excluding_if_but_not_else_suite(self):
self.check_coverage("""\
a = 1; b = 2
- if 0:
+ if len([]): # not-here
a = 4
b = 5
c = 6
@@ -1168,7 +1208,7 @@ class ExcludeTest(CoverageTest):
b = 9
assert a == 8 and b == 9
""",
- [1,8,9,10], "", excludes=['if 0:'])
+ [1,8,9,10], "", excludes=['not-here'])
def test_excluding_else_suite(self):
self.check_coverage("""\
@@ -1227,7 +1267,7 @@ class ExcludeTest(CoverageTest):
self.check_coverage("""\
def foo():
a = 2
- if 0: x = 3 # no cover
+ if len([]): x = 3 # no cover
b = 4
foo()
@@ -1363,7 +1403,10 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 123
""",
- [1,2,3,7,8], "", excludes=['#pragma: NO COVER'])
+ [1,2,3,7,8], "", excludes=['#pragma: NO COVER'],
+ arcz=".1 12 23 37 45 58 78 8.",
+ arcz_missing="45 58",
+ )
self.check_coverage("""\
a = 0
try:
@@ -1375,7 +1418,10 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 99
""",
- [1,2,3,4,5,6,9], "", excludes=['#pragma: NO COVER'])
+ [1,2,3,4,5,6,9], "", excludes=['#pragma: NO COVER'],
+ arcz=".1 12 23 34 45 56 69 89 9.",
+ arcz_missing="89",
+ )
def test_excluding_try_except_pass(self):
self.check_coverage("""\
@@ -1409,7 +1455,10 @@ class ExcludeTest(CoverageTest):
a = 123
assert a == 123
""",
- [1,2,3,7,8], "", excludes=['#pragma: NO COVER'])
+ [1,2,3,7,8], "", excludes=['#pragma: NO COVER'],
+ arcz=".1 12 23 37 45 58 78 8.",
+ arcz_missing="45 58",
+ )
self.check_coverage("""\
a = 0
try:
@@ -1421,10 +1470,13 @@ class ExcludeTest(CoverageTest):
x = 2
assert a == 99
""",
- [1,2,3,4,5,6,9], "", excludes=['#pragma: NO COVER'])
+ [1,2,3,4,5,6,9], "", excludes=['#pragma: NO COVER'],
+ arcz=".1 12 23 34 45 56 69 89 9.",
+ arcz_missing="89",
+ )
def test_excluding_if_pass(self):
- # From a comment on the coverage page by Michael McNeil Forbes:
+ # From a comment on the coverage.py page by Michael McNeil Forbes:
self.check_coverage("""\
def f():
if False: # pragma: no cover
@@ -1476,6 +1528,33 @@ class ExcludeTest(CoverageTest):
""",
[8,9], "", excludes=['#pragma: NO COVER'])
+ def test_excludes_non_ascii(self):
+ self.check_coverage("""\
+ # coding: utf-8
+ a = 1; b = 2
+
+ if len([]):
+ a = 5 # ✘cover
+ """,
+ [2, 4], "", excludes=['✘cover']
+ )
+
+ def test_formfeed(self):
+ # https://bitbucket.org/ned/coveragepy/issues/461/multiline-asserts-need-too-many-pragma
+ self.check_coverage("""\
+ x = 1
+ assert len([]) == 0, (
+ "This won't happen %s" % ("hello",)
+ )
+ \f
+ x = 6
+ assert len([]) == 0, (
+ "This won't happen %s" % ("hello",)
+ )
+ """,
+ [1, 6], "", excludes=['assert'],
+ )
+
class Py24Test(CoverageTest):
"""Tests of new syntax in Python 2.4."""
@@ -1584,7 +1663,9 @@ class Py25Test(CoverageTest):
b = 2
assert a == 1 and b == 2
""",
- [1,2,3,4,5,7,8], "4-5")
+ [1,2,3,4,5,7,8], "4-5",
+ arcz=".1 12 23 37 45 57 78 8.", arcz_missing="45 57",
+ )
self.check_coverage("""\
a = 0; b = 0
try:
@@ -1596,7 +1677,9 @@ class Py25Test(CoverageTest):
b = 2
assert a == 99 and b == 2
""",
- [1,2,3,4,5,6,8,9], "")
+ [1,2,3,4,5,6,8,9], "",
+ arcz=".1 12 23 34 45 56 68 89 9.",
+ )
self.check_coverage("""\
a = 0; b = 0
try:
@@ -1610,7 +1693,9 @@ class Py25Test(CoverageTest):
b = 2
assert a == 123 and b == 2
""",
- [1,2,3,4,5,6,7,8,10,11], "6")
+ [1,2,3,4,5,6,7,8,10,11], "6",
+ arcz=".1 12 23 34 45 56 57 78 6A 8A AB B.", arcz_missing="56 6A",
+ )
self.check_coverage("""\
a = 0; b = 0
try:
@@ -1626,7 +1711,10 @@ class Py25Test(CoverageTest):
b = 2
assert a == 17 and b == 2
""",
- [1,2,3,4,5,6,7,8,9,10,12,13], "6, 9-10")
+ [1,2,3,4,5,6,7,8,9,10,12,13], "6, 9-10",
+ arcz=".1 12 23 34 45 56 6C 57 78 8C 79 9A AC CD D.",
+ arcz_missing="56 6C 79 9A AC",
+ )
self.check_coverage("""\
a = 0; b = 0
try:
@@ -1639,7 +1727,10 @@ class Py25Test(CoverageTest):
b = 2
assert a == 123 and b == 2
""",
- [1,2,3,4,5,7,9,10], "4-5")
+ [1,2,3,4,5,7,9,10], "4-5",
+ arcz=".1 12 23 37 45 59 79 9A A.",
+ arcz_missing="45 59",
+ )
self.check_coverage("""\
a = 0; b = 0
try:
@@ -1653,7 +1744,10 @@ class Py25Test(CoverageTest):
b = 2
assert a == 99 and b == 2
""",
- [1,2,3,4,5,6,8,10,11], "8")
+ [1,2,3,4,5,6,8,10,11], "8",
+ arcz=".1 12 23 34 45 56 6A 8A AB B.",
+ arcz_missing="8A",
+ )
class ModuleTest(CoverageTest):
@@ -1663,25 +1757,30 @@ class ModuleTest(CoverageTest):
def test_not_singleton(self):
# You *can* create another coverage object.
- coverage.coverage()
- coverage.coverage()
+ coverage.Coverage()
+ coverage.Coverage()
+
+ def test_old_name_and_new_name(self):
+ self.assertIs(coverage.coverage, coverage.Coverage)
class ReportingTest(CoverageTest):
"""Tests of some reporting behavior."""
- # We don't make any temp files, but we need an empty directory to run the
- # tests in.
+ # We don't make any temporary files, but we need an empty directory to run
+ # the tests in.
no_files_in_temp_dir = True
def test_no_data_to_report_on_annotate(self):
- # Reporting with no data produces a nice message and no output dir.
+ # Reporting with no data produces a nice message and no output
+ # directory.
with self.assertRaisesRegex(CoverageException, "No data to report."):
self.command_line("annotate -d 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.
+ # Reporting with no data produces a nice message and no output
+ # directory.
with self.assertRaisesRegex(CoverageException, "No data to report."):
self.command_line("html -d htmlcov")
self.assert_doesnt_exist("htmlcov")
diff --git a/tests/test_data.py b/tests/test_data.py
index a53330f1..52702e97 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -1,16 +1,25 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for coverage.data"""
+import glob
+import json
import os
import os.path
+import re
+
+import mock
-from coverage.backward import pickle
-from coverage.data import CoverageData, CoverageDataFiles
+from coverage.backward import StringIO
+from coverage.data import CoverageData, CoverageDataFiles, debug_main, canonicalize_json_data
from coverage.files import PathAliases, canonical_filename
+from coverage.misc import CoverageException
-from tests.coveragetest import CoverageTest
+from tests.coveragetest import CoverageTest, DebugControlString
-DATA_1 = {
+LINES_1 = {
'a.py': {1: None, 2: None},
'b.py': {3: None},
}
@@ -19,14 +28,14 @@ MEASURED_FILES_1 = ['a.py', 'b.py']
A_PY_LINES_1 = [1, 2]
B_PY_LINES_1 = [3]
-DATA_2 = {
+LINES_2 = {
'a.py': {1: None, 5: None},
'c.py': {17: None},
}
SUMMARY_1_2 = {'a.py': 3, 'b.py': 1, 'c.py': 1}
MEASURED_FILES_1_2 = ['a.py', 'b.py', 'c.py']
-ARC_DATA_3 = {
+ARCS_3 = {
'x.py': {
(-1, 1): None,
(1, 2): None,
@@ -41,128 +50,672 @@ ARC_DATA_3 = {
}
X_PY_ARCS_3 = [(-1, 1), (1, 2), (2, 3), (3, -1)]
Y_PY_ARCS_3 = [(-1, 17), (17, 23), (23, -1)]
+SUMMARY_3 = {'x.py': 3, 'y.py': 2}
+MEASURED_FILES_3 = ['x.py', 'y.py']
+X_PY_LINES_3 = [1, 2, 3]
+Y_PY_LINES_3 = [17, 23]
+
+ARCS_4 = {
+ 'x.py': {
+ (-1, 2): None,
+ (2, 5): None,
+ (5, -1): None,
+ },
+ 'z.py': {
+ (-1, 1000): None,
+ (1000, -1): None,
+ },
+}
+SUMMARY_3_4 = {'x.py': 4, 'y.py': 2, 'z.py': 1}
+MEASURED_FILES_3_4 = ['x.py', 'y.py', 'z.py']
class DataTestHelpers(CoverageTest):
"""Test helpers for data tests."""
- def setUp(self):
- self.data_files = CoverageDataFiles()
- super(DataTestHelpers, self).setUp()
-
- def assert_summary(self, covdata, summary, fullpath=False):
- """Check that the summary of `covdata` is `summary`."""
- self.assertEqual(covdata.summary(fullpath), summary)
+ def assert_line_counts(self, covdata, line_counts, fullpath=False):
+ """Check that the line_counts of `covdata` is `line_counts`."""
+ self.assertEqual(covdata.line_counts(fullpath), line_counts)
def assert_measured_files(self, covdata, measured):
"""Check that `covdata`'s measured files are `measured`."""
self.assertCountEqual(covdata.measured_files(), measured)
+ def assert_lines1_data(self, covdata):
+ """Check that `covdata` has the data from LINES1."""
+ self.assert_line_counts(covdata, SUMMARY_1)
+ self.assert_measured_files(covdata, MEASURED_FILES_1)
+ self.assertCountEqual(covdata.lines("a.py"), A_PY_LINES_1)
+ self.assertEqual(covdata.run_infos(), [])
+ self.assertFalse(covdata.has_arcs())
+
+ def assert_arcs3_data(self, covdata):
+ """Check that `covdata` has the data from ARCS3."""
+ self.assert_line_counts(covdata, SUMMARY_3)
+ self.assert_measured_files(covdata, MEASURED_FILES_3)
+ self.assertCountEqual(covdata.lines("x.py"), X_PY_LINES_3)
+ self.assertCountEqual(covdata.arcs("x.py"), X_PY_ARCS_3)
+ self.assertCountEqual(covdata.lines("y.py"), Y_PY_LINES_3)
+ self.assertCountEqual(covdata.arcs("y.py"), Y_PY_ARCS_3)
+ self.assertTrue(covdata.has_arcs())
+ self.assertEqual(covdata.run_infos(), [])
+
-class DataTest(DataTestHelpers, CoverageTest):
- """Test cases for coverage.data."""
+class CoverageDataTest(DataTestHelpers, CoverageTest):
+ """Test cases for CoverageData."""
run_in_temp_dir = False
- def test_reading_empty(self):
- # Make sure there is no .coverage data file here.
- if os.path.exists(".coverage"):
- os.remove(".coverage")
+ def test_empty_data_is_false(self):
covdata = CoverageData()
- self.data_files.read(covdata)
- self.assert_summary(covdata, {})
+ self.assertFalse(covdata)
- def test_adding_data(self):
+ def test_line_data_is_true(self):
covdata = CoverageData()
- covdata.add_lines(DATA_1)
- self.assert_summary(covdata, SUMMARY_1)
- self.assert_measured_files(covdata, MEASURED_FILES_1)
+ covdata.add_lines(LINES_1)
+ self.assertTrue(covdata)
+
+ def test_arc_data_is_true(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ self.assertTrue(covdata)
+
+ def test_empty_line_data_is_false(self):
+ covdata = CoverageData()
+ covdata.add_lines({})
+ self.assertFalse(covdata)
+
+ def test_empty_arc_data_is_false(self):
+ covdata = CoverageData()
+ covdata.add_arcs({})
+ self.assertFalse(covdata)
+
+ def test_adding_lines(self):
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ self.assert_lines1_data(covdata)
+
+ def test_adding_arcs(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ self.assert_arcs3_data(covdata)
+
+ def test_ok_to_add_lines_twice(self):
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ covdata.add_lines(LINES_2)
+ self.assert_line_counts(covdata, SUMMARY_1_2)
+ self.assert_measured_files(covdata, MEASURED_FILES_1_2)
+
+ def test_ok_to_add_arcs_twice(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ covdata.add_arcs(ARCS_4)
+ self.assert_line_counts(covdata, SUMMARY_3_4)
+ self.assert_measured_files(covdata, MEASURED_FILES_3_4)
+
+ def test_cant_add_arcs_with_lines(self):
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ with self.assertRaisesRegex(CoverageException, "Can't add arcs to existing line data"):
+ covdata.add_arcs(ARCS_3)
+
+ def test_cant_add_lines_with_arcs(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ with self.assertRaisesRegex(CoverageException, "Can't add lines to existing arc data"):
+ covdata.add_lines(LINES_1)
+
+ def test_touch_file_with_lines(self):
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ covdata.touch_file('zzz.py')
+ self.assert_measured_files(covdata, MEASURED_FILES_1 + ['zzz.py'])
+
+ def test_touch_file_with_arcs(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ covdata.touch_file('zzz.py')
+ self.assert_measured_files(covdata, MEASURED_FILES_3 + ['zzz.py'])
+
+ def test_no_lines_vs_unmeasured_file(self):
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ covdata.touch_file('zzz.py')
+ self.assertEqual(covdata.lines('zzz.py'), [])
+ self.assertIsNone(covdata.lines('no_such_file.py'))
+
+ def test_run_info(self):
+ covdata = CoverageData()
+ self.assertEqual(covdata.run_infos(), [])
+ covdata.add_run_info(hello="there")
+ self.assertEqual(covdata.run_infos(), [{"hello": "there"}])
+ covdata.add_run_info(count=17)
+ self.assertEqual(covdata.run_infos(), [{"hello": "there", "count": 17}])
+
+ def test_no_arcs_vs_unmeasured_file(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ covdata.touch_file('zzz.py')
+ self.assertEqual(covdata.lines('zzz.py'), [])
+ self.assertIsNone(covdata.lines('no_such_file.py'))
+ self.assertEqual(covdata.arcs('zzz.py'), [])
+ self.assertIsNone(covdata.arcs('no_such_file.py'))
+
+ def test_file_tracer_name(self):
+ covdata = CoverageData()
+ covdata.add_lines({
+ "p1.foo": dict.fromkeys([1, 2, 3]),
+ "p2.html": dict.fromkeys([10, 11, 12]),
+ "main.py": dict.fromkeys([20]),
+ })
+ covdata.add_file_tracers({"p1.foo": "p1.plugin", "p2.html": "p2.plugin"})
+ self.assertEqual(covdata.file_tracer("p1.foo"), "p1.plugin")
+ self.assertEqual(covdata.file_tracer("main.py"), "")
+ self.assertIsNone(covdata.file_tracer("p3.not_here"))
+
+ def test_cant_file_tracer_unmeasured_files(self):
+ covdata = CoverageData()
+ msg = "Can't add file tracer data for unmeasured file 'p1.foo'"
+ with self.assertRaisesRegex(CoverageException, msg):
+ covdata.add_file_tracers({"p1.foo": "p1.plugin"})
+
+ covdata.add_lines({"p2.html": dict.fromkeys([10, 11, 12])})
+ with self.assertRaisesRegex(CoverageException, msg):
+ covdata.add_file_tracers({"p1.foo": "p1.plugin"})
- def test_touch_file(self):
+ def test_cant_change_file_tracer_name(self):
covdata = CoverageData()
- covdata.add_lines(DATA_1)
- covdata.touch_file('x.py')
- self.assert_measured_files(covdata, MEASURED_FILES_1 + ['x.py'])
+ covdata.add_lines({"p1.foo": dict.fromkeys([1, 2, 3])})
+ covdata.add_file_tracers({"p1.foo": "p1.plugin"})
+
+ msg = "Conflicting file tracer name for 'p1.foo': 'p1.plugin' vs 'p1.plugin.foo'"
+ with self.assertRaisesRegex(CoverageException, msg):
+ covdata.add_file_tracers({"p1.foo": "p1.plugin.foo"})
+
+ def test_update_lines(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines(LINES_1)
+
+ covdata2 = CoverageData()
+ covdata2.add_lines(LINES_2)
+
+ covdata3 = CoverageData()
+ covdata3.update(covdata1)
+ covdata3.update(covdata2)
+
+ self.assert_line_counts(covdata3, SUMMARY_1_2)
+ self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+ self.assertEqual(covdata3.run_infos(), [])
+
+ def test_update_arcs(self):
+ covdata1 = CoverageData()
+ covdata1.add_arcs(ARCS_3)
+
+ covdata2 = CoverageData()
+ covdata2.add_arcs(ARCS_4)
+
+ covdata3 = CoverageData()
+ covdata3.update(covdata1)
+ covdata3.update(covdata2)
+
+ self.assert_line_counts(covdata3, SUMMARY_3_4)
+ self.assert_measured_files(covdata3, MEASURED_FILES_3_4)
+ self.assertEqual(covdata3.run_infos(), [])
+
+ def test_update_run_info(self):
+ covdata1 = CoverageData()
+ covdata1.add_arcs(ARCS_3)
+ covdata1.add_run_info(hello="there", count=17)
+
+ covdata2 = CoverageData()
+ covdata2.add_arcs(ARCS_4)
+ covdata2.add_run_info(hello="goodbye", count=23)
+
+ covdata3 = CoverageData()
+ covdata3.update(covdata1)
+ covdata3.update(covdata2)
+
+ self.assertEqual(covdata3.run_infos(), [
+ {'hello': 'there', 'count': 17},
+ {'hello': 'goodbye', 'count': 23},
+ ])
+
+ def test_update_cant_mix_lines_and_arcs(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines(LINES_1)
+
+ covdata2 = CoverageData()
+ covdata2.add_arcs(ARCS_3)
+
+ with self.assertRaisesRegex(CoverageException, "Can't combine arc data with line data"):
+ covdata1.update(covdata2)
+
+ with self.assertRaisesRegex(CoverageException, "Can't combine line data with arc data"):
+ covdata2.update(covdata1)
+
+ def test_update_file_tracers(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines({
+ "p1.html": dict.fromkeys([1, 2, 3, 4]),
+ "p2.html": dict.fromkeys([5, 6, 7]),
+ "main.py": dict.fromkeys([10, 11, 12]),
+ })
+ covdata1.add_file_tracers({
+ "p1.html": "html.plugin",
+ "p2.html": "html.plugin2",
+ })
+
+ covdata2 = CoverageData()
+ covdata2.add_lines({
+ "p1.html": dict.fromkeys([3, 4, 5, 6]),
+ "p2.html": dict.fromkeys([7, 8, 9]),
+ "p3.foo": dict.fromkeys([1000, 1001]),
+ "main.py": dict.fromkeys([10, 11, 12]),
+ })
+ covdata2.add_file_tracers({
+ "p1.html": "html.plugin",
+ "p2.html": "html.plugin2",
+ "p3.foo": "foo_plugin",
+ })
+
+ covdata3 = CoverageData()
+ covdata3.update(covdata1)
+ covdata3.update(covdata2)
+ self.assertEqual(covdata3.file_tracer("p1.html"), "html.plugin")
+ self.assertEqual(covdata3.file_tracer("p2.html"), "html.plugin2")
+ self.assertEqual(covdata3.file_tracer("p3.foo"), "foo_plugin")
+ self.assertEqual(covdata3.file_tracer("main.py"), "")
+
+ def test_update_conflicting_file_tracers(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+ covdata1.add_file_tracers({"p1.html": "html.plugin"})
+
+ covdata2 = CoverageData()
+ covdata2.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+ covdata2.add_file_tracers({"p1.html": "html.other_plugin"})
+
+ msg = "Conflicting file tracer name for 'p1.html': 'html.plugin' vs 'html.other_plugin'"
+ with self.assertRaisesRegex(CoverageException, msg):
+ covdata1.update(covdata2)
+
+ msg = "Conflicting file tracer name for 'p1.html': 'html.other_plugin' vs 'html.plugin'"
+ with self.assertRaisesRegex(CoverageException, msg):
+ covdata2.update(covdata1)
+
+ def test_update_file_tracer_vs_no_file_tracer(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+ covdata1.add_file_tracers({"p1.html": "html.plugin"})
+
+ covdata2 = CoverageData()
+ covdata2.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+
+ msg = "Conflicting file tracer name for 'p1.html': 'html.plugin' vs ''"
+ with self.assertRaisesRegex(CoverageException, msg):
+ covdata1.update(covdata2)
+
+ msg = "Conflicting file tracer name for 'p1.html': '' vs 'html.plugin'"
+ with self.assertRaisesRegex(CoverageException, msg):
+ covdata2.update(covdata1)
+
+ def test_add_to_hash_with_lines(self):
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ hasher = mock.Mock()
+ covdata.add_to_hash("a.py", hasher)
+ self.assertEqual(hasher.method_calls, [
+ mock.call.update([1, 2]), # lines
+ mock.call.update(""), # file_tracer name
+ ])
+
+ def test_add_to_hash_with_arcs(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ covdata.add_file_tracers({"y.py": "hologram_plugin"})
+ hasher = mock.Mock()
+ covdata.add_to_hash("y.py", hasher)
+ self.assertEqual(hasher.method_calls, [
+ mock.call.update([(-1, 17), (17, 23), (23, -1)]), # arcs
+ mock.call.update("hologram_plugin"), # file_tracer name
+ ])
+
+ def test_add_to_lines_hash_with_missing_file(self):
+ # https://bitbucket.org/ned/coveragepy/issues/403
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ hasher = mock.Mock()
+ covdata.add_to_hash("missing.py", hasher)
+ self.assertEqual(hasher.method_calls, [
+ mock.call.update([]),
+ mock.call.update(None),
+ ])
+
+ def test_add_to_arcs_hash_with_missing_file(self):
+ # https://bitbucket.org/ned/coveragepy/issues/403
+ covdata = CoverageData()
+ covdata.add_arcs(ARCS_3)
+ covdata.add_file_tracers({"y.py": "hologram_plugin"})
+ hasher = mock.Mock()
+ covdata.add_to_hash("missing.py", hasher)
+ self.assertEqual(hasher.method_calls, [
+ mock.call.update([]),
+ mock.call.update(None),
+ ])
+
+ def test_empty_lines_are_still_lines(self):
+ covdata = CoverageData()
+ covdata.add_lines({})
+ covdata.touch_file("abc.py")
+ self.assertFalse(covdata.has_arcs())
+
+ def test_empty_arcs_are_still_arcs(self):
+ covdata = CoverageData()
+ covdata.add_arcs({})
+ covdata.touch_file("abc.py")
+ self.assertTrue(covdata.has_arcs())
+
+ def test_read_and_write_are_opposites(self):
+ covdata1 = CoverageData()
+ covdata1.add_arcs(ARCS_3)
+ stringio = StringIO()
+ covdata1.write_fileobj(stringio)
+
+ stringio.seek(0)
+ covdata2 = CoverageData()
+ covdata2.read_fileobj(stringio)
+ self.assert_arcs3_data(covdata2)
+
+
+class CoverageDataTestInTempDir(DataTestHelpers, CoverageTest):
+ """Tests of CoverageData that need a temporary directory to make files."""
+
+ def test_read_write_lines(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines(LINES_1)
+ covdata1.write_file("lines.dat")
+
+ covdata2 = CoverageData()
+ covdata2.read_file("lines.dat")
+ self.assert_lines1_data(covdata2)
+
+ def test_read_write_arcs(self):
+ covdata1 = CoverageData()
+ covdata1.add_arcs(ARCS_3)
+ covdata1.write_file("arcs.dat")
+
+ covdata2 = CoverageData()
+ covdata2.read_file("arcs.dat")
+ self.assert_arcs3_data(covdata2)
+
+ def test_read_errors(self):
+ covdata = CoverageData()
+
+ msg = r"Couldn't read data from '{0}': \S+"
+ self.make_file("xyzzy.dat", "xyzzy")
+ with self.assertRaisesRegex(CoverageException, msg.format("xyzzy.dat")):
+ covdata.read_file("xyzzy.dat")
+
+ self.make_file("empty.dat", "")
+ with self.assertRaisesRegex(CoverageException, msg.format("empty.dat")):
+ covdata.read_file("empty.dat")
+
+ with self.assertRaisesRegex(CoverageException, msg.format("nonexistent.dat")):
+ covdata.read_file("nonexistent.dat")
+
+ self.make_file("misleading.dat", CoverageData._GO_AWAY + " this isn't JSON")
+ with self.assertRaisesRegex(CoverageException, msg.format("misleading.dat")):
+ covdata.read_file("misleading.dat")
+
+ # After all that, no data should be in our CoverageData.
+ self.assertFalse(covdata)
+
+ def test_debug_main(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines(LINES_1)
+ covdata1.write_file(".coverage")
+ debug_main([])
+
+ covdata2 = CoverageData()
+ covdata2.add_arcs(ARCS_3)
+ covdata2.add_file_tracers({"y.py": "magic_plugin"})
+ covdata2.add_run_info(version="v3.14", chunks=["z", "a"])
+ covdata2.write_file("arcs.dat")
+
+ covdata3 = CoverageData()
+ covdata3.write_file("empty.dat")
+ debug_main(["arcs.dat", "empty.dat"])
+
+ expected = {
+ ".coverage": {
+ "lines": {
+ "a.py": [1, 2],
+ "b.py": [3],
+ },
+ },
+ "arcs.dat": {
+ "arcs": {
+ "x.py": [[-1, 1], [1, 2], [2, 3], [3, -1]],
+ "y.py": [[-1, 17], [17, 23], [23, -1]],
+ },
+ "file_tracers": {"y.py": "magic_plugin"},
+ "runs": [
+ {
+ "chunks": ["z", "a"],
+ "version": "v3.14",
+ },
+ ],
+ },
+ "empty.dat": {},
+ }
+ pieces = re.split(r"(?m)-+ ([\w.]+) -+$", self.stdout())
+ for name, json_out in zip(pieces[1::2], pieces[2::2]):
+ json_got = json.loads(json_out)
+ canonicalize_json_data(json_got)
+ self.assertEqual(expected[name], json_got)
+
+
+class CoverageDataFilesTest(DataTestHelpers, CoverageTest):
+ """Tests of CoverageDataFiles."""
+
+ no_files_in_temp_dir = True
+
+ def setUp(self):
+ super(CoverageDataFilesTest, self).setUp()
+ self.data_files = CoverageDataFiles()
+
+ def test_reading_missing(self):
+ self.assert_doesnt_exist(".coverage")
+ covdata = CoverageData()
+ self.data_files.read(covdata)
+ self.assert_line_counts(covdata, {})
def test_writing_and_reading(self):
covdata1 = CoverageData()
- covdata1.add_lines(DATA_1)
+ covdata1.add_lines(LINES_1)
self.data_files.write(covdata1)
covdata2 = CoverageData()
self.data_files.read(covdata2)
- self.assert_summary(covdata2, SUMMARY_1)
+ self.assert_line_counts(covdata2, SUMMARY_1)
+
+ def test_debug_output_with_debug_option(self):
+ # With debug option dataio, we get debug output about reading and
+ # writing files.
+ debug = DebugControlString(options=["dataio"])
+ covdata1 = CoverageData(debug=debug)
+ covdata1.add_lines(LINES_1)
+ self.data_files.write(covdata1)
+
+ covdata2 = CoverageData(debug=debug)
+ self.data_files.read(covdata2)
+ self.assert_line_counts(covdata2, SUMMARY_1)
+
+ self.assertRegex(
+ debug.get_output(),
+ r"^Writing data to '.*\.coverage'\n"
+ r"Reading data from '.*\.coverage'\n$"
+ )
+
+ def test_debug_output_without_debug_option(self):
+ # With a debug object, but not the dataio option, we don't get debug
+ # output.
+ debug = DebugControlString(options=[])
+ covdata1 = CoverageData(debug=debug)
+ covdata1.add_lines(LINES_1)
+ self.data_files.write(covdata1)
+
+ covdata2 = CoverageData(debug=debug)
+ self.data_files.read(covdata2)
+ self.assert_line_counts(covdata2, SUMMARY_1)
+
+ self.assertEqual(debug.get_output(), "")
+
+ def test_explicit_suffix(self):
+ self.assert_doesnt_exist(".coverage.SUFFIX")
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ self.data_files.write(covdata, suffix='SUFFIX')
+ self.assert_exists(".coverage.SUFFIX")
+ self.assert_doesnt_exist(".coverage")
+
+ def test_true_suffix(self):
+ self.assertEqual(glob.glob(".coverage.*"), [])
+
+ # suffix=True will make a randomly named data file.
+ covdata1 = CoverageData()
+ covdata1.add_lines(LINES_1)
+ self.data_files.write(covdata1, suffix=True)
+ self.assert_doesnt_exist(".coverage")
+ data_files1 = glob.glob(".coverage.*")
+ self.assertEqual(len(data_files1), 1)
+
+ # Another suffix=True will choose a different name.
+ covdata2 = CoverageData()
+ covdata2.add_lines(LINES_1)
+ self.data_files.write(covdata2, suffix=True)
+ self.assert_doesnt_exist(".coverage")
+ data_files2 = glob.glob(".coverage.*")
+ self.assertEqual(len(data_files2), 2)
+
+ # In addition to being different, the suffixes have the pid in them.
+ self.assertTrue(all(str(os.getpid()) in fn for fn in data_files2))
def test_combining(self):
+ self.assert_doesnt_exist(".coverage.1")
+ self.assert_doesnt_exist(".coverage.2")
+
covdata1 = CoverageData()
- covdata1.add_lines(DATA_1)
+ covdata1.add_lines(LINES_1)
self.data_files.write(covdata1, suffix='1')
+ self.assert_exists(".coverage.1")
+ self.assert_doesnt_exist(".coverage.2")
covdata2 = CoverageData()
- covdata2.add_lines(DATA_2)
+ covdata2.add_lines(LINES_2)
self.data_files.write(covdata2, suffix='2')
+ self.assert_exists(".coverage.2")
covdata3 = CoverageData()
self.data_files.combine_parallel_data(covdata3)
- self.assert_summary(covdata3, SUMMARY_1_2)
+ self.assert_line_counts(covdata3, SUMMARY_1_2)
self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+ self.assert_doesnt_exist(".coverage.1")
+ self.assert_doesnt_exist(".coverage.2")
def test_erasing(self):
covdata1 = CoverageData()
- covdata1.add_lines(DATA_1)
+ covdata1.add_lines(LINES_1)
self.data_files.write(covdata1)
covdata1.erase()
- self.assert_summary(covdata1, {})
+ self.assert_line_counts(covdata1, {})
self.data_files.erase()
covdata2 = CoverageData()
self.data_files.read(covdata2)
- self.assert_summary(covdata2, {})
+ self.assert_line_counts(covdata2, {})
+
+ def test_erasing_parallel(self):
+ self.make_file("datafile.1")
+ self.make_file("datafile.2")
+ self.make_file(".coverage")
+ data_files = CoverageDataFiles("datafile")
+ data_files.erase(parallel=True)
+ self.assert_doesnt_exist("datafile.1")
+ self.assert_doesnt_exist("datafile.2")
+ self.assert_exists(".coverage")
+
+ def read_json_data_file(self, fname):
+ """Read a JSON data file for testing the JSON directly."""
+ with open(fname, 'r') as fdata:
+ go_away = fdata.read(len(CoverageData._GO_AWAY))
+ self.assertEqual(go_away, CoverageData._GO_AWAY)
+ return json.load(fdata)
def test_file_format(self):
- # Write with CoverageData, then read the pickle explicitly.
+ # Write with CoverageData, then read the JSON explicitly.
covdata = CoverageData()
- covdata.add_lines(DATA_1)
+ covdata.add_lines(LINES_1)
self.data_files.write(covdata)
- with open(".coverage", 'rb') as fdata:
- data = pickle.load(fdata)
+ data = self.read_json_data_file(".coverage")
lines = data['lines']
self.assertCountEqual(lines.keys(), MEASURED_FILES_1)
self.assertCountEqual(lines['a.py'], A_PY_LINES_1)
self.assertCountEqual(lines['b.py'], B_PY_LINES_1)
# If not measuring branches, there's no arcs entry.
- self.assertEqual(data.get('arcs', 'not there'), 'not there')
+ self.assertNotIn('arcs', data)
+ # If no file tracers were involved, there's no file_tracers entry.
+ self.assertNotIn('file_tracers', data)
def test_file_format_with_arcs(self):
- # Write with CoverageData, then read the pickle explicitly.
+ # Write with CoverageData, then read the JSON explicitly.
covdata = CoverageData()
- covdata.add_arcs(ARC_DATA_3)
+ covdata.add_arcs(ARCS_3)
self.data_files.write(covdata)
- with open(".coverage", 'rb') as fdata:
- data = pickle.load(fdata)
+ data = self.read_json_data_file(".coverage")
- self.assertCountEqual(data['lines'].keys(), [])
+ self.assertNotIn('lines', data)
arcs = data['arcs']
- self.assertCountEqual(arcs['x.py'], X_PY_ARCS_3)
- self.assertCountEqual(arcs['y.py'], Y_PY_ARCS_3)
+ self.assertCountEqual(arcs.keys(), MEASURED_FILES_3)
+ self.assertCountEqual(arcs['x.py'], map(list, X_PY_ARCS_3))
+ self.assertCountEqual(arcs['y.py'], map(list, Y_PY_ARCS_3))
+ # If no file tracers were involved, there's no file_tracers entry.
+ self.assertNotIn('file_tracers', data)
+
+ def test_writing_to_other_file(self):
+ data_files = CoverageDataFiles(".otherfile")
+ covdata = CoverageData()
+ covdata.add_lines(LINES_1)
+ data_files.write(covdata)
+ self.assert_doesnt_exist(".coverage")
+ self.assert_exists(".otherfile")
+
+ data_files.write(covdata, suffix="extra")
+ self.assert_exists(".otherfile.extra")
+ self.assert_doesnt_exist(".coverage")
def test_combining_with_aliases(self):
covdata1 = CoverageData()
covdata1.add_lines({
'/home/ned/proj/src/a.py': {1: None, 2: None},
'/home/ned/proj/src/sub/b.py': {3: None},
- })
+ '/home/ned/proj/src/template.html': {10: None},
+ })
+ covdata1.add_file_tracers({
+ '/home/ned/proj/src/template.html': 'html.plugin',
+ })
self.data_files.write(covdata1, suffix='1')
covdata2 = CoverageData()
covdata2.add_lines({
r'c:\ned\test\a.py': {4: None, 5: None},
- r'c:\ned\test\sub\b.py': {6: None},
- })
+ r'c:\ned\test\sub\b.py': {3: None, 6: None},
+ })
self.data_files.write(covdata2, suffix='2')
covdata3 = CoverageData()
@@ -173,34 +726,66 @@ class DataTest(DataTestHelpers, CoverageTest):
apy = canonical_filename('./a.py')
sub_bpy = canonical_filename('./sub/b.py')
+ template_html = canonical_filename('./template.html')
- self.assert_summary(
- covdata3, { apy: 4, sub_bpy: 2, }, fullpath=True
- )
- self.assert_measured_files(covdata3, [apy,sub_bpy])
+ self.assert_line_counts(covdata3, {apy: 4, sub_bpy: 2, template_html: 1}, fullpath=True)
+ self.assert_measured_files(covdata3, [apy, sub_bpy, template_html])
+ self.assertEqual(covdata3.file_tracer(template_html), 'html.plugin')
+ def test_combining_from_different_directories(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines(LINES_1)
+ os.makedirs('cov1')
+ covdata1.write_file('cov1/.coverage.1')
-class DataTestInTempDir(DataTestHelpers, CoverageTest):
- """Test cases for coverage.data."""
+ covdata2 = CoverageData()
+ covdata2.add_lines(LINES_2)
+ os.makedirs('cov2')
+ covdata2.write_file('cov2/.coverage.2')
- no_files_in_temp_dir = True
+ # This data won't be included.
+ covdata_xxx = CoverageData()
+ covdata_xxx.add_arcs(ARCS_3)
+ covdata_xxx.write_file('.coverage.xxx')
- def test_combining_from_different_directories(self):
+ covdata3 = CoverageData()
+ self.data_files.combine_parallel_data(covdata3, data_paths=['cov1', 'cov2'])
+
+ self.assert_line_counts(covdata3, SUMMARY_1_2)
+ self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+ self.assert_doesnt_exist("cov1/.coverage.1")
+ self.assert_doesnt_exist("cov2/.coverage.2")
+ self.assert_exists(".coverage.xxx")
+
+ def test_combining_from_files(self):
covdata1 = CoverageData()
- covdata1.add_lines(DATA_1)
+ covdata1.add_lines(LINES_1)
os.makedirs('cov1')
covdata1.write_file('cov1/.coverage.1')
covdata2 = CoverageData()
- covdata2.add_lines(DATA_2)
+ covdata2.add_lines(LINES_2)
os.makedirs('cov2')
covdata2.write_file('cov2/.coverage.2')
+ # This data won't be included.
+ covdata_xxx = CoverageData()
+ covdata_xxx.add_arcs(ARCS_3)
+ covdata_xxx.write_file('.coverage.xxx')
+ covdata_xxx.write_file('cov2/.coverage.xxx')
+
covdata3 = CoverageData()
- self.data_files.combine_parallel_data(covdata3, data_dirs=[
- 'cov1/',
- 'cov2/',
- ])
+ self.data_files.combine_parallel_data(covdata3, data_paths=['cov1', 'cov2/.coverage.2'])
- self.assert_summary(covdata3, SUMMARY_1_2)
+ self.assert_line_counts(covdata3, SUMMARY_1_2)
self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+ self.assert_doesnt_exist("cov1/.coverage.1")
+ self.assert_doesnt_exist("cov2/.coverage.2")
+ self.assert_exists(".coverage.xxx")
+ self.assert_exists("cov2/.coverage.xxx")
+
+ def test_combining_from_nonexistent_directories(self):
+ covdata = CoverageData()
+ msg = "Couldn't combine from non-existent path 'xyzzy'"
+ with self.assertRaisesRegex(CoverageException, msg):
+ self.data_files.combine_parallel_data(covdata, data_paths=['xyzzy'])
diff --git a/tests/test_debug.py b/tests/test_debug.py
index 8576112d..2d553ee2 100644
--- a/tests/test_debug.py
+++ b/tests/test_debug.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests of coverage/debug.py"""
import os
@@ -5,7 +8,8 @@ import re
import coverage
from coverage.backward import StringIO
-from coverage.debug import info_formatter, info_header
+from coverage.debug import info_formatter, info_header, short_stack
+
from tests.coveragetest import CoverageTest
@@ -61,9 +65,10 @@ class DebugTraceTest(CoverageTest):
""")
debug_out = StringIO()
- cov = coverage.coverage(debug=debug)
+ cov = coverage.Coverage(debug=debug)
cov._debug_file = debug_out
self.start_import_stop(cov, "f1")
+ cov.save()
out_lines = debug_out.getvalue().splitlines()
return out_lines
@@ -99,6 +104,21 @@ class DebugTraceTest(CoverageTest):
self.assertTrue(lines_matching(out_lines, pid_prefix + "Tracing "))
self.assertTrue(lines_matching(out_lines, pid_prefix + "Not tracing "))
+ def test_debug_callers(self):
+ out_lines = self.f1_debug_output(["pid", "dataop", "dataio", "callers"])
+ print("\n".join(out_lines))
+ # For every real message, there should be a stack
+ # trace with a line like "f1_debug_output : /Users/ned/coverage/tests/test_debug.py @71"
+ real_messages = lines_matching(out_lines, r"^pid\s+\d+: ")
+ frame_pattern = r"\s+f1_debug_output : .*tests[/\\]test_debug.py @\d+$"
+ frames = lines_matching(out_lines, frame_pattern)
+ self.assertEqual(len(real_messages), len(frames))
+
+ # The last message should be "Writing data", and the last frame should
+ # be write_file in data.py.
+ self.assertRegex(real_messages[-1], r"^pid\s+\d+: Writing data")
+ self.assertRegex(out_lines[-1], r"\s+write_file : .*coverage[/\\]data.py @\d+$")
+
def test_debug_config(self):
out_lines = self.f1_debug_output(["config"])
@@ -129,6 +149,40 @@ class DebugTraceTest(CoverageTest):
)
+def f_one(*args, **kwargs):
+ """First of the chain of functions for testing `short_stack`."""
+ return f_two(*args, **kwargs)
+
+def f_two(*args, **kwargs):
+ """Second of the chain of functions for testing `short_stack`."""
+ return f_three(*args, **kwargs)
+
+def f_three(*args, **kwargs):
+ """Third of the chain of functions for testing `short_stack`."""
+ return short_stack(*args, **kwargs)
+
+
+class ShortStackTest(CoverageTest):
+ """Tests of coverage.debug.short_stack."""
+
+ run_in_temp_dir = False
+
+ def test_short_stack(self):
+ stack = f_one().splitlines()
+ self.assertGreater(len(stack), 10)
+ self.assertIn("f_three", stack[-1])
+ self.assertIn("f_two", stack[-2])
+ self.assertIn("f_one", stack[-3])
+
+ def test_short_stack_limit(self):
+ stack = f_one(limit=5).splitlines()
+ self.assertEqual(len(stack), 5)
+
+ def test_short_stack_skip(self):
+ stack = f_one(skip=1).splitlines()
+ self.assertIn("f_two", stack[-1])
+
+
def lines_matching(lines, pat):
"""Gives the list of lines from `lines` that match `pat`."""
return [l for l in lines if re.search(pat, l)]
diff --git a/tests/test_execfile.py b/tests/test_execfile.py
index 49d6cc8c..8585b16d 100644
--- a/tests/test_execfile.py
+++ b/tests/test_execfile.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for coverage.execfile"""
import compileall
@@ -13,15 +16,14 @@ from coverage.misc import NoCode, NoSource
from tests.coveragetest import CoverageTest
-HERE = os.path.dirname(__file__)
+TRY_EXECFILE = os.path.join(os.path.dirname(__file__), "modules/process_test/try_execfile.py")
class RunFileTest(CoverageTest):
"""Test cases for `run_python_file`."""
def test_run_python_file(self):
- tryfile = os.path.join(HERE, "try_execfile.py")
- run_python_file(tryfile, [tryfile, "arg1", "arg2"])
+ run_python_file(TRY_EXECFILE, [TRY_EXECFILE, "arg1", "arg2"])
mod_globs = json.loads(self.stdout())
# The file should think it is __main__
@@ -41,7 +43,7 @@ class RunFileTest(CoverageTest):
self.assertEqual(mod_globs['__main__.DATA'], "xyzzy")
# Argv should have the proper values.
- self.assertEqual(mod_globs['argv'], [tryfile, "arg1", "arg2"])
+ self.assertEqual(mod_globs['argv'], [TRY_EXECFILE, "arg1", "arg2"])
# __builtins__ should have the right values, like open().
self.assertEqual(mod_globs['__builtins__.has_open'], True)
@@ -82,6 +84,18 @@ class RunFileTest(CoverageTest):
with self.assertRaises(NoSource):
run_python_file("xyzzy.py", [])
+ def test_directory_with_main(self):
+ self.make_file("with_main/__main__.py", """\
+ print("I am __main__")
+ """)
+ run_python_file("with_main", ["with_main"])
+ self.assertEqual(self.stdout(), "I am __main__\n")
+
+ def test_directory_without_main(self):
+ self.make_file("without_main/__init__.py", "")
+ with self.assertRaisesRegex(NoSource, "Can't find '__main__' module in 'without_main'"):
+ run_python_file("without_main", ["without_main"])
+
class RunPycFileTest(CoverageTest):
"""Test cases for `run_python_file`."""
@@ -131,6 +145,25 @@ class RunPycFileTest(CoverageTest):
with self.assertRaisesRegex(NoCode, "No file to run: 'xyzzy.pyc'"):
run_python_file("xyzzy.pyc", [])
+ def test_running_py_from_binary(self):
+ # Use make_file to get the bookkeeping. Ideally, it would
+ # be able to write binary files.
+ bf = self.make_file("binary")
+ with open(bf, "wb") as f:
+ f.write(b'\x7fELF\x02\x01\x01\x00\x00\x00')
+
+ msg = (
+ r"Couldn't run 'binary' as Python code: "
+ r"(TypeError|ValueError): "
+ r"("
+ r"compile\(\) expected string without null bytes" # for py2
+ r"|"
+ r"source code string cannot contain null bytes" # for py3
+ r")"
+ )
+ with self.assertRaisesRegex(Exception, msg):
+ run_python_file(bf, [bf])
+
class RunModuleTest(CoverageTest):
"""Test run_python_module."""
@@ -150,22 +183,27 @@ class RunModuleTest(CoverageTest):
def test_runmod2(self):
run_python_module("pkg1.runmod2", ["runmod2", "hello"])
self.assertEqual(self.stderr(), "")
- self.assertEqual(self.stdout(), "runmod2: passed hello\n")
+ self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\nrunmod2: passed hello\n")
def test_runmod3(self):
run_python_module("pkg1.sub.runmod3", ["runmod3", "hello"])
self.assertEqual(self.stderr(), "")
- self.assertEqual(self.stdout(), "runmod3: passed hello\n")
+ self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\nrunmod3: passed hello\n")
def test_pkg1_main(self):
run_python_module("pkg1", ["pkg1", "hello"])
self.assertEqual(self.stderr(), "")
- self.assertEqual(self.stdout(), "pkg1.__main__: passed hello\n")
+ self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\npkg1.__main__: passed hello\n")
def test_pkg1_sub_main(self):
run_python_module("pkg1.sub", ["pkg1.sub", "hello"])
self.assertEqual(self.stderr(), "")
- self.assertEqual(self.stdout(), "pkg1.sub.__main__: passed hello\n")
+ self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\npkg1.sub.__main__: passed hello\n")
+
+ def test_pkg1_init(self):
+ run_python_module("pkg1.__init__", ["pkg1.__init__", "wut?"])
+ self.assertEqual(self.stderr(), "")
+ self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\npkg1.__init__: __main__\n")
def test_no_such_module(self):
with self.assertRaises(NoSource):
diff --git a/tests/test_farm.py b/tests/test_farm.py
index d8d4c0fa..7c9ac012 100644
--- a/tests/test_farm.py
+++ b/tests/test_farm.py
@@ -1,4 +1,7 @@
-"""Run tests in the farm sub-directory. Designed for nose."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Run tests in the farm sub-directory. Designed for pytest."""
import difflib
import filecmp
@@ -9,26 +12,30 @@ import re
import shutil
import sys
-from nose.plugins.skip import SkipTest
+import pytest
+from unittest_mixins import ModuleAwareMixin, SysPathAwareMixin, change_dir, saved_sys_path
from tests.helpers import run_command
from tests.backtest import execfile # pylint: disable=redefined-builtin
-from coverage.control import _TEST_NAME_FILE
+from coverage.backunittest import unittest
+from coverage.debug import _TEST_NAME_FILE
+
+
+# Look for files that become tests.
+TEST_FILES = glob.glob("tests/farm/*/*.py")
-def test_farm(clean_only=False):
- """A test-generating function for nose to find and run."""
- for fname in glob.glob("tests/farm/*/*.py"):
- case = FarmTestCase(fname, clean_only)
- yield (case,)
+@pytest.mark.parametrize("filename", TEST_FILES)
+def test_farm(filename):
+ FarmTestCase(filename).run_fully()
# "rU" was deprecated in 3.4
READ_MODE = "rU" if sys.version_info < (3, 4) else "r"
-class FarmTestCase(object):
+class FarmTestCase(ModuleAwareMixin, SysPathAwareMixin, unittest.TestCase):
"""A test case from the farm tree.
Tests are short Python script files, often called run.py:
@@ -45,7 +52,14 @@ class FarmTestCase(object):
has options to allow various uses of the test cases (normal execution,
cleaning-only, or run and leave the results for debugging).
+ This class is a unittest.TestCase so that we can use behavior-modifying
+ mixins, but it's only useful as a test function. Yes, this is confusing.
+
"""
+
+ # We don't want test runners finding this and instantiating it themselves.
+ __test__ = False
+
def __init__(self, runpy, clean_only=False, dont_clean=False):
"""Create a test case from a run.py file.
@@ -53,67 +67,65 @@ class FarmTestCase(object):
`dont_clean` means that the clean() action is not executed.
"""
+ super(FarmTestCase, self).__init__()
+
self.description = runpy
self.dir, self.runpy = os.path.split(runpy)
self.clean_only = clean_only
self.dont_clean = dont_clean
self.ok = True
- def cd(self, newdir):
- """Change the current directory, and return the old one."""
- cwd = os.getcwd()
- os.chdir(newdir)
- return cwd
+ def setUp(self):
+ """Test set up, run by the test runner before __call__."""
+ super(FarmTestCase, self).setUp()
+ # Modules should be importable from the current directory.
+ sys.path.insert(0, '')
- def addtopath(self, directory):
- """Add `directory` to the path, and return the old path."""
- oldpath = sys.path[:]
- if directory is not None:
- sys.path.insert(0, directory)
- return oldpath
+ def tearDown(self):
+ """Test tear down, run by the test runner after __call__."""
+ # Make sure the test is cleaned up, unless we never want to, or if the
+ # test failed.
+ if not self.dont_clean and self.ok: # pragma: part covered
+ self.clean_only = True
+ self()
- def restorepath(self, path):
- """Restore the system path to `path`."""
- sys.path = path
+ super(FarmTestCase, self).tearDown()
- def __call__(self):
- """Execute the test from the run.py file.
+ # This object will be run via the __call__ method, and test runners
+ # don't do cleanups in that case. Do them now.
+ self.doCleanups()
- """
+ def runTest(self):
+ """Here to make unittest.TestCase happy, but will never be invoked."""
+ raise Exception("runTest isn't used in this class!")
+
+ def __call__(self):
+ """Execute the test from the run.py file."""
if _TEST_NAME_FILE: # pragma: debugging
with open(_TEST_NAME_FILE, "w") as f:
f.write(self.description.replace("/", "_"))
- cwd = self.cd(self.dir)
-
# Prepare a dictionary of globals for the run.py files to use.
fns = """
copy run runfunc clean skip
compare contains contains_any doesnt_contain
""".split()
if self.clean_only:
- glo = dict((fn, self.noop) for fn in fns)
- glo['clean'] = self.clean
+ glo = dict((fn, noop) for fn in fns)
+ glo['clean'] = clean
else:
- glo = dict((fn, getattr(self, fn)) for fn in fns)
+ glo = dict((fn, globals()[fn]) for fn in fns)
if self.dont_clean: # pragma: not covered
- glo['clean'] = self.noop
+ glo['clean'] = noop
- old_mods = dict(sys.modules)
- try:
- execfile(self.runpy, glo)
- except Exception:
- self.ok = False
- raise
- finally:
- self.cd(cwd)
- # Remove any new modules imported during the test run. This lets us
- # import the same source files for more than one test.
- to_del = [m for m in sys.modules if m not in old_mods]
- for m in to_del:
- del sys.modules[m]
-
- def run_fully(self): # pragma: not covered
+ with change_dir(self.dir):
+ try:
+ execfile(self.runpy, glo)
+ except Exception:
+ self.ok = False
+ raise
+
+ def run_fully(self):
"""Run as a full test case, with setUp and tearDown."""
self.setUp()
try:
@@ -121,58 +133,30 @@ class FarmTestCase(object):
finally:
self.tearDown()
- def fnmatch_list(self, files, file_pattern):
- """Filter the list of `files` to only those that match `file_pattern`.
-
- If `file_pattern` is None, then return the entire list of files.
- Returns a list of the filtered files.
-
- """
- if file_pattern:
- files = [f for f in files if fnmatch.fnmatch(f, file_pattern)]
- return files
+# Functions usable inside farm run.py files
- def setUp(self):
- """Test set up, run by nose before __call__."""
+def noop(*args_unused, **kwargs_unused):
+ """A no-op function to stub out run, copy, etc, when only cleaning."""
+ pass
- # Modules should be importable from the current directory.
- self.old_syspath = sys.path[:]
- sys.path.insert(0, '')
- def tearDown(self):
- """Test tear down, run by nose after __call__."""
- # Make sure the test is cleaned up, unless we never want to, or if the
- # test failed.
- if not self.dont_clean and self.ok: # pragma: part covered
- self.clean_only = True
- self()
+def copy(src, dst):
+ """Copy a directory."""
+ if os.path.exists(dst):
+ shutil.rmtree(dst)
+ shutil.copytree(src, dst)
- # Restore the original sys.path
- sys.path = self.old_syspath
- # Functions usable inside farm run.py files
+def run(cmds, rundir="src", outfile=None):
+ """Run a list of commands.
- def noop(self, *args, **kwargs):
- """A no-op function to stub out run, copy, etc, when only cleaning."""
- pass
+ `cmds` is a string, commands separated by newlines.
+ `rundir` is the directory in which to run the commands.
+ `outfile` is a file name to redirect stdout to.
- def copy(self, src, dst):
- """Copy a directory."""
-
- if os.path.exists(dst):
- shutil.rmtree(dst)
- shutil.copytree(src, dst)
-
- def run(self, cmds, rundir="src", outfile=None):
- """Run a list of commands.
-
- `cmds` is a string, commands separated by newlines.
- `rundir` is the directory in which to run the commands.
- `outfile` is a filename to redirect stdout to.
-
- """
- cwd = self.cd(rundir)
+ """
+ with change_dir(rundir):
if outfile:
fout = open(outfile, "a+")
try:
@@ -189,194 +173,211 @@ class FarmTestCase(object):
finally:
if outfile:
fout.close()
- self.cd(cwd)
- def runfunc(self, fn, rundir="src", addtopath=None):
- """Run a function.
- `fn` is a callable.
- `rundir` is the directory in which to run the function.
+def runfunc(fn, rundir="src", addtopath=None):
+ """Run a function.
- """
+ `fn` is a callable.
+ `rundir` is the directory in which to run the function.
- cwd = self.cd(rundir)
- oldpath = self.addtopath(addtopath)
- try:
+ """
+ with change_dir(rundir):
+ with saved_sys_path():
+ if addtopath is not None:
+ sys.path.insert(0, addtopath)
fn()
- finally:
- self.cd(cwd)
- self.restorepath(oldpath)
- def compare(
- self, dir1, dir2, file_pattern=None, size_within=0,
- left_extra=False, right_extra=False, scrubs=None
- ):
- """Compare files matching `file_pattern` in `dir1` and `dir2`.
- `dir2` is interpreted as a prefix, with Python version numbers appended
- to find the actual directory to compare with. "foo" will compare
- against "foo_v241", "foo_v24", "foo_v2", or "foo", depending on which
- directory is found first.
+def compare(
+ dir1, dir2, file_pattern=None, size_within=0,
+ left_extra=False, right_extra=False, scrubs=None
+):
+ """Compare files matching `file_pattern` in `dir1` and `dir2`.
- `size_within` is a percentage delta for the file sizes. If non-zero,
- then the file contents are not compared (since they are expected to
- often be different), but the file sizes must be within this amount.
- For example, size_within=10 means that the two files' sizes must be
- within 10 percent of each other to compare equal.
+ `dir2` is interpreted as a prefix, with Python version numbers appended
+ to find the actual directory to compare with. "foo" will compare
+ against "foo_v241", "foo_v24", "foo_v2", or "foo", depending on which
+ directory is found first.
- `left_extra` true means the left directory can have extra files in it
- without triggering an assertion. `right_extra` means the right
- directory can.
+ `size_within` is a percentage delta for the file sizes. If non-zero,
+ then the file contents are not compared (since they are expected to
+ often be different), but the file sizes must be within this amount.
+ For example, size_within=10 means that the two files' sizes must be
+ within 10 percent of each other to compare equal.
- `scrubs` is a list of pairs, regexes to find and literal strings to
- replace them with to scrub the files of unimportant differences.
+ `left_extra` true means the left directory can have extra files in it
+ without triggering an assertion. `right_extra` means the right
+ directory can.
- An assertion will be raised if the directories fail one of their
- matches.
+ `scrubs` is a list of pairs, regexes to find and literal strings to
+ replace them with to scrub the files of unimportant differences.
- """
- # Search for a dir2 with a version suffix.
- version_suff = ''.join(map(str, sys.version_info[:3]))
- while version_suff:
- trydir = dir2 + '_v' + version_suff
- if os.path.exists(trydir):
- dir2 = trydir
- break
- version_suff = version_suff[:-1]
-
- assert os.path.exists(dir1), "Left directory missing: %s" % dir1
- assert os.path.exists(dir2), "Right directory missing: %s" % dir2
-
- dc = filecmp.dircmp(dir1, dir2)
- diff_files = self.fnmatch_list(dc.diff_files, file_pattern)
- left_only = self.fnmatch_list(dc.left_only, file_pattern)
- right_only = self.fnmatch_list(dc.right_only, file_pattern)
- show_diff = True
-
- if size_within:
- # The files were already compared, use the diff_files list as a
- # guide for size comparison.
- wrong_size = []
- for f in diff_files:
- with open(os.path.join(dir1, f), "rb") as fobj:
- left = fobj.read()
- with open(os.path.join(dir2, f), "rb") as fobj:
- right = fobj.read()
- size_l, size_r = len(left), len(right)
- big, little = max(size_l, size_r), min(size_l, size_r)
- if (big - little) / float(little) > size_within/100.0:
- # print "%d %d" % (big, little)
- # print "Left: ---\n%s\n-----\n%s" % (left, right)
- wrong_size.append("%s (%s,%s)" % (f, size_l, size_r))
- if wrong_size:
- print("File sizes differ between %s and %s: %s" % (
- dir1, dir2, ", ".join(wrong_size)
- ))
-
- # We'll show the diff iff the files differed enough in size.
- show_diff = bool(wrong_size)
-
- if show_diff:
- # filecmp only compares in binary mode, but we want text mode. So
- # look through the list of different files, and compare them
- # ourselves.
- text_diff = []
- for f in diff_files:
- with open(os.path.join(dir1, f), READ_MODE) as fobj:
- left = fobj.read()
- with open(os.path.join(dir2, f), READ_MODE) as fobj:
- right = fobj.read()
- if scrubs:
- left = self._scrub(left, scrubs)
- right = self._scrub(right, scrubs)
- if left != right:
- text_diff.append(f)
- left = left.splitlines()
- right = right.splitlines()
- print("\n".join(difflib.Differ().compare(left, right)))
- assert not text_diff, "Files differ: %s" % text_diff
-
- if not left_extra:
- assert not left_only, "Files in %s only: %s" % (dir1, left_only)
- if not right_extra:
- assert not right_only, "Files in %s only: %s" % (dir2, right_only)
-
- def _scrub(self, strdata, scrubs):
- """Scrub uninteresting data from the payload in `strdata`.
-
- `scrubs` is a list of (find, replace) pairs of regexes that are used on
- `strdata`. A string is returned.
+ An assertion will be raised if the directories fail one of their
+ matches.
- """
- for rgx_find, rgx_replace in scrubs:
- strdata = re.sub(rgx_find, re.escape(rgx_replace), strdata)
- return strdata
+ """
+ # Search for a dir2 with a version suffix.
+ version_suff = ''.join(map(str, sys.version_info[:3]))
+ while version_suff:
+ trydir = dir2 + '_v' + version_suff
+ if os.path.exists(trydir):
+ dir2 = trydir
+ break
+ version_suff = version_suff[:-1]
+
+ assert os.path.exists(dir1), "Left directory missing: %s" % dir1
+ assert os.path.exists(dir2), "Right directory missing: %s" % dir2
+
+ dc = filecmp.dircmp(dir1, dir2)
+ diff_files = fnmatch_list(dc.diff_files, file_pattern)
+ left_only = fnmatch_list(dc.left_only, file_pattern)
+ right_only = fnmatch_list(dc.right_only, file_pattern)
+ show_diff = True
+
+ if size_within:
+ # The files were already compared, use the diff_files list as a
+ # guide for size comparison.
+ wrong_size = []
+ for f in diff_files:
+ with open(os.path.join(dir1, f), "rb") as fobj:
+ left = fobj.read()
+ with open(os.path.join(dir2, f), "rb") as fobj:
+ right = fobj.read()
+ size_l, size_r = len(left), len(right)
+ big, little = max(size_l, size_r), min(size_l, size_r)
+ if (big - little) / float(little) > size_within/100.0:
+ # print "%d %d" % (big, little)
+ # print "Left: ---\n%s\n-----\n%s" % (left, right)
+ wrong_size.append("%s (%s,%s)" % (f, size_l, size_r))
+ if wrong_size:
+ print("File sizes differ between %s and %s: %s" % (
+ dir1, dir2, ", ".join(wrong_size)
+ ))
+
+ # We'll show the diff iff the files differed enough in size.
+ show_diff = bool(wrong_size)
+
+ if show_diff:
+ # filecmp only compares in binary mode, but we want text mode. So
+ # look through the list of different files, and compare them
+ # ourselves.
+ text_diff = []
+ for f in diff_files:
+ with open(os.path.join(dir1, f), READ_MODE) as fobj:
+ left = fobj.read()
+ with open(os.path.join(dir2, f), READ_MODE) as fobj:
+ right = fobj.read()
+ if scrubs:
+ left = scrub(left, scrubs)
+ right = scrub(right, scrubs)
+ if left != right:
+ text_diff.append(f)
+ left = left.splitlines()
+ right = right.splitlines()
+ print("\n".join(difflib.Differ().compare(left, right)))
+ assert not text_diff, "Files differ: %s" % text_diff
+
+ if not left_extra:
+ assert not left_only, "Files in %s only: %s" % (dir1, left_only)
+ if not right_extra:
+ assert not right_only, "Files in %s only: %s" % (dir2, right_only)
+
+
+def contains(filename, *strlist):
+ """Check that the file contains all of a list of strings.
+
+ An assert will be raised if one of the arguments in `strlist` is
+ missing in `filename`.
- def contains(self, filename, *strlist):
- """Check that the file contains all of a list of strings.
+ """
+ with open(filename, "r") as fobj:
+ text = fobj.read()
+ for s in strlist:
+ assert s in text, "Missing content in %s: %r" % (filename, s)
- An assert will be raised if one of the arguments in `strlist` is
- missing in `filename`.
- """
- with open(filename, "r") as fobj:
- text = fobj.read()
- for s in strlist:
- assert s in text, "Missing content in %s: %r" % (filename, s)
+def contains_any(filename, *strlist):
+ """Check that the file contains at least one of a list of strings.
- def contains_any(self, filename, *strlist):
- """Check that the file contains at least one of a list of strings.
+ An assert will be raised if none of the arguments in `strlist` is in
+ `filename`.
- An assert will be raised if none of the arguments in `strlist` is in
- `filename`.
+ """
+ with open(filename, "r") as fobj:
+ text = fobj.read()
+ for s in strlist:
+ if s in text:
+ return
+ assert False, "Missing content in %s: %r [1 of %d]" % (filename, strlist[0], len(strlist),)
- """
- with open(filename, "r") as fobj:
- text = fobj.read()
- for s in strlist:
- if s in text:
- return
- assert False, "Missing content in %s: %r [1 of %d]" % (
- filename, strlist[0], len(strlist),
- )
- def doesnt_contain(self, filename, *strlist):
- """Check that the file contains none of a list of strings.
+def doesnt_contain(filename, *strlist):
+ """Check that the file contains none of a list of strings.
- An assert will be raised if any of the strings in strlist appears in
- `filename`.
+ An assert will be raised if any of the strings in `strlist` appears in
+ `filename`.
- """
- with open(filename, "r") as fobj:
- text = fobj.read()
- for s in strlist:
- assert s not in text, "Forbidden content in %s: %r" % (filename, s)
-
- def clean(self, cleandir):
- """Clean `cleandir` by removing it and all its children completely."""
- # rmtree gives mysterious failures on Win7, so retry a "few" times.
- # I've seen it take over 100 tries, so, 1000! This is probably the
- # most unpleasant hack I've written in a long time...
- tries = 1000
- while tries: # pragma: part covered
- if os.path.exists(cleandir):
- try:
- shutil.rmtree(cleandir)
- except OSError: # pragma: not covered
- if tries == 1:
- raise
- else:
- tries -= 1
- continue
- break
+ """
+ with open(filename, "r") as fobj:
+ text = fobj.read()
+ for s in strlist:
+ assert s not in text, "Forbidden content in %s: %r" % (filename, s)
+
+
+def clean(cleandir):
+ """Clean `cleandir` by removing it and all its children completely."""
+ # rmtree gives mysterious failures on Win7, so retry a "few" times.
+ # I've seen it take over 100 tries, so, 1000! This is probably the
+ # most unpleasant hack I've written in a long time...
+ tries = 1000
+ while tries: # pragma: part covered
+ if os.path.exists(cleandir):
+ try:
+ shutil.rmtree(cleandir)
+ except OSError: # pragma: not covered
+ if tries == 1:
+ raise
+ else:
+ tries -= 1
+ continue
+ break
+
+
+def skip(msg=None):
+ """Skip the current test."""
+ raise unittest.SkipTest(msg)
+
+
+# Helpers
+
+def fnmatch_list(files, file_pattern):
+ """Filter the list of `files` to only those that match `file_pattern`.
- def skip(self, msg=None):
- """Skip the current test."""
- raise SkipTest(msg)
+ If `file_pattern` is None, then return the entire list of files.
+
+ Returns a list of the filtered files.
+
+ """
+ if file_pattern:
+ files = [f for f in files if fnmatch.fnmatch(f, file_pattern)]
+ return files
+
+
+def scrub(strdata, scrubs):
+ """Scrub uninteresting data from the payload in `strdata`.
+
+ `scrubs` is a list of (find, replace) pairs of regexes that are used on
+ `strdata`. A string is returned.
+
+ """
+ for rgx_find, rgx_replace in scrubs:
+ strdata = re.sub(rgx_find, re.escape(rgx_replace), strdata)
+ return strdata
def main(): # pragma: not covered
- """Command-line access to test_farm.
+ """Command-line access to farm tests.
Commands:
@@ -385,26 +386,23 @@ def main(): # pragma: not covered
clean - Clean all the output for all tests.
"""
- op = 'help'
try:
op = sys.argv[1]
except IndexError:
- pass
+ op = 'help'
if op == 'run':
# Run the test for real.
- for test_case in sys.argv[2:]:
- case = FarmTestCase(test_case)
- case.run_fully()
+ for filename in sys.argv[2:]:
+ FarmTestCase(filename).run_fully()
elif op == 'out':
# Run the test, but don't clean up, so we can examine the output.
- for test_case in sys.argv[2:]:
- case = FarmTestCase(test_case, dont_clean=True)
- case.run_fully()
+ for filename in sys.argv[2:]:
+ FarmTestCase(filename, dont_clean=True).run_fully()
elif op == 'clean':
# Run all the tests, but just clean.
- for test in test_farm(clean_only=True):
- test[0].run_fully()
+ for filename in TEST_FILES:
+ FarmTestCase(filename, clean_only=True).run_fully()
else:
print(main.__doc__)
diff --git a/tests/test_filereporter.py b/tests/test_filereporter.py
index 045081cf..a348a844 100644
--- a/tests/test_filereporter.py
+++ b/tests/test_filereporter.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for FileReporters"""
import os
@@ -35,9 +38,6 @@ class FileReporterTest(CoverageTest):
self.assertEqual(acu.relative_filename(), "aa/afile.py")
self.assertEqual(bcu.relative_filename(), "aa/bb/bfile.py")
self.assertEqual(ccu.relative_filename(), "aa/bb/cc/cfile.py")
- self.assertEqual(acu.flat_rootname(), "aa_afile_py")
- self.assertEqual(bcu.flat_rootname(), "aa_bb_bfile_py")
- self.assertEqual(ccu.flat_rootname(), "aa_bb_cc_cfile_py")
self.assertEqual(acu.source(), "# afile.py\n")
self.assertEqual(bcu.source(), "# bfile.py\n")
self.assertEqual(ccu.source(), "# cfile.py\n")
@@ -49,9 +49,6 @@ class FileReporterTest(CoverageTest):
self.assertEqual(acu.relative_filename(), "aa/afile.odd.py")
self.assertEqual(bcu.relative_filename(), "aa/bb/bfile.odd.py")
self.assertEqual(b2cu.relative_filename(), "aa/bb.odd/bfile.py")
- self.assertEqual(acu.flat_rootname(), "aa_afile_odd_py")
- self.assertEqual(bcu.flat_rootname(), "aa_bb_bfile_odd_py")
- self.assertEqual(b2cu.flat_rootname(), "aa_bb_odd_bfile_py")
self.assertEqual(acu.source(), "# afile.odd.py\n")
self.assertEqual(bcu.source(), "# bfile.odd.py\n")
self.assertEqual(b2cu.source(), "# bfile.py\n")
@@ -67,9 +64,6 @@ class FileReporterTest(CoverageTest):
self.assertEqual(acu.relative_filename(), native("aa.py"))
self.assertEqual(bcu.relative_filename(), native("aa/bb.py"))
self.assertEqual(ccu.relative_filename(), native("aa/bb/cc.py"))
- self.assertEqual(acu.flat_rootname(), "aa_py")
- self.assertEqual(bcu.flat_rootname(), "aa_bb_py")
- self.assertEqual(ccu.flat_rootname(), "aa_bb_cc_py")
self.assertEqual(acu.source(), "# aa\n")
self.assertEqual(bcu.source(), "# bb\n")
self.assertEqual(ccu.source(), "") # yes, empty
@@ -85,9 +79,6 @@ class FileReporterTest(CoverageTest):
self.assertEqual(acu.relative_filename(), native("aa/afile.py"))
self.assertEqual(bcu.relative_filename(), native("aa/bb/bfile.py"))
self.assertEqual(ccu.relative_filename(), native("aa/bb/cc/cfile.py"))
- self.assertEqual(acu.flat_rootname(), "aa_afile_py")
- self.assertEqual(bcu.flat_rootname(), "aa_bb_bfile_py")
- self.assertEqual(ccu.flat_rootname(), "aa_bb_cc_cfile_py")
self.assertEqual(acu.source(), "# afile.py\n")
self.assertEqual(bcu.source(), "# bfile.py\n")
self.assertEqual(ccu.source(), "# cfile.py\n")
@@ -117,4 +108,4 @@ class FileReporterTest(CoverageTest):
ecu = PythonFileReporter(egg1)
eecu = PythonFileReporter(egg1.egg1)
self.assertEqual(ecu.source(), u"")
- self.assertEqual(eecu.source().split("\n")[0], u"# My egg file!")
+ self.assertIn(u"# My egg file!", eecu.source().splitlines())
diff --git a/tests/test_files.py b/tests/test_files.py
index 4d9e3924..ec0332eb 100644
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for files.py"""
import os
@@ -6,7 +9,7 @@ import os.path
from coverage import files
from coverage.files import (
TreeMatcher, FnmatchMatcher, ModuleMatcher, PathAliases,
- find_python_files, abs_file, actual_path
+ find_python_files, abs_file, actual_path, flat_rootname,
)
from coverage.misc import CoverageException
from coverage import env
@@ -24,7 +27,7 @@ class FilesTest(CoverageTest):
def test_simple(self):
self.make_file("hello.py")
files.set_relative_directory()
- self.assertEqual(files.relative_filename("hello.py"), "hello.py")
+ self.assertEqual(files.relative_filename(u"hello.py"), u"hello.py")
a = self.abs_path("hello.py")
self.assertNotEqual(a, "hello.py")
self.assertEqual(files.relative_filename(a), "hello.py")
@@ -51,6 +54,10 @@ class FilesTest(CoverageTest):
rel = os.path.join('sub', trick, 'file1.py')
self.assertEqual(files.relative_filename(abs_file(rel)), rel)
+ def test_flat_rootname(self):
+ self.assertEqual(flat_rootname("a/b/c.py"), "a_b_c_py")
+ self.assertEqual(flat_rootname(r"c:\foo\bar.html"), "_foo_bar_html")
+
class MatcherTest(CoverageTest):
"""Tests of file matchers."""
@@ -218,6 +225,15 @@ class PathAliasesTest(CoverageTest):
aliases.add(r'c:\ned\src', r'.\mysrc')
self.assert_mapped(aliases, r'/home/ned/foo/src/sub/a.py', r'.\mysrc\sub\a.py')
+ def test_multiple_wildcard(self):
+ aliases = PathAliases()
+ aliases.add('/home/jenkins/*/a/*/b/*/django', './django')
+ self.assert_mapped(
+ aliases,
+ '/home/jenkins/xx/a/yy/b/zz/django/foo/bar.py',
+ './django/foo/bar.py'
+ )
+
def test_leading_wildcard(self):
aliases = PathAliases()
aliases.add('*/d1', './mysrc1')
@@ -264,8 +280,8 @@ class WindowsFileTest(CoverageTest):
def setUp(self):
if not env.WINDOWS:
- self.skip("Only need to run Windows tests on Windows.")
+ self.skipTest("Only need to run Windows tests on Windows.")
super(WindowsFileTest, self).setUp()
def test_actual_path(self):
- self.assertEquals(actual_path(r'c:\Windows'), actual_path(r'C:\wINDOWS'))
+ self.assertEqual(actual_path(r'c:\Windows'), actual_path(r'C:\wINDOWS'))
diff --git a/tests/test_html.py b/tests/test_html.py
index a5878448..b1f813ed 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -1,15 +1,25 @@
# -*- coding: utf-8 -*-
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests that HTML generation is awesome."""
import datetime
+import glob
+import json
+import os
import os.path
import re
+import sys
import coverage
+import coverage.files
import coverage.html
from coverage.misc import CoverageException, NotPython, NoSource
from tests.coveragetest import CoverageTest
+from tests.goldtest import CoverageGoldTest
+from tests.goldtest import change_dir, compare, contains, doesnt_contain, contains_any
class HtmlTestHelpers(CoverageTest):
@@ -33,9 +43,9 @@ class HtmlTestHelpers(CoverageTest):
""")
def run_coverage(self, covargs=None, htmlargs=None):
- """Run coverage on main_file.py, and create an HTML report."""
+ """Run coverage.py on main_file.py, and create an HTML report."""
self.clean_local_file_imports()
- cov = coverage.coverage(**(covargs or {}))
+ cov = coverage.Coverage(**(covargs or {}))
self.start_import_stop(cov, "main_file")
cov.html_report(**(htmlargs or {}))
@@ -53,23 +63,35 @@ class HtmlTestHelpers(CoverageTest):
with open(filename) as f:
return f.read()
- def get_html_index_content(self, scrub_time_stamp=True):
+ def get_html_index_content(self):
"""Return the content of index.html.
- If `scrub_time_stamp` is true, then replace the timestamp with a
- placeholder so that clocks don't matter.
+ Timestamps are replaced with a placeholder so that clocks don't matter.
"""
with open("htmlcov/index.html") as f:
index = f.read()
- if scrub_time_stamp:
- index = re.sub(
- r"created at \d{4}-\d{2}-\d{2} \d{2}:\d{2}",
- r"created at YYYY-MM-DD HH:MM",
- index,
- )
+ index = re.sub(
+ r"created at \d{4}-\d{2}-\d{2} \d{2}:\d{2}",
+ r"created at YYYY-MM-DD HH:MM",
+ index,
+ )
return index
+ def assert_correct_timestamp(self, html):
+ """Extract the timestamp from `html`, and assert it is recent."""
+ timestamp_pat = r"created at (\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})"
+ m = re.search(timestamp_pat, html)
+ self.assertTrue(m, "Didn't find a timestamp!")
+ timestamp = datetime.datetime(*map(int, m.groups()))
+ # The timestamp only records the minute, so the delta could be from
+ # 12:00 to 12:01:59, or two minutes.
+ self.assert_recent_datetime(
+ timestamp,
+ seconds=120,
+ msg="Timestamp is wrong: {0}".format(timestamp),
+ )
+
class HtmlDeltaTest(HtmlTestHelpers, CoverageTest):
"""Tests of the HTML delta speed-ups."""
@@ -77,12 +99,12 @@ class HtmlDeltaTest(HtmlTestHelpers, CoverageTest):
def setUp(self):
super(HtmlDeltaTest, self).setUp()
- # At least one of our tests monkey-patches the version of coverage,
+ # At least one of our tests monkey-patches the version of coverage.py,
# so grab it here to restore it later.
self.real_coverage_version = coverage.__version__
- self.addCleanup(self.restore_coverage_version)
+ self.addCleanup(self.cleanup_coverage_version)
- def restore_coverage_version(self):
+ def cleanup_coverage_version(self):
"""A cleanup."""
coverage.__version__ = self.real_coverage_version
@@ -147,8 +169,8 @@ class HtmlDeltaTest(HtmlTestHelpers, CoverageTest):
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.
+ # In this case, everything changes because the coverage.py settings
+ # have changed.
self.create_initial_files()
self.run_coverage(covargs=dict(omit=[]))
index1 = self.get_html_index_content()
@@ -166,7 +188,7 @@ class HtmlDeltaTest(HtmlTestHelpers, CoverageTest):
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
+ # In this case, everything changes because the coverage.py version has
# changed.
self.create_initial_files()
self.run_coverage()
@@ -187,6 +209,27 @@ class HtmlDeltaTest(HtmlTestHelpers, CoverageTest):
fixed_index2 = index2.replace("XYZZY", self.real_coverage_version)
self.assertMultiLineEqual(index1, fixed_index2)
+ def test_status_format_change(self):
+ self.create_initial_files()
+ self.run_coverage()
+ self.remove_html_files()
+
+ with open("htmlcov/status.json") as status_json:
+ status_data = json.load(status_json)
+
+ self.assertEqual(status_data['format'], 1)
+ status_data['format'] = 2
+ with open("htmlcov/status.json", "w") as status_json:
+ json.dump(status_data, status_json)
+
+ self.run_coverage()
+
+ # All the files have been reported again.
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/helper1_py.html")
+ self.assert_exists("htmlcov/main_file_py.html")
+ self.assert_exists("htmlcov/helper2_py.html")
+
class HtmlTitleTest(HtmlTestHelpers, CoverageTest):
"""Tests of the HTML title support."""
@@ -208,19 +251,17 @@ class HtmlTitleTest(HtmlTestHelpers, CoverageTest):
def test_non_ascii_title_set_in_config_file(self):
self.create_initial_files()
- self.make_file(".coveragerc",
- "[html]\ntitle = «ταБЬℓσ» numbers"
- )
+ self.make_file(".coveragerc", "[html]\ntitle = «ταБЬℓσ» numbers")
self.run_coverage()
index = self.get_html_index_content()
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()
@@ -230,11 +271,11 @@ class HtmlTitleTest(HtmlTestHelpers, CoverageTest):
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(HtmlTestHelpers, CoverageTest):
@@ -242,7 +283,7 @@ class HtmlWithUnparsableFilesTest(HtmlTestHelpers, CoverageTest):
def test_dotpy_not_python(self):
self.make_file("innocuous.py", "a = 1")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "innocuous")
self.make_file("innocuous.py", "<h1>This isn't python!</h1>")
msg = "Couldn't parse '.*innocuous.py' as Python source: .* at line 1"
@@ -251,10 +292,24 @@ class HtmlWithUnparsableFilesTest(HtmlTestHelpers, CoverageTest):
def test_dotpy_not_python_ignored(self):
self.make_file("innocuous.py", "a = 2")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "innocuous")
self.make_file("innocuous.py", "<h1>This isn't python!</h1>")
cov.html_report(ignore_errors=True)
+ self.assertEqual(
+ len(cov._warnings),
+ 1,
+ "Expected a warning to be thrown when an invalid python file is parsed")
+ self.assertIn(
+ "Could not parse Python file",
+ cov._warnings[0],
+ "Warning message should be in 'invalid file' warning"
+ )
+ self.assertIn(
+ "innocuous.py",
+ cov._warnings[0],
+ "Filename should be in 'invalid file' warning"
+ )
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")
@@ -278,7 +333,7 @@ class HtmlWithUnparsableFilesTest(HtmlTestHelpers, CoverageTest):
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 = coverage.Coverage()
self.start_import_stop(cov, "liar")
cov.html_report()
self.assert_exists("htmlcov/index.html")
@@ -291,7 +346,7 @@ class HtmlWithUnparsableFilesTest(HtmlTestHelpers, CoverageTest):
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 = coverage.Coverage()
self.start_import_stop(cov, "liar")
cov.html_report()
self.assert_exists("htmlcov/index.html")
@@ -307,7 +362,7 @@ class HtmlWithUnparsableFilesTest(HtmlTestHelpers, CoverageTest):
# coding: utf8
a = 1 # Isn't this great?!
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "main")
# Create the undecodable version of the file. make_file is too helpful,
@@ -322,13 +377,13 @@ class HtmlWithUnparsableFilesTest(HtmlTestHelpers, CoverageTest):
cov.html_report()
html_report = self.get_html_report_content("sub/not_ascii.py")
- expected = "# Isn&#39;t this great?&#65533;!"
+ expected = "# Isn't this great?&#65533;!"
self.assertIn(expected, html_report)
def test_formfeeds(self):
# https://bitbucket.org/ned/coveragepy/issue/360/html-reports-get-confused-by-l-in-the-code
self.make_file("formfeed.py", "line_one = 1\n\f\nline_two = 2\n")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "formfeed")
cov.html_report()
@@ -344,7 +399,7 @@ class HtmlTest(HtmlTestHelpers, CoverageTest):
self.make_file("thefile.py", "import sub.another\n")
self.make_file("sub/__init__.py", "")
self.make_file("sub/another.py", "print('another')\n")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, 'thefile')
os.remove("sub/another.py")
@@ -355,16 +410,16 @@ class HtmlTest(HtmlTestHelpers, CoverageTest):
cov.html_report()
def test_extensionless_file_collides_with_extension(self):
- # It used to be that "afile" and "afile.py" would both be reported to
- # "afile.html". Now they are not.
+ # It used to be that "program" and "program.py" would both be reported
+ # to "program.html". Now they are not.
# https://bitbucket.org/ned/coveragepy/issue/69
- self.make_file("afile", "import afile\n")
- self.make_file("afile.py", "a = 1\n")
- self.run_command("coverage run afile")
+ self.make_file("program", "import program\n")
+ self.make_file("program.py", "a = 1\n")
+ self.run_command("coverage run program")
self.run_command("coverage html")
self.assert_exists("htmlcov/index.html")
- self.assert_exists("htmlcov/afile.html")
- self.assert_exists("htmlcov/afile_py.html")
+ self.assert_exists("htmlcov/program.html")
+ self.assert_exists("htmlcov/program_py.html")
def test_has_date_stamp_in_files(self):
self.create_initial_files()
@@ -375,19 +430,22 @@ class HtmlTest(HtmlTestHelpers, CoverageTest):
with open("htmlcov/main_file_py.html") as f:
self.assert_correct_timestamp(f.read())
- def assert_correct_timestamp(self, html):
- """Extract the timestamp from `html`, and assert it is recent."""
- timestamp_pat = r"created at (\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})"
- m = re.search(timestamp_pat, html)
- self.assertTrue(m, "Didn't find a timestamp!")
- timestamp = datetime.datetime(*map(int, m.groups()))
- # The timestamp only records the minute, so the delta could be from
- # 12:00 to 12:01:59, or two minutes.
- self.assert_recent_datetime(
- timestamp,
- seconds=120,
- msg="Timestamp is wrong: {0}".format(timestamp),
- )
+ def test_reporting_on_unmeasured_file(self):
+ # It should be ok to ask for an HTML report on a file that wasn't even
+ # measured at all. https://bitbucket.org/ned/coveragepy/issues/403
+ self.create_initial_files()
+ self.make_file("other.py", "a = 1\n")
+ self.run_coverage(htmlargs=dict(morfs=['other.py']))
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/other_py.html")
+
+ def test_shining_panda_fix(self):
+ # The ShiningPanda plugin looks for "status.dat" to find HTML reports.
+ # Accommodate them, but only if we are running under Jenkins.
+ self.set_environ("JENKINS_URL", "Something or other")
+ self.create_initial_files()
+ self.run_coverage()
+ self.assert_exists("htmlcov/status.dat")
class HtmlStaticFileTest(CoverageTest):
@@ -396,9 +454,9 @@ class HtmlStaticFileTest(CoverageTest):
def setUp(self):
super(HtmlStaticFileTest, self).setUp()
self.original_path = list(coverage.html.STATIC_PATH)
- self.addCleanup(self.restore_static_path)
+ self.addCleanup(self.cleanup_static_path)
- def restore_static_path(self):
+ def cleanup_static_path(self):
"""A cleanup."""
coverage.html.STATIC_PATH = self.original_path
@@ -408,7 +466,7 @@ class HtmlStaticFileTest(CoverageTest):
coverage.html.STATIC_PATH.insert(0, "static_here")
self.make_file("main.py", "print(17)")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "main")
cov.html_report()
@@ -429,7 +487,7 @@ class HtmlStaticFileTest(CoverageTest):
coverage.html.STATIC_PATH.insert(0, "static_here")
self.make_file("main.py", "print(17)")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "main")
cov.html_report()
@@ -444,8 +502,310 @@ class HtmlStaticFileTest(CoverageTest):
coverage.html.STATIC_PATH = ["/xyzzy"]
self.make_file("main.py", "print(17)")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "main")
msg = "Couldn't find static file u?'.*'"
with self.assertRaisesRegex(CoverageException, msg):
cov.html_report()
+
+
+class HtmlGoldTests(CoverageGoldTest):
+ """Tests of HTML reporting that use gold files."""
+
+ root_dir = 'tests/farm/html'
+
+ def test_a(self):
+ self.output_dir("out/a")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage()
+ cov.start()
+ import a # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(a, directory='../out/a')
+
+ compare("gold_a", "out/a", size_within=10, file_pattern="*.html")
+ contains(
+ "out/a/a_py.html",
+ ('<span class="key">if</span> <span class="num">1</span> '
+ '<span class="op">&lt;</span> <span class="num">2</span>'),
+ (' <span class="nam">a</span> '
+ '<span class="op">=</span> <span class="num">3</span>'),
+ '<span class="pc_cov">67%</span>',
+ )
+ contains(
+ "out/a/index.html",
+ '<a href="a_py.html">a.py</a>',
+ '<span class="pc_cov">67%</span>',
+ '<td class="right" data-ratio="2 3">67%</td>',
+ )
+
+ def test_b_branch(self):
+ self.output_dir("out/b_branch")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(branch=True)
+ cov.start()
+ import b # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(b, directory="../out/b_branch")
+
+ compare("gold_b_branch", "out/b_branch", size_within=10, file_pattern="*.html")
+ contains(
+ "out/b_branch/b_py.html",
+ ('<span class="key">if</span> <span class="nam">x</span> '
+ '<span class="op">&lt;</span> <span class="num">2</span>'),
+ (' <span class="nam">a</span> <span class="op">=</span> '
+ '<span class="num">3</span>'),
+ '<span class="pc_cov">70%</span>',
+ ('<span class="annotate short">8&#x202F;&#x219B;&#x202F;11</span>'
+ '<span class="annotate long">line 8 didn\'t jump to line 11, '
+ 'because the condition on line 8 was never false</span>'),
+ ('<span class="annotate short">17&#x202F;&#x219B;&#x202F;exit</span>'
+ '<span class="annotate long">line 17 didn\'t return from function \'two\', '
+ 'because the condition on line 17 was never false</span>'),
+ ('<span class="annotate short">25&#x202F;&#x219B;&#x202F;26,&nbsp;&nbsp; '
+ '25&#x202F;&#x219B;&#x202F;28</span>'
+ '<span class="annotate long">2 missed branches: '
+ '1) line 25 didn\'t jump to line 26, '
+ 'because the condition on line 25 was never true, '
+ '2) line 25 didn\'t jump to line 28, '
+ 'because the condition on line 25 was never false</span>'),
+ )
+ contains(
+ "out/b_branch/index.html",
+ '<a href="b_py.html">b.py</a>',
+ '<span class="pc_cov">70%</span>',
+ '<td class="right" data-ratio="16 23">70%</td>',
+ )
+
+ def test_bom(self):
+ self.output_dir("out/bom")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage()
+ cov.start()
+ import bom # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(bom, directory="../out/bom")
+
+ compare("gold_bom", "out/bom", size_within=10, file_pattern="*.html")
+ contains(
+ "out/bom/bom_py.html",
+ '<span class="str">"3&#215;4 = 12, &#247;2 = 6&#177;0"</span>',
+ )
+
+ def test_isolatin1(self):
+ self.output_dir("out/isolatin1")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage()
+ cov.start()
+ import isolatin1 # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(isolatin1, directory="../out/isolatin1")
+
+ compare("gold_isolatin1", "out/isolatin1", size_within=10, file_pattern="*.html")
+ contains(
+ "out/isolatin1/isolatin1_py.html",
+ '<span class="str">"3&#215;4 = 12, &#247;2 = 6&#177;0"</span>',
+ )
+
+ def test_omit_1(self):
+ self.output_dir("out/omit_1")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(include=["./*"])
+ cov.start()
+ import main # pragma: nested # pylint: disable=unused-variable
+ cov.stop() # pragma: nested
+ cov.html_report(directory="../out/omit_1")
+
+ compare("gold_omit_1", "out/omit_1", size_within=10, file_pattern="*.html")
+
+ def test_omit_2(self):
+ self.output_dir("out/omit_2")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(include=["./*"])
+ cov.start()
+ import main # pragma: nested # pylint: disable=unused-variable
+ cov.stop() # pragma: nested
+ cov.html_report(directory="../out/omit_2", omit=["m1.py"])
+
+ compare("gold_omit_2", "out/omit_2", size_within=10, file_pattern="*.html")
+
+ def test_omit_3(self):
+ self.output_dir("out/omit_3")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(include=["./*"])
+ cov.start()
+ import main # pragma: nested # pylint: disable=unused-variable
+ cov.stop() # pragma: nested
+ cov.html_report(directory="../out/omit_3", omit=["m1.py", "m2.py"])
+
+ compare("gold_omit_3", "out/omit_3", size_within=10, file_pattern="*.html")
+
+ def test_omit_4(self):
+ self.output_dir("out/omit_4")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(config_file="omit4.ini", include=["./*"])
+ cov.start()
+ import main # pragma: nested # pylint: disable=unused-variable
+ cov.stop() # pragma: nested
+ cov.html_report(directory="../out/omit_4")
+
+ compare("gold_omit_4", "out/omit_4", size_within=10, file_pattern="*.html")
+
+ def test_omit_5(self):
+ self.output_dir("out/omit_5")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(config_file="omit5.ini", include=["./*"])
+ cov.start()
+ import main # pragma: nested # pylint: disable=unused-variable
+ cov.stop() # pragma: nested
+ cov.html_report()
+
+ compare("gold_omit_5", "out/omit_5", size_within=10, file_pattern="*.html")
+
+ def test_other(self):
+ self.output_dir("out/other")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ sys.path.insert(0, "../othersrc")
+ cov = coverage.Coverage(include=["./*", "../othersrc/*"])
+ cov.start()
+ import here # pragma: nested # pylint: disable=unused-variable
+ cov.stop() # pragma: nested
+ cov.html_report(directory="../out/other")
+
+ # Different platforms will name the "other" file differently. Rename it
+ for p in glob.glob("out/other/*_other_py.html"):
+ os.rename(p, "out/other/blah_blah_other_py.html")
+
+ compare("gold_other", "out/other", size_within=10, file_pattern="*.html")
+ contains(
+ "out/other/index.html",
+ '<a href="here_py.html">here.py</a>',
+ 'other_py.html">', 'other.py</a>',
+ )
+
+ def test_partial(self):
+ self.output_dir("out/partial")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(config_file="partial.ini")
+ cov.start()
+ import partial # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(partial, directory="../out/partial")
+
+ compare("gold_partial", "out/partial", size_within=10, file_pattern="*.html")
+ contains(
+ "out/partial/partial_py.html",
+ '<p id="t8" class="stm run hide_run">',
+ '<p id="t11" class="stm run hide_run">',
+ '<p id="t14" class="stm run hide_run">',
+ # The "if 0" and "if 1" statements are optimized away.
+ '<p id="t17" class="pln">',
+ # The "raise AssertionError" is excluded by regex in the .ini.
+ '<p id="t24" class="exc">',
+ )
+ contains(
+ "out/partial/index.html",
+ '<a href="partial_py.html">partial.py</a>',
+ )
+ contains(
+ "out/partial/index.html",
+ '<span class="pc_cov">100%</span>'
+ )
+
+ def test_styled(self):
+ self.output_dir("out/styled")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage()
+ cov.start()
+ import a # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(a, directory="../out/styled", extra_css="extra.css")
+
+ compare("gold_styled", "out/styled", size_within=10, file_pattern="*.html")
+ compare("gold_styled", "out/styled", size_within=10, file_pattern="*.css")
+ contains(
+ "out/styled/a_py.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>'),
+ (' <span class="nam">a</span> <span class="op">=</span> '
+ '<span class="num">3</span>'),
+ '<span class="pc_cov">67%</span>'
+ )
+ contains(
+ "out/styled/index.html",
+ '<link rel="stylesheet" href="extra.css" type="text/css">',
+ '<a href="a_py.html">a.py</a>',
+ '<span class="pc_cov">67%</span>'
+ )
+
+ def test_tabbed(self):
+ self.output_dir("out/tabbed")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage()
+ cov.start()
+ import tabbed # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(tabbed, directory="../out/tabbed")
+
+ # Editors like to change things, make sure our source file still has tabs.
+ contains("src/tabbed.py", "\tif x:\t\t\t\t\t# look nice")
+
+ contains(
+ "out/tabbed/tabbed_py.html",
+ '> <span class="key">if</span> '
+ '<span class="nam">x</span><span class="op">:</span>'
+ ' '
+ '<span class="com"># look nice</span>'
+ )
+
+ doesnt_contain("out/tabbed/tabbed_py.html", "\t")
+
+ def test_unicode(self):
+ self.output_dir("out/unicode")
+
+ with change_dir("src"):
+ # pylint: disable=import-error, redefined-builtin
+ cov = coverage.Coverage()
+ cov.start()
+ import unicode # pragma: nested
+ cov.stop() # pragma: nested
+ cov.html_report(unicode, directory="../out/unicode")
+
+ compare("gold_unicode", "out/unicode", size_within=10, file_pattern="*.html")
+ contains(
+ "out/unicode/unicode_py.html",
+ '<span class="str">"&#654;d&#729;&#477;b&#592;&#633;&#477;&#652;o&#596;"</span>',
+ )
+
+ contains_any(
+ "out/unicode/unicode_py.html",
+ '<span class="str">"db40,dd00: x&#56128;&#56576;"</span>',
+ '<span class="str">"db40,dd00: x&#917760;"</span>',
+ )
diff --git a/tests/test_misc.py b/tests/test_misc.py
index c5c03b71..96b5100b 100644
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -1,9 +1,14 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests of miscellaneous stuff."""
import sys
+import coverage
+from coverage.version import _make_url, _make_version
from coverage.misc import Hasher, file_be_gone
-from coverage import __version__, __url__
+
from tests.coveragetest import CoverageTest
@@ -29,6 +34,13 @@ class HasherTest(CoverageTest):
h2.update(b"Goodbye!")
self.assertNotEqual(h1.hexdigest(), h2.hexdigest())
+ def test_unicode_hashing(self):
+ h1 = Hasher()
+ h1.update(u"Hello, world! \N{SNOWMAN}")
+ h2 = Hasher()
+ h2.update(u"Goodbye!")
+ self.assertNotEqual(h1.hexdigest(), h2.hexdigest())
+
def test_dict_hashing(self):
h1 = Hasher()
h1.update({'a': 17, 'b': 23})
@@ -57,6 +69,36 @@ class RemoveFileTest(CoverageTest):
file_be_gone(".")
+class VersionTest(CoverageTest):
+ """Tests of version.py"""
+
+ run_in_temp_dir = False
+
+ def test_version_info(self):
+ # Make sure we didn't screw up the version_info tuple.
+ self.assertIsInstance(coverage.version_info, tuple)
+ self.assertEqual([type(d) for d in coverage.version_info], [int, int, int, str, int])
+ self.assertIn(coverage.version_info[3], ['alpha', 'beta', 'candidate', 'final'])
+
+ def test_make_version(self):
+ self.assertEqual(_make_version(4, 0, 0, 'alpha', 0), "4.0a0")
+ self.assertEqual(_make_version(4, 0, 0, 'alpha', 1), "4.0a1")
+ self.assertEqual(_make_version(4, 0, 0, 'final', 0), "4.0")
+ self.assertEqual(_make_version(4, 1, 2, 'beta', 3), "4.1.2b3")
+ self.assertEqual(_make_version(4, 1, 2, 'final', 0), "4.1.2")
+ self.assertEqual(_make_version(5, 10, 2, 'candidate', 7), "5.10.2rc7")
+
+ def test_make_url(self):
+ self.assertEqual(
+ _make_url(4, 0, 0, 'final', 0),
+ "https://coverage.readthedocs.io"
+ )
+ self.assertEqual(
+ _make_url(4, 1, 2, 'beta', 3),
+ "https://coverage.readthedocs.io/en/coverage-4.1.2b3"
+ )
+
+
class SetupPyTest(CoverageTest):
"""Tests of setup.py"""
@@ -69,8 +111,8 @@ class SetupPyTest(CoverageTest):
self.assertEqual(status, 0)
out = output.splitlines()
self.assertIn("measurement", out[0])
- self.assertEqual(out[1], __version__)
- self.assertEqual(out[2], __url__)
+ self.assertEqual(out[1], coverage.__version__)
+ self.assertEqual(out[2], coverage.__url__)
self.assertIn("Ned Batchelder", out[3])
def test_more_metadata(self):
diff --git a/tests/test_oddball.py b/tests/test_oddball.py
index 5288f022..e1099e62 100644
--- a/tests/test_oddball.py
+++ b/tests/test_oddball.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Oddball cases for testing coverage.py"""
import sys
@@ -107,7 +110,7 @@ class RecursionTest(CoverageTest):
i = 11
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "recur")
pytrace = (cov.collector.tracer_name() == "PyTracer")
@@ -173,10 +176,10 @@ class MemoryLeakTest(CoverageTest):
# Running the code 10k times shouldn't grow the ram much more than
# running it 10 times.
ram_growth = (ram_10k - ram_10) - (ram_10 - ram_0)
- if ram_growth > 100000:
+ if ram_growth > 100000: # pragma: if failure
fails += 1
- if fails > 8: # pragma: only failure
+ if fails > 8: # pragma: if failure
self.fail("RAM grew by %d" % (ram_growth))
@@ -209,7 +212,7 @@ class PyexpatTest(CoverageTest):
self.make_file("outer.py", "\n"*100 + "import trydom\na = 102\n")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.erase()
# Import the Python file, executing it.
@@ -223,6 +226,14 @@ class PyexpatTest(CoverageTest):
self.assertEqual(statements, [101, 102])
self.assertEqual(missing, [])
+ # Make sure pyexpat isn't recorded as a source file.
+ # https://bitbucket.org/ned/coveragepy/issues/419/nosource-no-source-for-code-path-to-c
+ files = cov.get_data().measured_files()
+ self.assertFalse(
+ any(f.endswith("pyexpat.c") for f in files),
+ "Pyexpat.c is in the measured files!: %r:" % (files,)
+ )
+
class ExceptionTest(CoverageTest):
"""I suspect different versions of Python deal with exceptions differently
@@ -310,7 +321,7 @@ class ExceptionTest(CoverageTest):
callnames = callnames.split()
calls = [getattr(sys.modules[cn], cn) for cn in callnames]
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.start()
# Call our list of functions: invoke the first, with the rest as
# an argument.
@@ -318,12 +329,12 @@ class ExceptionTest(CoverageTest):
cov.stop() # pragma: nested
# Clean the line data and compare to expected results.
- # The filenames are absolute, so keep just the base.
+ # The file names are absolute, so keep just the base.
clean_lines = {}
data = cov.get_data()
for callname in callnames:
filename = callname + ".py"
- lines = data.line_data(abs_file(filename))
+ lines = data.lines(abs_file(filename))
clean_lines[filename] = sorted(lines)
self.assertEqual(clean_lines, lines_expected)
@@ -342,7 +353,8 @@ class DoctestTest(CoverageTest):
# of coverage will get. Deleting the imported module here is
# enough: when the test imports doctest again, it will get a fresh
# copy without the monkeypatch.
- del sys.modules['doctest']
+ if 'doctest' in sys.modules:
+ del sys.modules['doctest']
def test_doctest(self):
self.check_coverage('''\
@@ -399,6 +411,46 @@ class GettraceTest(CoverageTest):
''',
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], "")
+ def test_setting_new_trace_function(self):
+ # https://bitbucket.org/ned/coveragepy/issues/436/disabled-coverage-ctracer-may-rise-from
+ self.check_coverage('''\
+ import sys
+
+ def tracer(frame, event, arg):
+ print("%s: %s @ %d" % (event, frame.f_code.co_filename, frame.f_lineno))
+ return tracer
+
+ def begin():
+ sys.settrace(tracer)
+
+ def collect():
+ t = sys.gettrace()
+ assert t is tracer, t
+
+ def test_unsets_trace():
+ begin()
+ collect()
+
+ old = sys.gettrace()
+ test_unsets_trace()
+ sys.settrace(old)
+ ''',
+ lines=[1, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20],
+ missing="4-5, 11-12",
+ )
+
+ out = self.stdout().replace(self.last_module_name, "coverage_test")
+
+ self.assertEqual(
+ out,
+ (
+ "call: coverage_test.py @ 10\n"
+ "line: coverage_test.py @ 11\n"
+ "line: coverage_test.py @ 12\n"
+ "return: coverage_test.py @ 12\n"
+ ),
+ )
+
class ExecTest(CoverageTest):
"""Tests of exec."""
@@ -421,7 +473,7 @@ class ExecTest(CoverageTest):
print("done") # line 35
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "main")
_, statements, missing, _ = cov.analysis("main.py")
@@ -430,3 +482,39 @@ class ExecTest(CoverageTest):
_, statements, missing, _ = cov.analysis("to_exec.py")
self.assertEqual(statements, [31])
self.assertEqual(missing, [])
+
+
+class MockingProtectionTest(CoverageTest):
+ """Tests about protecting ourselves from aggressive mocking.
+
+ https://bitbucket.org/ned/coveragepy/issues/416/coverage-40-is-causing-existing-unit-tests
+
+ """
+ def test_os_path_exists(self):
+ # To see if this test still detects the problem, change isolate_module
+ # in misc.py to simply return its argument. It should fail with a
+ # StopIteration error.
+ self.make_file("bug416.py", """\
+ import os.path
+
+ import mock
+
+ @mock.patch('os.path.exists')
+ def test_path_exists(mock_exists):
+ mock_exists.side_effect = [17]
+ print("in test")
+ import bug416a
+ print(bug416a.foo)
+ print(os.path.exists("."))
+
+ test_path_exists()
+ """)
+ self.make_file("bug416a.py", """\
+ print("bug416a.py")
+ foo = 23
+ """)
+
+ import py_compile
+ py_compile.compile("bug416a.py")
+ out = self.run_command("coverage run bug416.py")
+ self.assertEqual(out, "in test\nbug416a.py\n23\n17\n")
diff --git a/tests/test_parser.py b/tests/test_parser.py
index b3f41dd5..5fee823e 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -1,15 +1,19 @@
-"""Tests for Coverage.py's code parsing."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Tests for coverage.py's code parsing."""
import textwrap
from tests.coveragetest import CoverageTest
from coverage import env
+from coverage.misc import NotPython
from coverage.parser import PythonParser
class PythonParserTest(CoverageTest):
- """Tests for Coverage.py's Python code parsing."""
+ """Tests for coverage.py's Python code parsing."""
run_in_temp_dir = False
@@ -68,7 +72,7 @@ class PythonParserTest(CoverageTest):
b = 9
""")
self.assertEqual(parser.exit_counts(), {
- 1: 1, 2:1, 3:1, 4:1, 5:1, 6:1, 7:1, 8:1, 9:1
+ 1: 1, 2:1, 3:2, 4:1, 5:2, 6:1, 7:1, 8:1, 9:1
})
def test_excluded_classes(self):
@@ -77,7 +81,7 @@ class PythonParserTest(CoverageTest):
def __init__(self):
pass
- if 0: # nocover
+ if len([]): # nocover
class Bar:
pass
""")
@@ -113,15 +117,240 @@ class PythonParserTest(CoverageTest):
""")
self.assertEqual(parser.exit_counts(), { 1:1, 2:1, 3:1, 6:1 })
+ def test_indentation_error(self):
+ msg = (
+ "Couldn't parse '<code>' as Python source: "
+ "'unindent does not match any outer indentation level' at line 3"
+ )
+ with self.assertRaisesRegex(NotPython, msg):
+ _ = self.parse_source("""\
+ 0 spaces
+ 2
+ 1
+ """)
+
+ def test_token_error(self):
+ msg = "Couldn't parse '<code>' as Python source: 'EOF in multi-line string' at line 1"
+ with self.assertRaisesRegex(NotPython, msg):
+ _ = self.parse_source("""\
+ '''
+ """)
+
+ def test_decorator_pragmas(self):
+ parser = self.parse_source("""\
+ # 1
+
+ @foo(3) # nocover
+ @bar
+ def func(x, y=5):
+ return 6
+
+ class Foo: # this is the only statement.
+ '''9'''
+ @foo # nocover
+ def __init__(self):
+ '''12'''
+ return 13
+
+ @foo( # nocover
+ 16,
+ 17,
+ )
+ def meth(self):
+ return 20
+
+ @foo( # nocover
+ 23
+ )
+ def func(x=25):
+ return 26
+ """)
+ self.assertEqual(
+ parser.raw_statements,
+ set([3, 4, 5, 6, 8, 9, 10, 13, 15, 16, 17, 20, 22, 23, 25, 26])
+ )
+ self.assertEqual(parser.statements, set([8]))
+
+ def test_class_decorator_pragmas(self):
+ parser = self.parse_source("""\
+ class Foo(object):
+ def __init__(self):
+ self.x = 3
+
+ @foo # nocover
+ class Bar(object):
+ def __init__(self):
+ self.x = 8
+ """)
+ self.assertEqual(parser.raw_statements, set([1, 2, 3, 5, 6, 7, 8]))
+ self.assertEqual(parser.statements, set([1, 2, 3]))
+
+
+class ParserMissingArcDescriptionTest(CoverageTest):
+ """Tests for PythonParser.missing_arc_description."""
+
+ run_in_temp_dir = False
+
+ def parse_text(self, source):
+ """Parse Python source, and return the parser object."""
+ parser = PythonParser(textwrap.dedent(source))
+ parser.parse_source()
+ return parser
+
+ def test_missing_arc_description(self):
+ # This code is never run, so the actual values don't matter.
+ parser = self.parse_text(u"""\
+ if x:
+ print(2)
+ print(3)
+
+ def func5():
+ for x in range(6):
+ if x == 7:
+ break
+
+ def func10():
+ while something(11):
+ thing(12)
+ more_stuff(13)
+ """)
+ self.assertEqual(
+ parser.missing_arc_description(1, 2),
+ "line 1 didn't jump to line 2, because the condition on line 1 was never true"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(1, 3),
+ "line 1 didn't jump to line 3, because the condition on line 1 was never false"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(6, -5),
+ "line 6 didn't return from function 'func5', "
+ "because the loop on line 6 didn't complete"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(6, 7),
+ "line 6 didn't jump to line 7, because the loop on line 6 never started"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(11, 12),
+ "line 11 didn't jump to line 12, because the condition on line 11 was never true"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(11, 13),
+ "line 11 didn't jump to line 13, because the condition on line 11 was never false"
+ )
+
+ def test_missing_arc_descriptions_for_small_callables(self):
+ # We use 2.7 features here, so just skip this test on 2.6
+ if env.PYVERSION < (2, 7):
+ self.skipTest("No dict or set comps in 2.6")
+
+ parser = self.parse_text(u"""\
+ callables = [
+ lambda: 2,
+ (x for x in range(3)),
+ {x:1 for x in range(4)},
+ {x for x in range(5)},
+ ]
+ x = 7
+ """)
+ self.assertEqual(
+ parser.missing_arc_description(2, -2),
+ "line 2 didn't finish the lambda on line 2"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(3, -3),
+ "line 3 didn't finish the generator expression on line 3"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(4, -4),
+ "line 4 didn't finish the dictionary comprehension on line 4"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(5, -5),
+ "line 5 didn't finish the set comprehension on line 5"
+ )
+
+ def test_missing_arc_descriptions_for_exceptions(self):
+ parser = self.parse_text(u"""\
+ try:
+ pass
+ except ZeroDivideError:
+ print("whoops")
+ except ValueError:
+ print("yikes")
+ """)
+ self.assertEqual(
+ parser.missing_arc_description(3, 4),
+ "line 3 didn't jump to line 4, because the exception caught by line 3 didn't happen"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(5, 6),
+ "line 5 didn't jump to line 6, because the exception caught by line 5 didn't happen"
+ )
+
+ def test_missing_arc_descriptions_for_finally(self):
+ parser = self.parse_text(u"""\
+ def function():
+ for i in range(2):
+ try:
+ if something(4):
+ break
+ else:
+ if something(7):
+ continue
+ else:
+ continue
+ if also_this(11):
+ return 12
+ else:
+ raise Exception(14)
+ finally:
+ this_thing(16)
+ that_thing(17)
+ """)
+ self.assertEqual(
+ parser.missing_arc_description(16, 17),
+ "line 16 didn't jump to line 17, because the break on line 5 wasn't executed"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(16, 2),
+ "line 16 didn't jump to line 2, "
+ "because the continue on line 8 wasn't executed"
+ " or "
+ "the continue on line 10 wasn't executed"
+ )
+ self.assertEqual(
+ parser.missing_arc_description(16, -1),
+ "line 16 didn't except from function 'function', "
+ "because the raise on line 14 wasn't executed"
+ " or "
+ "line 16 didn't return from function 'function', "
+ "because the return on line 12 wasn't executed"
+ )
+
+ def test_missing_arc_descriptions_bug460(self):
+ parser = self.parse_text(u"""\
+ x = 1
+ d = {
+ 3: lambda: [],
+ 4: lambda: [],
+ }
+ x = 6
+ """)
+ self.assertEqual(
+ parser.missing_arc_description(2, -3),
+ "line 3 didn't finish the lambda on line 3",
+ )
+
class ParserFileTest(CoverageTest):
- """Tests for Coverage.py's code parsing from files."""
+ """Tests for coverage.py's code parsing from files."""
def parse_file(self, filename):
"""Parse `text` as source, and return the `PythonParser` used."""
- # pylint: disable=attribute-defined-outside-init
parser = PythonParser(filename=filename, exclude="nocover")
- self.statements, self.excluded = parser.parse_source()
+ parser.parse_source()
return parser
def test_line_endings(self):
@@ -168,8 +397,8 @@ class ParserFileTest(CoverageTest):
stderr=subprocess.PIPE).communicate()
""")
- self.parse_file("normal.py")
- self.assertEqual(self.statements, set([1]))
+ parser = self.parse_file("normal.py")
+ self.assertEqual(parser.statements, set([1]))
self.make_file("abrupt.py", """\
out, err = subprocess.Popen(
@@ -181,5 +410,5 @@ class ParserFileTest(CoverageTest):
with open("abrupt.py") as f:
self.assertEqual(f.read()[-1], ")")
- self.parse_file("abrupt.py")
- self.assertEqual(self.statements, set([1]))
+ parser = self.parse_file("abrupt.py")
+ self.assertEqual(parser.statements, set([1]))
diff --git a/tests/test_phystokens.py b/tests/test_phystokens.py
index 6fa4a441..15c6cb3a 100644
--- a/tests/test_phystokens.py
+++ b/tests/test_phystokens.py
@@ -1,33 +1,54 @@
-"""Tests for Coverage.py's improved tokenizer."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Tests for coverage.py's improved tokenizer."""
import os.path
import re
+import textwrap
from coverage import env
from coverage.phystokens import source_token_lines, source_encoding
-from coverage.phystokens import neuter_encoding_declaration
+from coverage.phystokens import neuter_encoding_declaration, compile_unicode
from coverage.python import get_python_source
from tests.coveragetest import CoverageTest
+# A simple program and its token stream.
SIMPLE = u"""\
# yay!
def foo():
say('two = %d' % 2)
"""
+SIMPLE_TOKENS = [
+ [('com', "# yay!")],
+ [('key', 'def'), ('ws', ' '), ('nam', 'foo'), ('op', '('), ('op', ')'), ('op', ':')],
+ [('ws', ' '), ('nam', 'say'), ('op', '('),
+ ('str', "'two = %d'"), ('ws', ' '), ('op', '%'),
+ ('ws', ' '), ('num', '2'), ('op', ')')],
+]
+
+# Mixed-whitespace program, and its token stream.
MIXED_WS = u"""\
def hello():
a="Hello world!"
\tb="indented"
"""
+MIXED_WS_TOKENS = [
+ [('key', 'def'), ('ws', ' '), ('nam', 'hello'), ('op', '('), ('op', ')'), ('op', ':')],
+ [('ws', ' '), ('nam', 'a'), ('op', '='), ('str', '"Hello world!"')],
+ [('ws', ' '), ('nam', 'b'), ('op', '='), ('str', '"indented"')],
+]
+
+# Where this file is, so we can find other files next to it.
HERE = os.path.dirname(__file__)
class PhysTokensTest(CoverageTest):
- """Tests for Coverage.py's improved tokenizer."""
+ """Tests for coverage.py's improved tokenizer."""
run_in_temp_dir = False
@@ -49,28 +70,16 @@ class PhysTokensTest(CoverageTest):
self.check_tokenization(get_python_source(fname))
def test_simple(self):
- self.assertEqual(list(source_token_lines(SIMPLE)),
- [
- [('com', "# yay!")],
- [('key', 'def'), ('ws', ' '), ('nam', 'foo'), ('op', '('),
- ('op', ')'), ('op', ':')],
- [('ws', ' '), ('nam', 'say'), ('op', '('),
- ('str', "'two = %d'"), ('ws', ' '), ('op', '%'),
- ('ws', ' '), ('num', '2'), ('op', ')')]
- ])
+ self.assertEqual(list(source_token_lines(SIMPLE)), SIMPLE_TOKENS)
self.check_tokenization(SIMPLE)
+ def test_missing_final_newline(self):
+ # We can tokenize source that is missing the final newline.
+ self.assertEqual(list(source_token_lines(SIMPLE.rstrip())), SIMPLE_TOKENS)
+
def test_tab_indentation(self):
# Mixed tabs and spaces...
- self.assertEqual(list(source_token_lines(MIXED_WS)),
- [
- [('key', 'def'), ('ws', ' '), ('nam', 'hello'), ('op', '('),
- ('op', ')'), ('op', ':')],
- [('ws', ' '), ('nam', 'a'), ('op', '='),
- ('str', '"Hello world!"')],
- [('ws', ' '), ('nam', 'b'), ('op', '='),
- ('str', '"indented"')],
- ])
+ self.assertEqual(list(source_token_lines(MIXED_WS)), MIXED_WS_TOKENS)
def test_tokenize_real_file(self):
# Check the tokenization of a real file (large, btw).
@@ -94,11 +103,15 @@ else:
ENCODING_DECLARATION_SOURCES = [
# Various forms from http://www.python.org/dev/peps/pep-0263/
- b"# coding=cp850\n\n",
- b"#!/usr/bin/python\n# -*- coding: cp850 -*-\n",
- b"#!/usr/bin/python\n# vim: set fileencoding=cp850:\n",
- b"# This Python file uses this encoding: cp850\n",
- b"# This file uses a different encoding:\n# coding: cp850\n",
+ (1, b"# coding=cp850\n\n", "cp850"),
+ (1, b"# coding=latin-1\n", "iso-8859-1"),
+ (1, b"# coding=iso-latin-1\n", "iso-8859-1"),
+ (1, b"#!/usr/bin/python\n# -*- coding: cp850 -*-\n", "cp850"),
+ (1, b"#!/usr/bin/python\n# vim: set fileencoding=cp850:\n", "cp850"),
+ (1, b"# This Python file uses this encoding: cp850\n", "cp850"),
+ (1, b"# This file uses a different encoding:\n# coding: cp850\n", "cp850"),
+ (1, b"\n# coding=cp850\n\n", "cp850"),
+ (2, b"# -*- coding:cp850 -*-\n# vim: fileencoding=cp850\n", "cp850"),
]
class SourceEncodingTest(CoverageTest):
@@ -107,10 +120,10 @@ class SourceEncodingTest(CoverageTest):
run_in_temp_dir = False
def test_detect_source_encoding(self):
- for source in ENCODING_DECLARATION_SOURCES:
+ for _, source, expected in ENCODING_DECLARATION_SOURCES:
self.assertEqual(
source_encoding(source),
- 'cp850',
+ expected,
"Wrong encoding in %r" % source
)
@@ -118,16 +131,11 @@ class SourceEncodingTest(CoverageTest):
if env.PYPY and env.PY3:
# PyPy3 gets this case wrong. Not sure what I can do about it,
# so skip the test.
- self.skip("PyPy3 is wrong about non-comment encoding. Skip it.")
+ self.skipTest("PyPy3 is wrong about non-comment encoding. Skip it.")
# Should not detect anything here
source = b'def parse(src, encoding=None):\n pass'
self.assertEqual(source_encoding(source), DEF_ENCODING)
- def test_detect_source_encoding_on_second_line(self):
- # A coding declaration should be found despite a first blank line.
- source = b"\n# coding=cp850\n\n"
- self.assertEqual(source_encoding(source), 'cp850')
-
def test_dont_detect_source_encoding_on_third_line(self):
# A coding declaration doesn't count on the third line.
source = b"\n\n# coding=cp850\n\n"
@@ -142,9 +150,19 @@ class SourceEncodingTest(CoverageTest):
source = b"\xEF\xBB\xBFtext = 'hello'\n"
self.assertEqual(source_encoding(source), 'utf-8-sig')
- # But it has to be the only authority.
+ def test_bom_with_encoding(self):
+ source = b"\xEF\xBB\xBF# coding: utf-8\ntext = 'hello'\n"
+ self.assertEqual(source_encoding(source), 'utf-8-sig')
+
+ def test_bom_is_wrong(self):
+ # A BOM with an explicit non-utf8 encoding is an error.
source = b"\xEF\xBB\xBF# coding: cp850\n"
- with self.assertRaises(SyntaxError):
+ with self.assertRaisesRegex(SyntaxError, "encoding problem: utf-8"):
+ source_encoding(source)
+
+ def test_unknown_encoding(self):
+ source = b"# coding: klingon\n"
+ with self.assertRaisesRegex(SyntaxError, "unknown encoding: klingon"):
source_encoding(source)
@@ -154,11 +172,107 @@ class NeuterEncodingDeclarationTest(CoverageTest):
run_in_temp_dir = False
def test_neuter_encoding_declaration(self):
- for source in ENCODING_DECLARATION_SOURCES:
+ for lines_diff_expected, source, _ in ENCODING_DECLARATION_SOURCES:
neutered = neuter_encoding_declaration(source.decode("ascii"))
neutered = neutered.encode("ascii")
+
+ # The neutered source should have the same number of lines.
+ source_lines = source.splitlines()
+ neutered_lines = neutered.splitlines()
+ self.assertEqual(len(source_lines), len(neutered_lines))
+
+ # Only one of the lines should be different.
+ lines_different = sum(
+ int(nline != sline) for nline, sline in zip(neutered_lines, source_lines)
+ )
+ self.assertEqual(lines_diff_expected, lines_different)
+
+ # The neutered source will be detected as having no encoding
+ # declaration.
self.assertEqual(
source_encoding(neutered),
DEF_ENCODING,
"Wrong encoding in %r" % neutered
)
+
+ def test_two_encoding_declarations(self):
+ input_src = textwrap.dedent(u"""\
+ # -*- coding: ascii -*-
+ # -*- coding: utf-8 -*-
+ # -*- coding: utf-16 -*-
+ """)
+ expected_src = textwrap.dedent(u"""\
+ # (deleted declaration) -*-
+ # (deleted declaration) -*-
+ # -*- coding: utf-16 -*-
+ """)
+ output_src = neuter_encoding_declaration(input_src)
+ self.assertEqual(expected_src, output_src)
+
+ def test_one_encoding_declaration(self):
+ input_src = textwrap.dedent(u"""\
+ # -*- coding: utf-16 -*-
+ # Just a comment.
+ # -*- coding: ascii -*-
+ """)
+ expected_src = textwrap.dedent(u"""\
+ # (deleted declaration) -*-
+ # Just a comment.
+ # -*- coding: ascii -*-
+ """)
+ output_src = neuter_encoding_declaration(input_src)
+ self.assertEqual(expected_src, output_src)
+
+
+class Bug529Test(CoverageTest):
+ """Test of bug 529"""
+
+ def test_bug_529(self):
+ self.make_file("the_test.py", '''\
+ # -*- coding: utf-8 -*-
+ import unittest
+ class FailsUnderCoverageTest(unittest.TestCase):
+ def test_fails_under_coverage(self):
+ src1 = u"""\\
+ # -*- coding: utf-8 -*-
+ # Just a comment.
+ """
+ src2 = u"""\\
+ # -*- coding: utf-8 -*-
+ # Just a comment.
+ """
+ self.assertEqual(src1, src2)
+
+ if __name__ == "__main__":
+ unittest.main()
+ ''')
+ status, out = self.run_command_status("coverage run the_test.py")
+ self.assertEqual(status, 0)
+ self.assertIn("OK", out)
+ # If this test fails, the output will be super-confusing, because it
+ # has a failing unit test contained within the failing unit test.
+
+
+class CompileUnicodeTest(CoverageTest):
+ """Tests of compiling Unicode strings."""
+
+ run_in_temp_dir = False
+
+ def assert_compile_unicode(self, source):
+ """Assert that `source` will compile properly with `compile_unicode`."""
+ source += u"a = 42\n"
+ # This doesn't raise an exception:
+ code = compile_unicode(source, "<string>", "exec")
+ globs = {}
+ exec(code, globs)
+ self.assertEqual(globs['a'], 42)
+
+ def test_cp1252(self):
+ uni = u"""# coding: cp1252\n# \u201C curly \u201D\n"""
+ self.assert_compile_unicode(uni)
+
+ def test_double_coding_declaration(self):
+ # Build this string in a weird way so that actual vim's won't try to
+ # interpret it...
+ uni = u"# -*- coding:utf-8 -*-\n# v" "im: fileencoding=utf-8\n"
+ self.assert_compile_unicode(uni)
diff --git a/tests/test_pickle2json.py b/tests/test_pickle2json.py
new file mode 100644
index 00000000..433dade6
--- /dev/null
+++ b/tests/test_pickle2json.py
@@ -0,0 +1,55 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Tests for coverage.pickle2json"""
+
+from coverage.backward import pickle, iitems
+from coverage.data import CoverageData
+from coverage.pickle2json import pickle2json
+
+from tests.coveragetest import CoverageTest
+from tests.test_data import DataTestHelpers, LINES_1, ARCS_3
+
+
+class Pickle2JsonTestInTempDir(DataTestHelpers, CoverageTest):
+ """Tests pickle2json.py."""
+
+ no_files_in_temp_dir = True
+
+ def write_pickled_file(self, covdata, filename):
+ """Write coverage data as pickled `filename`."""
+ # Create the file data.
+ file_data = {}
+
+ if covdata._arcs:
+ file_data['arcs'] = dict((f, list(amap)) for f, amap in iitems(covdata._arcs))
+ else:
+ file_data['lines'] = dict((f, list(lmap)) for f, lmap in iitems(covdata._lines))
+
+ # Write the pickle to the file.
+ with open(filename, 'wb') as file_obj:
+ pickle.dump(file_data, file_obj, 2)
+
+ def test_read_write_lines_pickle(self):
+ # Test the old pickle format.
+ covdata1 = CoverageData()
+ covdata1.add_lines(LINES_1)
+ self.write_pickled_file(covdata1, "lines.pkl")
+
+ pickle2json("lines.pkl", "lines.json")
+
+ covdata2 = CoverageData()
+ covdata2.read_file("lines.json")
+ self.assert_lines1_data(covdata2)
+
+ def test_read_write_arcs_pickle(self):
+ # Test the old pickle format.
+ covdata1 = CoverageData()
+ covdata1.add_arcs(ARCS_3)
+ self.write_pickled_file(covdata1, "arcs.pkl")
+
+ pickle2json("arcs.pkl", "arcs.json")
+
+ covdata2 = CoverageData()
+ covdata2.read_file("arcs.json")
+ self.assert_arcs3_data(covdata2)
diff --git a/tests/test_plugins.py b/tests/test_plugins.py
index 2f58eceb..8ea0a8f5 100644
--- a/tests/test_plugins.py
+++ b/tests/test_plugins.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for plugins."""
import os.path
@@ -145,9 +148,9 @@ class PluginTest(CoverageTest):
self.assert_doesnt_exist("evidence.out")
cov = coverage.Coverage()
- cov.config["run:plugins"] = ["my_plugin"]
+ cov.set_option("run:plugins", ["my_plugin"])
cov.start()
- cov.stop()
+ cov.stop() # pragma: nested
with open("evidence.out") as f:
self.assertEqual(f.read(), "we are here!")
@@ -156,7 +159,7 @@ class PluginTest(CoverageTest):
# Prove that a missing plugin will raise an ImportError.
with self.assertRaises(ImportError):
cov = coverage.Coverage()
- cov.config["run:plugins"] = ["does_not_exist_woijwoicweo"]
+ cov.set_option("run:plugins", ["does_not_exist_woijwoicweo"])
cov.start()
cov.stop()
@@ -167,7 +170,7 @@ class PluginTest(CoverageTest):
""")
with self.assertRaises(ZeroDivisionError):
cov = coverage.Coverage()
- cov.config["run:plugins"] = ["plugin_over_zero"]
+ cov.set_option("run:plugins", ["plugin_over_zero"])
cov.start()
cov.stop()
@@ -185,7 +188,7 @@ class PluginTest(CoverageTest):
debug_out = StringIO()
cov = coverage.Coverage(debug=["sys"])
cov._debug_file = debug_out
- cov.config["run:plugins"] = ["plugin_sys_info"]
+ cov.set_option("run:plugins", ["plugin_sys_info"])
cov.load()
out_lines = debug_out.getvalue().splitlines()
@@ -209,7 +212,7 @@ class PluginTest(CoverageTest):
debug_out = StringIO()
cov = coverage.Coverage(debug=["sys"])
cov._debug_file = debug_out
- cov.config["run:plugins"] = ["plugin_no_sys_info"]
+ cov.set_option("run:plugins", ["plugin_no_sys_info"])
cov.load()
out_lines = debug_out.getvalue().splitlines()
@@ -245,24 +248,18 @@ class PluginWarningOnPyTracer(CoverageTest):
"""Test that we get a controlled exception with plugins on PyTracer."""
def test_exception_if_plugins_on_pytracer(self):
if env.C_TRACER:
- self.skip("This test is only about PyTracer.")
+ self.skipTest("This test is only about PyTracer.")
self.make_file("simple.py", """a = 1""")
cov = coverage.Coverage()
- cov.config["run:plugins"] = ["tests.plugin1"]
-
- warnings = []
- def capture_warning(msg):
- """A fake implementation of Coverage._warn, to capture warnings."""
- warnings.append(msg)
- cov._warn = capture_warning
+ cov.set_option("run:plugins", ["tests.plugin1"])
- self.start_import_stop(cov, "simple")
- self.assertIn(
- "Plugin file tracers (tests.plugin1.Plugin) aren't supported with PyTracer",
- warnings
- )
+ expected_warnings = [
+ r"Plugin file tracers \(tests.plugin1.Plugin\) aren't supported with PyTracer",
+ ]
+ with self.assert_warnings(cov, expected_warnings):
+ self.start_import_stop(cov, "simple")
class FileTracerTest(CoverageTest):
@@ -271,7 +268,7 @@ class FileTracerTest(CoverageTest):
def setUp(self):
super(FileTracerTest, self).setUp()
if not env.C_TRACER:
- self.skip("Plugins are only supported with the C tracer.")
+ self.skipTest("Plugins are only supported with the C tracer.")
class GoodPluginTest(FileTracerTest):
@@ -291,7 +288,7 @@ class GoodPluginTest(FileTracerTest):
cov = coverage.Coverage()
CheckUniqueFilenames.hook(cov, '_should_trace')
CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
- cov.config["run:plugins"] = ["tests.plugin1"]
+ cov.set_option("run:plugins", ["tests.plugin1"])
# Import the Python file, executing it.
self.start_import_stop(cov, "simple")
@@ -356,7 +353,7 @@ class GoodPluginTest(FileTracerTest):
cov = coverage.Coverage(omit=["*quux*"])
CheckUniqueFilenames.hook(cov, '_should_trace')
CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
- cov.config["run:plugins"] = ["tests.plugin2"]
+ cov.set_option("run:plugins", ["tests.plugin2"])
self.start_import_stop(cov, "caller")
@@ -366,20 +363,20 @@ class GoodPluginTest(FileTracerTest):
_, statements, missing, _ = cov.analysis("foo_7.html")
self.assertEqual(statements, [1, 2, 3, 4, 5, 6, 7])
self.assertEqual(missing, [1, 2, 3, 6, 7])
- self.assertIn("foo_7.html", cov.data.summary())
+ self.assertIn("foo_7.html", cov.data.line_counts())
_, statements, missing, _ = cov.analysis("bar_4.html")
self.assertEqual(statements, [1, 2, 3, 4])
self.assertEqual(missing, [1, 4])
- self.assertIn("bar_4.html", cov.data.summary())
+ self.assertIn("bar_4.html", cov.data.line_counts())
- self.assertNotIn("quux_5.html", cov.data.summary())
+ self.assertNotIn("quux_5.html", cov.data.line_counts())
if env.PY2:
_, statements, missing, _ = cov.analysis("uni_3.html")
self.assertEqual(statements, [1, 2, 3])
self.assertEqual(missing, [1])
- self.assertIn("uni_3.html", cov.data.summary())
+ self.assertIn("uni_3.html", cov.data.line_counts())
def test_plugin2_with_branch(self):
self.make_render_and_caller()
@@ -387,7 +384,7 @@ class GoodPluginTest(FileTracerTest):
cov = coverage.Coverage(branch=True, omit=["*quux*"])
CheckUniqueFilenames.hook(cov, '_should_trace')
CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
- cov.config["run:plugins"] = ["tests.plugin2"]
+ cov.set_option("run:plugins", ["tests.plugin2"])
self.start_import_stop(cov, "caller")
@@ -406,12 +403,12 @@ class GoodPluginTest(FileTracerTest):
self.make_render_and_caller()
cov = coverage.Coverage(branch=True, omit=["*quux*"])
- cov.config["run:plugins"] = ["tests.plugin2"]
+ cov.set_option("run:plugins", ["tests.plugin2"])
self.start_import_stop(cov, "caller")
repout = StringIO()
- total = cov.report(file=repout, include=["*.html"], omit=["uni*.html"])
+ total = cov.report(file=repout, include=["*.html"], omit=["uni*.html"], show_missing=True)
report = repout.getvalue().splitlines()
expected = [
'Name Stmts Miss Branch BrPart Cover Missing',
@@ -419,7 +416,7 @@ class GoodPluginTest(FileTracerTest):
'bar_4.html 4 2 0 0 50% 1, 4',
'foo_7.html 7 5 0 0 29% 1-3, 6-7',
'--------------------------------------------------------',
- 'TOTAL 11 7 0 0 36% ',
+ 'TOTAL 11 7 0 0 36%',
]
self.assertEqual(report, expected)
self.assertAlmostEqual(total, 36.36, places=2)
@@ -428,7 +425,7 @@ class GoodPluginTest(FileTracerTest):
self.make_render_and_caller()
cov = coverage.Coverage(branch=True, omit=["*quux*"])
- cov.config["run:plugins"] = ["tests.plugin2"]
+ cov.set_option("run:plugins", ["tests.plugin2"])
self.start_import_stop(cov, "caller")
@@ -443,7 +440,7 @@ class GoodPluginTest(FileTracerTest):
self.make_render_and_caller()
cov = coverage.Coverage(branch=True, omit=["*quux*"])
- cov.config["run:plugins"] = ["tests.plugin2"]
+ cov.set_option("run:plugins", ["tests.plugin2"])
self.start_import_stop(cov, "caller")
@@ -456,23 +453,70 @@ class GoodPluginTest(FileTracerTest):
for snip in [
'filename="bar_4.html" line-rate="0.5" name="bar_4.html"',
'filename="foo_7.html" line-rate="0.2857" name="foo_7.html"',
- ]:
+ ]:
self.assertIn(snip, xml)
+ def test_defer_to_python(self):
+ # A plugin that measures, but then wants built-in python reporting.
+ self.make_file("fairly_odd_plugin.py", """\
+ # A plugin that claims all the odd lines are executed, and none of
+ # the even lines, and then punts reporting off to the built-in
+ # Python reporting.
+ import coverage.plugin
+ class Plugin(coverage.CoveragePlugin):
+ def file_tracer(self, filename):
+ return OddTracer(filename)
+ def file_reporter(self, filename):
+ return "python"
+
+ class OddTracer(coverage.plugin.FileTracer):
+ def __init__(self, filename):
+ self.filename = filename
+ def source_filename(self):
+ return self.filename
+ def line_number_range(self, frame):
+ lineno = frame.f_lineno
+ if lineno % 2:
+ return (lineno, lineno)
+ else:
+ return (-1, -1)
+
+ def coverage_init(reg, options):
+ reg.add_file_tracer(Plugin())
+ """)
+ self.make_file("unsuspecting.py", """\
+ a = 1
+ b = 2
+ c = 3
+ d = 4
+ e = 5
+ f = 6
+ """)
+ cov = coverage.Coverage(include=["unsuspecting.py"])
+ cov.set_option("run:plugins", ["fairly_odd_plugin"])
+ self.start_import_stop(cov, "unsuspecting")
+
+ repout = StringIO()
+ total = cov.report(file=repout, show_missing=True)
+ report = repout.getvalue().splitlines()
+ expected = [
+ 'Name Stmts Miss Cover Missing',
+ '-----------------------------------------------',
+ 'unsuspecting.py 6 3 50% 2, 4, 6',
+ ]
+ self.assertEqual(report, expected)
+ self.assertEqual(total, 50)
+
class BadPluginTest(FileTracerTest):
"""Test error handling around plugins."""
- def run_bad_plugin(self, module_name, plugin_name, our_error=True):
- """Run a file, and see that the plugin failed.
-
- `plugin_name` is the name of the plugin to use.
+ def run_plugin(self, module_name):
+ """Run a plugin with the given module_name.
- `our_error` is True if the error reported to the user will be an
- explicit error in our test code, marked with an # Oh noes! comment.
+ Uses a few fixed Python files.
- The plugin will be disabled, and we check that a warning is output
- explaining why.
+ Returns the Coverage object.
"""
self.make_file("simple.py", """\
@@ -494,8 +538,26 @@ class BadPluginTest(FileTracerTest):
""")
cov = coverage.Coverage()
- cov.config["run:plugins"] = [module_name]
+ cov.set_option("run:plugins", [module_name])
self.start_import_stop(cov, "simple")
+ return cov
+
+ def run_bad_plugin(self, module_name, plugin_name, our_error=True, excmsg=None):
+ """Run a file, and see that the plugin failed.
+
+ `module_name` and `plugin_name` is the module and name of the plugin to
+ use.
+
+ `our_error` is True if the error reported to the user will be an
+ explicit error in our test code, marked with an '# Oh noes!' comment.
+
+ `excmsg`, if provided, is text that should appear in the stderr.
+
+ The plugin will be disabled, and we check that a warning is output
+ explaining why.
+
+ """
+ self.run_plugin(module_name)
stderr = self.stderr()
print(stderr) # for diagnosing test failures.
@@ -509,11 +571,14 @@ class BadPluginTest(FileTracerTest):
# The message can be in two forms:
# Disabling plugin '...' due to previous exception
# or:
- # Disabling plugin '...' due to an excepton:
+ # Disabling plugin '...' due to an exception:
msg = "Disabling plugin '%s.%s' due to " % (module_name, plugin_name)
warnings = stderr.count(msg)
self.assertEqual(warnings, 1)
+ if excmsg:
+ self.assertIn(excmsg, stderr)
+
def test_file_tracer_has_no_file_tracer_method(self):
self.make_file("bad_plugin.py", """\
class Plugin(object):
@@ -524,6 +589,45 @@ class BadPluginTest(FileTracerTest):
""")
self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
+ def test_file_tracer_has_inherited_sourcefilename_method(self):
+ self.make_file("bad_plugin.py", """\
+ import coverage
+ class Plugin(coverage.CoveragePlugin):
+ def file_tracer(self, filename):
+ # Just grab everything.
+ return FileTracer()
+
+ class FileTracer(coverage.FileTracer):
+ pass
+
+ def coverage_init(reg, options):
+ reg.add_file_tracer(Plugin())
+ """)
+ self.run_bad_plugin(
+ "bad_plugin", "Plugin", our_error=False,
+ excmsg="Class 'bad_plugin.FileTracer' needs to implement source_filename()",
+ )
+
+ def test_plugin_has_inherited_filereporter_method(self):
+ self.make_file("bad_plugin.py", """\
+ import coverage
+ class Plugin(coverage.CoveragePlugin):
+ def file_tracer(self, filename):
+ # Just grab everything.
+ return FileTracer()
+
+ class FileTracer(coverage.FileTracer):
+ def source_filename(self):
+ return "foo.xxx"
+
+ def coverage_init(reg, options):
+ reg.add_file_tracer(Plugin())
+ """)
+ cov = self.run_plugin("bad_plugin")
+ expected_msg = "Plugin 'bad_plugin.Plugin' needs to implement file_reporter()"
+ with self.assertRaisesRegex(NotImplementedError, expected_msg):
+ cov.report()
+
def test_file_tracer_fails(self):
self.make_file("bad_plugin.py", """\
import coverage.plugin
diff --git a/tests/test_process.py b/tests/test_process.py
index 78fba81a..81cd5ade 100644
--- a/tests/test_process.py
+++ b/tests/test_process.py
@@ -1,29 +1,35 @@
+# coding: utf8
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for process behavior of coverage.py."""
import glob
import os
import os.path
+import re
import sys
import textwrap
import coverage
-from coverage import env
+from coverage import env, CoverageData
+from coverage.misc import output_encoding
from tests.coveragetest import CoverageTest
-HERE = os.path.dirname(__file__)
+TRY_EXECFILE = os.path.join(os.path.dirname(__file__), "modules/process_test/try_execfile.py")
class ProcessTest(CoverageTest):
"""Tests of the per-process behavior of coverage.py."""
+ def data_files(self):
+ """Return the names of coverage data files in this directory."""
+ return [f for f in os.listdir('.') if (f.startswith('.coverage.') or f == '.coverage')]
+
def number_of_data_files(self):
"""Return the number of coverage data files in this directory."""
- num = 0
- for f in os.listdir('.'):
- if f.startswith('.coverage.') or f == '.coverage':
- num += 1
- return num
+ return len(self.data_files())
def test_save_on_exit(self):
self.make_file("mycode.py", """\
@@ -36,7 +42,7 @@ class ProcessTest(CoverageTest):
self.assert_exists(".coverage")
def test_environment(self):
- # Checks that we can import modules from the test directory at all!
+ # Checks that we can import modules from the tests directory at all!
self.make_file("mycode.py", """\
import covmod1
import covmodzip1
@@ -49,7 +55,8 @@ class ProcessTest(CoverageTest):
self.assert_exists(".coverage")
self.assertEqual(out, 'done\n')
- def test_combine_parallel_data(self):
+ def make_b_or_c_py(self):
+ """Create b_or_c.py, used in a few of these tests."""
self.make_file("b_or_c.py", """\
import sys
a = 1
@@ -61,9 +68,12 @@ class ProcessTest(CoverageTest):
print('done')
""")
+ def test_combine_parallel_data(self):
+ self.make_b_or_c_py()
out = self.run_command("coverage run -p b_or_c.py b")
self.assertEqual(out, 'done\n')
self.assert_doesnt_exist(".coverage")
+ self.assertEqual(self.number_of_data_files(), 1)
out = self.run_command("coverage run -p b_or_c.py c")
self.assertEqual(out, 'done\n')
@@ -83,19 +93,57 @@ class ProcessTest(CoverageTest):
# executed.
data = coverage.CoverageData()
data.read_file(".coverage")
- self.assertEqual(data.summary()['b_or_c.py'], 7)
+ self.assertEqual(data.line_counts()['b_or_c.py'], 7)
+
+ # Running combine again should fail, because there are no parallel data
+ # files to combine.
+ status, out = self.run_command_status("coverage combine")
+ self.assertEqual(status, 1)
+ self.assertEqual(out, "No data to combine\n")
+
+ # And the originally combined data is still there.
+ data = coverage.CoverageData()
+ data.read_file(".coverage")
+ self.assertEqual(data.line_counts()['b_or_c.py'], 7)
+
+ def test_combine_parallel_data_with_a_corrupt_file(self):
+ self.make_b_or_c_py()
+ out = self.run_command("coverage run -p b_or_c.py b")
+ self.assertEqual(out, 'done\n')
+ self.assert_doesnt_exist(".coverage")
+ self.assertEqual(self.number_of_data_files(), 1)
+
+ out = self.run_command("coverage run -p b_or_c.py c")
+ self.assertEqual(out, 'done\n')
+ 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)
+
+ # Make a bogus data file.
+ self.make_file(".coverage.bad", "This isn't a coverage data file.")
+
+ # Combine the parallel coverage data files into .coverage .
+ out = self.run_command("coverage combine")
+ self.assert_exists(".coverage")
+ self.assert_exists(".coverage.bad")
+ warning_regex = (
+ r"Coverage.py warning: Couldn't read data from '.*\.coverage\.bad': "
+ r"CoverageException: Doesn't seem to be a coverage\.py data file"
+ )
+ self.assertRegex(out, warning_regex)
+
+ # After combining, those two should be the only data files.
+ self.assertEqual(self.number_of_data_files(), 2)
+
+ # Read the coverage file and see that b_or_c.py has all 7 lines
+ # executed.
+ data = coverage.CoverageData()
+ data.read_file(".coverage")
+ self.assertEqual(data.line_counts()['b_or_c.py'], 7)
def test_combine_parallel_data_in_two_steps(self):
- self.make_file("b_or_c.py", """\
- import sys
- a = 1
- if sys.argv[1] == 'b':
- b = 1
- else:
- c = 1
- d = 1
- print('done')
- """)
+ self.make_b_or_c_py()
out = self.run_command("coverage run -p b_or_c.py b")
self.assertEqual(out, 'done\n')
@@ -107,13 +155,13 @@ class ProcessTest(CoverageTest):
self.assert_exists(".coverage")
self.assertEqual(self.number_of_data_files(), 1)
- out = self.run_command("coverage run --append -p b_or_c.py c")
+ out = self.run_command("coverage run -p b_or_c.py c")
self.assertEqual(out, 'done\n')
self.assert_exists(".coverage")
self.assertEqual(self.number_of_data_files(), 2)
# Combine the parallel coverage data files into .coverage .
- self.run_command("coverage combine")
+ self.run_command("coverage combine --append")
self.assert_exists(".coverage")
# After combining, there should be only the .coverage file.
@@ -123,20 +171,68 @@ class ProcessTest(CoverageTest):
# executed.
data = coverage.CoverageData()
data.read_file(".coverage")
- self.assertEqual(data.summary()['b_or_c.py'], 7)
+ self.assertEqual(data.line_counts()['b_or_c.py'], 7)
- def test_combine_with_rc(self):
- self.make_file("b_or_c.py", """\
- import sys
- a = 1
- if sys.argv[1] == 'b':
- b = 1
- else:
- c = 1
- d = 1
- print('done')
+ def test_append_data(self):
+ self.make_b_or_c_py()
+
+ out = self.run_command("coverage run b_or_c.py b")
+ self.assertEqual(out, 'done\n')
+ self.assert_exists(".coverage")
+ self.assertEqual(self.number_of_data_files(), 1)
+
+ out = self.run_command("coverage run --append b_or_c.py c")
+ self.assertEqual(out, 'done\n')
+ self.assert_exists(".coverage")
+ self.assertEqual(self.number_of_data_files(), 1)
+
+ # Read the coverage file and see that b_or_c.py has all 7 lines
+ # executed.
+ data = coverage.CoverageData()
+ data.read_file(".coverage")
+ self.assertEqual(data.line_counts()['b_or_c.py'], 7)
+
+ def test_append_data_with_different_file(self):
+ self.make_b_or_c_py()
+
+ self.make_file(".coveragerc", """\
+ [run]
+ data_file = .mycovdata
""")
+ out = self.run_command("coverage run b_or_c.py b")
+ self.assertEqual(out, 'done\n')
+ self.assert_doesnt_exist(".coverage")
+ self.assert_exists(".mycovdata")
+
+ out = self.run_command("coverage run --append b_or_c.py c")
+ self.assertEqual(out, 'done\n')
+ self.assert_doesnt_exist(".coverage")
+ self.assert_exists(".mycovdata")
+
+ # Read the coverage file and see that b_or_c.py has all 7 lines
+ # executed.
+ data = coverage.CoverageData()
+ data.read_file(".mycovdata")
+ self.assertEqual(data.line_counts()['b_or_c.py'], 7)
+
+ def test_append_can_create_a_data_file(self):
+ self.make_b_or_c_py()
+
+ out = self.run_command("coverage run --append b_or_c.py b")
+ self.assertEqual(out, 'done\n')
+ self.assert_exists(".coverage")
+ self.assertEqual(self.number_of_data_files(), 1)
+
+ # Read the coverage file and see that b_or_c.py has only 6 lines
+ # executed.
+ data = coverage.CoverageData()
+ data.read_file(".coverage")
+ self.assertEqual(data.line_counts()['b_or_c.py'], 6)
+
+ def test_combine_with_rc(self):
+ self.make_b_or_c_py()
+
self.make_file(".coveragerc", """\
[run]
parallel = true
@@ -165,7 +261,7 @@ class ProcessTest(CoverageTest):
# executed.
data = coverage.CoverageData()
data.read_file(".coverage")
- self.assertEqual(data.summary()['b_or_c.py'], 7)
+ self.assertEqual(data.line_counts()['b_or_c.py'], 7)
# Reporting should still work even with the .rc file
out = self.run_command("coverage report")
@@ -219,13 +315,30 @@ class ProcessTest(CoverageTest):
# files have been combined together.
data = coverage.CoverageData()
data.read_file(".coverage")
- summary = data.summary(fullpath=True)
+ summary = data.line_counts(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_erase_parallel(self):
+ self.make_file(".coveragerc", """\
+ [run]
+ data_file = data.dat
+ parallel = True
+ """)
+ self.make_file("data.dat")
+ self.make_file("data.dat.fooey")
+ self.make_file("data.dat.gooey")
+ self.make_file(".coverage")
+
+ self.run_command("coverage erase")
+ self.assert_doesnt_exist("data.dat")
+ self.assert_doesnt_exist("data.dat.fooey")
+ self.assert_doesnt_exist("data.dat.gooey")
+ self.assert_exists(".coverage")
+
def test_missing_source_file(self):
# Check what happens if the source is missing when reporting happens.
self.make_file("fleeting.py", """\
@@ -323,19 +436,44 @@ class ProcessTest(CoverageTest):
self.assertEqual(status, status2)
self.assertEqual(status, 0)
+ def assert_execfile_output(self, out):
+ """Assert that the output we got is a successful run of try_execfile.py"""
+ self.assertIn('"DATA": "xyzzy"', out)
+
def test_coverage_run_is_like_python(self):
- tryfile = os.path.join(HERE, "try_execfile.py")
- with open(tryfile) as f:
+ with open(TRY_EXECFILE) as f:
self.make_file("run_me.py", f.read())
out_cov = self.run_command("coverage run run_me.py")
out_py = self.run_command("python run_me.py")
self.assertMultiLineEqual(out_cov, out_py)
+ self.assert_execfile_output(out_cov)
def test_coverage_run_dashm_is_like_python_dashm(self):
# These -m commands assume the coverage tree is on the path.
- out_cov = self.run_command("coverage run -m tests.try_execfile")
- out_py = self.run_command("python -m tests.try_execfile")
+ out_cov = self.run_command("coverage run -m process_test.try_execfile")
+ out_py = self.run_command("python -m process_test.try_execfile")
+ self.assertMultiLineEqual(out_cov, out_py)
+ self.assert_execfile_output(out_cov)
+
+ def test_coverage_run_dir_is_like_python_dir(self):
+ with open(TRY_EXECFILE) as f:
+ self.make_file("with_main/__main__.py", f.read())
+ out_cov = self.run_command("coverage run with_main")
+ out_py = self.run_command("python with_main")
+
+ # The coverage.py results are not identical to the Python results, and
+ # I don't know why. For now, ignore those failures. If someone finds
+ # a real problem with the discrepancies, we can work on it some more.
+ ignored = r"__file__|__loader__|__package__"
+ # PyPy includes the current directory in the path when running a
+ # directory, while CPython and coverage.py do not. Exclude that from
+ # the comparison also...
+ if env.PYPY:
+ ignored += "|"+re.escape(os.getcwd())
+ out_cov = remove_matching_lines(out_cov, ignored)
+ out_py = remove_matching_lines(out_py, ignored)
self.assertMultiLineEqual(out_cov, out_py)
+ self.assert_execfile_output(out_cov)
def test_coverage_run_dashm_equal_to_doubledashsource(self):
"""regression test for #328
@@ -345,19 +483,21 @@ class ProcessTest(CoverageTest):
"""
# These -m commands assume the coverage tree is on the path.
out_cov = self.run_command(
- "coverage run --source tests.try_execfile -m tests.try_execfile"
+ "coverage run --source process_test.try_execfile -m process_test.try_execfile"
)
- out_py = self.run_command("python -m tests.try_execfile")
+ out_py = self.run_command("python -m process_test.try_execfile")
self.assertMultiLineEqual(out_cov, out_py)
+ self.assert_execfile_output(out_cov)
def test_coverage_run_dashm_superset_of_doubledashsource(self):
"""Edge case: --source foo -m foo.bar"""
# These -m commands assume the coverage tree is on the path.
out_cov = self.run_command(
- "coverage run --source tests -m tests.try_execfile"
+ "coverage run --source process_test -m process_test.try_execfile"
)
- out_py = self.run_command("python -m tests.try_execfile")
+ out_py = self.run_command("python -m process_test.try_execfile")
self.assertMultiLineEqual(out_cov, out_py)
+ self.assert_execfile_output(out_cov)
st, out = self.run_command_status("coverage report")
self.assertEqual(st, 0)
@@ -371,15 +511,16 @@ class ProcessTest(CoverageTest):
# keeps the test working.
self.make_file("myscript", """\
import sys; sys.dont_write_bytecode = True
- import tests.try_execfile
+ import process_test.try_execfile
""")
# These -m commands assume the coverage tree is on the path.
out_cov = self.run_command(
- "coverage run --source tests myscript"
+ "coverage run --source process_test myscript"
)
out_py = self.run_command("python myscript")
self.assertMultiLineEqual(out_cov, out_py)
+ self.assert_execfile_output(out_cov)
st, out = self.run_command_status("coverage report")
self.assertEqual(st, 0)
@@ -387,19 +528,19 @@ class ProcessTest(CoverageTest):
def test_coverage_run_dashm_is_like_python_dashm_off_path(self):
# https://bitbucket.org/ned/coveragepy/issue/242
- tryfile = os.path.join(HERE, "try_execfile.py")
self.make_file("sub/__init__.py", "")
- with open(tryfile) as f:
+ with open(TRY_EXECFILE) as f:
self.make_file("sub/run_me.py", f.read())
out_cov = self.run_command("coverage run -m sub.run_me")
out_py = self.run_command("python -m sub.run_me")
self.assertMultiLineEqual(out_cov, out_py)
+ self.assert_execfile_output(out_cov)
def test_coverage_run_dashm_is_like_python_dashm_with__main__207(self):
if sys.version_info < (2, 7):
- # Coverage isn't bug-for-bug compatible in the behavior of -m for
+ # Coverage.py isn't bug-for-bug compatible in the behavior of -m for
# Pythons < 2.7
- self.skip("-m doesn't work the same < Python 2.7")
+ self.skipTest("-m doesn't work the same < Python 2.7")
# https://bitbucket.org/ned/coveragepy/issue/207
self.make_file("package/__init__.py", "print('init')")
self.make_file("package/__main__.py", "print('main')")
@@ -409,7 +550,7 @@ class ProcessTest(CoverageTest):
def test_fork(self):
if not hasattr(os, 'fork'):
- self.skip("Can't test os.fork since it doesn't exist.")
+ self.skipTest("Can't test os.fork since it doesn't exist.")
self.make_file("fork.py", """\
import os
@@ -436,6 +577,11 @@ class ProcessTest(CoverageTest):
# .coverage.machine.123 files.
self.assertEqual(self.number_of_data_files(), 2)
+ # The two data files should have different random numbers at the end of
+ # the file name.
+ nums = set(name.rpartition(".")[-1] for name in self.data_files())
+ self.assertEqual(len(nums), 2, "Same random: %s" % (self.data_files(),))
+
# Combine the parallel coverage data files into .coverage .
self.run_command("coverage combine")
self.assert_exists(".coverage")
@@ -447,7 +593,7 @@ class ProcessTest(CoverageTest):
# executed.
data = coverage.CoverageData()
data.read_file(".coverage")
- self.assertEqual(data.summary()['fork.py'], 9)
+ self.assertEqual(data.line_counts()['fork.py'], 9)
def test_warnings(self):
self.make_file("hello.py", """\
@@ -531,12 +677,27 @@ class ProcessTest(CoverageTest):
self.assertIn("Trace function changed", out)
+ def test_note(self):
+ self.make_file(".coveragerc", """\
+ [run]
+ data_file = mydata.dat
+ note = These are musical notes: ♫𝅗𝅥♩
+ """)
+ self.make_file("simple.py", """print('hello')""")
+ self.run_command("coverage run simple.py")
+
+ data = CoverageData()
+ data.read_file("mydata.dat")
+ infos = data.run_infos()
+ self.assertEqual(len(infos), 1)
+ self.assertEqual(infos[0]['note'], u"These are musical notes: ♫𝅗𝅥♩")
+
def test_fullcoverage(self): # pragma: not covered
if env.PY2: # This doesn't work on Python 2.
- self.skip("fullcoverage doesn't work on Python 2.")
+ self.skipTest("fullcoverage doesn't work on Python 2.")
# It only works with the C tracer, and if we aren't measuring ourselves.
if not env.C_TRACER or env.METACOV:
- self.skip("fullcoverage only works with the C tracer.")
+ self.skipTest("fullcoverage only works with the C tracer.")
# fullcoverage is a trick to get stdlib modules measured from
# the very beginning of the process. Here we import os and
@@ -558,7 +719,27 @@ class ProcessTest(CoverageTest):
# 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)
+ self.assertGreater(data.line_counts()['os.py'], 50)
+
+ def test_lang_c(self):
+ if env.PY3 and sys.version_info < (3, 4):
+ # Python 3.3 can't compile the non-ascii characters in the file name.
+ self.skipTest("3.3 can't handle this test")
+ # LANG=C forces getfilesystemencoding on Linux to 'ascii', which causes
+ # failures with non-ascii file names. We don't want to make a real file
+ # with strange characters, though, because that gets the test runners
+ # tangled up. This will isolate the concerns to the coverage.py code.
+ # https://bitbucket.org/ned/coveragepy/issues/533/exception-on-unencodable-file-name
+ self.make_file("weird_file.py", r"""
+ globs = {}
+ code = "a = 1\nb = 2\n"
+ exec(compile(code, "wut\xe9\xea\xeb\xec\x01\x02.py", 'exec'), globs)
+ print(globs['a'])
+ print(globs['b'])
+ """)
+ self.set_environ("LANG", "C")
+ out = self.run_command("coverage run weird_file.py")
+ self.assertEqual(out, "1\n2\n")
def test_deprecation_warnings(self):
# Test that coverage doesn't trigger deprecation warnings.
@@ -587,16 +768,23 @@ class ProcessTest(CoverageTest):
inst.start()
import foo
inst.stop()
- inst.combine()
inst.save()
""")
out = self.run_command("python run_twice.py")
self.assertEqual(
out,
- "Coverage.py warning: "
- "Module foo was previously imported, but not measured.\n"
+ "Coverage.py warning: Module foo was previously imported, but not measured.\n"
)
+ def test_module_name(self):
+ if sys.version_info < (2, 7):
+ # Python 2.6 thinks that coverage is a package that can't be
+ # executed
+ self.skipTest("-m doesn't work the same < Python 2.7")
+ # https://bitbucket.org/ned/coveragepy/issues/478/help-shows-silly-program-name-when-running
+ out = self.run_command("python -m coverage")
+ self.assertIn("Use 'coverage help' for help", out)
+
class AliasedCommandTest(CoverageTest):
"""Tests of the version-specific command aliases."""
@@ -621,6 +809,17 @@ class AliasedCommandTest(CoverageTest):
out = self.run_command(cmd)
self.assertIn("Code coverage for Python", out)
+ def test_aliases_used_in_messages(self):
+ cmds = [
+ "coverage",
+ "coverage%d" % sys.version_info[0],
+ "coverage-%d.%d" % sys.version_info[:2],
+ ]
+ for cmd in cmds:
+ out = self.run_command("%s foobar" % cmd)
+ self.assertIn("Unknown command: 'foobar'", out)
+ self.assertIn("Use '%s help' for help" % cmd, out)
+
class PydocTest(CoverageTest):
"""Test that pydoc can get our information."""
@@ -749,6 +948,122 @@ class FailUnderEmptyFilesTest(CoverageTest):
self.assertEqual(st, 2)
+class FailUnder100Test(CoverageTest):
+ """Tests of the --fail-under switch."""
+
+ def test_99_8(self):
+ self.make_file("ninety_nine_eight.py",
+ "".join("v{i} = {i}\n".format(i=i) for i in range(498)) +
+ "if v0 > 498:\n v499 = 499\n"
+ )
+ st, _ = self.run_command_status("coverage run ninety_nine_eight.py")
+ self.assertEqual(st, 0)
+ st, out = self.run_command_status("coverage report")
+ self.assertEqual(st, 0)
+ self.assertEqual(
+ self.last_line_squeezed(out),
+ "ninety_nine_eight.py 500 1 99%"
+ )
+
+ st, _ = self.run_command_status("coverage report --fail-under=100")
+ self.assertEqual(st, 2)
+
+
+ def test_100(self):
+ self.make_file("one_hundred.py",
+ "".join("v{i} = {i}\n".format(i=i) for i in range(500))
+ )
+ st, _ = self.run_command_status("coverage run one_hundred.py")
+ self.assertEqual(st, 0)
+ st, out = self.run_command_status("coverage report")
+ self.assertEqual(st, 0)
+ self.assertEqual(
+ self.last_line_squeezed(out),
+ "one_hundred.py 500 0 100%"
+ )
+
+ st, _ = self.run_command_status("coverage report --fail-under=100")
+ self.assertEqual(st, 0)
+
+
+class UnicodeFilePathsTest(CoverageTest):
+ """Tests of using non-ascii characters in the names of files."""
+
+ def test_accented_dot_py(self):
+ # Make a file with a non-ascii character in the filename.
+ self.make_file(u"h\xe2t.py", "print('accented')")
+ out = self.run_command(u"coverage run h\xe2t.py")
+ self.assertEqual(out, "accented\n")
+
+ # The HTML report uses ascii-encoded HTML entities.
+ out = self.run_command("coverage html")
+ self.assertEqual(out, "")
+ self.assert_exists(u"htmlcov/h\xe2t_py.html")
+ with open("htmlcov/index.html") as indexf:
+ index = indexf.read()
+ self.assertIn('<a href="h&#226;t_py.html">h&#226;t.py</a>', index)
+
+ # The XML report is always UTF8-encoded.
+ out = self.run_command("coverage xml")
+ self.assertEqual(out, "")
+ with open("coverage.xml", "rb") as xmlf:
+ xml = xmlf.read()
+ self.assertIn(u' filename="h\xe2t.py"'.encode('utf8'), xml)
+ self.assertIn(u' name="h\xe2t.py"'.encode('utf8'), xml)
+
+ report_expected = (
+ u"Name Stmts Miss Cover\n"
+ u"----------------------------\n"
+ u"h\xe2t.py 1 0 100%\n"
+ )
+
+ if env.PY2:
+ # pylint: disable=redefined-variable-type
+ report_expected = report_expected.encode(output_encoding())
+
+ out = self.run_command("coverage report")
+ self.assertEqual(out, report_expected)
+
+ def test_accented_directory(self):
+ # Make a file with a non-ascii character in the directory name.
+ self.make_file(u"\xe2/accented.py", "print('accented')")
+ out = self.run_command(u"coverage run \xe2/accented.py")
+ self.assertEqual(out, "accented\n")
+
+ # The HTML report uses ascii-encoded HTML entities.
+ out = self.run_command("coverage html")
+ self.assertEqual(out, "")
+ self.assert_exists(u"htmlcov/\xe2_accented_py.html")
+ with open("htmlcov/index.html") as indexf:
+ index = indexf.read()
+ self.assertIn('<a href="&#226;_accented_py.html">&#226;%saccented.py</a>' % os.sep, index)
+
+ # The XML report is always UTF8-encoded.
+ out = self.run_command("coverage xml")
+ self.assertEqual(out, "")
+ with open("coverage.xml", "rb") as xmlf:
+ xml = xmlf.read()
+ self.assertIn(u' filename="\xe2/accented.py"'.encode('utf8'), xml)
+ self.assertIn(u' name="accented.py"'.encode('utf8'), xml)
+ self.assertIn(
+ u'<package branch-rate="0" complexity="0" line-rate="1" name="\xe2">'.encode('utf8'),
+ xml
+ )
+
+ report_expected = (
+ u"Name Stmts Miss Cover\n"
+ u"-----------------------------------\n"
+ u"\xe2%saccented.py 1 0 100%%\n" % os.sep
+ )
+
+ if env.PY2:
+ # pylint: disable=redefined-variable-type
+ report_expected = report_expected.encode(output_encoding())
+
+ out = self.run_command("coverage report")
+ self.assertEqual(out, report_expected)
+
+
def possible_pth_dirs():
"""Produce a sequence of directories for trying to write .pth files."""
# First look through sys.path, and we find a .pth file, then it's a good
@@ -764,24 +1079,38 @@ def possible_pth_dirs():
yield distutils.sysconfig.get_python_lib()
+def find_writable_pth_directory():
+ """Find a place to write a .pth file."""
+ for pth_dir in possible_pth_dirs(): # pragma: part covered
+ try_it = os.path.join(pth_dir, "touch_{0}.it".format(WORKER))
+ with open(try_it, "w") as f:
+ try:
+ f.write("foo")
+ except (IOError, OSError): # pragma: not covered
+ continue
+
+ os.remove(try_it)
+ return pth_dir
+
+ return None
+
+WORKER = os.environ.get('PYTEST_XDIST_WORKER', '')
+PTH_DIR = find_writable_pth_directory()
+
+
class ProcessCoverageMixin(object):
- """Set up a .pth file that causes all sub-processes to be coverage'd"""
+ """Set up a .pth file to coverage-measure all sub-processes."""
def setUp(self):
super(ProcessCoverageMixin, self).setUp()
- # Find a place to put a .pth file.
+
+ # Create the .pth file.
+ self.assert_(PTH_DIR)
pth_contents = "import coverage; coverage.process_startup()\n"
- for pth_dir in possible_pth_dirs(): # pragma: part covered
- pth_path = os.path.join(pth_dir, "subcover.pth")
- with open(pth_path, "w") as pth:
- try:
- pth.write(pth_contents)
- self.pth_path = pth_path
- break
- except (IOError, OSError): # pragma: not covered
- pass
- else: # pragma: not covered
- raise Exception("Couldn't find a place for the .pth file")
+ pth_path = os.path.join(PTH_DIR, "subcover_{0}.pth".format(WORKER))
+ with open(pth_path, "w") as pth:
+ pth.write(pth_contents)
+ self.pth_path = pth_path
self.addCleanup(os.remove, self.pth_path)
@@ -789,11 +1118,8 @@ class ProcessCoverageMixin(object):
class ProcessStartupTest(ProcessCoverageMixin, CoverageTest):
"""Test that we can measure coverage in sub-processes."""
- def test_subprocess_with_pth_files(self): # pragma: not covered
- if env.METACOV:
- self.skip(
- "Can't test sub-process pth file suppport during metacoverage"
- )
+ def setUp(self):
+ super(ProcessStartupTest, self).setUp()
# Main will run sub.py
self.make_file("main.py", """\
@@ -806,12 +1132,24 @@ class ProcessStartupTest(ProcessCoverageMixin, CoverageTest):
with open("out.txt", "w") as f:
f.write("Hello, world!\\n")
""")
+
+ def test_subprocess_with_pth_files(self): # pragma: not covered
+ if env.METACOV:
+ self.skipTest("Can't test sub-process pth file suppport during metacoverage")
+
+ # An existing data file should not be read when a subprocess gets
+ # measured automatically. Create the data file here with bogus data in
+ # it.
+ data = coverage.CoverageData()
+ data.add_lines({os.path.abspath('sub.py'): dict.fromkeys(range(100))})
+ data.write_file(".mycovdata")
+
self.make_file("coverage.ini", """\
[run]
data_file = .mycovdata
""")
self.set_environ("COVERAGE_PROCESS_START", "coverage.ini")
- import main # pylint: disable=import-error,unused-variable
+ import main # pylint: disable=import-error, unused-variable
with open("out.txt") as f:
self.assertEqual(f.read(), "Hello, world!\n")
@@ -820,7 +1158,37 @@ class ProcessStartupTest(ProcessCoverageMixin, CoverageTest):
self.assert_exists(".mycovdata")
data = coverage.CoverageData()
data.read_file(".mycovdata")
- self.assertEqual(data.summary()['sub.py'], 2)
+ self.assertEqual(data.line_counts()['sub.py'], 2)
+
+ def test_subprocess_with_pth_files_and_parallel(self): # pragma: not covered
+ # https://bitbucket.org/ned/coveragepy/issues/492/subprocess-coverage-strange-detection-of
+ if env.METACOV:
+ self.skipTest("Can't test sub-process pth file suppport during metacoverage")
+
+ self.make_file("coverage.ini", """\
+ [run]
+ parallel = true
+ """)
+
+ self.set_environ("COVERAGE_PROCESS_START", "coverage.ini")
+ self.run_command("coverage run main.py")
+
+ with open("out.txt") as f:
+ self.assertEqual(f.read(), "Hello, world!\n")
+
+ self.run_command("coverage combine")
+
+ # assert that the combined .coverage data file is correct
+ self.assert_exists(".coverage")
+ data = coverage.CoverageData()
+ data.read_file(".coverage")
+ self.assertEqual(data.line_counts()['sub.py'], 2)
+
+ # assert that there are *no* extra data files left over after a combine
+ data_files = glob.glob(os.getcwd() + '/.coverage*')
+ self.assertEqual(len(data_files), 1,
+ "Expected only .coverage after combine, looks like there are "
+ "extra data files that were not cleaned up: %r" % data_files)
class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
@@ -842,21 +1210,20 @@ class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
): # pragma: not covered
"""Run the test for a particular combination of factors.
- Arguments:
- dashm (str): Either "" (run the program as a file) or "-m" (run the
- program as a module).
+ The arguments are all strings:
- package (str): Either "" (put the source at the top level) or a
- package name to use to hold the source.
+ * `dashm`: Either "" (run the program as a file) or "-m" (run the
+ program as a module).
- source (str): Either "main" or "sub", which file to use as the
- ``--source`` argument.
+ * `package`: Either "" (put the source at the top level) or a
+ package name to use to hold the source.
+
+ * `source`: Either "main" or "sub", which file to use as the
+ ``--source`` argument.
"""
if env.METACOV:
- self.skip(
- "Can't test sub-process pth file suppport during metacoverage"
- )
+ self.skipTest("Can't test sub-process pth file suppport during metacoverage")
def fullname(modname):
"""What is the full module name for `modname` for this test?"""
@@ -902,7 +1269,7 @@ class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
self.assert_exists(".coverage")
data = coverage.CoverageData()
data.read_file(".coverage")
- summary = data.summary()
+ summary = data.line_counts()
print(summary)
self.assertEqual(summary[source + '.py'], 2)
self.assertEqual(len(summary), 1)
@@ -930,3 +1297,9 @@ class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
def test_script_pkg_sub(self):
self.assert_pth_and_source_work_together('', 'pkg', 'sub')
+
+
+def remove_matching_lines(text, pat):
+ """Return `text` with all lines matching `pat` removed."""
+ lines = [l for l in text.splitlines(True) if not re.search(pat, l)]
+ return "".join(lines)
diff --git a/tests/test_python.py b/tests/test_python.py
index f2c18a10..ee1e1f95 100644
--- a/tests/test_python.py
+++ b/tests/test_python.py
@@ -1,3 +1,6 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests of coverage/python.py"""
import os
@@ -17,7 +20,7 @@ class GetZipBytesTest(CoverageTest):
# See igor.py, do_zipmods, for the text of these files.
zip_file = "tests/zipmods.zip"
sys.path.append(zip_file) # So we can import the files.
- for encoding in ["utf8", "gb2312", "hebrew", "shift_jis"]:
+ for encoding in ["utf8", "gb2312", "hebrew", "shift_jis", "cp1252"]:
filename = zip_file + "/encoded_" + encoding + ".py"
filename = filename.replace("/", os.sep)
zip_data = get_zip_bytes(filename)
diff --git a/tests/test_results.py b/tests/test_results.py
index 4ce048b6..c4d8ae5a 100644
--- a/tests/test_results.py
+++ b/tests/test_results.py
@@ -1,11 +1,14 @@
-"""Tests for Coverage.py's results analysis."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Tests for coverage.py's results analysis."""
from coverage.results import Numbers
from tests.coveragetest import CoverageTest
class NumbersTest(CoverageTest):
- """Tests for Coverage.py's numeric measurement summaries."""
+ """Tests for coverage.py's numeric measurement summaries."""
run_in_temp_dir = False
@@ -37,6 +40,8 @@ class NumbersTest(CoverageTest):
self.assertAlmostEqual(n3.pc_covered, 86.666666666)
def test_pc_covered_str(self):
+ # Numbers._precision is a global, which is bad.
+ Numbers.set_precision(0)
n0 = Numbers(n_files=1, n_statements=1000, n_missing=0)
n1 = Numbers(n_files=1, n_statements=1000, n_missing=1)
n999 = Numbers(n_files=1, n_statements=1000, n_missing=999)
@@ -47,7 +52,7 @@ class NumbersTest(CoverageTest):
self.assertEqual(n1000.pc_covered_str, "0")
def test_pc_covered_str_precision(self):
- assert Numbers._precision == 0
+ # Numbers._precision is a global, which is bad.
Numbers.set_precision(1)
n0 = Numbers(n_files=1, n_statements=10000, n_missing=0)
n1 = Numbers(n_files=1, n_statements=10000, n_missing=1)
diff --git a/tests/test_summary.py b/tests/test_summary.py
index 6e7dbeba..5ba00389 100644
--- a/tests/test_summary.py
+++ b/tests/test_summary.py
@@ -1,3 +1,7 @@
+# coding: utf8
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Test text-based summary reporting for coverage.py"""
import glob
@@ -10,6 +14,11 @@ import sys
import coverage
from coverage import env
from coverage.backward import StringIO
+from coverage.config import CoverageConfig
+from coverage.control import Coverage
+from coverage.data import CoverageData
+from coverage.misc import CoverageException, output_encoding
+from coverage.summary import SummaryReporter
from tests.coveragetest import CoverageTest
@@ -42,16 +51,16 @@ class SummaryTest(CoverageTest):
# Name Stmts Miss Cover
# ------------------------------------------------------------------
# c:/ned/coverage/tests/modules/covmod1.py 2 0 100%
- # c:/ned/coverage/tests/zipmods.zip/covmodzip1.py 2 0 100%
+ # c:/ned/coverage/tests/zipmods.zip/covmodzip1.py 3 0 100%
# mycode.py 4 0 100%
# ------------------------------------------------------------------
- # TOTAL 8 0 100%
+ # TOTAL 9 0 100%
self.assertNotIn("/coverage/__init__/", report)
self.assertIn("/tests/modules/covmod1.py ", report)
self.assertIn("/tests/zipmods.zip/covmodzip1.py ", report)
self.assertIn("mycode.py ", report)
- self.assertEqual(self.last_line_squeezed(report), "TOTAL 8 0 100%")
+ self.assertEqual(self.last_line_squeezed(report), "TOTAL 9 0 100%")
def test_report_just_one(self):
# Try reporting just one module
@@ -91,9 +100,7 @@ class SummaryTest(CoverageTest):
# Try reporting while omitting some modules
self.make_mycode()
self.run_command("coverage run mycode.py")
- report = self.report_from_command(
- "coverage report --omit '%s/*'" % HERE
- )
+ report = self.report_from_command("coverage report --omit '%s/*'" % HERE)
# Name Stmts Miss Cover
# -------------------------------
@@ -141,8 +148,7 @@ class SummaryTest(CoverageTest):
self.assertEqual(self.line_count(report), 3)
self.assertIn("mybranch.py ", report)
- self.assertEqual(self.last_line_squeezed(report),
- "mybranch.py 5 0 2 1 86%")
+ self.assertEqual(self.last_line_squeezed(report), "mybranch.py 5 0 2 1 86%")
def test_report_show_missing(self):
self.make_file("mymissing.py", """\
@@ -171,8 +177,7 @@ class SummaryTest(CoverageTest):
self.assertEqual(self.line_count(report), 3)
self.assertIn("mymissing.py ", report)
- self.assertEqual(self.last_line_squeezed(report),
- "mymissing.py 14 3 79% 3-4, 10")
+ self.assertEqual(self.last_line_squeezed(report), "mymissing.py 14 3 79% 3-4, 10")
def test_report_show_missing_branches(self):
self.make_file("mybranch.py", """\
@@ -181,7 +186,6 @@ class SummaryTest(CoverageTest):
print("x")
if y:
print("y")
- return x
branch(1, 1)
""")
out = self.run_command("coverage run --branch mybranch.py")
@@ -190,12 +194,11 @@ class SummaryTest(CoverageTest):
# Name Stmts Miss Branch BrPart Cover Missing
# ----------------------------------------------------------
- # mybranch.py 7 0 4 2 82% 2->4, 4->6
+ # mybranch.py 6 0 4 2 80% 2->4, 4->exit
self.assertEqual(self.line_count(report), 3)
self.assertIn("mybranch.py ", report)
- self.assertEqual(self.last_line_squeezed(report),
- "mybranch.py 7 0 4 2 82% 2->4, 4->6")
+ self.assertEqual(self.last_line_squeezed(report), "mybranch.py 6 0 4 2 80% 2->4, 4->exit")
def test_report_show_missing_branches_and_lines(self):
self.make_file("main.py", """\
@@ -216,28 +219,17 @@ class SummaryTest(CoverageTest):
out = self.run_command("coverage run --branch main.py")
self.assertEqual(out, 'x\ny\n')
report = self.report_from_command("coverage report --show-missing")
-
- # Name Stmts Miss Branch BrPart Cover Missing
- # -------------------------------------------------------
- # main.py 1 0 0 0 100%
- # mybranch.py 10 2 8 3 61% 7-8, 2->4, 4->6, 6->7
- # -------------------------------------------------------
- # TOTAL 11 2 8 3 63%
-
- self.assertEqual(self.line_count(report), 6)
- squeezed = self.squeezed_lines(report)
- self.assertEqual(
- squeezed[2],
- "main.py 1 0 0 0 100%"
- )
- self.assertEqual(
- squeezed[3],
- "mybranch.py 10 2 8 3 61% 7-8, 2->4, 4->6, 6->7"
- )
- self.assertEqual(
- squeezed[5],
- "TOTAL 11 2 8 3 63%"
- )
+ report_lines = report.splitlines()
+
+ expected = [
+ 'Name Stmts Miss Branch BrPart Cover Missing',
+ '---------------------------------------------------------',
+ 'main.py 1 0 0 0 100%',
+ 'mybranch.py 10 2 8 3 61% 7-8, 2->4, 4->6, 6->7',
+ '---------------------------------------------------------',
+ 'TOTAL 11 2 8 3 63%',
+ ]
+ self.assertEqual(report_lines, expected)
def test_report_skip_covered_no_branches(self):
self.make_file("main.py", """
@@ -253,19 +245,26 @@ class SummaryTest(CoverageTest):
""")
out = self.run_command("coverage run main.py")
self.assertEqual(out, "z\n")
- report = self.report_from_command("coverage report --skip-covered")
+ report = self.report_from_command("coverage report --skip-covered --fail-under=70")
# Name Stmts Miss Cover
# ------------------------------------
# not_covered.py 2 1 50%
+ # ------------------------------------
+ # TOTAL 6 1 83%
+ #
+ # 1 file skipped due to complete coverage.
- self.assertEqual(self.line_count(report), 3, report)
+ self.assertEqual(self.line_count(report), 7, report)
squeezed = self.squeezed_lines(report)
self.assertEqual(squeezed[2], "not_covered.py 2 1 50%")
+ self.assertEqual(squeezed[4], "TOTAL 6 1 83%")
+ self.assertEqual(squeezed[6], "1 file skipped due to complete coverage.")
+ self.assertEqual(self.last_command_status, 0)
def test_report_skip_covered_branches(self):
self.make_file("main.py", """
- import not_covered
+ import not_covered, covered
def normal(z):
if z:
@@ -279,6 +278,11 @@ class SummaryTest(CoverageTest):
print("n")
not_covered(True)
""")
+ self.make_file("covered.py", """
+ def foo():
+ pass
+ foo()
+ """)
out = self.run_command("coverage run --branch main.py")
self.assertEqual(out, "n\nz\n")
report = self.report_from_command("coverage report --skip-covered")
@@ -286,10 +290,16 @@ class SummaryTest(CoverageTest):
# Name Stmts Miss Branch BrPart Cover
# --------------------------------------------------
# not_covered.py 4 0 2 1 83%
+ # --------------------------------------------------
+ # TOTAL 13 0 4 1 94%
+ #
+ # 2 files skipped due to complete coverage.
- self.assertEqual(self.line_count(report), 3, report)
+ self.assertEqual(self.line_count(report), 7, report)
squeezed = self.squeezed_lines(report)
self.assertEqual(squeezed[2], "not_covered.py 4 0 2 1 83%")
+ self.assertEqual(squeezed[4], "TOTAL 13 0 4 1 94%")
+ self.assertEqual(squeezed[6], "2 files skipped due to complete coverage.")
def test_report_skip_covered_branches_with_totals(self):
self.make_file("main.py", """
@@ -321,13 +331,67 @@ class SummaryTest(CoverageTest):
# also_not_run.py 2 1 0 0 50%
# not_covered.py 4 0 2 1 83%
# --------------------------------------------------
- # TOTAL 6 1 2 1 75%
+ # TOTAL 13 1 4 1 88%
+ #
+ # 1 file skipped due to complete coverage.
- self.assertEqual(self.line_count(report), 6, report)
+ self.assertEqual(self.line_count(report), 8, report)
squeezed = self.squeezed_lines(report)
self.assertEqual(squeezed[2], "also_not_run.py 2 1 0 0 50%")
self.assertEqual(squeezed[3], "not_covered.py 4 0 2 1 83%")
- self.assertEqual(squeezed[5], "TOTAL 6 1 2 1 75%")
+ self.assertEqual(squeezed[5], "TOTAL 13 1 4 1 88%")
+ self.assertEqual(squeezed[7], "1 file skipped due to complete coverage.")
+
+ def test_report_skip_covered_all_files_covered(self):
+ self.make_file("main.py", """
+ def foo():
+ pass
+ foo()
+ """)
+ out = self.run_command("coverage run --branch main.py")
+ self.assertEqual(out, "")
+ report = self.report_from_command("coverage report --skip-covered")
+
+ # Name Stmts Miss Branch BrPart Cover
+ # -------------------------------------------
+ #
+ # 1 file skipped due to complete coverage.
+
+ self.assertEqual(self.line_count(report), 4, report)
+ squeezed = self.squeezed_lines(report)
+ self.assertEqual(squeezed[3], "1 file skipped due to complete coverage.")
+
+ def test_report_skip_covered_longfilename(self):
+ self.make_file("long_______________filename.py", """
+ def foo():
+ pass
+ foo()
+ """)
+ out = self.run_command("coverage run --branch long_______________filename.py")
+ self.assertEqual(out, "")
+ report = self.report_from_command("coverage report --skip-covered")
+
+ # Name Stmts Miss Branch BrPart Cover
+ # -----------------------------------------
+ #
+ # 1 file skipped due to complete coverage.
+
+ self.assertEqual(self.line_count(report), 4, report)
+ lines = self.report_lines(report)
+ self.assertEqual(lines[0], "Name Stmts Miss Branch BrPart Cover")
+ squeezed = self.squeezed_lines(report)
+ self.assertEqual(squeezed[3], "1 file skipped due to complete coverage.")
+
+ def test_report_skip_covered_no_data(self):
+ report = self.report_from_command("coverage report --skip-covered")
+
+ # Name Stmts Miss Branch BrPart Cover
+ # -------------------------------------------
+ # No data to report.
+
+ self.assertEqual(self.line_count(report), 3, report)
+ squeezed = self.squeezed_lines(report)
+ self.assertEqual(squeezed[2], "No data to report.")
def test_dotpy_not_python(self):
# We run a .py file, and when reporting, we can't parse it as Python.
@@ -338,22 +402,48 @@ class SummaryTest(CoverageTest):
self.make_file("mycode.py", "This isn't python at all!")
report = self.report_from_command("coverage report mycode.py")
- # pylint: disable=line-too-long
+ # mycode NotPython: Couldn't parse '...' as Python source: 'invalid syntax' at line 1
+ # Name Stmts Miss Cover
+ # ----------------------------
+ # No data to report.
+
+ errmsg = self.squeezed_lines(report)[0]
+ # The actual file name varies run to run.
+ errmsg = re.sub(r"parse '.*mycode.py", "parse 'mycode.py", errmsg)
+ # The actual error message varies version to version
+ errmsg = re.sub(r": '.*' at", ": 'error' at", errmsg)
+ self.assertEqual(
+ errmsg,
+ "mycode.py NotPython: Couldn't parse 'mycode.py' as Python source: 'error' at line 1"
+ )
+
+ def test_accenteddotpy_not_python(self):
+ # We run a .py file with a non-ascii name, and when reporting, we can't
+ # parse it as Python. We should get an error message in the report.
+
+ self.make_file(u"accented\xe2.py", "print('accented')")
+ self.run_command(u"coverage run accented\xe2.py")
+ self.make_file(u"accented\xe2.py", "This isn't python at all!")
+ report = self.report_from_command(u"coverage report accented\xe2.py")
+
+ # xxxx NotPython: Couldn't parse '...' as Python source: 'invalid syntax' at line 1
# Name Stmts Miss Cover
# ----------------------------
- # mycode NotPython: Couldn't parse '/tmp/test_cover/63354509363/mycode.py' as Python source: 'invalid syntax' at line 1
# No data to report.
- last = self.squeezed_lines(report)[-2]
+ errmsg = self.squeezed_lines(report)[0]
# The actual file name varies run to run.
- last = re.sub(r"parse '.*mycode.py", "parse 'mycode.py", last)
+ errmsg = re.sub(r"parse '.*(accented.*?\.py)", r"parse '\1", errmsg)
# The actual error message varies version to version
- last = re.sub(r": '.*' at", ": 'error' at", last)
- self.assertEqual(last,
- "mycode.py NotPython: "
- "Couldn't parse 'mycode.py' as Python source: "
- "'error' at line 1"
- )
+ errmsg = re.sub(r": '.*' at", ": 'error' at", errmsg)
+ expected = (
+ u"accented\xe2.py NotPython: "
+ u"Couldn't parse 'accented\xe2.py' as Python source: 'error' at line 1"
+ )
+ if env.PY2:
+ # pylint: disable=redefined-variable-type
+ expected = expected.encode(output_encoding())
+ self.assertEqual(errmsg, expected)
def test_dotpy_not_python_ignored(self):
# We run a .py file, and when reporting, we can't parse it as Python,
@@ -407,18 +497,18 @@ class SummaryTest(CoverageTest):
self.make_file("main.py", """\
print("y")
""")
- cov = coverage.coverage(branch=True, source=["."])
+ cov = coverage.Coverage(branch=True, source=["."])
cov.start()
- import main # pragma: nested # pylint: disable=import-error,unused-variable
+ import main # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
report = self.get_report(cov).splitlines()
self.assertIn("mybranch.py 5 5 2 0 0%", report)
def run_TheCode_and_report_it(self):
"""A helper for the next few tests."""
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.start()
- import TheCode # pragma: nested # pylint: disable=import-error,unused-variable
+ import TheCode # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
return self.get_report(cov)
@@ -441,7 +531,7 @@ class SummaryTest(CoverageTest):
def test_pyw_files(self):
if not env.WINDOWS:
- self.skip(".pyw files are only on Windows.")
+ self.skipTest(".pyw files are only on Windows.")
# https://bitbucket.org/ned/coveragepy/issue/261
self.make_file("start.pyw", """\
@@ -451,9 +541,9 @@ class SummaryTest(CoverageTest):
self.make_file("mod.pyw", """\
print("In mod.pyw")
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.start()
- import start # pragma: nested # pylint: disable=import-error,unused-variable
+ import start # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
report = self.get_report(cov)
@@ -471,9 +561,9 @@ class SummaryTest(CoverageTest):
py_compile.compile("mod.py")
# Run the program.
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.start()
- import main # pragma: nested # pylint: disable=import-error,unused-variable
+ import main # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
report = self.get_report(cov).splitlines()
@@ -482,7 +572,7 @@ class SummaryTest(CoverageTest):
def test_missing_py_file_during_run(self):
# PyPy2 doesn't run bare .pyc files.
if env.PYPY and env.PY2:
- self.skip("PyPy2 doesn't run bare .pyc files")
+ self.skipTest("PyPy2 doesn't run bare .pyc files")
# Create two Python files.
self.make_file("mod.py", "a = 1\n")
@@ -501,9 +591,9 @@ class SummaryTest(CoverageTest):
os.rename(pycs[0], "mod.pyc")
# Run the program.
- cov = coverage.coverage()
+ cov = coverage.Coverage()
cov.start()
- import main # pragma: nested # pylint: disable=import-error,unused-variable
+ import main # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
# Put back the missing Python file.
@@ -529,9 +619,9 @@ class SummaryTest2(CoverageTest):
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 = coverage.Coverage(branch=True)
cov.start()
- import usepkgs # pragma: nested # pylint: disable=import-error,unused-variable
+ import usepkgs # pragma: nested # pylint: disable=import-error, unused-variable
cov.stop() # pragma: nested
repout = StringIO()
@@ -539,8 +629,8 @@ class SummaryTest2(CoverageTest):
report = repout.getvalue().replace('\\', '/')
report = re.sub(r"\s+", " ", report)
- self.assertIn("tests/modules/pkg1/__init__.py 1 0 100%", report)
- self.assertIn("tests/modules/pkg2/__init__.py 0 0 100%", report)
+ self.assertIn("tests/modules/pkg1/__init__.py 2 0 0 0 100%", report)
+ self.assertIn("tests/modules/pkg2/__init__.py 0 0 0 0 100%", report)
class ReportingReturnValueTest(CoverageTest):
@@ -558,7 +648,7 @@ class ReportingReturnValueTest(CoverageTest):
g = 7
""")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
self.start_import_stop(cov, "doit")
return cov
@@ -576,3 +666,112 @@ class ReportingReturnValueTest(CoverageTest):
cov = self.run_coverage()
val = cov.xml_report(include="*/doit.py")
self.assertAlmostEqual(val, 85.7, 1)
+
+
+class TestSummaryReporterConfiguration(CoverageTest):
+ """Tests of SummaryReporter."""
+
+ run_in_temp_dir = False
+
+ # We just need some readable files to work with. These will do.
+ HERE = os.path.dirname(__file__)
+
+ LINES_1 = {
+ os.path.join(HERE, "test_api.py"): dict.fromkeys(range(300)),
+ os.path.join(HERE, "test_backward.py"): dict.fromkeys(range(20)),
+ os.path.join(HERE, "test_coverage.py"): dict.fromkeys(range(15)),
+ }
+
+ def get_coverage_data(self, lines):
+ """Get a CoverageData object that includes the requested lines."""
+ data = CoverageData()
+ data.add_lines(lines)
+ return data
+
+ def get_summary_text(self, coverage_data, options):
+ """Get text output from the SummaryReporter."""
+ cov = Coverage()
+ cov.start()
+ cov.stop() # pragma: nested
+ cov.data = coverage_data
+ printer = SummaryReporter(cov, options)
+ destination = StringIO()
+ printer.report([], destination)
+ return destination.getvalue()
+
+ def test_test_data(self):
+ # We use our own test files as test data. Check that our assumptions
+ # about them are still valid. We want the three columns of numbers to
+ # sort in three different orders.
+ data = self.get_coverage_data(self.LINES_1)
+ report = self.get_summary_text(data, CoverageConfig())
+ print(report)
+ # Name Stmts Miss Cover
+ # --------------------------------------------
+ # tests/test_api.py 339 155 54%
+ # tests/test_backward.py 13 3 77%
+ # tests/test_coverage.py 234 228 3%
+ # --------------------------------------------
+ # TOTAL 586 386 34%
+
+ lines = report.splitlines()[2:-2]
+ self.assertEqual(len(lines), 3)
+ nums = [list(map(int, l.replace('%', '').split()[1:])) for l in lines]
+ # [
+ # [339, 155, 54],
+ # [ 13, 3, 77],
+ # [234, 228, 3]
+ # ]
+ self.assertTrue(nums[1][0] < nums[2][0] < nums[0][0])
+ self.assertTrue(nums[1][1] < nums[0][1] < nums[2][1])
+ self.assertTrue(nums[2][2] < nums[0][2] < nums[1][2])
+
+ def test_defaults(self):
+ """Run the report with no configuration options."""
+ data = self.get_coverage_data(self.LINES_1)
+ opts = CoverageConfig()
+ report = self.get_summary_text(data, opts)
+ self.assertNotIn('Missing', report)
+ self.assertNotIn('Branch', report)
+
+ def test_print_missing(self):
+ """Run the report printing the missing lines."""
+ data = self.get_coverage_data(self.LINES_1)
+ opts = CoverageConfig()
+ opts.from_args(show_missing=True)
+ report = self.get_summary_text(data, opts)
+ self.assertIn('Missing', report)
+ self.assertNotIn('Branch', report)
+
+ def assert_ordering(self, text, *words):
+ """Assert that the `words` appear in order in `text`."""
+ indexes = list(map(text.find, words))
+ self.assertEqual(
+ indexes, sorted(indexes),
+ "The words %r don't appear in order in %r" % (words, text)
+ )
+
+ def test_sort_report_by_stmts(self):
+ # Sort the text report by the Stmts column.
+ data = self.get_coverage_data(self.LINES_1)
+ opts = CoverageConfig()
+ opts.from_args(sort='Stmts')
+ report = self.get_summary_text(data, opts)
+ self.assert_ordering(report, "test_backward.py", "test_coverage.py", "test_api.py")
+
+ def test_sort_report_by_cover(self):
+ # Sort the text report by the Cover column.
+ data = self.get_coverage_data(self.LINES_1)
+ opts = CoverageConfig()
+ opts.from_args(sort='Cover')
+ report = self.get_summary_text(data, opts)
+ self.assert_ordering(report, "test_coverage.py", "test_api.py", "test_backward.py")
+
+ def test_sort_report_by_invalid_option(self):
+ # Sort the text report by a nonsense column.
+ data = self.get_coverage_data(self.LINES_1)
+ opts = CoverageConfig()
+ opts.from_args(sort='Xyzzy')
+ msg = "Invalid sorting option: 'Xyzzy'"
+ with self.assertRaisesRegex(CoverageException, msg):
+ self.get_summary_text(data, opts)
diff --git a/tests/test_templite.py b/tests/test_templite.py
index 2b64e4e3..1df942ee 100644
--- a/tests/test_templite.py
+++ b/tests/test_templite.py
@@ -1,4 +1,7 @@
# -*- coding: utf8 -*-
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for coverage.templite."""
import re
@@ -30,6 +33,7 @@ class TempliteTest(CoverageTest):
Result defaults to None so we can shorten the calls where we expect
an exception and never get to the result comparison.
+
"""
actual = Templite(text).render(ctx or {})
# If result is None, then an exception should have prevented us getting
@@ -41,6 +45,7 @@ class TempliteTest(CoverageTest):
"""Assert that a `TempliteSyntaxError` will happen.
A context manager, and the message should be `msg`.
+
"""
pat = "^" + re.escape(msg) + "$"
return self.assertRaisesRegex(TempliteSyntaxError, pat)
@@ -235,6 +240,26 @@ class TempliteTest(CoverageTest):
"@a0b0c0a1b1c1a2b2c2!"
)
+ def test_whitespace_handling(self):
+ self.try_render(
+ "@{% for n in nums %}\n"
+ " {% for a in abc %}{{a}}{{n}}{% endfor %}\n"
+ "{% endfor %}!\n",
+ {'nums': [0, 1, 2], 'abc': ['a', 'b', 'c']},
+ "@\n a0b0c0\n\n a1b1c1\n\n a2b2c2\n!\n"
+ )
+ self.try_render(
+ "@{% for n in nums -%}\n"
+ " {% for a in abc -%}\n"
+ " {# this disappears completely -#}\n"
+ " {{a -}}\n"
+ " {{n -}}\n"
+ " {% endfor %}\n"
+ "{% endfor %}!\n",
+ {'nums': [0, 1, 2], 'abc': ['a', 'b', 'c']},
+ "@a0b0c0\na1b1c1\na2b2c2\n!\n"
+ )
+
def test_non_ascii(self):
self.try_render(
u"{{where}} ollǝɥ",
diff --git a/tests/test_testing.py b/tests/test_testing.py
index 08ff257d..c5858bf1 100644
--- a/tests/test_testing.py
+++ b/tests/test_testing.py
@@ -1,14 +1,18 @@
# -*- coding: utf-8 -*-
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests that our test infrastructure is really working!"""
import datetime
import os
import sys
+import coverage
from coverage.backunittest import TestCase
-from coverage.backward import to_bytes
+from coverage.files import actual_path
-from tests.coveragetest import TempDirMixin, CoverageTest
+from tests.coveragetest import CoverageTest
class TestingTest(TestCase):
@@ -23,46 +27,17 @@ class TestingTest(TestCase):
self.assertCountEqual(set([1,2,3]), set([4,5,6]))
-class TempDirMixinTest(TempDirMixin, TestCase):
- """Test the methods in TempDirMixin."""
-
- def file_text(self, fname):
- """Return the text read from a file."""
- with open(fname, "rb") as f:
- return f.read().decode('ascii')
-
- def test_make_file(self):
- # A simple file.
- self.make_file("fooey.boo", "Hello there")
- self.assertEqual(self.file_text("fooey.boo"), "Hello there")
- # A file in a sub-directory
- self.make_file("sub/another.txt", "Another")
- self.assertEqual(self.file_text("sub/another.txt"), "Another")
- # A second file in that sub-directory
- self.make_file("sub/second.txt", "Second")
- self.assertEqual(self.file_text("sub/second.txt"), "Second")
- # A deeper directory
- self.make_file("sub/deeper/evenmore/third.txt")
- self.assertEqual(self.file_text("sub/deeper/evenmore/third.txt"), "")
-
- 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: «ταБЬℓσ»")
- with open("unicode.txt", "rb") as f:
- text = f.read()
- self.assertEqual(text, to_bytes("tabblo: «ταБЬℓσ»"))
-
-
class CoverageTestTest(CoverageTest):
"""Test the methods in `CoverageTest`."""
+ def test_arcz_to_arcs(self):
+ self.assertEqual(self.arcz_to_arcs(".1 12 2."), [(-1, 1), (1, 2), (2, -1)])
+ self.assertEqual(self.arcz_to_arcs("-11 12 2-5"), [(-1, 1), (1, 2), (2, -5)])
+ self.assertEqual(
+ self.arcz_to_arcs("-QA CB IT Z-A"),
+ [(-26, 10), (12, 11), (18, 29), (35, -10)]
+ )
+
def test_file_exists(self):
self.make_file("whoville.txt", "We are here!")
self.assert_exists("whoville.txt")
@@ -102,6 +77,44 @@ class CoverageTestTest(CoverageTest):
with self.assertRaises(AssertionError):
self.assert_recent_datetime(now_delta(1), seconds=120)
+ def test_assert_warnings(self):
+ cov = coverage.Coverage()
+
+ # Make a warning, it should catch it properly.
+ with self.assert_warnings(cov, ["Hello there!"]):
+ cov._warn("Hello there!")
+
+ # The expected warnings are regexes.
+ with self.assert_warnings(cov, ["Hello.*!"]):
+ cov._warn("Hello there!")
+
+ # There can be a bunch of actual warnings.
+ with self.assert_warnings(cov, ["Hello.*!"]):
+ cov._warn("You there?")
+ cov._warn("Hello there!")
+
+ # There can be a bunch of expected warnings.
+ with self.assert_warnings(cov, ["Hello.*!", "You"]):
+ cov._warn("You there?")
+ cov._warn("Hello there!")
+
+ # But if there are a bunch of expected warnings, they have to all happen.
+ warn_regex = r"Didn't find warning 'You' in \['Hello there!'\]"
+ with self.assertRaisesRegex(AssertionError, warn_regex):
+ with self.assert_warnings(cov, ["Hello.*!", "You"]):
+ cov._warn("Hello there!")
+
+ # Make a different warning than expected, it should raise an assertion.
+ warn_regex = r"Didn't find warning 'Not me' in \['Hello there!'\]"
+ with self.assertRaisesRegex(AssertionError, warn_regex):
+ with self.assert_warnings(cov, ["Not me"]):
+ cov._warn("Hello there!")
+
+ # assert_warnings shouldn't hide a real exception.
+ with self.assertRaises(ZeroDivisionError):
+ with self.assert_warnings(cov, ["Hello there!"]):
+ raise ZeroDivisionError("oops")
+
def test_sub_python_is_this_python(self):
# Try it with a Python command.
os.environ['COV_FOOBAR'] = 'XYZZY'
@@ -112,17 +125,17 @@ class CoverageTestTest(CoverageTest):
print(os.environ['COV_FOOBAR'])
""")
out = self.run_command("python showme.py").splitlines()
- self.assertEqual(out[0], sys.executable)
+ self.assertEqual(actual_path(out[0]), actual_path(sys.executable))
self.assertEqual(out[1], os.__file__)
self.assertEqual(out[2], 'XYZZY')
# Try it with a "coverage debug sys" command.
out = self.run_command("coverage debug sys").splitlines()
# "environment: COV_FOOBAR = XYZZY" or "COV_FOOBAR = XYZZY"
- executable = next(l for l in out if "executable:" in l)
+ executable = next(l for l in out if "executable:" in l) # pragma: part covered
executable = executable.split(":", 1)[1].strip()
self.assertTrue(same_python_executable(executable, sys.executable))
- environ = next(l for l in out if "COV_FOOBAR" in l)
+ environ = next(l for l in out if "COV_FOOBAR" in l) # pragma: part covered
_, _, environ = environ.rpartition(":")
self.assertEqual(environ.strip(), "COV_FOOBAR = XYZZY")
diff --git a/tests/test_xml.py b/tests/test_xml.py
index b9b36efb..dd14b920 100644
--- a/tests/test_xml.py
+++ b/tests/test_xml.py
@@ -1,11 +1,18 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Tests for XML reports from coverage.py."""
import os
+import os.path
import re
import coverage
+from coverage.files import abs_file
from tests.coveragetest import CoverageTest
+from tests.goldtest import CoverageGoldTest
+from tests.goldtest import change_dir, compare
class XmlTestHelpers(CoverageTest):
@@ -21,7 +28,7 @@ class XmlTestHelpers(CoverageTest):
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 = coverage.Coverage()
self.start_import_stop(cov, "main")
return cov
@@ -30,7 +37,7 @@ class XmlTestHelpers(CoverageTest):
Makes `width` directories, named d0 .. d{width-1}. Each directory has
__init__.py, and `width` files, named f0.py .. f{width-1}.py. Each
- directory also has `width` subdirectories, in the same fashion, until
+ directory also has `width` sub-directories, in the same fashion, until
a depth of `depth` is reached.
"""
@@ -88,7 +95,7 @@ class XmlReportTest(XmlTestHelpers, CoverageTest):
# 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 = coverage.Coverage()
self.start_import_stop(cov, "innocuous")
os.remove("innocuous.py")
cov.xml_report(ignore_errors=True)
@@ -120,7 +127,7 @@ class XmlReportTest(XmlTestHelpers, CoverageTest):
# Used to raise a zero division error:
# https://bitbucket.org/ned/coveragepy/issue/250
self.make_file("empty.py", "")
- cov = coverage.coverage()
+ cov = coverage.Coverage()
empty = self.start_import_stop(cov, "empty")
cov.xml_report([empty], outfile="-")
xml = self.stdout()
@@ -136,6 +143,47 @@ class XmlReportTest(XmlTestHelpers, CoverageTest):
init_line = re_line(xml, 'filename="sub/__init__.py"')
self.assertIn('line-rate="1"', init_line)
+ def assert_source(self, xml, src):
+ """Assert that the XML has a <source> element with `src`."""
+ src = abs_file(src)
+ self.assertRegex(xml, r'<source>\s*{0}\s*</source>'.format(re.escape(src)))
+
+ def test_curdir_source(self):
+ # With no source= option, the XML report should explain that the source
+ # is in the current directory.
+ cov = self.run_doit()
+ cov.xml_report(outfile="-")
+ xml = self.stdout()
+ self.assert_source(xml, ".")
+ self.assertEqual(xml.count('<source>'), 1)
+
+ def test_deep_source(self):
+ # When using source=, the XML report needs to mention those directories
+ # in the <source> elements.
+ # https://bitbucket.org/ned/coveragepy/issues/439/incorrect-cobertura-file-sources-generated
+ self.make_file("src/main/foo.py", "a = 1")
+ self.make_file("also/over/there/bar.py", "b = 2")
+ cov = coverage.Coverage(source=["src/main", "also/over/there", "not/really"])
+ cov.start()
+ mod_foo = self.import_local_file("foo", "src/main/foo.py") # pragma: nested
+ mod_bar = self.import_local_file("bar", "also/over/there/bar.py") # pragma: nested
+ cov.stop() # pragma: nested
+ cov.xml_report([mod_foo, mod_bar], outfile="-")
+ xml = self.stdout()
+
+ self.assert_source(xml, "src/main")
+ self.assert_source(xml, "also/over/there")
+ self.assertEqual(xml.count('<source>'), 2)
+
+ self.assertIn(
+ '<class branch-rate="0" complexity="0" filename="foo.py" line-rate="1" name="foo.py">',
+ xml
+ )
+ self.assertIn(
+ '<class branch-rate="0" complexity="0" filename="bar.py" line-rate="1" name="bar.py">',
+ xml
+ )
+
class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
"""Tests about the package structure reported in the coverage.xml file."""
@@ -160,7 +208,7 @@ class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
self.make_file("main.py", """\
from d0.d0 import f0
""")
- cov = coverage.coverage(source=".")
+ cov = coverage.Coverage(source=".")
self.start_import_stop(cov, "main")
self.assert_package_and_class_tags(cov, """\
<package name=".">
@@ -178,10 +226,10 @@ class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
self.make_file("main.py", """\
from d0.d0 import f0
""")
- cov = coverage.coverage(source=".")
+ cov = coverage.Coverage(source=".")
self.start_import_stop(cov, "main")
- cov.config["xml:package_depth"] = 1
+ cov.set_option("xml:package_depth", 1)
self.assert_package_and_class_tags(cov, """\
<package name=".">
<class filename="main.py" name="main.py">
@@ -194,7 +242,7 @@ class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
<class filename="d0/f0.py" name="f0.py">
""")
- cov.config["xml:package_depth"] = 2
+ cov.set_option("xml:package_depth", 2)
self.assert_package_and_class_tags(cov, """\
<package name=".">
<class filename="main.py" name="main.py">
@@ -208,7 +256,7 @@ class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
<class filename="d0/d0/f0.py" name="f0.py">
""")
- cov.config["xml:package_depth"] = 3
+ cov.set_option("xml:package_depth", 3)
self.assert_package_and_class_tags(cov, """\
<package name=".">
<class filename="main.py" name="main.py">
@@ -223,6 +271,16 @@ class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
<class filename="d0/d0/d0/f0.py" name="f0.py">
""")
+ def test_source_prefix(self):
+ # https://bitbucket.org/ned/coveragepy/issues/465
+ self.make_file("src/mod.py", "print(17)")
+ cov = coverage.Coverage(source=["src"])
+ self.start_import_stop(cov, "mod", modfile="src/mod.py")
+ self.assert_package_and_class_tags(cov, """\
+ <package name=".">
+ <class filename="src/mod.py" name="mod.py">
+ """)
+
def re_lines(text, pat):
"""Return a list of lines that match `pat` in the string `text`."""
@@ -249,3 +307,67 @@ def clean(text, scrub=None):
text = re.sub(r"(?m)^\s+", "", text)
text = re.sub(r"\\", "/", text)
return text
+
+
+class XmlGoldTest(CoverageGoldTest):
+ """Tests of XML reporting that use gold files."""
+
+ # TODO: this should move out of html.
+ root_dir = 'tests/farm/html'
+
+ def test_a_xml_1(self):
+ self.output_dir("out/xml_1")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage()
+ cov.start()
+ import a # pragma: nested
+ cov.stop() # pragma: nested
+ cov.xml_report(a, outfile="../out/xml_1/coverage.xml")
+ source_path = coverage.files.relative_directory().rstrip(r"\/")
+
+ compare("gold_x_xml", "out/xml_1", scrubs=[
+ (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
+ (r' version="[-.\w]+"', ' version="VERSION"'),
+ (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
+ (r'/coverage.readthedocs.io/?[-.\w/]*', '/coverage.readthedocs.io/VER'),
+ ])
+
+ def test_a_xml_2(self):
+ self.output_dir("out/xml_2")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(config_file="run_a_xml_2.ini")
+ cov.start()
+ import a # pragma: nested
+ cov.stop() # pragma: nested
+ cov.xml_report(a)
+ source_path = coverage.files.relative_directory().rstrip(r"\/")
+
+ compare("gold_x_xml", "out/xml_2", scrubs=[
+ (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
+ (r' version="[-.\w]+"', ' version="VERSION"'),
+ (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
+ (r'/coverage.readthedocs.io/?[-.\w/]*', '/coverage.readthedocs.io/VER'),
+ ])
+
+ def test_y_xml_branch(self):
+ self.output_dir("out/y_xml_branch")
+
+ with change_dir("src"):
+ # pylint: disable=import-error
+ cov = coverage.Coverage(branch=True)
+ cov.start()
+ import y # pragma: nested
+ cov.stop() # pragma: nested
+ cov.xml_report(y, outfile="../out/y_xml_branch/coverage.xml")
+ source_path = coverage.files.relative_directory().rstrip(r"\/")
+
+ compare("gold_y_xml_branch", "out/y_xml_branch", scrubs=[
+ (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
+ (r' version="[-.\w]+"', ' version="VERSION"'),
+ (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
+ (r'/coverage.readthedocs.io/?[-.\w/]*', '/coverage.readthedocs.io/VER'),
+ ])