Skip to content

Commit

Permalink
test: add more tests of run_python_file
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nedbat committed Oct 11, 2021
1 parent cedd319 commit fdaa822
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 9 deletions.
6 changes: 2 additions & 4 deletions coverage/execfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ def run(self):

# 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
Expand All @@ -231,8 +230,7 @@ def run(self):
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
Expand Down
87 changes: 86 additions & 1 deletion tests/test_execfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
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

Expand Down Expand Up @@ -102,6 +102,91 @@ def test_directory_without_main(self):
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`."""
Expand Down
11 changes: 7 additions & 4 deletions tests/test_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,11 @@ def test_running_missing_file(self):

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()
Expand All @@ -488,9 +491,9 @@ def f2():

# 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):
Expand Down Expand Up @@ -1121,7 +1124,7 @@ def excepthook(*args):
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.")
Expand Down

0 comments on commit fdaa822

Please sign in to comment.