mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Revise 10 tests in 7 files, with 1 test split into 2.
(cherry picked from commit dbb25ce)
		
	
			
		
			
				
	
	
		
			298 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			298 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Test debugger, coverage 66%
 | 
						|
 | 
						|
Try to make tests pass with draft bdbx, which may replace bdb in 3.13+.
 | 
						|
"""
 | 
						|
 | 
						|
from idlelib import debugger
 | 
						|
from collections import namedtuple
 | 
						|
from textwrap import dedent
 | 
						|
from tkinter import Tk
 | 
						|
 | 
						|
from test.support import requires
 | 
						|
from test.support.testcase import ExtraAssertions
 | 
						|
import unittest
 | 
						|
from unittest import mock
 | 
						|
from unittest.mock import Mock, patch
 | 
						|
 | 
						|
"""A test python script for the debug tests."""
 | 
						|
TEST_CODE = dedent("""
 | 
						|
    i = 1
 | 
						|
    i += 2
 | 
						|
    if i == 3:
 | 
						|
       print(i)
 | 
						|
    """)
 | 
						|
 | 
						|
 | 
						|
class MockFrame:
 | 
						|
    "Minimal mock frame."
 | 
						|
 | 
						|
    def __init__(self, code, lineno):
 | 
						|
        self.f_code = code
 | 
						|
        self.f_lineno = lineno
 | 
						|
 | 
						|
 | 
						|
class IdbTest(unittest.TestCase):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        cls.gui = Mock()
 | 
						|
        cls.idb = debugger.Idb(cls.gui)
 | 
						|
 | 
						|
        # Create test and code objects to simulate a debug session.
 | 
						|
        code_obj = compile(TEST_CODE, 'idlelib/file.py', mode='exec')
 | 
						|
        frame1 = MockFrame(code_obj, 1)
 | 
						|
        frame1.f_back = None
 | 
						|
        frame2 = MockFrame(code_obj, 2)
 | 
						|
        frame2.f_back = frame1
 | 
						|
        cls.frame = frame2
 | 
						|
        cls.msg = 'file.py:2: <module>()'
 | 
						|
 | 
						|
    def test_init(self):
 | 
						|
        self.assertIs(self.idb.gui, self.gui)
 | 
						|
        # Won't test super call since two Bdbs are very different.
 | 
						|
 | 
						|
    def test_user_line(self):
 | 
						|
        # Test that .user_line() creates a string message for a frame.
 | 
						|
        self.gui.interaction = Mock()
 | 
						|
        self.idb.user_line(self.frame)
 | 
						|
        self.gui.interaction.assert_called_once_with(self.msg, self.frame)
 | 
						|
 | 
						|
    def test_user_exception(self):
 | 
						|
        # Test that .user_exception() creates a string message for a frame.
 | 
						|
        exc_info = (type(ValueError), ValueError(), None)
 | 
						|
        self.gui.interaction = Mock()
 | 
						|
        self.idb.user_exception(self.frame, exc_info)
 | 
						|
        self.gui.interaction.assert_called_once_with(
 | 
						|
                self.msg, self.frame, exc_info)
 | 
						|
 | 
						|
 | 
						|
class FunctionTest(unittest.TestCase):
 | 
						|
    # Test module functions together.
 | 
						|
 | 
						|
    def test_functions(self):
 | 
						|
        rpc_obj = compile(TEST_CODE,'rpc.py', mode='exec')
 | 
						|
        rpc_frame = MockFrame(rpc_obj, 2)
 | 
						|
        rpc_frame.f_back = rpc_frame
 | 
						|
        self.assertTrue(debugger._in_rpc_code(rpc_frame))
 | 
						|
        self.assertEqual(debugger._frame2message(rpc_frame),
 | 
						|
                         'rpc.py:2: <module>()')
 | 
						|
 | 
						|
        code_obj = compile(TEST_CODE, 'idlelib/debugger.py', mode='exec')
 | 
						|
        code_frame = MockFrame(code_obj, 1)
 | 
						|
        code_frame.f_back = None
 | 
						|
        self.assertFalse(debugger._in_rpc_code(code_frame))
 | 
						|
        self.assertEqual(debugger._frame2message(code_frame),
 | 
						|
                         'debugger.py:1: <module>()')
 | 
						|
 | 
						|
        code_frame.f_back = code_frame
 | 
						|
        self.assertFalse(debugger._in_rpc_code(code_frame))
 | 
						|
        code_frame.f_back = rpc_frame
 | 
						|
        self.assertTrue(debugger._in_rpc_code(code_frame))
 | 
						|
 | 
						|
 | 
						|
class DebuggerTest(unittest.TestCase):
 | 
						|
    "Tests for Debugger that do not need a real root."
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        cls.pyshell = Mock()
 | 
						|
        cls.pyshell.root = Mock()
 | 
						|
        cls.idb = Mock()
 | 
						|
        with patch.object(debugger.Debugger, 'make_gui'):
 | 
						|
            cls.debugger = debugger.Debugger(cls.pyshell, cls.idb)
 | 
						|
        cls.debugger.root = Mock()
 | 
						|
 | 
						|
    def test_cont(self):
 | 
						|
        self.debugger.cont()
 | 
						|
        self.idb.set_continue.assert_called_once()
 | 
						|
 | 
						|
    def test_step(self):
 | 
						|
        self.debugger.step()
 | 
						|
        self.idb.set_step.assert_called_once()
 | 
						|
 | 
						|
    def test_quit(self):
 | 
						|
        self.debugger.quit()
 | 
						|
        self.idb.set_quit.assert_called_once()
 | 
						|
 | 
						|
    def test_next(self):
 | 
						|
        with patch.object(self.debugger, 'frame') as frame:
 | 
						|
            self.debugger.next()
 | 
						|
            self.idb.set_next.assert_called_once_with(frame)
 | 
						|
 | 
						|
    def test_ret(self):
 | 
						|
        with patch.object(self.debugger, 'frame') as frame:
 | 
						|
            self.debugger.ret()
 | 
						|
            self.idb.set_return.assert_called_once_with(frame)
 | 
						|
 | 
						|
    def test_clear_breakpoint(self):
 | 
						|
        self.debugger.clear_breakpoint('test.py', 4)
 | 
						|
        self.idb.clear_break.assert_called_once_with('test.py', 4)
 | 
						|
 | 
						|
    def test_clear_file_breaks(self):
 | 
						|
        self.debugger.clear_file_breaks('test.py')
 | 
						|
        self.idb.clear_all_file_breaks.assert_called_once_with('test.py')
 | 
						|
 | 
						|
    def test_set_load_breakpoints(self):
 | 
						|
        # Test the .load_breakpoints() method calls idb.
 | 
						|
        FileIO = namedtuple('FileIO', 'filename')
 | 
						|
 | 
						|
        class MockEditWindow(object):
 | 
						|
            def __init__(self, fn, breakpoints):
 | 
						|
                self.io = FileIO(fn)
 | 
						|
                self.breakpoints = breakpoints
 | 
						|
 | 
						|
        self.pyshell.flist = Mock()
 | 
						|
        self.pyshell.flist.inversedict = (
 | 
						|
            MockEditWindow('test1.py', [4, 4]),
 | 
						|
            MockEditWindow('test2.py', [13, 44, 45]),
 | 
						|
        )
 | 
						|
        self.debugger.set_breakpoint('test0.py', 1)
 | 
						|
        self.idb.set_break.assert_called_once_with('test0.py', 1)
 | 
						|
        self.debugger.load_breakpoints()  # Call set_breakpoint 5 times.
 | 
						|
        self.idb.set_break.assert_has_calls(
 | 
						|
            [mock.call('test0.py', 1),
 | 
						|
             mock.call('test1.py', 4),
 | 
						|
             mock.call('test1.py', 4),
 | 
						|
             mock.call('test2.py', 13),
 | 
						|
             mock.call('test2.py', 44),
 | 
						|
             mock.call('test2.py', 45)])
 | 
						|
 | 
						|
    def test_sync_source_line(self):
 | 
						|
        # Test that .sync_source_line() will set the flist.gotofileline with fixed frame.
 | 
						|
        test_code = compile(TEST_CODE, 'test_sync.py', 'exec')
 | 
						|
        test_frame = MockFrame(test_code, 1)
 | 
						|
        self.debugger.frame = test_frame
 | 
						|
 | 
						|
        self.debugger.flist = Mock()
 | 
						|
        with patch('idlelib.debugger.os.path.exists', return_value=True):
 | 
						|
            self.debugger.sync_source_line()
 | 
						|
        self.debugger.flist.gotofileline.assert_called_once_with('test_sync.py', 1)
 | 
						|
 | 
						|
 | 
						|
class DebuggerGuiTest(unittest.TestCase):
 | 
						|
    """Tests for debugger.Debugger that need tk root.
 | 
						|
 | 
						|
    close needs debugger.top set in make_gui.
 | 
						|
    """
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        requires('gui')
 | 
						|
        cls.root = root = Tk()
 | 
						|
        root.withdraw()
 | 
						|
        cls.pyshell = Mock()
 | 
						|
        cls.pyshell.root = root
 | 
						|
        cls.idb = Mock()
 | 
						|
# stack tests fail with debugger here.
 | 
						|
##        cls.debugger = debugger.Debugger(cls.pyshell, cls.idb)
 | 
						|
##        cls.debugger.root = root
 | 
						|
##        # real root needed for real make_gui
 | 
						|
##        # run, interacting, abort_loop
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def tearDownClass(cls):
 | 
						|
        cls.root.destroy()
 | 
						|
        del cls.root
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        self.debugger = debugger.Debugger(self.pyshell, self.idb)
 | 
						|
        self.debugger.root = self.root
 | 
						|
        # real root needed for real make_gui
 | 
						|
        # run, interacting, abort_loop
 | 
						|
 | 
						|
    def test_run_debugger(self):
 | 
						|
        self.debugger.run(1, 'two')
 | 
						|
        self.idb.run.assert_called_once_with(1, 'two')
 | 
						|
        self.assertEqual(self.debugger.interacting, 0)
 | 
						|
 | 
						|
    def test_close(self):
 | 
						|
        # Test closing the window in an idle state.
 | 
						|
        self.debugger.close()
 | 
						|
        self.pyshell.close_debugger.assert_called_once()
 | 
						|
 | 
						|
    def test_show_stack(self):
 | 
						|
        self.debugger.show_stack()
 | 
						|
        self.assertEqual(self.debugger.stackviewer.gui, self.debugger)
 | 
						|
 | 
						|
    def test_show_stack_with_frame(self):
 | 
						|
        test_frame = MockFrame(None, None)
 | 
						|
        self.debugger.frame = test_frame
 | 
						|
 | 
						|
        # Reset the stackviewer to force it to be recreated.
 | 
						|
        self.debugger.stackviewer = None
 | 
						|
        self.idb.get_stack.return_value = ([], 0)
 | 
						|
        self.debugger.show_stack()
 | 
						|
 | 
						|
        # Check that the newly created stackviewer has the test gui as a field.
 | 
						|
        self.assertEqual(self.debugger.stackviewer.gui, self.debugger)
 | 
						|
        self.idb.get_stack.assert_called_once_with(test_frame, None)
 | 
						|
 | 
						|
 | 
						|
class StackViewerTest(unittest.TestCase, ExtraAssertions):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        requires('gui')
 | 
						|
        cls.root = Tk()
 | 
						|
        cls.root.withdraw()
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def tearDownClass(cls):
 | 
						|
        cls.root.destroy()
 | 
						|
        del cls.root
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        self.code = compile(TEST_CODE, 'test_stackviewer.py', 'exec')
 | 
						|
        self.stack = [
 | 
						|
            (MockFrame(self.code, 1), 1),
 | 
						|
            (MockFrame(self.code, 2), 2)
 | 
						|
        ]
 | 
						|
        # Create a stackviewer and load the test stack.
 | 
						|
        self.sv = debugger.StackViewer(self.root, None, None)
 | 
						|
        self.sv.load_stack(self.stack)
 | 
						|
 | 
						|
    def test_init(self):
 | 
						|
        # Test creation of StackViewer.
 | 
						|
        gui = None
 | 
						|
        flist = None
 | 
						|
        master_window = self.root
 | 
						|
        sv = debugger.StackViewer(master_window, flist, gui)
 | 
						|
        self.assertHasAttr(sv, 'stack')
 | 
						|
 | 
						|
    def test_load_stack(self):
 | 
						|
        # Test the .load_stack() method against a fixed test stack.
 | 
						|
        # Check the test stack is assigned and the list contains the repr of them.
 | 
						|
        self.assertEqual(self.sv.stack, self.stack)
 | 
						|
        self.assertTrue('?.<module>(), line 1:' in self.sv.get(0))
 | 
						|
        self.assertEqual(self.sv.get(1), '?.<module>(), line 2: ')
 | 
						|
 | 
						|
    def test_show_source(self):
 | 
						|
        # Test the .show_source() method against a fixed test stack.
 | 
						|
        # Patch out the file list to monitor it
 | 
						|
        self.sv.flist = Mock()
 | 
						|
        # Patch out isfile to pretend file exists.
 | 
						|
        with patch('idlelib.debugger.os.path.isfile', return_value=True) as isfile:
 | 
						|
            self.sv.show_source(1)
 | 
						|
            isfile.assert_called_once_with('test_stackviewer.py')
 | 
						|
            self.sv.flist.open.assert_called_once_with('test_stackviewer.py')
 | 
						|
 | 
						|
 | 
						|
class NameSpaceTest(unittest.TestCase):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        requires('gui')
 | 
						|
        cls.root = Tk()
 | 
						|
        cls.root.withdraw()
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def tearDownClass(cls):
 | 
						|
        cls.root.destroy()
 | 
						|
        del cls.root
 | 
						|
 | 
						|
    def test_init(self):
 | 
						|
        debugger.NamespaceViewer(self.root, 'Test')
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    unittest.main(verbosity=2)
 |