@@ -576,7 +576,8 @@ def test_1():
576576 child .sendline ("c" )
577577 child .expect ("LEAVING RECURSIVE DEBUGGER" )
578578 assert b"PDB continue" not in child .before
579- assert b"print_from_foo" in child .before
579+ # No extra newline.
580+ assert child .before .endswith (b"c\r \n print_from_foo\r \n " )
580581 child .sendline ("c" )
581582 child .expect (r"PDB continue \(IO-capturing resumed\)" )
582583 rest = child .read ().decode ("utf8" )
@@ -603,6 +604,98 @@ def test_1():
603604 child .expect ("1 passed" )
604605 self .flush (child )
605606
607+ @pytest .mark .parametrize ("capture_arg" , ("" , "-s" , "-p no:capture" ))
608+ def test_pdb_continue_with_recursive_debug (self , capture_arg , testdir ):
609+ """Full coverage for do_debug without capturing.
610+
611+ This is very similar to test_pdb_interaction_continue_recursive in general,
612+ but mocks out ``pdb.set_trace`` for providing more coverage.
613+ """
614+ p1 = testdir .makepyfile (
615+ """
616+ try:
617+ input = raw_input
618+ except NameError:
619+ pass
620+
621+ def set_trace():
622+ __import__('pdb').set_trace()
623+
624+ def test_1(monkeypatch):
625+ import _pytest.debugging
626+
627+ class pytestPDBTest(_pytest.debugging.pytestPDB):
628+ @classmethod
629+ def set_trace(cls, *args, **kwargs):
630+ # Init _PdbWrapper to handle capturing.
631+ _pdb = cls._init_pdb(*args, **kwargs)
632+
633+ # Mock out pdb.Pdb.do_continue.
634+ import pdb
635+ pdb.Pdb.do_continue = lambda self, arg: None
636+
637+ print("=== SET_TRACE ===")
638+ assert input() == "debug set_trace()"
639+
640+ # Simulate _PdbWrapper.do_debug
641+ cls._recursive_debug += 1
642+ print("ENTERING RECURSIVE DEBUGGER")
643+ print("=== SET_TRACE_2 ===")
644+
645+ assert input() == "c"
646+ _pdb.do_continue("")
647+ print("=== SET_TRACE_3 ===")
648+
649+ # Simulate _PdbWrapper.do_debug
650+ print("LEAVING RECURSIVE DEBUGGER")
651+ cls._recursive_debug -= 1
652+
653+ print("=== SET_TRACE_4 ===")
654+ assert input() == "c"
655+ _pdb.do_continue("")
656+
657+ def do_continue(self, arg):
658+ print("=== do_continue")
659+ # _PdbWrapper.do_continue("")
660+
661+ monkeypatch.setattr(_pytest.debugging, "pytestPDB", pytestPDBTest)
662+
663+ import pdb
664+ monkeypatch.setattr(pdb, "set_trace", pytestPDBTest.set_trace)
665+
666+ set_trace()
667+ """
668+ )
669+ child = testdir .spawn_pytest ("%s %s" % (p1 , capture_arg ))
670+ child .expect ("=== SET_TRACE ===" )
671+ before = child .before .decode ("utf8" )
672+ if not capture_arg :
673+ assert ">>> PDB set_trace (IO-capturing turned off) >>>" in before
674+ else :
675+ assert ">>> PDB set_trace >>>" in before
676+ child .sendline ("debug set_trace()" )
677+ child .expect ("=== SET_TRACE_2 ===" )
678+ before = child .before .decode ("utf8" )
679+ assert "\r \n ENTERING RECURSIVE DEBUGGER\r \n " in before
680+ child .sendline ("c" )
681+ child .expect ("=== SET_TRACE_3 ===" )
682+
683+ # No continue message with recursive debugging.
684+ before = child .before .decode ("utf8" )
685+ assert ">>> PDB continue " not in before
686+
687+ child .sendline ("c" )
688+ child .expect ("=== SET_TRACE_4 ===" )
689+ before = child .before .decode ("utf8" )
690+ assert "\r \n LEAVING RECURSIVE DEBUGGER\r \n " in before
691+ child .sendline ("c" )
692+ rest = child .read ().decode ("utf8" )
693+ if not capture_arg :
694+ assert "> PDB continue (IO-capturing resumed) >" in rest
695+ else :
696+ assert "> PDB continue >" in rest
697+ assert "1 passed in" in rest
698+
606699 def test_pdb_used_outside_test (self , testdir ):
607700 p1 = testdir .makepyfile (
608701 """
@@ -970,3 +1063,52 @@ def test_2():
9701063 rest = child .read ().decode ("utf8" )
9711064 assert "no tests ran" in rest
9721065 TestPDB .flush (child )
1066+
1067+
1068+ @pytest .mark .parametrize ("fixture" , ("capfd" , "capsys" ))
1069+ def test_pdb_suspends_fixture_capturing (testdir , fixture ):
1070+ """Using "-s" with pytest should suspend/resume fixture capturing."""
1071+ p1 = testdir .makepyfile (
1072+ """
1073+ def test_inner({fixture}):
1074+ import sys
1075+
1076+ print("out_inner_before")
1077+ sys.stderr.write("err_inner_before\\ n")
1078+
1079+ __import__("pdb").set_trace()
1080+
1081+ print("out_inner_after")
1082+ sys.stderr.write("err_inner_after\\ n")
1083+
1084+ out, err = {fixture}.readouterr()
1085+ assert out =="out_inner_before\\ nout_inner_after\\ n"
1086+ assert err =="err_inner_before\\ nerr_inner_after\\ n"
1087+ """ .format (
1088+ fixture = fixture
1089+ )
1090+ )
1091+
1092+ child = testdir .spawn_pytest (str (p1 ) + " -s" )
1093+
1094+ child .expect ("Pdb" )
1095+ before = child .before .decode ("utf8" )
1096+ assert (
1097+ "> PDB set_trace (IO-capturing turned off for fixture %s) >" % (fixture )
1098+ in before
1099+ )
1100+
1101+ # Test that capturing is really suspended.
1102+ child .sendline ("p 40 + 2" )
1103+ child .expect ("Pdb" )
1104+ assert "\r \n 42\r \n " in child .before .decode ("utf8" )
1105+
1106+ child .sendline ("c" )
1107+ rest = child .read ().decode ("utf8" )
1108+ assert "out_inner" not in rest
1109+ assert "err_inner" not in rest
1110+
1111+ TestPDB .flush (child )
1112+ assert child .exitstatus == 0
1113+ assert "= 1 passed in " in rest
1114+ assert "> PDB continue (IO-capturing resumed for fixture %s) >" % (fixture ) in rest
0 commit comments