summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/coveragetest.py15
-rw-r--r--tests/farm/html/src/partial.ini9
-rw-r--r--tests/farm/html/src/partial.py9
-rw-r--r--tests/test_arcs.py60
-rw-r--r--tests/test_cmdline.py8
-rw-r--r--tests/test_config.py2
-rw-r--r--tests/test_execfile.py19
-rw-r--r--tests/test_html.py60
-rw-r--r--tests/test_misc.py7
-rw-r--r--tests/test_process.py42
-rw-r--r--tests/test_summary.py41
11 files changed, 222 insertions, 50 deletions
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index dacb9b6..539dd59 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -240,17 +240,17 @@ class CoverageTest(
with self.delayed_assertions():
self.assert_equal_args(
analysis.arc_possibilities(), arcs,
- "Possible arcs differ",
+ "Possible arcs differ: minus is actual, plus is expected"
)
self.assert_equal_args(
analysis.arcs_missing(), arcs_missing,
- "Missing arcs differ"
+ "Missing arcs differ: minus is actual, plus is expected"
)
self.assert_equal_args(
analysis.arcs_unpredicted(), arcs_unpredicted,
- "Unpredicted arcs differ"
+ "Unpredicted arcs differ: minus is actual, plus is expected"
)
if report:
@@ -397,9 +397,8 @@ class CoverageTest(
# 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__, ".."))
- testmods = self.nice_file(here, 'tests/modules')
- zipfile = self.nice_file(here, 'tests/zipmods.zip')
+ testmods = self.nice_file(self.working_root(), 'tests/modules')
+ zipfile = self.nice_file(self.working_root(), 'tests/zipmods.zip')
pypath = os.getenv('PYTHONPATH', '')
if pypath:
pypath += os.pathsep
@@ -410,6 +409,10 @@ class CoverageTest(
print(self.last_command_output)
return self.last_command_status, self.last_command_output
+ def working_root(self):
+ """Where is the root of the coverage.py working tree?"""
+ return os.path.dirname(self.nice_file(coverage.__file__, ".."))
+
def report_from_command(self, cmd):
"""Return the report from the `cmd`, with some convenience added."""
report = self.run_command(cmd).replace('\\', '/')
diff --git a/tests/farm/html/src/partial.ini b/tests/farm/html/src/partial.ini
new file mode 100644
index 0000000..cdb241b
--- /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 66dddac..0f8fbe3c 100644
--- a/tests/farm/html/src/partial.py
+++ b/tests/farm/html/src/partial.py
@@ -1,9 +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
-# partial branches
+# partial branches and excluded lines
-a = 3
+a = 6
while True:
break
@@ -18,4 +18,7 @@ if 0:
never_happen()
if 1:
- a = 13
+ a = 21
+
+if a == 23:
+ raise AssertionError("Can't")
diff --git a/tests/test_arcs.py b/tests/test_arcs.py
index b03ac53..d9b77dc 100644
--- a/tests/test_arcs.py
+++ b/tests/test_arcs.py
@@ -252,12 +252,12 @@ class LoopArcTest(CoverageTest):
""",
arcz=".1 12 23 34 45 36 63 57 7.",
)
- # With "while True", 2.x thinks it's computation, 3.x thinks it's
- # constant.
+ # With "while True", 2.x thinks it's computation,
+ # 3.x thinks it's constant.
if env.PY3:
arcz = ".1 12 23 34 45 36 63 57 7."
else:
- arcz = ".1 12 23 27 34 45 36 62 57 7."
+ arcz = ".1 12 23 34 45 36 62 57 7."
self.check_coverage("""\
a, i = 1, 0
while True:
@@ -270,6 +270,37 @@ class LoopArcTest(CoverageTest):
arcz=arcz,
)
+ def test_zero_coverage_while_loop(self):
+ # https://bitbucket.org/ned/coveragepy/issue/502
+ self.make_file("main.py", "print('done')")
+ self.make_file("zero.py", """\
+ def method(self):
+ while True:
+ return 1
+ """)
+ out = self.run_command("coverage run --branch --source=. main.py")
+ self.assertEqual(out, 'done\n')
+ report = self.report_from_command("coverage report -m")
+ squeezed = self.squeezed_lines(report)
+ self.assertIn("zero.py 3 3 0 0 0% 1-3", squeezed[3])
+
+ def test_bug_496_continue_in_constant_while(self):
+ # https://bitbucket.org/ned/coveragepy/issue/496
+ if env.PY3:
+ arcz = ".1 12 23 34 45 53 46 6."
+ else:
+ arcz = ".1 12 23 34 45 52 46 6."
+ self.check_coverage("""\
+ up = iter('ta')
+ while True:
+ char = next(up)
+ if char == 't':
+ continue
+ break
+ """,
+ arcz=arcz
+ )
+
def test_for_if_else_for(self):
self.check_coverage("""\
def branches_2(l):
@@ -762,16 +793,19 @@ class ExceptionArcTest(CoverageTest):
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 check_token(data):
+ if data:
+ try:
+ return 5
+ finally:
+ a.append(7)
+ return 8
+ assert check_token(False) == 8
+ assert a == [1]
+ assert check_token(True) == 5
+ assert a == [1, 7]
+ """,
+ arcz=".1 12 29 9A AB BC C-1 -23 34 45 57 7-2 38 8-2",
)
def test_except_jump_finally(self):
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index 3b982eb..45898f1 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -16,7 +16,7 @@ import coverage.cmdline
from coverage import env
from coverage.config import CoverageConfig
from coverage.data import CoverageData, CoverageDataFiles
-from coverage.misc import ExceptionDuringRun
+from coverage.misc import CoverageException, ExceptionDuringRun
from tests.coveragetest import CoverageTest, OK, ERR
@@ -39,7 +39,7 @@ class BaseCmdLineTest(CoverageTest):
)
defaults.html_report(
directory=None, ignore_errors=None, include=None, omit=None, morfs=[],
- title=None,
+ skip_covered=None, title=None
)
defaults.report(
ignore_errors=None, include=None, omit=None, morfs=[],
@@ -459,6 +459,10 @@ class CmdLineTest(BaseCmdLineTest):
.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()
diff --git a/tests/test_config.py b/tests/test_config.py
index 6cb5e46..2aa592b 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -239,7 +239,6 @@ class ConfigFileTest(CoverageTest):
branch = 1
cover_pylib = TRUE
parallel = on
- include = a/ , b/
concurrency = thread
source = myapp
plugins =
@@ -329,7 +328,6 @@ class ConfigFileTest(CoverageTest):
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.precision, 3)
diff --git a/tests/test_execfile.py b/tests/test_execfile.py
index 889d6cf..8585b16 100644
--- a/tests/test_execfile.py
+++ b/tests/test_execfile.py
@@ -145,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."""
diff --git a/tests/test_html.py b/tests/test_html.py
index 1df602f..1c9fa43 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -6,6 +6,7 @@
import datetime
import glob
+import json
import os
import os.path
import re
@@ -208,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."""
@@ -425,6 +447,40 @@ class HtmlTest(HtmlTestHelpers, CoverageTest):
self.run_coverage()
self.assert_exists("htmlcov/status.dat")
+ def test_report_skip_covered_no_branches(self):
+ self.make_file("main_file.py", """
+ import not_covered
+
+ def normal():
+ print("z")
+ normal()
+ """)
+ self.make_file("not_covered.py", """
+ def not_covered():
+ print("n")
+ """)
+ self.run_coverage(htmlargs=dict(skip_covered=True))
+ self.assert_exists("htmlcov/index.html")
+ self.assert_doesnt_exist("htmlcov/main_file_py.html")
+ self.assert_exists("htmlcov/not_covered_py.html")
+
+ def test_report_skip_covered_branches(self):
+ self.make_file("main_file.py", """
+ import not_covered
+
+ def normal():
+ print("z")
+ normal()
+ """)
+ self.make_file("not_covered.py", """
+ def not_covered():
+ print("n")
+ """)
+ self.run_coverage(covargs=dict(branch=True), htmlargs=dict(skip_covered=True))
+ self.assert_exists("htmlcov/index.html")
+ self.assert_doesnt_exist("htmlcov/main_file_py.html")
+ self.assert_exists("htmlcov/not_covered_py.html")
+
class HtmlStaticFileTest(CoverageTest):
"""Tests of the static file copying for the HTML report."""
@@ -686,7 +742,7 @@ class HtmlGoldTests(CoverageGoldTest):
with change_dir("src"):
# pylint: disable=import-error
- cov = coverage.Coverage(branch=True)
+ cov = coverage.Coverage(config_file="partial.ini")
cov.start()
import partial # pragma: nested
cov.stop() # pragma: nested
@@ -700,6 +756,8 @@ class HtmlGoldTests(CoverageGoldTest):
'<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",
diff --git a/tests/test_misc.py b/tests/test_misc.py
index 38be345..96b5100 100644
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -34,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})
diff --git a/tests/test_process.py b/tests/test_process.py
index dda43ba..2e94c19 100644
--- a/tests/test_process.py
+++ b/tests/test_process.py
@@ -11,6 +11,8 @@ import re
import sys
import textwrap
+import pytest
+
import coverage
from coverage import env, CoverageData
from coverage.misc import output_encoding
@@ -692,6 +694,7 @@ class ProcessTest(CoverageTest):
self.assertEqual(len(infos), 1)
self.assertEqual(infos[0]['note'], u"These are musical notes: ♫𝅗𝅥♩")
+ @pytest.mark.expensive
def test_fullcoverage(self): # pragma: not covered
if env.PY2: # This doesn't work on Python 2.
self.skipTest("fullcoverage doesn't work on Python 2.")
@@ -1139,25 +1142,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 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
- worker = os.environ.get('PYTEST_XDIST_WORKER', '')
- pth_path = os.path.join(pth_dir, "subcover_{0}.pth".format(worker))
- 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)
diff --git a/tests/test_summary.py b/tests/test_summary.py
index bda6568..5ba0038 100644
--- a/tests/test_summary.py
+++ b/tests/test_summary.py
@@ -361,6 +361,27 @@ class SummaryTest(CoverageTest):
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")
@@ -381,18 +402,18 @@ class SummaryTest(CoverageTest):
self.make_file("mycode.py", "This isn't python at all!")
report = self.report_from_command("coverage report mycode.py")
+ # mycode NotPython: Couldn't parse '...' as Python source: 'invalid syntax' at line 1
# Name Stmts Miss Cover
# ----------------------------
- # mycode NotPython: Couldn't parse '...' 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 '.*mycode.py", "parse 'mycode.py", errmsg)
# The actual error message varies version to version
- last = re.sub(r": '.*' at", ": 'error' at", last)
+ errmsg = re.sub(r": '.*' at", ": 'error' at", errmsg)
self.assertEqual(
- last,
+ errmsg,
"mycode.py NotPython: Couldn't parse 'mycode.py' as Python source: 'error' at line 1"
)
@@ -405,16 +426,16 @@ class SummaryTest(CoverageTest):
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
# ----------------------------
- # xxxx NotPython: Couldn't parse '...' 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 '.*(accented.*?\.py)", r"parse '\1", 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)
+ 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"
@@ -422,7 +443,7 @@ class SummaryTest(CoverageTest):
if env.PY2:
# pylint: disable=redefined-variable-type
expected = expected.encode(output_encoding())
- self.assertEqual(last, expected)
+ 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,