|
1 | 1 | # A test suite for pdb; not very comprehensive at the moment.
|
2 | 2 |
|
| 3 | +import dis |
3 | 4 | import doctest
|
4 | 5 | import os
|
5 | 6 | import pdb
|
@@ -2351,6 +2352,101 @@ def _create_fake_frozen_module():
|
2351 | 2352 | # verify that pdb found the source of the "frozen" function
|
2352 | 2353 | self.assertIn('x = "Sentinel string for gh-93696"', stdout, "Sentinel statement not found")
|
2353 | 2354 |
|
| 2355 | + def get_func_opnames(self, func_def, func_name): |
| 2356 | + extract_code = f""" |
| 2357 | + import dis |
| 2358 | + for inst in dis.get_instructions({func_name}): |
| 2359 | + print(inst.opname) |
| 2360 | + """ |
| 2361 | + |
| 2362 | + with redirect_stdout(StringIO()) as s: |
| 2363 | + exec(textwrap.dedent(func_def) + textwrap.dedent(extract_code)) |
| 2364 | + |
| 2365 | + return s.getvalue().splitlines() |
| 2366 | + |
| 2367 | + def test_list_instruction(self): |
| 2368 | + func_def = """ |
| 2369 | + def f(): |
| 2370 | + a = [1, 2, 3] |
| 2371 | + return a[0] |
| 2372 | + """ |
| 2373 | + func_exec = """ |
| 2374 | + f() |
| 2375 | + """ |
| 2376 | + script = func_def + func_exec |
| 2377 | + |
| 2378 | + commands_li = """ |
| 2379 | + break f |
| 2380 | + c |
| 2381 | + li |
| 2382 | + """ |
| 2383 | + |
| 2384 | + commands_lli = """ |
| 2385 | + break f |
| 2386 | + c |
| 2387 | + lli |
| 2388 | + """ |
| 2389 | + |
| 2390 | + # Make sure all the opcodes are listed |
| 2391 | + stdout, stderr = self.run_pdb_module(script, commands_li) |
| 2392 | + for opname in self.get_func_opnames(func_def, "f"): |
| 2393 | + self.assertIn(opname, stdout) |
| 2394 | + |
| 2395 | + stdout, stderr = self.run_pdb_module(script, commands_lli) |
| 2396 | + for opname in self.get_func_opnames(func_def, "f"): |
| 2397 | + self.assertIn(opname, stdout) |
| 2398 | + |
| 2399 | + def test_instruction_level_control(self): |
| 2400 | + func_def = """ |
| 2401 | + def f(): |
| 2402 | + a = [1, 2, 3] |
| 2403 | + return a[0] |
| 2404 | + """ |
| 2405 | + func_exec = """ |
| 2406 | + f() |
| 2407 | + """ |
| 2408 | + script = func_def + func_exec |
| 2409 | + |
| 2410 | + commands = """ |
| 2411 | + ni |
| 2412 | + li |
| 2413 | + """ |
| 2414 | + |
| 2415 | + # Check that after ni, current instruction is displayed |
| 2416 | + stdout, stderr = self.run_pdb_module(script, commands) |
| 2417 | + lines = [line.strip() for line in stdout.splitlines()] |
| 2418 | + for idx, line in enumerate(lines): |
| 2419 | + if "-->" in line: |
| 2420 | + # Found the current instruction indicator after ni |
| 2421 | + # Make sure that is listed in li |
| 2422 | + self.assertIn(line, lines[idx+1:]) |
| 2423 | + break |
| 2424 | + |
| 2425 | + commands = """ |
| 2426 | + ni |
| 2427 | + ni |
| 2428 | + ni |
| 2429 | + c |
| 2430 | + """ |
| 2431 | + |
| 2432 | + stdout, stderr = self.run_pdb_module(script, commands) |
| 2433 | + curr_instr_lines = [line.strip() for line in stdout.splitlines() if "-->" in line] |
| 2434 | + self.assertEqual(len(curr_instr_lines), 3) |
| 2435 | + for line in curr_instr_lines: |
| 2436 | + # Make sure ni is moving forward, not stopping at the same instrunction |
| 2437 | + self.assertEqual(curr_instr_lines.count(line), 1) |
| 2438 | + |
| 2439 | + # this test is under the assumption that within 10 instructions the function |
| 2440 | + # f should be called |
| 2441 | + commands = "si\n" * 10 + "c\n" |
| 2442 | + |
| 2443 | + stdout, stderr = self.run_pdb_module(script, commands) |
| 2444 | + curr_instr_lines = [line.strip() for line in stdout.splitlines()] |
| 2445 | + # Make sure si stepped into the function so the users can see the source |
| 2446 | + # code of the function |
| 2447 | + self.assertTrue(any("-> a = [1, 2, 3]" in line for line in curr_instr_lines)) |
| 2448 | + |
| 2449 | + |
2354 | 2450 | class ChecklineTests(unittest.TestCase):
|
2355 | 2451 | def setUp(self):
|
2356 | 2452 | linecache.clearcache() # Pdb.checkline() uses linecache.getline()
|
|
0 commit comments