|
5 | 5 | importdis |
6 | 6 | importfunctools |
7 | 7 | importio |
| 8 | +importitertools |
| 9 | +importopcode |
8 | 10 | importre |
9 | 11 | importsys |
| 12 | +importtempfile |
| 13 | +importtextwrap |
10 | 14 | importtypes |
11 | 15 | importunittest |
12 | 16 | fromtest.supportimport (captured_stdout,requires_debug_ranges, |
13 | | -requires_specialization,cpython_only) |
| 17 | +requires_specialization,cpython_only, |
| 18 | +os_helper) |
14 | 19 | fromtest.support.bytecode_helperimportBytecodeTestCase |
15 | 20 |
|
16 | | -importopcode |
17 | 21 |
|
18 | 22 | CACHE=dis.opmap["CACHE"] |
19 | 23 |
|
@@ -2426,5 +2430,119 @@ def _unroll_caches_as_Instructions(instrs, show_caches=False): |
2426 | 2430 | False,None,None,instr.positions) |
2427 | 2431 |
|
2428 | 2432 |
|
| 2433 | +classTestDisCLI(unittest.TestCase): |
| 2434 | + |
| 2435 | +defsetUp(self): |
| 2436 | +self.filename=tempfile.mktemp() |
| 2437 | +self.addCleanup(os_helper.unlink,self.filename) |
| 2438 | + |
| 2439 | +@staticmethod |
| 2440 | +deftext_normalize(string): |
| 2441 | +"""Dedent *string* and strip it from its surrounding whitespaces. |
| 2442 | +
|
| 2443 | + This method is used by the other utility functions so that any |
| 2444 | + string to write or to match against can be freely indented. |
| 2445 | + """ |
| 2446 | +returntextwrap.dedent(string).strip() |
| 2447 | + |
| 2448 | +defset_source(self,content): |
| 2449 | +withopen(self.filename,'w')asfp: |
| 2450 | +fp.write(self.text_normalize(content)) |
| 2451 | + |
| 2452 | +definvoke_dis(self,*flags): |
| 2453 | +output=io.StringIO() |
| 2454 | +withcontextlib.redirect_stdout(output): |
| 2455 | +dis.main(args=[*flags,self.filename]) |
| 2456 | +returnself.text_normalize(output.getvalue()) |
| 2457 | + |
| 2458 | +defcheck_output(self,source,expect,*flags): |
| 2459 | +withself.subTest(source=source,flags=flags): |
| 2460 | +self.set_source(source) |
| 2461 | +res=self.invoke_dis(*flags) |
| 2462 | +expect=self.text_normalize(expect) |
| 2463 | +self.assertListEqual(res.splitlines(),expect.splitlines()) |
| 2464 | + |
| 2465 | +deftest_invocation(self): |
| 2466 | +# test various combinations of parameters |
| 2467 | +base_flags= [ |
| 2468 | + ('-C','--show-caches'), |
| 2469 | + ('-O','--show-offsets'), |
| 2470 | + ('-P','--show-positions'), |
| 2471 | + ('-S','--specialized'), |
| 2472 | + ] |
| 2473 | + |
| 2474 | +self.set_source(''' |
| 2475 | + def f(): |
| 2476 | + print(x) |
| 2477 | + return None |
| 2478 | + ''') |
| 2479 | + |
| 2480 | +forrinrange(1,len(base_flags)+1): |
| 2481 | +forchoicesinitertools.combinations(base_flags,r=r): |
| 2482 | +forargsinitertools.product(*choices): |
| 2483 | +withself.subTest(args=args[1:]): |
| 2484 | +_=self.invoke_dis(*args) |
| 2485 | + |
| 2486 | +withself.assertRaises(SystemExit): |
| 2487 | +# suppress argparse error message |
| 2488 | +withcontextlib.redirect_stderr(io.StringIO()): |
| 2489 | +_=self.invoke_dis('--unknown') |
| 2490 | + |
| 2491 | +deftest_show_cache(self): |
| 2492 | +# test 'python -m dis -C/--show-caches' |
| 2493 | +source='print()' |
| 2494 | +expect=''' |
| 2495 | + 0 RESUME 0 |
| 2496 | +
|
| 2497 | + 1 LOAD_NAME 0 (print) |
| 2498 | + PUSH_NULL |
| 2499 | + CALL 0 |
| 2500 | + CACHE 0 (counter: 0) |
| 2501 | + CACHE 0 (func_version: 0) |
| 2502 | + CACHE 0 |
| 2503 | + POP_TOP |
| 2504 | + LOAD_CONST 0 (None) |
| 2505 | + RETURN_VALUE |
| 2506 | + ''' |
| 2507 | +forflagin ['-C','--show-caches']: |
| 2508 | +self.check_output(source,expect,flag) |
| 2509 | + |
| 2510 | +deftest_show_offsets(self): |
| 2511 | +# test 'python -m dis -O/--show-offsets' |
| 2512 | +source='pass' |
| 2513 | +expect=''' |
| 2514 | + 0 0 RESUME 0 |
| 2515 | +
|
| 2516 | + 1 2 LOAD_CONST 0 (None) |
| 2517 | + 4 RETURN_VALUE |
| 2518 | + ''' |
| 2519 | +forflagin ['-O','--show-offsets']: |
| 2520 | +self.check_output(source,expect,flag) |
| 2521 | + |
| 2522 | +deftest_show_positions(self): |
| 2523 | +# test 'python -m dis -P/--show-positions' |
| 2524 | +source='pass' |
| 2525 | +expect=''' |
| 2526 | + 0:0-1:0 RESUME 0 |
| 2527 | +
|
| 2528 | + 1:0-1:4 LOAD_CONST 0 (None) |
| 2529 | + 1:0-1:4 RETURN_VALUE |
| 2530 | + ''' |
| 2531 | +forflagin ['-P','--show-positions']: |
| 2532 | +self.check_output(source,expect,flag) |
| 2533 | + |
| 2534 | +deftest_specialized_code(self): |
| 2535 | +# test 'python -m dis -S/--specialized' |
| 2536 | +source='pass' |
| 2537 | +expect=''' |
| 2538 | + 0 RESUME 0 |
| 2539 | +
|
| 2540 | + 1 LOAD_CONST_IMMORTAL 0 (None) |
| 2541 | + RETURN_VALUE |
| 2542 | + ''' |
| 2543 | +forflagin ['-S','--specialized']: |
| 2544 | +self.check_output(source,expect,flag) |
| 2545 | + |
| 2546 | + |
2429 | 2547 | if__name__=="__main__": |
2430 | 2548 | unittest.main() |