summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2021-10-11 07:55:05 -0400
committerNed Batchelder <ned@nedbatchelder.com>2021-10-11 07:55:05 -0400
commitfdaa8224ccfa16233fda0c84860ef95ca073ee95 (patch)
tree58ea8499c9a059358348f620ea98a42aefa69c6b
parentcedd319b6bc76843e570e7e53c4cb98ce359136e (diff)
downloadpython-coveragepy-git-fdaa8224ccfa16233fda0c84860ef95ca073ee95.tar.gz
test: add more tests of run_python_file
The tests in test_process run the exception handling in execfile.py, but only under coverage, so metacov can't see it. These smaller tests exercise the code without coverage on top.
-rw-r--r--coverage/execfile.py6
-rw-r--r--tests/test_execfile.py87
-rw-r--r--tests/test_process.py11
3 files changed, 95 insertions, 9 deletions
diff --git a/coverage/execfile.py b/coverage/execfile.py
index 539e368d..3da3ba1f 100644
--- a/coverage/execfile.py
+++ b/coverage/execfile.py
@@ -220,8 +220,7 @@ class PyRunner:
# Call the excepthook.
try:
- if hasattr(err, "__traceback__"):
- err.__traceback__ = err.__traceback__.tb_next
+ err.__traceback__ = err.__traceback__.tb_next
sys.excepthook(typ, err, tb.tb_next)
except SystemExit: # pylint: disable=try-except-raise
raise
@@ -231,8 +230,7 @@ class PyRunner:
sys.stderr.write("Error in sys.excepthook:\n")
typ2, err2, tb2 = sys.exc_info()
err2.__suppress_context__ = True
- if hasattr(err2, "__traceback__"):
- err2.__traceback__ = err2.__traceback__.tb_next
+ err2.__traceback__ = err2.__traceback__.tb_next
sys.__excepthook__(typ2, err2, tb2.tb_next)
sys.stderr.write("\nOriginal exception was:\n")
raise ExceptionDuringRun(typ, err, tb.tb_next) from exc
diff --git a/tests/test_execfile.py b/tests/test_execfile.py
index b1306233..21cbb727 100644
--- a/tests/test_execfile.py
+++ b/tests/test_execfile.py
@@ -14,7 +14,7 @@ import re
import pytest
from coverage import env
-from coverage.exceptions import NoCode, NoSource
+from coverage.exceptions import NoCode, NoSource, ExceptionDuringRun
from coverage.execfile import run_python_file, run_python_module
from coverage.files import python_reported_file
@@ -102,6 +102,91 @@ class RunFileTest(CoverageTest):
with pytest.raises(NoSource, match="Can't find '__main__' module in 'without_main'"):
run_python_file(["without_main"])
+ def test_code_throws(self):
+ self.make_file("throw.py", """\
+ class MyException(Exception):
+ pass
+
+ def f1():
+ print("about to raise..")
+ raise MyException("hey!")
+
+ def f2():
+ f1()
+
+ f2()
+ """)
+
+ with pytest.raises(SystemExit) as exc_info:
+ run_python_file(["throw.py"])
+ assert exc_info.value.args == (1,)
+ assert self.stdout() == "about to raise..\n"
+ assert self.stderr() == ""
+
+ def test_code_exits(self):
+ self.make_file("exit.py", """\
+ import sys
+ def f1():
+ print("about to exit..")
+ sys.exit(17)
+
+ def f2():
+ f1()
+
+ f2()
+ """)
+
+ with pytest.raises(SystemExit) as exc_info:
+ run_python_file(["exit.py"])
+ assert exc_info.value.args == (17,)
+ assert self.stdout() == "about to exit..\n"
+ assert self.stderr() == ""
+
+ @pytest.mark.skipif(not env.CPYTHON,
+ reason="non-CPython handles excepthook exits differently, punt for now."
+ )
+ def test_excepthook_exit(self):
+ self.make_file("excepthook_exit.py", """\
+ import sys
+
+ def excepthook(*args):
+ print('in excepthook')
+ sys.exit(0)
+
+ sys.excepthook = excepthook
+
+ raise RuntimeError('Error Outside')
+ """)
+ with pytest.raises(SystemExit):
+ run_python_file(["excepthook_exit.py"])
+ cov_out = self.stdout()
+ assert cov_out == "in excepthook\n"
+
+ @pytest.mark.skipif(env.PYPY, reason="PyPy handles excepthook throws differently.")
+ def test_excepthook_throw(self):
+ self.make_file("excepthook_throw.py", """\
+ import sys
+
+ def excepthook(*args):
+ # Write this message to stderr so that we don't have to deal
+ # with interleaved stdout/stderr comparisons in the assertions
+ # in the test.
+ sys.stderr.write('in excepthook\\n')
+ raise RuntimeError('Error Inside')
+
+ sys.excepthook = excepthook
+
+ raise RuntimeError('Error Outside')
+ """)
+ with pytest.raises(ExceptionDuringRun) as exc_info:
+ run_python_file(["excepthook_throw.py"])
+ # The ExceptionDuringRun exception has the RuntimeError as its argument.
+ assert exc_info.value.args[1].args[0] == "Error Outside"
+ stderr = self.stderr()
+ assert "in excepthook\n" in stderr
+ assert "Error in sys.excepthook:\n" in stderr
+ assert "RuntimeError: Error Inside" in stderr
+
class RunPycFileTest(CoverageTest):
"""Test cases for `run_python_file`."""
diff --git a/tests/test_process.py b/tests/test_process.py
index 781a0170..63dd1d5b 100644
--- a/tests/test_process.py
+++ b/tests/test_process.py
@@ -468,8 +468,11 @@ class ProcessTest(CoverageTest):
def test_code_throws(self):
self.make_file("throw.py", """\
+ class MyException(Exception):
+ pass
+
def f1():
- raise Exception("hey!")
+ raise MyException("hey!")
def f2():
f1()
@@ -488,9 +491,9 @@ class ProcessTest(CoverageTest):
# But also make sure that the output is what we expect.
path = python_reported_file('throw.py')
- msg = f'File "{re.escape(path)}", line 5,? in f2'
+ msg = f'File "{re.escape(path)}", line 8, in f2'
assert re.search(msg, out)
- assert 'raise Exception("hey!")' in out
+ assert 'raise MyException("hey!")' in out
assert status == 1
def test_code_exits(self):
@@ -1121,7 +1124,7 @@ class ExcepthookTest(CoverageTest):
assert cov_st == py_st
assert cov_st == 0
- assert "in excepthook" in py_out
+ assert py_out == "in excepthook\n"
assert cov_out == py_out
@pytest.mark.skipif(env.PYPY, reason="PyPy handles excepthook throws differently.")