diff options
Diffstat (limited to 'tests')
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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='pln'><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'><</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t4' class='pln'> <span class='com'># Needed a < to look at HTML entities.</span><span class='strut'> </span></p> -<p id='t5' class='stm run hide_run'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'> </span></p> -<p id='t6' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t7' class='stm mis'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</span><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">if</span> <span class="num">1</span> <span class="op"><</span> <span class="num">2</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t7" class="pln"> <span class="com"># Needed a < to look at HTML entities.</span><span class="strut"> </span></p> +<p id="t8" class="stm run hide_run"> <span class="nam">a</span> <span class="op">=</span> <span class="num">3</span><span class="strut"> </span></p> +<p id="t9" class="pln"><span class="key">else</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t10" class="stm mis"> <span class="nam">a</span> <span class="op">=</span> <span class="num">4</span><span class="strut"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='pln'><span class='strut'> </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'> </span></p> -<p id='t4' class='pln'> <span class='com'># This will be a branch that misses the else.</span><span class='strut'> </span></p> -<p id='t5' class='stm par run hide_run'><span class='annotate' title='no jump to this line number'>8</span> <span class='key'>if</span> <span class='nam'>x</span> <span class='op'><</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'> </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'> </span></p> -<p id='t7' class='pln'> <span class='key'>else</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t8' class='stm mis'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'> </span></p> -<p id='t9' class='pln'><span class='strut'> </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'> </span></p> -<p id='t11' class='pln'><span class='strut'> </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'> </span></p> -<p id='t13' class='pln'> <span class='com'># A missed else that branches to "exit"</span><span class='strut'> </span></p> -<p id='t14' class='stm par run hide_run'><span class='annotate' title='no jump to this line number'>exit</span> <span class='key'>if</span> <span class='nam'>x</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t15' class='stm run hide_run'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>5</span><span class='strut'> </span></p> -<p id='t16' class='pln'><span class='strut'> </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'> </span></p> -<p id='t18' class='pln'><span class='strut'> </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'> </span></p> -<p id='t20' class='stm run hide_run'> <span class='key'>try</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t21' class='pln'> <span class='com'># This if has two branches, *neither* one taken.</span><span class='strut'> </span></p> -<p id='t22' class='stm par run hide_run'><span class='annotate' title='no jumps to these line numbers'>23 25</span> <span class='key'>if</span> <span class='nam'>name_error_this_variable_doesnt_exist</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t23' class='stm mis'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>1</span><span class='strut'> </span></p> -<p id='t24' class='pln'> <span class='key'>else</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t25' class='stm mis'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>2</span><span class='strut'> </span></p> -<p id='t26' class='stm run hide_run'> <span class='key'>except</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t27' class='stm run hide_run'> <span class='key'>pass</span><span class='strut'> </span></p> -<p id='t28' class='pln'><span class='strut'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</span><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="strut"> </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"> </span></p> +<p id="t7" class="pln"> <span class="com"># This will be a branch that misses the else.</span><span class="strut"> </span></p> +<p id="t8" class="stm par run hide_run"><span class="annotate" title="no jump to this line number">11</span> <span class="key">if</span> <span class="nam">x</span> <span class="op"><</span> <span class="num">2</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t9" class="stm run hide_run"> <span class="nam">a</span> <span class="op">=</span> <span class="num">3</span><span class="strut"> </span></p> +<p id="t10" class="pln"> <span class="key">else</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t11" class="stm mis"> <span class="nam">a</span> <span class="op">=</span> <span class="num">4</span><span class="strut"> </span></p> +<p id="t12" class="pln"><span class="strut"> </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"> </span></p> +<p id="t14" class="pln"><span class="strut"> </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"> </span></p> +<p id="t16" class="pln"> <span class="com"># A missed else that branches to "exit"</span><span class="strut"> </span></p> +<p id="t17" class="stm par run hide_run"><span class="annotate" title="no jump to this line number">exit</span> <span class="key">if</span> <span class="nam">x</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t18" class="stm run hide_run"> <span class="nam">a</span> <span class="op">=</span> <span class="num">5</span><span class="strut"> </span></p> +<p id="t19" class="pln"><span class="strut"> </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"> </span></p> +<p id="t21" class="pln"><span class="strut"> </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"> </span></p> +<p id="t23" class="stm run hide_run"> <span class="key">try</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t24" class="pln"> <span class="com"># This if has two branches, *neither* one taken.</span><span class="strut"> </span></p> +<p id="t25" class="stm par run hide_run"><span class="annotate" title="no jumps to these line numbers">26 28</span> <span class="key">if</span> <span class="nam">name_error_this_variable_doesnt_exist</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t26" class="stm mis"> <span class="nam">a</span> <span class="op">=</span> <span class="num">1</span><span class="strut"> </span></p> +<p id="t27" class="pln"> <span class="key">else</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t28" class="stm mis"> <span class="nam">a</span> <span class="op">=</span> <span class="num">2</span><span class="strut"> </span></p> +<p id="t29" class="stm run hide_run"> <span class="key">except</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t30" class="stm run hide_run"> <span class="key">pass</span><span class="strut"> </span></p> +<p id="t31" class="pln"><span class="strut"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'>�</span><span class='err'>�</span><span class='err'>�</span><span class='com'># A python source file in utf-8, with BOM</span><span class='strut'> </span></p> -<p id='t2' class='stm run hide_run'><span class='nam'>math</span> <span class='op'>=</span> <span class='str'>"3×4 = 12, ÷2 = 6±0"</span><span class='strut'> </span></p> -<p id='t3' class='pln'><span class='strut'> </span></p> -<p id='t4' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>sys</span><span class='strut'> </span></p> -<p id='t5' class='pln'><span class='strut'> </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'>>=</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'> </span></p> -<p id='t7' class='stm mis'> <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'> </span></p> -<p id='t8' class='stm mis'> <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'>'utf-8'</span><span class='op'>)</span><span class='op'>)</span> <span class='op'>==</span> <span class='num'>21</span><span class='strut'> </span></p> -<p id='t9' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t10' 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'>21</span><span class='strut'> </span></p> -<p id='t11' 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='nam'>decode</span><span class='op'>(</span><span class='str'>'utf-8'</span><span class='op'>)</span><span class='op'>)</span> <span class='op'>==</span> <span class='num'>18</span><span class='strut'> </span></p> + <td class="text"> +<p id="t1" class="pln"><span class="err">�</span><span class="err">�</span><span class="err">�</span><span class="com"># A python source file in utf-8, with BOM</span><span class="strut"> </span></p> +<p id="t2" class="stm run hide_run"><span class="nam">math</span> <span class="op">=</span> <span class="str">"3×4 = 12, ÷2 = 6±0"</span><span class="strut"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="stm run hide_run"><span class="key">import</span> <span class="nam">sys</span><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="strut"> </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">>=</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"> </span></p> +<p id="t7" class="stm mis"> <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"> </span></p> +<p id="t8" class="stm mis"> <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">'utf-8'</span><span class="op">)</span><span class="op">)</span> <span class="op">==</span> <span class="num">21</span><span class="strut"> </span></p> +<p id="t9" class="pln"><span class="key">else</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t10" 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">21</span><span class="strut"> </span></p> +<p id="t11" 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="nam">decode</span><span class="op">(</span><span class="str">'utf-8'</span><span class="op">)</span><span class="op">)</span> <span class="op">==</span> <span class="num">18</span><span class="strut"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</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/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> change column sorting + <span class="key">c</span> 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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='pln'><span class='com'># -*- coding: iso8859-1 -*-</span><span class='strut'> </span></p> -<p id='t3' class='pln'><span class='strut'> </span></p> -<p id='t4' class='stm run hide_run'><span class='nam'>math</span> <span class='op'>=</span> <span class='str'>"3×4 = 12, ÷2 = 6±0"</span><span class='strut'> </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'> </span></p> + <td class="text"> +<p id="t1" class="pln"><span class="com"># -*- coding: iso8859-1 -*-</span><span class="strut"> </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"> </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"> </span></p> +<p id="t4" class="pln"><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="com"># A Python source file in another encoding.</span><span class="strut"> </span></p> +<p id="t6" class="pln"><span class="strut"> </span></p> +<p id="t7" class="stm run hide_run"><span class="nam">math</span> <span class="op">=</span> <span class="str">"3×4 = 12, ÷2 = 6±0"</span><span class="strut"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'> </span></p> -<p id='t4' class='pln'><span class='strut'> </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'> </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'> </span></p> -<p id='t7' class='pln'><span class='strut'> </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'> </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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="stm run hide_run"><span class="key">import</span> <span class="nam">m1</span><span class="strut"> </span></p> +<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</span><span class="strut"> </span></p> +<p id="t7" class="pln"><span class="strut"> </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"> </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"> </span></p> +<p id="t10" class="pln"><span class="strut"> </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"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'> </span></p> -<p id='t4' class='pln'><span class='strut'> </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'> </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'> </span></p> -<p id='t7' class='pln'><span class='strut'> </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'> </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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="stm run hide_run"><span class="key">import</span> <span class="nam">m1</span><span class="strut"> </span></p> +<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</span><span class="strut"> </span></p> +<p id="t7" class="pln"><span class="strut"> </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"> </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"> </span></p> +<p id="t10" class="pln"><span class="strut"> </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"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'> </span></p> -<p id='t4' class='pln'><span class='strut'> </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'> </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'> </span></p> -<p id='t7' class='pln'><span class='strut'> </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'> </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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="stm run hide_run"><span class="key">import</span> <span class="nam">m1</span><span class="strut"> </span></p> +<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</span><span class="strut"> </span></p> +<p id="t7" class="pln"><span class="strut"> </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"> </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"> </span></p> +<p id="t10" class="pln"><span class="strut"> </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"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'> </span></p> -<p id='t4' class='pln'><span class='strut'> </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'> </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'> </span></p> -<p id='t7' class='pln'><span class='strut'> </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'> </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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="stm run hide_run"><span class="key">import</span> <span class="nam">m1</span><span class="strut"> </span></p> +<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</span><span class="strut"> </span></p> +<p id="t7" class="pln"><span class="strut"> </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"> </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"> </span></p> +<p id="t10" class="pln"><span class="strut"> </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"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m2</span><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>m3</span><span class='strut'> </span></p> -<p id='t4' class='pln'><span class='strut'> </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'> </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'> </span></p> -<p id='t7' class='pln'><span class='strut'> </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'> </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'> </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'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="stm run hide_run"><span class="key">import</span> <span class="nam">m1</span><span class="strut"> </span></p> +<p id="t5" class="stm run hide_run"><span class="key">import</span> <span class="nam">m2</span><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">m3</span><span class="strut"> </span></p> +<p id="t7" class="pln"><span class="strut"> </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"> </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"> </span></p> +<p id="t10" class="pln"><span class="strut"> </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"> </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"> </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"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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. We're checking that it ends up in the</span><span class='strut'> </span></p> -<p id='t2' class='pln'><span class='com'># HTML report.</span><span class='strut'> </span></p> -<p id='t3' class='pln'><span class='strut'> </span></p> -<p id='t4' class='stm run hide_run'><span class='key'>print</span><span class='op'>(</span><span class='str'>"This is the other src!"</span><span class='op'>)</span><span class='strut'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="pln"><span class="com"># A file in another directory. We're checking that it ends up in the</span><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="com"># HTML report.</span><span class="strut"> </span></p> +<p id="t6" class="pln"><span class="strut"> </span></p> +<p id="t7" class="stm run hide_run"><span class="key">print</span><span class="op">(</span><span class="str">"This is the other src!"</span><span class="op">)</span><span class="strut"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='pln'><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>import</span> <span class='nam'>other</span><span class='strut'> </span></p> -<p id='t4' class='pln'><span class='strut'> </span></p> -<p id='t5' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'><</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t6' class='stm run hide_run'> <span class='nam'>h</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'> </span></p> -<p id='t7' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t8' class='stm mis'> <span class='nam'>h</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</span><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">import</span> <span class="nam">other</span><span class="strut"> </span></p> +<p id="t7" class="pln"><span class="strut"> </span></p> +<p id="t8" class="stm run hide_run"><span class="key">if</span> <span class="num">1</span> <span class="op"><</span> <span class="num">2</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t9" class="stm run hide_run"> <span class="nam">h</span> <span class="op">=</span> <span class="num">3</span><span class="strut"> </span></p> +<p id="t10" class="pln"><span class="key">else</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t11" class="stm mis"> <span class="nam">h</span> <span class="op">=</span> <span class="num">4</span><span class="strut"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='pln'><span class='strut'> </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'> </span></p> -<p id='t4' class='pln'><span class='strut'> </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'> </span></p> -<p id='t6' class='stm run hide_run'> <span class='key'>break</span><span class='strut'> </span></p> -<p id='t7' class='pln'><span class='strut'> </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'> </span></p> -<p id='t9' class='stm run hide_run'> <span class='key'>break</span><span class='strut'> </span></p> -<p id='t10' class='pln'><span class='strut'> </span></p> -<p id='t11' class='stm run hide_run'><span class='key'>while</span> <span class='nam'>a</span><span class='op'>:</span> <span class='com'># pragma: no branch</span><span class='strut'> </span></p> -<p id='t12' class='stm run hide_run'> <span class='key'>break</span><span class='strut'> </span></p> -<p id='t13' class='pln'><span class='strut'> </span></p> -<p id='t14' class='pln'><span class='key'>if</span> <span class='num'>0</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t15' class='pln'> <span class='nam'>never_happen</span><span class='op'>(</span><span class='op'>)</span><span class='strut'> </span></p> -<p id='t16' class='pln'><span class='strut'> </span></p> -<p id='t17' class='pln'><span class='key'>if</span> <span class='num'>1</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t18' class='stm run hide_run'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>13</span><span class='strut'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="pln"><span class="com"># partial branches</span><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="strut"> </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"> </span></p> +<p id="t7" class="pln"><span class="strut"> </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"> </span></p> +<p id="t9" class="stm run hide_run"> <span class="key">break</span><span class="strut"> </span></p> +<p id="t10" class="pln"><span class="strut"> </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"> </span></p> +<p id="t12" class="stm run hide_run"> <span class="key">break</span><span class="strut"> </span></p> +<p id="t13" class="pln"><span class="strut"> </span></p> +<p id="t14" class="stm run hide_run"><span class="key">while</span> <span class="nam">a</span><span class="op">:</span> <span class="com"># pragma: no branch</span><span class="strut"> </span></p> +<p id="t15" class="stm run hide_run"> <span class="key">break</span><span class="strut"> </span></p> +<p id="t16" class="pln"><span class="strut"> </span></p> +<p id="t17" class="pln"><span class="key">if</span> <span class="num">0</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t18" class="pln"> <span class="nam">never_happen</span><span class="op">(</span><span class="op">)</span><span class="strut"> </span></p> +<p id="t19" class="pln"><span class="strut"> </span></p> +<p id="t20" class="pln"><span class="key">if</span> <span class="num">1</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t21" class="stm run hide_run"> <span class="nam">a</span> <span class="op">=</span> <span class="num">13</span><span class="strut"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='pln'><span class='strut'> </span></p> -<p id='t3' class='stm run hide_run'><span class='key'>if</span> <span class='num'>1</span> <span class='op'><</span> <span class='num'>2</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t4' class='pln'> <span class='com'># Needed a < to look at HTML entities.</span><span class='strut'> </span></p> -<p id='t5' class='stm run hide_run'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>3</span><span class='strut'> </span></p> -<p id='t6' class='pln'><span class='key'>else</span><span class='op'>:</span><span class='strut'> </span></p> -<p id='t7' class='stm mis'> <span class='nam'>a</span> <span class='op'>=</span> <span class='num'>4</span><span class='strut'> </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"> </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"> </span></p> +<p id="t3" class="pln"><span class="strut"> </span></p> +<p id="t4" class="pln"><span class="com"># A test file for HTML reporting by coverage.py.</span><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="strut"> </span></p> +<p id="t6" class="stm run hide_run"><span class="key">if</span> <span class="num">1</span> <span class="op"><</span> <span class="num">2</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t7" class="pln"> <span class="com"># Needed a < to look at HTML entities.</span><span class="strut"> </span></p> +<p id="t8" class="stm run hide_run"> <span class="nam">a</span> <span class="op">=</span> <span class="num">3</span><span class="strut"> </span></p> +<p id="t9" class="pln"><span class="key">else</span><span class="op">:</span><span class="strut"> </span></p> +<p id="t10" class="stm mis"> <span class="nam">a</span> <span class="op">=</span> <span class="num">4</span><span class="strut"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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> change column sorting + <span class="key">c</span> 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> change column sorting + <span class="key">c</span> 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 - <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> 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> toggle line displays </p> -<p class='keyhelp'> - <span class='key'>j</span> - <span class='key'>k</span> next/prev highlighted chunk +<p class="keyhelp"> + <span class="key">j</span> + <span class="key">k</span> next/prev highlighted chunk </p> -<p class='keyhelp'> - <span class='key'>0</span> (zero) top of page +<p class="keyhelp"> + <span class="key">0</span> (zero) top of page </p> -<p class='keyhelp'> - <span class='key'>1</span> (one) first highlighted chunk +<p class="keyhelp"> + <span class="key">1</span> (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'> </span></p> -<p id='t2' class='pln'><span class='com'># -*- coding: utf-8 -*-</span><span class='strut'> </span></p> -<p id='t3' class='pln'><span class='strut'> </span></p> -<p id='t4' class='stm run hide_run'><span class='nam'>upside_down</span> <span class='op'>=</span> <span class='str'>"ʎd˙ǝbɐɹǝʌoɔ"</span><span class='strut'> </span></p> -<p id='t5' class='stm run hide_run'><span class='nam'>surrogate</span> <span class='op'>=</span> <span class='str'>"db40,dd00: x󠄀"</span><span class='strut'> </span></p> + <td class="text"> +<p id="t1" class="pln"><span class="com"># -*- coding: utf-8 -*-</span><span class="strut"> </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"> </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"> </span></p> +<p id="t4" class="pln"><span class="strut"> </span></p> +<p id="t5" class="pln"><span class="com"># A Python source file with exotic characters.</span><span class="strut"> </span></p> +<p id="t6" class="pln"><span class="strut"> </span></p> +<p id="t7" class="stm run hide_run"><span class="nam">upside_down</span> <span class="op">=</span> <span class="str">"ʎd˙ǝbɐɹǝʌoɔ"</span><span class="strut"> </span></p> +<p id="t8" class="stm run hide_run"><span class="nam">surrogate</span> <span class="op">=</span> <span class="str">"db40,dd00: x󠄀"</span><span class="strut"> </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'>« index</a> <a class='nav' href='http://nedbatchelder.com/code/coverage/4.0a1'>coverage.py v4.0a1</a> + <a class="nav" href="index.html">« index</a> <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"><</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("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"><</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" 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 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">"3×4 = 12, ÷2 = 6±0"</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">"3×4 = 12, ÷2 = 6±0"</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"><</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("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", - '> <span class="key">if</span> ' - '<span class="nam">x</span><span class="op">:</span>' - ' ' - ' ' - '<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">"ʎd˙ǝbɐɹǝʌoɔ"</span>', - ) - -contains_any("html_unicode/unicode_py.html", - '<span class="str">"db40,dd00: x��"</span>', - '<span class="str">"db40,dd00: x󠄀"</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/> '; - } - }, - - /** - * 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 "&"; - case "\\": return "\\\\"; - case '"': return '\"'; - case "<": return "<"; - case ">": return ">"; - 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 ? ' ' : ' '; - }, - 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,' '); - 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 ? '<' : '<', - close = QUnit.jsDump.HTML ? '>' : '>'; - - 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>«ταБЬℓσ»" " numbers", index - ) + ) self.assertIn( "<h1>«ταБЬℓσ»" " numbers", index - ) + ) def test_title_set_in_args(self): self.create_initial_files() @@ -230,11 +271,11 @@ class HtmlTitleTest(HtmlTestHelpers, CoverageTest): self.assertIn( "<title>«ταБЬℓσ»" " & stüff!</title>", index - ) + ) self.assertIn( "<h1>«ταБЬℓσ»" " & stü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't this great?�!" + expected = "# Isn't this great?�!" 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"><</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"><</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 ↛ 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 ↛ 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 ↛ 26, ' + '25 ↛ 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×4 = 12, ÷2 = 6±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×4 = 12, ÷2 = 6±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"><</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">"ʎd˙ǝbɐɹǝʌoɔ"</span>', + ) + + contains_any( + "out/unicode/unicode_py.html", + '<span class="str">"db40,dd00: x��"</span>', + '<span class="str">"db40,dd00: x󠄀"</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ât_py.html">hâ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="â_accented_py.html">â%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'), + ]) |