- Notifications
You must be signed in to change notification settings - Fork 31.8k
/
Copy pathtest_debugger.py
298 lines (237 loc) · 9.56 KB
/
test_debugger.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
"""Test debugger, coverage 66%
Try to make tests pass with draft bdbx, which may replace bdb in 3.13+.
"""
fromidlelibimportdebugger
fromcollectionsimportnamedtuple
fromtextwrapimportdedent
fromtkinterimportTk
fromtest.supportimportrequires
fromtest.support.testcaseimportExtraAssertions
importunittest
fromunittestimportmock
fromunittest.mockimportMock, patch
"""A test python script for the debug tests."""
TEST_CODE=dedent("""
i = 1
i += 2
if i == 3:
print(i)
""")
classMockFrame:
"Minimal mock frame."
def__init__(self, code, lineno):
self.f_code=code
self.f_lineno=lineno
classIdbTest(unittest.TestCase):
@classmethod
defsetUpClass(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>()'
deftest_init(self):
self.assertIs(self.idb.gui, self.gui)
# Won't test super call since two Bdbs are very different.
deftest_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)
deftest_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)
classFunctionTest(unittest.TestCase):
# Test module functions together.
deftest_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))
classDebuggerTest(unittest.TestCase):
"Tests for Debugger that do not need a real root."
@classmethod
defsetUpClass(cls):
cls.pyshell=Mock()
cls.pyshell.root=Mock()
cls.idb=Mock()
withpatch.object(debugger.Debugger, 'make_gui'):
cls.debugger=debugger.Debugger(cls.pyshell, cls.idb)
cls.debugger.root=Mock()
deftest_cont(self):
self.debugger.cont()
self.idb.set_continue.assert_called_once()
deftest_step(self):
self.debugger.step()
self.idb.set_step.assert_called_once()
deftest_quit(self):
self.debugger.quit()
self.idb.set_quit.assert_called_once()
deftest_next(self):
withpatch.object(self.debugger, 'frame') asframe:
self.debugger.next()
self.idb.set_next.assert_called_once_with(frame)
deftest_ret(self):
withpatch.object(self.debugger, 'frame') asframe:
self.debugger.ret()
self.idb.set_return.assert_called_once_with(frame)
deftest_clear_breakpoint(self):
self.debugger.clear_breakpoint('test.py', 4)
self.idb.clear_break.assert_called_once_with('test.py', 4)
deftest_clear_file_breaks(self):
self.debugger.clear_file_breaks('test.py')
self.idb.clear_all_file_breaks.assert_called_once_with('test.py')
deftest_set_load_breakpoints(self):
# Test the .load_breakpoints() method calls idb.
FileIO=namedtuple('FileIO', 'filename')
classMockEditWindow(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)])
deftest_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()
withpatch('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)
classDebuggerGuiTest(unittest.TestCase):
"""Tests for debugger.Debugger that need tk root.
close needs debugger.top set in make_gui.
"""
@classmethod
defsetUpClass(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
deftearDownClass(cls):
cls.root.destroy()
delcls.root
defsetUp(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
deftest_run_debugger(self):
self.debugger.run(1, 'two')
self.idb.run.assert_called_once_with(1, 'two')
self.assertEqual(self.debugger.interacting, 0)
deftest_close(self):
# Test closing the window in an idle state.
self.debugger.close()
self.pyshell.close_debugger.assert_called_once()
deftest_show_stack(self):
self.debugger.show_stack()
self.assertEqual(self.debugger.stackviewer.gui, self.debugger)
deftest_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)
classStackViewerTest(unittest.TestCase, ExtraAssertions):
@classmethod
defsetUpClass(cls):
requires('gui')
cls.root=Tk()
cls.root.withdraw()
@classmethod
deftearDownClass(cls):
cls.root.destroy()
delcls.root
defsetUp(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)
deftest_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')
deftest_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:'inself.sv.get(0))
self.assertEqual(self.sv.get(1), '?.<module>(), line 2: ')
deftest_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.
withpatch('idlelib.debugger.os.path.isfile', return_value=True) asisfile:
self.sv.show_source(1)
isfile.assert_called_once_with('test_stackviewer.py')
self.sv.flist.open.assert_called_once_with('test_stackviewer.py')
classNameSpaceTest(unittest.TestCase):
@classmethod
defsetUpClass(cls):
requires('gui')
cls.root=Tk()
cls.root.withdraw()
@classmethod
deftearDownClass(cls):
cls.root.destroy()
delcls.root
deftest_init(self):
debugger.NamespaceViewer(self.root, 'Test')
if__name__=='__main__':
unittest.main(verbosity=2)