2018-10-25 15:01:29 +08:00
|
|
|
from __future__ import absolute_import
|
|
|
|
from __future__ import division
|
|
|
|
from __future__ import print_function
|
|
|
|
|
2018-03-22 17:40:35 +08:00
|
|
|
import os
|
2018-10-25 15:01:29 +08:00
|
|
|
import sys
|
2009-09-06 22:59:39 +08:00
|
|
|
|
2015-11-27 22:43:01 +08:00
|
|
|
import _pytest._code
|
2016-07-12 09:03:53 +08:00
|
|
|
import pytest
|
2019-03-01 01:10:57 +08:00
|
|
|
from _pytest.debugging import _validate_usepdb_cls
|
2015-11-27 22:43:01 +08:00
|
|
|
|
2018-09-24 09:39:50 +08:00
|
|
|
try:
|
|
|
|
breakpoint
|
|
|
|
except NameError:
|
|
|
|
SUPPORTS_BREAKPOINT_BUILTIN = False
|
|
|
|
else:
|
|
|
|
SUPPORTS_BREAKPOINT_BUILTIN = True
|
|
|
|
|
2015-11-27 22:43:01 +08:00
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
_ENVIRON_PYTHONBREAKPOINT = os.environ.get("PYTHONBREAKPOINT", "")
|
2018-03-23 11:18:56 +08:00
|
|
|
|
|
|
|
|
2015-04-28 17:54:53 +08:00
|
|
|
def runpdb_and_get_report(testdir, source):
|
|
|
|
p = testdir.makepyfile(source)
|
|
|
|
result = testdir.runpytest_inprocess("--pdb", p)
|
|
|
|
reports = result.reprec.getreports("pytest_runtest_logreport")
|
2017-07-17 07:25:09 +08:00
|
|
|
assert len(reports) == 3, reports # setup/call/teardown
|
2015-04-28 17:54:53 +08:00
|
|
|
return reports[1]
|
|
|
|
|
2013-09-06 17:56:04 +08:00
|
|
|
|
2016-09-20 00:05:57 +08:00
|
|
|
@pytest.fixture
|
|
|
|
def custom_pdb_calls():
|
|
|
|
called = []
|
|
|
|
|
|
|
|
# install dummy debugger class and track which methods were called on it
|
2017-02-17 02:41:51 +08:00
|
|
|
class _CustomPdb(object):
|
2018-10-13 22:49:30 +08:00
|
|
|
quitting = False
|
|
|
|
|
2016-09-20 00:05:57 +08:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
called.append("init")
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
called.append("reset")
|
|
|
|
|
|
|
|
def interaction(self, *args):
|
|
|
|
called.append("interaction")
|
|
|
|
|
|
|
|
_pytest._CustomPdb = _CustomPdb
|
|
|
|
return called
|
|
|
|
|
|
|
|
|
2018-03-23 12:30:05 +08:00
|
|
|
@pytest.fixture
|
|
|
|
def custom_debugger_hook():
|
|
|
|
called = []
|
|
|
|
|
|
|
|
# install dummy debugger class and track which methods were called on it
|
|
|
|
class _CustomDebugger(object):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
called.append("init")
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
called.append("reset")
|
|
|
|
|
|
|
|
def interaction(self, *args):
|
|
|
|
called.append("interaction")
|
|
|
|
|
|
|
|
def set_trace(self, frame):
|
|
|
|
print("**CustomDebugger**")
|
|
|
|
called.append("set_trace")
|
|
|
|
|
|
|
|
_pytest._CustomDebugger = _CustomDebugger
|
2018-03-27 14:38:17 +08:00
|
|
|
yield called
|
|
|
|
del _pytest._CustomDebugger
|
2018-03-23 12:30:05 +08:00
|
|
|
|
|
|
|
|
2017-02-17 02:41:51 +08:00
|
|
|
class TestPDB(object):
|
2016-07-12 09:03:53 +08:00
|
|
|
@pytest.fixture
|
|
|
|
def pdblist(self, request):
|
2016-06-21 18:09:55 +08:00
|
|
|
monkeypatch = request.getfixturevalue("monkeypatch")
|
2009-09-06 22:59:39 +08:00
|
|
|
pdblist = []
|
2016-11-21 04:59:15 +08:00
|
|
|
|
2009-09-06 22:59:39 +08:00
|
|
|
def mypdb(*args):
|
|
|
|
pdblist.append(args)
|
2016-11-21 04:59:15 +08:00
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
plugin = request.config.pluginmanager.getplugin("debugging")
|
|
|
|
monkeypatch.setattr(plugin, "post_mortem", mypdb)
|
2010-07-27 03:15:15 +08:00
|
|
|
return pdblist
|
|
|
|
|
2009-09-06 22:59:39 +08:00
|
|
|
def test_pdb_on_fail(self, testdir, pdblist):
|
2018-05-23 22:48:46 +08:00
|
|
|
rep = runpdb_and_get_report(
|
|
|
|
testdir,
|
|
|
|
"""
|
2010-07-27 03:15:15 +08:00
|
|
|
def test_func():
|
2009-09-06 22:59:39 +08:00
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
""",
|
|
|
|
)
|
2009-09-06 22:59:39 +08:00
|
|
|
assert rep.failed
|
|
|
|
assert len(pdblist) == 1
|
2015-11-27 22:43:01 +08:00
|
|
|
tb = _pytest._code.Traceback(pdblist[0][0])
|
2009-09-06 22:59:39 +08:00
|
|
|
assert tb[-1].name == "test_func"
|
|
|
|
|
2010-06-16 18:35:08 +08:00
|
|
|
def test_pdb_on_xfail(self, testdir, pdblist):
|
2018-05-23 22:48:46 +08:00
|
|
|
rep = runpdb_and_get_report(
|
|
|
|
testdir,
|
|
|
|
"""
|
2010-11-18 05:12:16 +08:00
|
|
|
import pytest
|
|
|
|
@pytest.mark.xfail
|
2010-07-27 03:15:15 +08:00
|
|
|
def test_func():
|
2010-06-16 18:35:08 +08:00
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
""",
|
|
|
|
)
|
2010-06-16 18:35:08 +08:00
|
|
|
assert "xfail" in rep.keywords
|
2010-07-27 03:15:15 +08:00
|
|
|
assert not pdblist
|
2010-06-16 18:35:08 +08:00
|
|
|
|
2009-09-06 22:59:39 +08:00
|
|
|
def test_pdb_on_skip(self, testdir, pdblist):
|
2018-05-23 22:48:46 +08:00
|
|
|
rep = runpdb_and_get_report(
|
|
|
|
testdir,
|
|
|
|
"""
|
2010-11-18 05:12:16 +08:00
|
|
|
import pytest
|
2009-09-06 22:59:39 +08:00
|
|
|
def test_func():
|
2010-11-18 05:12:16 +08:00
|
|
|
pytest.skip("hello")
|
2018-05-23 22:48:46 +08:00
|
|
|
""",
|
|
|
|
)
|
2010-07-27 03:15:15 +08:00
|
|
|
assert rep.skipped
|
2009-09-06 22:59:39 +08:00
|
|
|
assert len(pdblist) == 0
|
|
|
|
|
2010-10-06 20:28:06 +08:00
|
|
|
def test_pdb_on_BdbQuit(self, testdir, pdblist):
|
2018-05-23 22:48:46 +08:00
|
|
|
rep = runpdb_and_get_report(
|
|
|
|
testdir,
|
|
|
|
"""
|
2010-11-18 05:12:16 +08:00
|
|
|
import bdb
|
2010-10-06 20:28:06 +08:00
|
|
|
def test_func():
|
|
|
|
raise bdb.BdbQuit
|
2018-05-23 22:48:46 +08:00
|
|
|
""",
|
|
|
|
)
|
2010-10-06 20:28:06 +08:00
|
|
|
assert rep.failed
|
|
|
|
assert len(pdblist) == 0
|
|
|
|
|
2018-05-02 05:58:35 +08:00
|
|
|
def test_pdb_on_KeyboardInterrupt(self, testdir, pdblist):
|
2018-05-23 22:48:46 +08:00
|
|
|
rep = runpdb_and_get_report(
|
|
|
|
testdir,
|
|
|
|
"""
|
2018-05-02 05:58:35 +08:00
|
|
|
def test_func():
|
|
|
|
raise KeyboardInterrupt
|
2018-05-23 22:48:46 +08:00
|
|
|
""",
|
|
|
|
)
|
2018-05-02 05:58:35 +08:00
|
|
|
assert rep.failed
|
|
|
|
assert len(pdblist) == 1
|
|
|
|
|
2016-10-22 00:10:35 +08:00
|
|
|
@staticmethod
|
|
|
|
def flush(child):
|
2010-07-27 03:15:15 +08:00
|
|
|
if child.isalive():
|
2019-05-27 09:00:32 +08:00
|
|
|
# Read if the test has not (e.g. test_pdb_unittest_skip).
|
|
|
|
child.read()
|
2009-09-06 22:59:39 +08:00
|
|
|
child.wait()
|
2019-05-27 09:00:32 +08:00
|
|
|
assert not child.isalive()
|
2010-02-08 21:17:01 +08:00
|
|
|
|
2016-09-01 02:22:54 +08:00
|
|
|
def test_pdb_unittest_postmortem(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2016-09-01 02:22:54 +08:00
|
|
|
import unittest
|
|
|
|
class Blub(unittest.TestCase):
|
|
|
|
def tearDown(self):
|
|
|
|
self.filename = None
|
|
|
|
def test_false(self):
|
2016-09-01 04:33:47 +08:00
|
|
|
self.filename = 'debug' + '.me'
|
2016-09-01 02:22:54 +08:00
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2016-09-01 02:22:54 +08:00
|
|
|
child = testdir.spawn_pytest("--pdb %s" % p1)
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-05-23 22:48:46 +08:00
|
|
|
child.sendline("p self.filename")
|
2016-09-01 02:22:54 +08:00
|
|
|
child.sendeof()
|
|
|
|
rest = child.read().decode("utf8")
|
2018-05-23 22:48:46 +08:00
|
|
|
assert "debug.me" in rest
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2016-09-01 02:22:54 +08:00
|
|
|
|
2017-01-31 04:20:12 +08:00
|
|
|
def test_pdb_unittest_skip(self, testdir):
|
2017-02-02 12:01:51 +08:00
|
|
|
"""Test for issue #2137"""
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2017-01-31 04:20:12 +08:00
|
|
|
import unittest
|
|
|
|
@unittest.skipIf(True, 'Skipping also with pdb active')
|
|
|
|
class MyTestCase(unittest.TestCase):
|
|
|
|
def test_one(self):
|
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2017-01-31 04:20:12 +08:00
|
|
|
child = testdir.spawn_pytest("-rs --pdb %s" % p1)
|
2018-05-23 22:48:46 +08:00
|
|
|
child.expect("Skipping also with pdb active")
|
|
|
|
child.expect("1 skipped in")
|
2017-01-31 04:20:12 +08:00
|
|
|
child.sendeof()
|
|
|
|
self.flush(child)
|
|
|
|
|
2018-10-31 23:20:44 +08:00
|
|
|
def test_pdb_print_captured_stdout_and_stderr(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2016-01-08 20:41:01 +08:00
|
|
|
def test_1():
|
2018-10-31 23:20:44 +08:00
|
|
|
import sys
|
|
|
|
sys.stderr.write("get\\x20rekt")
|
2018-02-13 05:17:51 +08:00
|
|
|
print("get\\x20rekt")
|
2016-01-08 20:41:01 +08:00
|
|
|
assert False
|
2018-10-31 23:20:44 +08:00
|
|
|
|
|
|
|
def test_not_called_due_to_quit():
|
|
|
|
pass
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2016-01-08 20:41:01 +08:00
|
|
|
child = testdir.spawn_pytest("--pdb %s" % p1)
|
2018-02-13 05:17:51 +08:00
|
|
|
child.expect("captured stdout")
|
|
|
|
child.expect("get rekt")
|
|
|
|
child.expect("captured stderr")
|
|
|
|
child.expect("get rekt")
|
2018-10-31 23:20:44 +08:00
|
|
|
child.expect("traceback")
|
|
|
|
child.expect("def test_1")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-02-13 05:17:51 +08:00
|
|
|
child.sendeof()
|
|
|
|
rest = child.read().decode("utf8")
|
2018-10-31 23:20:44 +08:00
|
|
|
assert "Exit: Quitting debugger" in rest
|
|
|
|
assert "= 1 failed in" in rest
|
|
|
|
assert "def test_1" not in rest
|
2018-02-13 05:17:51 +08:00
|
|
|
assert "get rekt" not in rest
|
|
|
|
self.flush(child)
|
|
|
|
|
|
|
|
def test_pdb_dont_print_empty_captured_stdout_and_stderr(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2018-02-13 05:17:51 +08:00
|
|
|
def test_1():
|
|
|
|
assert False
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-02-13 05:17:51 +08:00
|
|
|
child = testdir.spawn_pytest("--pdb %s" % p1)
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-02-13 05:17:51 +08:00
|
|
|
output = child.before.decode("utf8")
|
|
|
|
child.sendeof()
|
|
|
|
assert "captured stdout" not in output
|
|
|
|
assert "captured stderr" not in output
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2018-02-13 04:05:46 +08:00
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.parametrize("showcapture", ["all", "no", "log"])
|
2018-02-18 19:42:25 +08:00
|
|
|
def test_pdb_print_captured_logs(self, testdir, showcapture):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2018-02-13 04:05:46 +08:00
|
|
|
def test_1():
|
|
|
|
import logging
|
2018-02-18 19:42:25 +08:00
|
|
|
logging.warn("get " + "rekt")
|
2018-02-13 04:05:46 +08:00
|
|
|
assert False
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-08-23 09:30:42 +08:00
|
|
|
child = testdir.spawn_pytest(
|
|
|
|
"--show-capture={} --pdb {}".format(showcapture, p1)
|
|
|
|
)
|
2018-05-23 22:48:46 +08:00
|
|
|
if showcapture in ("all", "log"):
|
2018-02-18 19:42:25 +08:00
|
|
|
child.expect("captured log")
|
|
|
|
child.expect("get rekt")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-02-13 04:05:46 +08:00
|
|
|
child.sendeof()
|
|
|
|
rest = child.read().decode("utf8")
|
|
|
|
assert "1 failed" in rest
|
|
|
|
self.flush(child)
|
2016-01-08 20:41:01 +08:00
|
|
|
|
2018-02-23 02:26:46 +08:00
|
|
|
def test_pdb_print_captured_logs_nologging(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2018-02-23 02:26:46 +08:00
|
|
|
def test_1():
|
|
|
|
import logging
|
|
|
|
logging.warn("get " + "rekt")
|
|
|
|
assert False
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-10-11 06:53:21 +08:00
|
|
|
child = testdir.spawn_pytest("--show-capture=all --pdb -p no:logging %s" % p1)
|
2018-02-23 02:26:46 +08:00
|
|
|
child.expect("get rekt")
|
|
|
|
output = child.before.decode("utf8")
|
|
|
|
assert "captured log" not in output
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-02-23 02:26:46 +08:00
|
|
|
child.sendeof()
|
|
|
|
rest = child.read().decode("utf8")
|
|
|
|
assert "1 failed" in rest
|
|
|
|
self.flush(child)
|
|
|
|
|
2010-02-08 21:17:01 +08:00
|
|
|
def test_pdb_interaction_exception(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2010-11-18 05:12:16 +08:00
|
|
|
import pytest
|
2010-02-08 21:17:01 +08:00
|
|
|
def globalfunc():
|
|
|
|
pass
|
|
|
|
def test_1():
|
2010-11-18 05:12:16 +08:00
|
|
|
pytest.raises(ValueError, globalfunc)
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2010-02-08 21:17:01 +08:00
|
|
|
child = testdir.spawn_pytest("--pdb %s" % p1)
|
|
|
|
child.expect(".*def test_1")
|
2010-11-18 05:12:16 +08:00
|
|
|
child.expect(".*pytest.raises.*globalfunc")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2010-02-08 21:17:01 +08:00
|
|
|
child.sendline("globalfunc")
|
|
|
|
child.expect(".*function")
|
|
|
|
child.sendeof()
|
|
|
|
child.expect("1 failed")
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2010-10-06 20:48:24 +08:00
|
|
|
|
2013-09-06 17:56:04 +08:00
|
|
|
def test_pdb_interaction_on_collection_issue181(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2013-09-06 17:56:04 +08:00
|
|
|
import pytest
|
|
|
|
xxx
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2013-09-06 17:56:04 +08:00
|
|
|
child = testdir.spawn_pytest("--pdb %s" % p1)
|
2017-07-17 07:25:09 +08:00
|
|
|
# child.expect(".*import pytest.*")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-10-13 22:49:30 +08:00
|
|
|
child.sendline("c")
|
2013-09-06 17:56:04 +08:00
|
|
|
child.expect("1 error")
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2013-09-06 17:56:04 +08:00
|
|
|
|
|
|
|
def test_pdb_interaction_on_internal_error(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
testdir.makeconftest(
|
|
|
|
"""
|
2013-09-06 17:56:04 +08:00
|
|
|
def pytest_runtest_protocol():
|
|
|
|
0/0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2013-09-06 17:56:04 +08:00
|
|
|
p1 = testdir.makepyfile("def test_func(): pass")
|
|
|
|
child = testdir.spawn_pytest("--pdb %s" % p1)
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-10-13 22:33:53 +08:00
|
|
|
|
|
|
|
# INTERNALERROR is only displayed once via terminal reporter.
|
2018-10-14 09:13:25 +08:00
|
|
|
assert (
|
|
|
|
len(
|
|
|
|
[
|
|
|
|
x
|
|
|
|
for x in child.before.decode().splitlines()
|
|
|
|
if x.startswith("INTERNALERROR> Traceback")
|
|
|
|
]
|
|
|
|
)
|
|
|
|
== 1
|
|
|
|
)
|
2018-10-13 22:33:53 +08:00
|
|
|
|
2013-09-06 17:56:04 +08:00
|
|
|
child.sendeof()
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2013-09-06 17:56:04 +08:00
|
|
|
|
2010-10-06 20:48:24 +08:00
|
|
|
def test_pdb_interaction_capturing_simple(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2010-11-18 05:12:16 +08:00
|
|
|
import pytest
|
2010-10-06 20:48:24 +08:00
|
|
|
def test_1():
|
|
|
|
i = 0
|
2018-10-13 22:42:33 +08:00
|
|
|
print("hello17")
|
2010-11-18 05:12:16 +08:00
|
|
|
pytest.set_trace()
|
2018-10-31 23:20:44 +08:00
|
|
|
i == 1
|
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2010-10-06 20:48:24 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
2018-10-31 23:20:44 +08:00
|
|
|
child.expect(r"test_1\(\)")
|
|
|
|
child.expect("i == 1")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-10-31 23:20:44 +08:00
|
|
|
child.sendline("c")
|
2013-11-19 17:10:27 +08:00
|
|
|
rest = child.read().decode("utf-8")
|
2018-10-31 23:20:44 +08:00
|
|
|
assert "AssertionError" in rest
|
2010-10-06 20:48:24 +08:00
|
|
|
assert "1 failed" in rest
|
|
|
|
assert "def test_1" in rest
|
2017-07-17 07:25:09 +08:00
|
|
|
assert "hello17" in rest # out is captured
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2010-10-06 20:48:24 +08:00
|
|
|
|
2018-11-19 03:18:42 +08:00
|
|
|
def test_pdb_set_trace_kwargs(self, testdir):
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
import pytest
|
|
|
|
def test_1():
|
|
|
|
i = 0
|
|
|
|
print("hello17")
|
|
|
|
pytest.set_trace(header="== my_header ==")
|
|
|
|
x = 3
|
2018-10-31 23:20:44 +08:00
|
|
|
assert 0
|
2018-11-19 03:18:42 +08:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("== my_header ==")
|
|
|
|
assert "PDB set_trace" not in child.before.decode()
|
|
|
|
child.expect("Pdb")
|
2018-10-31 23:20:44 +08:00
|
|
|
child.sendline("c")
|
2018-11-19 03:18:42 +08:00
|
|
|
rest = child.read().decode("utf-8")
|
|
|
|
assert "1 failed" in rest
|
|
|
|
assert "def test_1" in rest
|
|
|
|
assert "hello17" in rest # out is captured
|
|
|
|
self.flush(child)
|
|
|
|
|
2013-09-06 21:29:00 +08:00
|
|
|
def test_pdb_set_trace_interception(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2013-09-06 21:29:00 +08:00
|
|
|
import pdb
|
|
|
|
def test_1():
|
|
|
|
pdb.set_trace()
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2013-09-06 21:29:00 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("test_1")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2019-05-09 06:06:36 +08:00
|
|
|
child.sendline("q")
|
2013-11-19 17:10:27 +08:00
|
|
|
rest = child.read().decode("utf8")
|
2018-10-31 23:20:44 +08:00
|
|
|
assert "no tests ran" in rest
|
2013-09-06 21:29:00 +08:00
|
|
|
assert "reading from stdin while output" not in rest
|
2018-10-31 23:20:44 +08:00
|
|
|
assert "BdbQuit" not in rest
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2013-09-06 21:29:00 +08:00
|
|
|
|
2012-11-22 03:43:31 +08:00
|
|
|
def test_pdb_and_capsys(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2012-11-22 03:43:31 +08:00
|
|
|
import pytest
|
|
|
|
def test_1(capsys):
|
2018-10-13 22:42:33 +08:00
|
|
|
print("hello1")
|
2012-11-22 03:43:31 +08:00
|
|
|
pytest.set_trace()
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2012-11-22 03:43:31 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("test_1")
|
|
|
|
child.send("capsys.readouterr()\n")
|
|
|
|
child.expect("hello1")
|
|
|
|
child.sendeof()
|
2013-10-12 21:39:22 +08:00
|
|
|
child.read()
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2012-11-22 03:43:31 +08:00
|
|
|
|
2018-09-19 18:31:00 +08:00
|
|
|
def test_pdb_with_caplog_on_pdb_invocation(self, testdir):
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
def test_1(capsys, caplog):
|
|
|
|
import logging
|
|
|
|
logging.getLogger(__name__).warning("some_warning")
|
|
|
|
assert 0
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
child = testdir.spawn_pytest("--pdb %s" % str(p1))
|
|
|
|
child.send("caplog.record_tuples\n")
|
|
|
|
child.expect_exact(
|
|
|
|
"[('test_pdb_with_caplog_on_pdb_invocation', 30, 'some_warning')]"
|
|
|
|
)
|
|
|
|
child.sendeof()
|
|
|
|
child.read()
|
|
|
|
self.flush(child)
|
|
|
|
|
2014-04-01 20:32:12 +08:00
|
|
|
def test_set_trace_capturing_afterwards(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2014-04-01 20:32:12 +08:00
|
|
|
import pdb
|
|
|
|
def test_1():
|
|
|
|
pdb.set_trace()
|
|
|
|
def test_2():
|
2018-10-13 22:42:33 +08:00
|
|
|
print("hello")
|
2014-04-01 20:32:12 +08:00
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2014-04-01 20:32:12 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("test_1")
|
|
|
|
child.send("c\n")
|
|
|
|
child.expect("test_2")
|
|
|
|
child.expect("Captured")
|
|
|
|
child.expect("hello")
|
|
|
|
child.sendeof()
|
|
|
|
child.read()
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2014-04-01 20:32:12 +08:00
|
|
|
|
2019-03-15 02:06:46 +08:00
|
|
|
def test_pdb_interaction_doctest(self, testdir, monkeypatch):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2011-11-15 21:28:22 +08:00
|
|
|
import pytest
|
|
|
|
def function_1():
|
|
|
|
'''
|
|
|
|
>>> i = 0
|
|
|
|
>>> assert i == 1
|
|
|
|
'''
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2011-11-15 21:28:22 +08:00
|
|
|
child = testdir.spawn_pytest("--doctest-modules --pdb %s" % p1)
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2019-03-15 02:06:46 +08:00
|
|
|
|
|
|
|
assert "UNEXPECTED EXCEPTION: AssertionError()" in child.before.decode("utf8")
|
|
|
|
|
|
|
|
child.sendline("'i=%i.' % i")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2019-03-15 02:06:46 +08:00
|
|
|
assert "\r\n'i=0.'\r\n" in child.before.decode("utf8")
|
|
|
|
|
2011-11-15 21:28:22 +08:00
|
|
|
child.sendeof()
|
2013-11-19 17:10:27 +08:00
|
|
|
rest = child.read().decode("utf8")
|
2011-11-15 21:28:22 +08:00
|
|
|
assert "1 failed" in rest
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2011-11-15 21:28:22 +08:00
|
|
|
|
2010-10-06 20:48:24 +08:00
|
|
|
def test_pdb_interaction_capturing_twice(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2010-11-18 05:12:16 +08:00
|
|
|
import pytest
|
2010-10-06 20:48:24 +08:00
|
|
|
def test_1():
|
|
|
|
i = 0
|
2018-10-13 22:42:33 +08:00
|
|
|
print("hello17")
|
2010-11-18 05:12:16 +08:00
|
|
|
pytest.set_trace()
|
2010-10-06 20:48:24 +08:00
|
|
|
x = 3
|
2018-10-13 22:42:33 +08:00
|
|
|
print("hello18")
|
2010-11-18 05:12:16 +08:00
|
|
|
pytest.set_trace()
|
2010-10-06 20:48:24 +08:00
|
|
|
x = 4
|
2018-10-31 23:20:44 +08:00
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2010-10-06 20:48:24 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
child.expect(r"PDB set_trace \(IO-capturing turned off\)")
|
2010-10-06 20:48:24 +08:00
|
|
|
child.expect("test_1")
|
|
|
|
child.expect("x = 3")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-05-23 22:48:46 +08:00
|
|
|
child.sendline("c")
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
child.expect(r"PDB continue \(IO-capturing resumed\)")
|
|
|
|
child.expect(r"PDB set_trace \(IO-capturing turned off\)")
|
2010-10-06 20:48:24 +08:00
|
|
|
child.expect("x = 4")
|
2018-10-11 02:49:45 +08:00
|
|
|
child.expect("Pdb")
|
2018-10-31 23:20:44 +08:00
|
|
|
child.sendline("c")
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
child.expect("_ test_1 _")
|
|
|
|
child.expect("def test_1")
|
2013-11-19 17:10:27 +08:00
|
|
|
rest = child.read().decode("utf8")
|
2018-10-31 23:20:44 +08:00
|
|
|
assert "Captured stdout call" in rest
|
2017-07-17 07:25:09 +08:00
|
|
|
assert "hello17" in rest # out is captured
|
|
|
|
assert "hello18" in rest # out is captured
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
assert "1 failed" in rest
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2010-10-06 20:48:24 +08:00
|
|
|
|
2019-03-21 14:22:15 +08:00
|
|
|
def test_pdb_with_injected_do_debug(self, testdir):
|
|
|
|
"""Simulates pdbpp, which injects Pdb into do_debug, and uses
|
|
|
|
self.__class__ in do_continue.
|
|
|
|
"""
|
2018-11-09 05:17:57 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
mytest="""
|
|
|
|
import pdb
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
count_continue = 0
|
|
|
|
|
|
|
|
class CustomPdb(pdb.Pdb, object):
|
|
|
|
def do_debug(self, arg):
|
|
|
|
import sys
|
|
|
|
import types
|
|
|
|
|
2019-05-28 07:31:52 +08:00
|
|
|
do_debug_func = pdb.Pdb.do_debug
|
2018-11-09 05:17:57 +08:00
|
|
|
|
2019-03-15 01:32:42 +08:00
|
|
|
newglobals = do_debug_func.__globals__.copy()
|
|
|
|
newglobals['Pdb'] = self.__class__
|
2018-11-09 05:17:57 +08:00
|
|
|
orig_do_debug = types.FunctionType(
|
|
|
|
do_debug_func.__code__, newglobals,
|
|
|
|
do_debug_func.__name__, do_debug_func.__defaults__,
|
|
|
|
)
|
|
|
|
return orig_do_debug(self, arg)
|
|
|
|
do_debug.__doc__ = pdb.Pdb.do_debug.__doc__
|
|
|
|
|
|
|
|
def do_continue(self, *args, **kwargs):
|
|
|
|
global count_continue
|
|
|
|
count_continue += 1
|
|
|
|
return super(CustomPdb, self).do_continue(*args, **kwargs)
|
|
|
|
|
|
|
|
def foo():
|
|
|
|
print("print_from_foo")
|
|
|
|
|
|
|
|
def test_1():
|
|
|
|
i = 0
|
|
|
|
print("hello17")
|
|
|
|
pytest.set_trace()
|
|
|
|
x = 3
|
|
|
|
print("hello18")
|
|
|
|
|
|
|
|
assert count_continue == 2, "unexpected_failure: %d != 2" % count_continue
|
|
|
|
pytest.fail("expected_failure")
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
child = testdir.spawn_pytest("--pdbcls=mytest:CustomPdb %s" % str(p1))
|
|
|
|
child.expect(r"PDB set_trace \(IO-capturing turned off\)")
|
|
|
|
child.expect(r"\n\(Pdb")
|
|
|
|
child.sendline("debug foo()")
|
|
|
|
child.expect("ENTERING RECURSIVE DEBUGGER")
|
|
|
|
child.expect(r"\n\(\(Pdb")
|
|
|
|
child.sendline("c")
|
|
|
|
child.expect("LEAVING RECURSIVE DEBUGGER")
|
|
|
|
assert b"PDB continue" not in child.before
|
2019-03-19 07:47:22 +08:00
|
|
|
# No extra newline.
|
|
|
|
assert child.before.endswith(b"c\r\nprint_from_foo\r\n")
|
2019-03-21 14:22:15 +08:00
|
|
|
|
|
|
|
# set_debug should not raise outcomes.Exit, if used recrursively.
|
|
|
|
child.sendline("debug 42")
|
|
|
|
child.sendline("q")
|
|
|
|
child.expect("LEAVING RECURSIVE DEBUGGER")
|
|
|
|
assert b"ENTERING RECURSIVE DEBUGGER" in child.before
|
|
|
|
assert b"Quitting debugger" not in child.before
|
|
|
|
|
2018-11-09 05:17:57 +08:00
|
|
|
child.sendline("c")
|
|
|
|
child.expect(r"PDB continue \(IO-capturing resumed\)")
|
|
|
|
rest = child.read().decode("utf8")
|
|
|
|
assert "hello17" in rest # out is captured
|
|
|
|
assert "hello18" in rest # out is captured
|
|
|
|
assert "1 failed" in rest
|
|
|
|
assert "Failed: expected_failure" in rest
|
|
|
|
assert "AssertionError: unexpected_failure" not in rest
|
|
|
|
self.flush(child)
|
|
|
|
|
2018-10-31 23:59:07 +08:00
|
|
|
def test_pdb_without_capture(self, testdir):
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
import pytest
|
|
|
|
def test_1():
|
|
|
|
pytest.set_trace()
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
child = testdir.spawn_pytest("-s %s" % p1)
|
|
|
|
child.expect(r">>> PDB set_trace >>>")
|
|
|
|
child.expect("Pdb")
|
|
|
|
child.sendline("c")
|
|
|
|
child.expect(r">>> PDB continue >>>")
|
|
|
|
child.expect("1 passed")
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2010-10-06 20:48:24 +08:00
|
|
|
|
2019-03-19 11:10:29 +08:00
|
|
|
@pytest.mark.parametrize("capture_arg", ("", "-s", "-p no:capture"))
|
|
|
|
def test_pdb_continue_with_recursive_debug(self, capture_arg, testdir):
|
2019-03-19 08:04:15 +08:00
|
|
|
"""Full coverage for do_debug without capturing.
|
|
|
|
|
2019-03-19 11:10:29 +08:00
|
|
|
This is very similar to test_pdb_interaction_continue_recursive in general,
|
|
|
|
but mocks out ``pdb.set_trace`` for providing more coverage.
|
2019-03-19 08:04:15 +08:00
|
|
|
"""
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2019-03-19 11:10:29 +08:00
|
|
|
try:
|
|
|
|
input = raw_input
|
|
|
|
except NameError:
|
|
|
|
pass
|
|
|
|
|
2019-03-19 08:04:15 +08:00
|
|
|
def set_trace():
|
|
|
|
__import__('pdb').set_trace()
|
|
|
|
|
2019-03-19 11:10:29 +08:00
|
|
|
def test_1(monkeypatch):
|
|
|
|
import _pytest.debugging
|
|
|
|
|
|
|
|
class pytestPDBTest(_pytest.debugging.pytestPDB):
|
|
|
|
@classmethod
|
|
|
|
def set_trace(cls, *args, **kwargs):
|
2019-05-28 20:31:35 +08:00
|
|
|
# Init PytestPdbWrapper to handle capturing.
|
|
|
|
_pdb = cls._init_pdb("set_trace", *args, **kwargs)
|
2019-03-19 11:10:29 +08:00
|
|
|
|
|
|
|
# Mock out pdb.Pdb.do_continue.
|
|
|
|
import pdb
|
|
|
|
pdb.Pdb.do_continue = lambda self, arg: None
|
|
|
|
|
2019-05-28 20:31:35 +08:00
|
|
|
print("===" + " SET_TRACE ===")
|
2019-03-19 11:10:29 +08:00
|
|
|
assert input() == "debug set_trace()"
|
|
|
|
|
2019-05-28 20:31:35 +08:00
|
|
|
# Simulate PytestPdbWrapper.do_debug
|
2019-03-19 11:10:29 +08:00
|
|
|
cls._recursive_debug += 1
|
|
|
|
print("ENTERING RECURSIVE DEBUGGER")
|
2019-05-28 20:31:35 +08:00
|
|
|
print("===" + " SET_TRACE_2 ===")
|
2019-03-19 11:10:29 +08:00
|
|
|
|
|
|
|
assert input() == "c"
|
|
|
|
_pdb.do_continue("")
|
2019-05-28 20:31:35 +08:00
|
|
|
print("===" + " SET_TRACE_3 ===")
|
2019-03-19 11:10:29 +08:00
|
|
|
|
2019-05-28 20:31:35 +08:00
|
|
|
# Simulate PytestPdbWrapper.do_debug
|
2019-03-19 11:10:29 +08:00
|
|
|
print("LEAVING RECURSIVE DEBUGGER")
|
|
|
|
cls._recursive_debug -= 1
|
|
|
|
|
2019-05-28 20:31:35 +08:00
|
|
|
print("===" + " SET_TRACE_4 ===")
|
2019-03-19 11:10:29 +08:00
|
|
|
assert input() == "c"
|
|
|
|
_pdb.do_continue("")
|
|
|
|
|
|
|
|
def do_continue(self, arg):
|
|
|
|
print("=== do_continue")
|
|
|
|
|
|
|
|
monkeypatch.setattr(_pytest.debugging, "pytestPDB", pytestPDBTest)
|
|
|
|
|
|
|
|
import pdb
|
|
|
|
monkeypatch.setattr(pdb, "set_trace", pytestPDBTest.set_trace)
|
|
|
|
|
2019-03-19 08:04:15 +08:00
|
|
|
set_trace()
|
|
|
|
"""
|
|
|
|
)
|
2019-05-28 20:31:35 +08:00
|
|
|
child = testdir.spawn_pytest("--tb=short %s %s" % (p1, capture_arg))
|
2019-03-19 11:10:29 +08:00
|
|
|
child.expect("=== SET_TRACE ===")
|
2019-03-19 08:04:15 +08:00
|
|
|
before = child.before.decode("utf8")
|
2019-03-19 11:10:29 +08:00
|
|
|
if not capture_arg:
|
2019-03-19 08:04:15 +08:00
|
|
|
assert ">>> PDB set_trace (IO-capturing turned off) >>>" in before
|
|
|
|
else:
|
|
|
|
assert ">>> PDB set_trace >>>" in before
|
|
|
|
child.sendline("debug set_trace()")
|
2019-03-19 11:10:29 +08:00
|
|
|
child.expect("=== SET_TRACE_2 ===")
|
2019-03-19 08:04:15 +08:00
|
|
|
before = child.before.decode("utf8")
|
|
|
|
assert "\r\nENTERING RECURSIVE DEBUGGER\r\n" in before
|
|
|
|
child.sendline("c")
|
2019-03-19 11:10:29 +08:00
|
|
|
child.expect("=== SET_TRACE_3 ===")
|
2019-03-19 08:04:15 +08:00
|
|
|
|
|
|
|
# No continue message with recursive debugging.
|
|
|
|
before = child.before.decode("utf8")
|
|
|
|
assert ">>> PDB continue " not in before
|
|
|
|
|
|
|
|
child.sendline("c")
|
2019-03-19 11:10:29 +08:00
|
|
|
child.expect("=== SET_TRACE_4 ===")
|
2019-03-19 08:04:15 +08:00
|
|
|
before = child.before.decode("utf8")
|
|
|
|
assert "\r\nLEAVING RECURSIVE DEBUGGER\r\n" in before
|
|
|
|
child.sendline("c")
|
|
|
|
rest = child.read().decode("utf8")
|
2019-03-19 11:10:29 +08:00
|
|
|
if not capture_arg:
|
2019-03-19 08:04:15 +08:00
|
|
|
assert "> PDB continue (IO-capturing resumed) >" in rest
|
|
|
|
else:
|
|
|
|
assert "> PDB continue >" in rest
|
|
|
|
assert "1 passed in" in rest
|
|
|
|
|
2010-10-06 20:48:24 +08:00
|
|
|
def test_pdb_used_outside_test(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2010-11-18 05:12:16 +08:00
|
|
|
import pytest
|
|
|
|
pytest.set_trace()
|
2010-10-06 20:48:24 +08:00
|
|
|
x = 5
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-08-23 09:30:42 +08:00
|
|
|
child = testdir.spawn("{} {}".format(sys.executable, p1))
|
2010-10-06 20:48:24 +08:00
|
|
|
child.expect("x = 5")
|
2018-10-11 02:49:45 +08:00
|
|
|
child.expect("Pdb")
|
2010-10-06 20:48:24 +08:00
|
|
|
child.sendeof()
|
2016-10-22 00:11:35 +08:00
|
|
|
self.flush(child)
|
2010-11-23 23:10:47 +08:00
|
|
|
|
2011-08-01 16:53:37 +08:00
|
|
|
def test_pdb_used_in_generate_tests(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2011-08-01 16:53:37 +08:00
|
|
|
import pytest
|
|
|
|
def pytest_generate_tests(metafunc):
|
|
|
|
pytest.set_trace()
|
|
|
|
x = 5
|
|
|
|
def test_foo(a):
|
|
|
|
pass
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2011-08-01 16:53:37 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("x = 5")
|
2018-10-11 02:49:45 +08:00
|
|
|
child.expect("Pdb")
|
2011-08-01 16:53:37 +08:00
|
|
|
child.sendeof()
|
2016-10-22 00:11:35 +08:00
|
|
|
self.flush(child)
|
2013-11-19 17:10:27 +08:00
|
|
|
|
2010-11-23 23:10:47 +08:00
|
|
|
def test_pdb_collection_failure_is_shown(self, testdir):
|
2017-12-06 22:22:45 +08:00
|
|
|
p1 = testdir.makepyfile("xxx")
|
2015-04-28 17:54:46 +08:00
|
|
|
result = testdir.runpytest_subprocess("--pdb", p1)
|
2018-10-13 22:49:30 +08:00
|
|
|
result.stdout.fnmatch_lines(
|
|
|
|
["E NameError: *xxx*", "*! *Exit: Quitting debugger !*"] # due to EOF
|
|
|
|
)
|
2014-09-18 20:58:42 +08:00
|
|
|
|
2019-03-11 22:47:07 +08:00
|
|
|
@pytest.mark.parametrize("post_mortem", (False, True))
|
|
|
|
def test_enter_leave_pdb_hooks_are_called(self, post_mortem, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
testdir.makeconftest(
|
|
|
|
"""
|
2018-10-25 05:27:14 +08:00
|
|
|
mypdb = None
|
2015-11-23 23:05:56 +08:00
|
|
|
|
|
|
|
def pytest_configure(config):
|
|
|
|
config.testing_verification = 'configured'
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
|
2018-10-25 05:27:14 +08:00
|
|
|
def pytest_enter_pdb(config, pdb):
|
2015-11-23 23:05:56 +08:00
|
|
|
assert config.testing_verification == 'configured'
|
2018-10-13 22:42:33 +08:00
|
|
|
print('enter_pdb_hook')
|
2015-11-23 23:05:56 +08:00
|
|
|
|
2018-10-25 05:27:14 +08:00
|
|
|
global mypdb
|
|
|
|
mypdb = pdb
|
|
|
|
mypdb.set_attribute = "bar"
|
|
|
|
|
|
|
|
def pytest_leave_pdb(config, pdb):
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
assert config.testing_verification == 'configured'
|
|
|
|
print('leave_pdb_hook')
|
2018-10-25 05:27:14 +08:00
|
|
|
|
|
|
|
global mypdb
|
|
|
|
assert mypdb is pdb
|
|
|
|
assert mypdb.set_attribute == "bar"
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2014-09-18 20:58:42 +08:00
|
|
|
import pytest
|
|
|
|
|
2019-03-11 22:47:07 +08:00
|
|
|
def test_set_trace():
|
2014-09-18 20:58:42 +08:00
|
|
|
pytest.set_trace()
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
assert 0
|
2019-03-11 22:47:07 +08:00
|
|
|
|
|
|
|
def test_post_mortem():
|
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2019-03-11 22:47:07 +08:00
|
|
|
if post_mortem:
|
|
|
|
child = testdir.spawn_pytest(str(p1) + " --pdb -s -k test_post_mortem")
|
|
|
|
else:
|
|
|
|
child = testdir.spawn_pytest(str(p1) + " -k test_set_trace")
|
2014-09-18 20:58:42 +08:00
|
|
|
child.expect("enter_pdb_hook")
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
child.sendline("c")
|
2019-03-11 22:47:07 +08:00
|
|
|
if post_mortem:
|
|
|
|
child.expect(r"PDB continue")
|
|
|
|
else:
|
|
|
|
child.expect(r"PDB continue \(IO-capturing resumed\)")
|
|
|
|
child.expect("Captured stdout call")
|
pdb: resume capturing after `continue`
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.
Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.
Without this, `debug …` would fail like this:
/usr/lib/python3.6/cmd.py:217: in onecmd
return func(arg)
.venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
return orig_do_debug(self, arg)
/usr/lib/python3.6/pdb.py:1099: in do_debug
sys.call_tracing(p.run, (arg, globals, locals))
/usr/lib/python3.6/bdb.py:434: in run
exec(cmd, globals, locals)
/usr/lib/python3.6/bdb.py:51: in trace_dispatch
return self.dispatch_line(frame)
/usr/lib/python3.6/bdb.py:69: in dispatch_line
self.user_line(frame)
/usr/lib/python3.6/pdb.py:261: in user_line
self.interaction(frame, None)
.venv/lib/python3.6/site-packages/pdb.py:203: in interaction
self.setup(frame, traceback)
E AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'
- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
but works here
2017-07-26 23:18:29 +08:00
|
|
|
rest = child.read().decode("utf8")
|
|
|
|
assert "leave_pdb_hook" in rest
|
|
|
|
assert "1 failed" in rest
|
2016-10-22 00:10:35 +08:00
|
|
|
self.flush(child)
|
2016-07-12 08:43:06 +08:00
|
|
|
|
2016-09-20 00:05:57 +08:00
|
|
|
def test_pdb_custom_cls(self, testdir, custom_pdb_calls):
|
|
|
|
p1 = testdir.makepyfile("""xxx """)
|
2018-05-23 22:48:46 +08:00
|
|
|
result = testdir.runpytest_inprocess("--pdb", "--pdbcls=_pytest:_CustomPdb", p1)
|
|
|
|
result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"])
|
2016-09-20 00:05:57 +08:00
|
|
|
assert custom_pdb_calls == ["init", "reset", "interaction"]
|
2016-07-12 08:43:06 +08:00
|
|
|
|
2019-03-01 00:46:09 +08:00
|
|
|
def test_pdb_custom_cls_invalid(self, testdir):
|
|
|
|
result = testdir.runpytest_inprocess("--pdbcls=invalid")
|
|
|
|
result.stderr.fnmatch_lines(
|
|
|
|
[
|
|
|
|
"*: error: argument --pdbcls: 'invalid' is not in the format 'modname:classname'"
|
|
|
|
]
|
|
|
|
)
|
2019-03-01 01:10:57 +08:00
|
|
|
|
|
|
|
def test_pdb_validate_usepdb_cls(self, testdir):
|
2019-04-04 03:37:27 +08:00
|
|
|
assert _validate_usepdb_cls("os.path:dirname.__name__") == (
|
|
|
|
"os.path",
|
|
|
|
"dirname.__name__",
|
|
|
|
)
|
2019-03-01 01:10:57 +08:00
|
|
|
|
2019-04-04 03:37:27 +08:00
|
|
|
assert _validate_usepdb_cls("pdb:DoesNotExist") == ("pdb", "DoesNotExist")
|
2019-03-01 00:46:09 +08:00
|
|
|
|
2016-09-20 00:05:57 +08:00
|
|
|
def test_pdb_custom_cls_without_pdb(self, testdir, custom_pdb_calls):
|
2016-07-12 08:43:06 +08:00
|
|
|
p1 = testdir.makepyfile("""xxx """)
|
2018-05-23 22:48:46 +08:00
|
|
|
result = testdir.runpytest_inprocess("--pdbcls=_pytest:_CustomPdb", p1)
|
|
|
|
result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"])
|
2016-09-20 00:05:57 +08:00
|
|
|
assert custom_pdb_calls == []
|
2016-09-21 16:44:39 +08:00
|
|
|
|
2019-05-14 12:51:30 +08:00
|
|
|
def test_pdb_custom_cls_with_set_trace(self, testdir, monkeypatch):
|
2018-05-23 22:48:46 +08:00
|
|
|
testdir.makepyfile(
|
|
|
|
custom_pdb="""
|
2017-02-17 02:41:51 +08:00
|
|
|
class CustomPdb(object):
|
2018-11-19 03:18:42 +08:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
skip = kwargs.pop("skip")
|
|
|
|
assert skip == ["foo.*"]
|
|
|
|
print("__init__")
|
|
|
|
super(CustomPdb, self).__init__(*args, **kwargs)
|
|
|
|
|
2016-09-21 16:44:39 +08:00
|
|
|
def set_trace(*args, **kwargs):
|
2018-10-13 22:42:33 +08:00
|
|
|
print('custom set_trace>')
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2016-09-21 16:44:39 +08:00
|
|
|
import pytest
|
|
|
|
|
|
|
|
def test_foo():
|
2018-11-19 03:18:42 +08:00
|
|
|
pytest.set_trace(skip=['foo.*'])
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
monkeypatch.setenv("PYTHONPATH", str(testdir.tmpdir))
|
2016-09-21 16:44:39 +08:00
|
|
|
child = testdir.spawn_pytest("--pdbcls=custom_pdb:CustomPdb %s" % str(p1))
|
|
|
|
|
2018-11-19 03:18:42 +08:00
|
|
|
child.expect("__init__")
|
2018-05-23 22:48:46 +08:00
|
|
|
child.expect("custom set_trace>")
|
2018-01-15 05:00:23 +08:00
|
|
|
self.flush(child)
|
2018-03-22 17:40:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
class TestDebuggingBreakpoints(object):
|
|
|
|
def test_supports_breakpoint_module_global(self):
|
|
|
|
"""
|
2018-03-23 12:39:34 +08:00
|
|
|
Test that supports breakpoint global marks on Python 3.7+ and not on
|
2018-03-22 17:40:35 +08:00
|
|
|
CPython 3.5, 2.7
|
|
|
|
"""
|
|
|
|
if sys.version_info.major == 3 and sys.version_info.minor >= 7:
|
|
|
|
assert SUPPORTS_BREAKPOINT_BUILTIN is True
|
|
|
|
if sys.version_info.major == 3 and sys.version_info.minor == 5:
|
|
|
|
assert SUPPORTS_BREAKPOINT_BUILTIN is False
|
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.skipif(
|
|
|
|
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
|
|
|
|
)
|
|
|
|
@pytest.mark.parametrize("arg", ["--pdb", ""])
|
2018-03-29 07:19:28 +08:00
|
|
|
def test_sys_breakpointhook_configure_and_unconfigure(self, testdir, arg):
|
2018-03-23 11:18:56 +08:00
|
|
|
"""
|
|
|
|
Test that sys.breakpointhook is set to the custom Pdb class once configured, test that
|
|
|
|
hook is reset to system value once pytest has been unconfigured
|
|
|
|
"""
|
2018-05-23 22:48:46 +08:00
|
|
|
testdir.makeconftest(
|
|
|
|
"""
|
2018-03-29 06:03:20 +08:00
|
|
|
import sys
|
2018-03-27 14:38:17 +08:00
|
|
|
from pytest import hookimpl
|
|
|
|
from _pytest.debugging import pytestPDB
|
2018-03-23 11:18:56 +08:00
|
|
|
|
2018-03-27 14:38:17 +08:00
|
|
|
def pytest_configure(config):
|
2018-03-29 07:19:28 +08:00
|
|
|
config._cleanup.append(check_restored)
|
2018-03-27 14:38:17 +08:00
|
|
|
|
2018-03-29 07:19:28 +08:00
|
|
|
def check_restored():
|
|
|
|
assert sys.breakpointhook == sys.__breakpointhook__
|
2018-03-23 11:18:56 +08:00
|
|
|
|
2018-03-29 07:19:28 +08:00
|
|
|
def test_check():
|
|
|
|
assert sys.breakpointhook == pytestPDB.set_trace
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
testdir.makepyfile(
|
|
|
|
"""
|
2018-03-27 14:38:17 +08:00
|
|
|
def test_nothing(): pass
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-03-29 07:19:28 +08:00
|
|
|
args = (arg,) if arg else ()
|
|
|
|
result = testdir.runpytest_subprocess(*args)
|
2018-05-23 22:48:46 +08:00
|
|
|
result.stdout.fnmatch_lines(["*1 passed in *"])
|
2018-03-23 11:18:56 +08:00
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.skipif(
|
|
|
|
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
|
|
|
|
)
|
2018-03-23 12:30:05 +08:00
|
|
|
def test_pdb_custom_cls(self, testdir, custom_debugger_hook):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2018-03-29 07:19:28 +08:00
|
|
|
def test_nothing():
|
|
|
|
breakpoint()
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-03-23 12:30:05 +08:00
|
|
|
result = testdir.runpytest_inprocess(
|
2018-05-23 22:48:46 +08:00
|
|
|
"--pdb", "--pdbcls=_pytest:_CustomDebugger", p1
|
|
|
|
)
|
|
|
|
result.stdout.fnmatch_lines(["*CustomDebugger*", "*1 passed*"])
|
2018-03-23 12:30:05 +08:00
|
|
|
assert custom_debugger_hook == ["init", "set_trace"]
|
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.parametrize("arg", ["--pdb", ""])
|
|
|
|
@pytest.mark.skipif(
|
|
|
|
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
|
|
|
|
)
|
2018-03-29 07:19:28 +08:00
|
|
|
def test_environ_custom_class(self, testdir, custom_debugger_hook, arg):
|
2018-05-23 22:48:46 +08:00
|
|
|
testdir.makeconftest(
|
|
|
|
"""
|
2018-03-28 06:02:37 +08:00
|
|
|
import os
|
2018-03-29 06:03:20 +08:00
|
|
|
import sys
|
2018-03-28 06:02:37 +08:00
|
|
|
|
2018-03-29 07:19:28 +08:00
|
|
|
os.environ['PYTHONBREAKPOINT'] = '_pytest._CustomDebugger.set_trace'
|
|
|
|
|
2018-03-28 06:02:37 +08:00
|
|
|
def pytest_configure(config):
|
2018-03-29 07:19:28 +08:00
|
|
|
config._cleanup.append(check_restored)
|
|
|
|
|
|
|
|
def check_restored():
|
|
|
|
assert sys.breakpointhook == sys.__breakpointhook__
|
|
|
|
|
|
|
|
def test_check():
|
|
|
|
import _pytest
|
|
|
|
assert sys.breakpointhook is _pytest._CustomDebugger.set_trace
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
testdir.makepyfile(
|
|
|
|
"""
|
2018-03-28 06:02:37 +08:00
|
|
|
def test_nothing(): pass
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-03-29 07:19:28 +08:00
|
|
|
args = (arg,) if arg else ()
|
|
|
|
result = testdir.runpytest_subprocess(*args)
|
2018-05-23 22:48:46 +08:00
|
|
|
result.stdout.fnmatch_lines(["*1 passed in *"])
|
|
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
|
|
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
|
|
|
|
)
|
|
|
|
@pytest.mark.skipif(
|
|
|
|
not _ENVIRON_PYTHONBREAKPOINT == "",
|
|
|
|
reason="Requires breakpoint() default value",
|
|
|
|
)
|
2018-03-23 11:18:56 +08:00
|
|
|
def test_sys_breakpoint_interception(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2018-03-23 11:18:56 +08:00
|
|
|
def test_1():
|
|
|
|
breakpoint()
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-03-23 11:18:56 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("test_1")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2019-05-09 06:06:36 +08:00
|
|
|
child.sendline("quit")
|
2018-03-23 11:18:56 +08:00
|
|
|
rest = child.read().decode("utf8")
|
2018-10-31 23:20:44 +08:00
|
|
|
assert "Quitting debugger" in rest
|
2018-03-23 11:18:56 +08:00
|
|
|
assert "reading from stdin while output" not in rest
|
|
|
|
TestPDB.flush(child)
|
|
|
|
|
2018-05-23 22:48:46 +08:00
|
|
|
@pytest.mark.skipif(
|
|
|
|
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
|
|
|
|
)
|
2018-03-23 11:18:56 +08:00
|
|
|
def test_pdb_not_altered(self, testdir):
|
2018-05-23 22:48:46 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
2018-03-23 11:18:56 +08:00
|
|
|
import pdb
|
|
|
|
def test_1():
|
|
|
|
pdb.set_trace()
|
2018-10-31 23:20:44 +08:00
|
|
|
assert 0
|
2018-05-23 22:48:46 +08:00
|
|
|
"""
|
|
|
|
)
|
2018-03-23 11:18:56 +08:00
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("test_1")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-10-31 23:20:44 +08:00
|
|
|
child.sendline("c")
|
2018-03-23 11:18:56 +08:00
|
|
|
rest = child.read().decode("utf8")
|
|
|
|
assert "1 failed" in rest
|
|
|
|
assert "reading from stdin while output" not in rest
|
|
|
|
TestPDB.flush(child)
|
2018-07-01 09:26:58 +08:00
|
|
|
|
2018-07-02 11:22:50 +08:00
|
|
|
|
2018-07-02 11:18:00 +08:00
|
|
|
class TestTraceOption:
|
2018-07-01 09:26:58 +08:00
|
|
|
def test_trace_sets_breakpoint(self, testdir):
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
def test_1():
|
2018-07-01 12:36:27 +08:00
|
|
|
assert True
|
2018-10-31 23:20:44 +08:00
|
|
|
|
|
|
|
def test_2():
|
|
|
|
pass
|
|
|
|
|
|
|
|
def test_3():
|
|
|
|
pass
|
2018-07-01 09:26:58 +08:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
child = testdir.spawn_pytest("--trace " + str(p1))
|
|
|
|
child.expect("test_1")
|
2018-10-11 02:48:20 +08:00
|
|
|
child.expect("Pdb")
|
2018-10-31 23:20:44 +08:00
|
|
|
child.sendline("c")
|
|
|
|
child.expect("test_2")
|
|
|
|
child.expect("Pdb")
|
|
|
|
child.sendline("c")
|
|
|
|
child.expect("test_3")
|
|
|
|
child.expect("Pdb")
|
|
|
|
child.sendline("q")
|
|
|
|
child.expect_exact("Exit: Quitting debugger")
|
2018-07-01 09:26:58 +08:00
|
|
|
rest = child.read().decode("utf8")
|
2018-10-31 23:20:44 +08:00
|
|
|
assert "2 passed in" in rest
|
2018-07-01 09:26:58 +08:00
|
|
|
assert "reading from stdin while output" not in rest
|
2019-04-03 10:07:42 +08:00
|
|
|
# Only printed once - not on stderr.
|
|
|
|
assert "Exit: Quitting debugger" not in child.before.decode("utf8")
|
2018-07-02 11:18:00 +08:00
|
|
|
TestPDB.flush(child)
|
2018-07-03 10:46:26 +08:00
|
|
|
|
2018-11-02 02:40:38 +08:00
|
|
|
|
|
|
|
def test_trace_after_runpytest(testdir):
|
|
|
|
"""Test that debugging's pytest_configure is re-entrant."""
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
from _pytest.debugging import pytestPDB
|
|
|
|
|
|
|
|
def test_outer(testdir):
|
|
|
|
assert len(pytestPDB._saved) == 1
|
|
|
|
|
2019-05-11 20:30:54 +08:00
|
|
|
testdir.makepyfile(
|
|
|
|
\"""
|
|
|
|
from _pytest.debugging import pytestPDB
|
2018-11-02 02:40:38 +08:00
|
|
|
|
2019-05-11 20:30:54 +08:00
|
|
|
def test_inner():
|
|
|
|
assert len(pytestPDB._saved) == 2
|
|
|
|
print()
|
|
|
|
print("test_inner_" + "end")
|
|
|
|
\"""
|
|
|
|
)
|
|
|
|
|
|
|
|
result = testdir.runpytest("-s", "-k", "test_inner")
|
|
|
|
assert result.ret == 0
|
2018-11-02 02:40:38 +08:00
|
|
|
|
2019-05-11 20:30:54 +08:00
|
|
|
assert len(pytestPDB._saved) == 1
|
2018-11-02 02:40:38 +08:00
|
|
|
"""
|
|
|
|
)
|
2019-05-11 20:30:54 +08:00
|
|
|
result = testdir.runpytest_subprocess("-s", "-p", "pytester", str(p1))
|
|
|
|
result.stdout.fnmatch_lines(["test_inner_end"])
|
|
|
|
assert result.ret == 0
|
2018-10-31 23:20:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
def test_quit_with_swallowed_SystemExit(testdir):
|
|
|
|
"""Test that debugging's pytest_configure is re-entrant."""
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
def call_pdb_set_trace():
|
|
|
|
__import__('pdb').set_trace()
|
|
|
|
|
|
|
|
|
|
|
|
def test_1():
|
|
|
|
try:
|
|
|
|
call_pdb_set_trace()
|
|
|
|
except SystemExit:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def test_2():
|
|
|
|
pass
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
child = testdir.spawn_pytest(str(p1))
|
|
|
|
child.expect("Pdb")
|
|
|
|
child.sendline("q")
|
|
|
|
child.expect_exact("Exit: Quitting debugger")
|
|
|
|
rest = child.read().decode("utf8")
|
|
|
|
assert "no tests ran" in rest
|
|
|
|
TestPDB.flush(child)
|
2019-03-19 05:58:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("fixture", ("capfd", "capsys"))
|
|
|
|
def test_pdb_suspends_fixture_capturing(testdir, fixture):
|
|
|
|
"""Using "-s" with pytest should suspend/resume fixture capturing."""
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
def test_inner({fixture}):
|
|
|
|
import sys
|
|
|
|
|
|
|
|
print("out_inner_before")
|
|
|
|
sys.stderr.write("err_inner_before\\n")
|
|
|
|
|
|
|
|
__import__("pdb").set_trace()
|
|
|
|
|
|
|
|
print("out_inner_after")
|
|
|
|
sys.stderr.write("err_inner_after\\n")
|
|
|
|
|
|
|
|
out, err = {fixture}.readouterr()
|
|
|
|
assert out =="out_inner_before\\nout_inner_after\\n"
|
|
|
|
assert err =="err_inner_before\\nerr_inner_after\\n"
|
|
|
|
""".format(
|
|
|
|
fixture=fixture
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
child = testdir.spawn_pytest(str(p1) + " -s")
|
|
|
|
|
|
|
|
child.expect("Pdb")
|
|
|
|
before = child.before.decode("utf8")
|
|
|
|
assert (
|
|
|
|
"> PDB set_trace (IO-capturing turned off for fixture %s) >" % (fixture)
|
|
|
|
in before
|
|
|
|
)
|
|
|
|
|
|
|
|
# Test that capturing is really suspended.
|
|
|
|
child.sendline("p 40 + 2")
|
|
|
|
child.expect("Pdb")
|
|
|
|
assert "\r\n42\r\n" in child.before.decode("utf8")
|
|
|
|
|
|
|
|
child.sendline("c")
|
|
|
|
rest = child.read().decode("utf8")
|
|
|
|
assert "out_inner" not in rest
|
|
|
|
assert "err_inner" not in rest
|
|
|
|
|
|
|
|
TestPDB.flush(child)
|
|
|
|
assert child.exitstatus == 0
|
|
|
|
assert "= 1 passed in " in rest
|
|
|
|
assert "> PDB continue (IO-capturing resumed for fixture %s) >" % (fixture) in rest
|
2019-02-28 21:18:16 +08:00
|
|
|
|
|
|
|
|
2019-04-04 03:37:27 +08:00
|
|
|
def test_pdbcls_via_local_module(testdir):
|
|
|
|
"""It should be imported in pytest_configure or later only."""
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
def test():
|
2019-05-14 12:51:30 +08:00
|
|
|
print("before_set_trace")
|
2019-04-04 03:37:27 +08:00
|
|
|
__import__("pdb").set_trace()
|
|
|
|
""",
|
|
|
|
mypdb="""
|
|
|
|
class Wrapped:
|
|
|
|
class MyPdb:
|
|
|
|
def set_trace(self, *args):
|
2019-05-14 12:51:30 +08:00
|
|
|
print("set_trace_called", args)
|
2019-04-08 08:00:28 +08:00
|
|
|
|
|
|
|
def runcall(self, *args, **kwds):
|
|
|
|
print("runcall_called", args, kwds)
|
|
|
|
assert "func" in kwds
|
2019-04-04 03:37:27 +08:00
|
|
|
""",
|
|
|
|
)
|
|
|
|
result = testdir.runpytest(
|
|
|
|
str(p1), "--pdbcls=really.invalid:Value", syspathinsert=True
|
|
|
|
)
|
2019-05-25 00:10:05 +08:00
|
|
|
result.stdout.fnmatch_lines(
|
2019-04-04 03:37:27 +08:00
|
|
|
[
|
2019-05-25 00:10:05 +08:00
|
|
|
"*= FAILURES =*",
|
|
|
|
"E * --pdbcls: could not import 'really.invalid:Value': No module named *really*",
|
2019-04-04 03:37:27 +08:00
|
|
|
]
|
|
|
|
)
|
2019-05-25 00:10:05 +08:00
|
|
|
assert result.ret == 1
|
2019-04-04 03:37:27 +08:00
|
|
|
|
|
|
|
result = testdir.runpytest(
|
|
|
|
str(p1), "--pdbcls=mypdb:Wrapped.MyPdb", syspathinsert=True
|
|
|
|
)
|
|
|
|
assert result.ret == 0
|
2019-05-14 12:51:30 +08:00
|
|
|
result.stdout.fnmatch_lines(["*set_trace_called*", "* 1 passed in *"])
|
2019-04-08 08:00:28 +08:00
|
|
|
|
|
|
|
# Ensure that it also works with --trace.
|
|
|
|
result = testdir.runpytest(
|
|
|
|
str(p1), "--pdbcls=mypdb:Wrapped.MyPdb", "--trace", syspathinsert=True
|
|
|
|
)
|
|
|
|
assert result.ret == 0
|
|
|
|
result.stdout.fnmatch_lines(["*runcall_called*", "* 1 passed in *"])
|
2019-05-09 06:06:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
def test_raises_bdbquit_with_eoferror(testdir):
|
|
|
|
"""It is not guaranteed that DontReadFromInput's read is called."""
|
2019-05-28 07:31:52 +08:00
|
|
|
|
2019-05-09 06:06:36 +08:00
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
def input_without_read(*args, **kwargs):
|
|
|
|
raise EOFError()
|
|
|
|
|
|
|
|
def test(monkeypatch):
|
2019-05-28 07:31:52 +08:00
|
|
|
import builtins
|
|
|
|
monkeypatch.setattr(builtins, "input", input_without_read)
|
2019-05-09 06:06:36 +08:00
|
|
|
__import__('pdb').set_trace()
|
2019-05-28 07:31:52 +08:00
|
|
|
"""
|
2019-05-09 06:06:36 +08:00
|
|
|
)
|
|
|
|
result = testdir.runpytest(str(p1))
|
|
|
|
result.stdout.fnmatch_lines(["E *BdbQuit", "*= 1 failed in*"])
|
|
|
|
assert result.ret == 1
|
2019-05-28 20:31:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
def test_pdb_wrapper_class_is_reused(testdir):
|
|
|
|
p1 = testdir.makepyfile(
|
|
|
|
"""
|
|
|
|
def test():
|
|
|
|
__import__("pdb").set_trace()
|
|
|
|
__import__("pdb").set_trace()
|
|
|
|
|
|
|
|
import mypdb
|
|
|
|
instances = mypdb.instances
|
|
|
|
assert len(instances) == 2
|
|
|
|
assert instances[0].__class__ is instances[1].__class__
|
|
|
|
""",
|
|
|
|
mypdb="""
|
|
|
|
instances = []
|
|
|
|
|
|
|
|
class MyPdb:
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
instances.append(self)
|
|
|
|
|
|
|
|
def set_trace(self, *args):
|
|
|
|
print("set_trace_called", args)
|
|
|
|
""",
|
|
|
|
)
|
|
|
|
result = testdir.runpytest(str(p1), "--pdbcls=mypdb:MyPdb", syspathinsert=True)
|
|
|
|
assert result.ret == 0
|
|
|
|
result.stdout.fnmatch_lines(
|
|
|
|
["*set_trace_called*", "*set_trace_called*", "* 1 passed in *"]
|
|
|
|
)
|