def test_attaching_by_pid(pyfile, run_as, start_method): @pyfile def code_to_debug(): # import_and_enable_debugger() import time def do_something(i): time.sleep(0.1) print(i) for i in range(100): do_something(i) bp_line = 5 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.set_breakpoints(code_to_debug, [bp_line]) session.start_debugging() hit = session.wait_for_thread_stopped() frames = hit.stacktrace.body['stackFrames'] assert bp_line == frames[0]['line'] # remove breakpoint and continue session.set_breakpoints(code_to_debug, []) session.send_request('continue').wait_for_response(freeze=False) session.wait_for_next( Event('output', ANY.dict_with({'category': 'stdout'}))) session.wait_for_exit()
def test_with_tab_in_output(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() a = '\t'.join(('Hello', 'World')) print(a) # Break here so we are sure to get the output event. a = 1 # @bp1 line_numbers = get_marked_line_numbers(code_to_debug) with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.set_breakpoints(code_to_debug, [line_numbers['bp1']]) session.start_debugging() # Breakpoint at the end just to make sure we get all output events. session.wait_for_thread_stopped() session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit() output = session.all_occurrences_of( Event('output', ANY.dict_with({'category': 'stdout'}))) output_str = ''.join(o.body['output'] for o in output) assert output_str.startswith('Hello\tWorld')
def _initialize_flask_session_no_multiproc(session, start_method): env = { 'FLASK_APP': 'app.py', 'FLASK_ENV': 'development', 'FLASK_DEBUG': '0', } if platform.system() != 'Windows': locale = 'en_US.utf8' if platform.system( ) == 'Linux' else 'en_US.UTF-8' env.update({ 'LC_ALL': locale, 'LANG': locale, }) session.initialize( start_method=start_method, target=('module', 'flask'), program_args=[ 'run', '--no-debugger', '--no-reload', '--with-threads', '--port', str(FLASK_PORT) ], ignore_unobserved=[Event('stopped'), Event('continued')], debug_options=['Jinja'], cwd=FLASK1_ROOT, env=env, expected_returncode=ANY.int, # No clean way to kill Flask server )
def test_continue_on_disconnect_for_attach(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import backchannel backchannel.write_json('continued') bp_line = 4 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('exited'), Event('terminated')], use_backchannel=True, ) session.set_breakpoints(code_to_debug, [bp_line]) session.start_debugging() hit = session.wait_for_thread_stopped('breakpoint') frames = hit.stacktrace.body['stackFrames'] assert frames[0]['line'] == bp_line session.send_request('disconnect').wait_for_response() session.wait_for_disconnect() assert 'continued' == session.read_json()
def test_completions_scope(pyfile, bp_line, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() class SomeClass(): def __init__(self, someVar): self.some_var = someVar def do_someting(self): someVariable = self.some_var return someVariable def someFunction(someVar): someVariable = someVar return SomeClass(someVariable).do_someting() someFunction('value') print('done') expected = expected_at_line[bp_line] with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('stopped'), Event('continued')], ) session.set_breakpoints(code_to_debug, [bp_line]) session.start_debugging() thread_stopped = session.wait_for_next(Event('stopped', ANY.dict_with({'reason': 'breakpoint'}))) assert thread_stopped.body['threadId'] is not None tid = thread_stopped.body['threadId'] resp_stacktrace = session.send_request('stackTrace', arguments={ 'threadId': tid, }).wait_for_response() assert resp_stacktrace.body['totalFrames'] > 0 frames = resp_stacktrace.body['stackFrames'] assert len(frames) > 0 fid = frames[0]['id'] resp_completions = session.send_request('completions', arguments={ 'text': 'some', 'frameId': fid, 'column': 5, }).wait_for_response() targets = resp_completions.body['targets'] session.send_request('continue').wait_for_response(freeze=False) targets.sort(key=lambda t: t['label']) expected.sort(key=lambda t: t['label']) assert targets == expected session.wait_for_exit()
def test_set_variable(pyfile, run_as, start_method): @pyfile def code_to_debug(): import backchannel from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import ptvsd a = 1 ptvsd.break_into_debugger() backchannel.write_json(a) with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], use_backchannel=True, ) session.start_debugging() hit = session.wait_for_thread_stopped() resp_scopes = session.send_request('scopes', arguments={ 'frameId': hit.frame_id }).wait_for_response() scopes = resp_scopes.body['scopes'] assert len(scopes) > 0 resp_variables = session.send_request( 'variables', arguments={ 'variablesReference': scopes[0]['variablesReference'] }).wait_for_response() variables = list(v for v in resp_variables.body['variables'] if v['name'] == 'a') assert len(variables) == 1 assert variables[0] == { 'type': 'int', 'value': '1', 'name': 'a', 'evaluateName': "a" } resp_set_variable = session.send_request( 'setVariable', arguments={ 'variablesReference': scopes[0]['variablesReference'], 'name': 'a', 'value': '1000' }).wait_for_response() assert resp_set_variable.body == ANY.dict_with({ 'type': 'int', 'value': '1000' }) session.send_request('continue').wait_for_response(freeze=False) assert session.read_json() == 1000 session.wait_for_exit()
def test_redirect_output(pyfile, run_as, start_method, redirect): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() for i in [111, 222, 333, 444]: print(i) print() # @bp1 line_numbers = get_marked_line_numbers(code_to_debug) with DebugSession() as session: # By default 'RedirectOutput' is always set. So using this way # to override the default in session. session.debug_options = [redirect] if bool(redirect) else [] session.initialize( target=(run_as, code_to_debug), start_method=start_method, ) session.set_breakpoints(code_to_debug, [line_numbers['bp1']]) session.start_debugging() # Breakpoint at the end just to make sure we get all output events. session.wait_for_thread_stopped() session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit() output = session.all_occurrences_of( Event('output', ANY.dict_with({'category': 'stdout'}))) expected = ['111', '222', '333', '444'] if bool(redirect) else [] assert expected == list(o.body['output'] for o in output if len(o.body['output']) == 3)
def test_break_on_entry(pyfile, run_as, start_method): @pyfile def code_to_debug(): import backchannel from dbgimporter import import_and_enable_debugger import_and_enable_debugger() backchannel.write_json('done') with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, debug_options=['StopOnEntry'], ignore_unobserved=[Event('continued')], use_backchannel=True, ) session.start_debugging() thread_stopped, resp_stacktrace, tid, _ = session.wait_for_thread_stopped( ) frames = resp_stacktrace.body['stackFrames'] assert frames[0]['line'] == 1 session.send_request('continue').wait_for_response(freeze=False) session.wait_for_termination() assert session.read_json() == 'done' session.wait_for_exit()
def test_attaching_by_pid_no_threading(pyfile, run_as, start_method): @pyfile def code_to_debug(): # import_and_enable_debugger import time wait = True i = 0 while wait: i += 1 print('in loop') time.sleep(0.1) if i > 100: raise AssertionError( 'Debugger did not change wait to False as expected within the timeout.' ) with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ) session.start_debugging() # Wait for the first print to make sure we're in the proper state to pause. session.wait_for_next( Event('output', ANY.dict_with({ 'category': 'stdout', 'output': 'in loop' }))) _change_wait_to_false_and_exit(session)
def test_success_exitcodes(pyfile, run_as, start_method, exit_code): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import sys exit_code = eval(sys.argv[1]) print('sys.exit(%r)' % (exit_code, )) sys.exit(exit_code) with DebugSession() as session: session.program_args = [repr(exit_code)] session.success_exitcodes = [3] session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], expected_returncode=exit_code, ) session.send_request('setExceptionBreakpoints', { 'filters': ['uncaught'] }).wait_for_response() session.start_debugging() if exit_code == 0: session.wait_for_thread_stopped(reason='exception') session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit()
def test_wait_on_normal_exit_enabled(pyfile, run_as, start_method): @pyfile def code_to_debug(): import backchannel from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import ptvsd ptvsd.break_into_debugger() backchannel.write_json('done') with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, debug_options=['WaitOnNormalExit'], ignore_unobserved=[Event('continued')], use_backchannel=True, ) session.start_debugging() session.wait_for_thread_stopped() session.send_request('continue').wait_for_response(freeze=False) session.expected_returncode = ANY.int assert session.read_json() == 'done' session.process.stdin.write(b' \r\n') session.wait_for_exit() decoded = u'\n'.join((x.decode('utf-8') if isinstance(x, bytes) else x) for x in session.output_data['OUT']) assert u'Press' in decoded
def test_nodebug(pyfile, run_as): @pyfile def code_to_debug(): # import_and_enable_debugger import backchannel backchannel.read_json() print('ok') with DebugSession() as session: session.no_debug = True session.initialize(target=(run_as, code_to_debug), start_method='launch', use_backchannel=True) session.set_breakpoints(code_to_debug, [3]) session.start_debugging() session.write_json(None) # Breakpoint shouldn't be hit. session.wait_for_exit() session.expect_realized( Event('output', ANY.dict_with({ 'category': 'stdout', 'output': 'ok', })))
def test_exit_normally_with_wait_on_abnormal_exit_enabled( pyfile, run_as, start_method): @pyfile def code_to_debug(): import backchannel from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import ptvsd ptvsd.break_into_debugger() backchannel.write_json('done') with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, debug_options=['WaitOnAbnormalExit'], ignore_unobserved=[Event('continued')], use_backchannel=True, ) session.start_debugging() session.wait_for_thread_stopped() session.send_request('continue').wait_for_response(freeze=False) session.wait_for_termination() assert session.read_json() == 'done' session.wait_for_exit()
def test_exit_on_disconnect_for_launch(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import os.path fp = os.join(os.path.dirname(os.path.abspath(__file__)), 'here.txt') # should not execute this with open(fp, 'w') as f: print('Should not continue after disconnect on launch', file=f) bp_line = 4 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], use_backchannel=True, expected_returncode=ANY.int, ) session.set_breakpoints(code_to_debug, [bp_line]) session.start_debugging() hit = session.wait_for_thread_stopped('breakpoint') frames = hit.stacktrace.body['stackFrames'] assert frames[0]['line'] == bp_line session.send_request('disconnect').wait_for_response() session.wait_for_exit() fp = os.join(os.path.dirname(os.path.abspath(code_to_debug)), 'here.txt') assert not os.path.exists(fp)
def test_log_point(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() a = 10 for i in range(1, a): print('value: %d' % i) # Break at end too so that we're sure we get all output # events before the break. a = 10 bp_line = 5 end_bp_line = 8 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.send_request('setBreakpoints', arguments={ 'source': {'path': code_to_debug}, 'breakpoints': [{ 'line': bp_line, 'logMessage': 'log: {a + i}' }, {'line': end_bp_line}], }).wait_for_response() session.start_debugging() # Breakpoint at the end just to make sure we get all output events. hit = session.wait_for_thread_stopped() frames = hit.stacktrace.body['stackFrames'] assert end_bp_line == frames[0]['line'] session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit() assert session.get_stderr_as_string() == b'' output = session.all_occurrences_of(Event('output', ANY.dict_with({'category': 'stdout'}))) output_str = ''.join(o.body['output'] for o in output) logged = sorted(int(i) for i in re.findall(r"log:\s([0-9]*)", output_str)) values = sorted(int(i) for i in re.findall(r"value:\s([0-9]*)", output_str)) assert logged == list(range(11, 20)) assert values == list(range(1, 10))
def test_run_submodule(): cwd = get_test_root('testpkgs') with DebugSession() as session: session.initialize( target=('module', 'pkg1.sub'), start_method='launch', ignore_unobserved=[Event('continued')], cwd=cwd, ) session.start_debugging() session.wait_for_next( Event('output', ANY.dict_with({ 'category': 'stdout', 'output': 'three' }))) session.wait_for_exit()
def test_argv_quoting(pyfile, run_as, start_method): @pyfile def args(): # import_and_enable_debugger args = [ # noqa r'regular', r'', r'with spaces' r'"quoted"', r'" quote at start', r'quote at end "', r'quote in " the middle', r'quotes "in the" middle', r'\path with\spaces', r'\path\with\terminal\backslash' + '\\', r'backslash \" before quote', ] @pyfile def parent(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import sys import subprocess from args import args child = sys.argv[1] subprocess.check_call([sys.executable] + [child] + args) @pyfile def child(): # import_and_enable_debugger import backchannel import sys from args import args as expected_args backchannel.write_json(expected_args) actual_args = sys.argv[1:] backchannel.write_json(actual_args) with DebugSession() as session: session.initialize( target=(run_as, parent), start_method=start_method, program_args=[child], use_backchannel=True, ignore_unobserved=[Event('continued')], ) session.start_debugging() expected_args = session.read_json() actual_args = session.read_json() assert expected_args == actual_args session.wait_for_exit()
def test_vsc_exception_options_raise_with_except(pyfile, run_as, start_method, raised, uncaught): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() def raise_with_except(): try: raise ArithmeticError('bad code') # @exception_line except Exception: pass raise_with_except() line_numbers = get_marked_line_numbers(code_to_debug) ex_line = line_numbers['exception_line'] filters = [] filters += ['raised'] if raised == 'raisedOn' else [] filters += ['uncaught'] if uncaught == 'uncaughtOn' else [] with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.send_request('setExceptionBreakpoints', { 'filters': filters }).wait_for_response() session.start_debugging() expected = ANY.dict_with({ 'exceptionId': ANY.such_that(lambda s: s.endswith('ArithmeticError')), 'description': 'bad code', 'breakMode': 'always' if raised == 'raisedOn' else 'unhandled', 'details': ANY.dict_with({ 'typeName': ANY.such_that(lambda s: s.endswith('ArithmeticError')), 'message': 'bad code', 'source': Path(code_to_debug), }), }) if raised == 'raisedOn': hit = session.wait_for_thread_stopped(reason='exception') frames = hit.stacktrace.body['stackFrames'] assert ex_line == frames[0]['line'] resp_exc_info = session.send_request('exceptionInfo', { 'threadId': hit.thread_id }).wait_for_response() assert resp_exc_info.body == expected session.send_request('continue').wait_for_response(freeze=False) # uncaught should not 'stop' matter since the exception is caught session.wait_for_exit()
def test_module_events(pyfile, run_as, start_method): @pyfile def module2(): # import_and_enable_debugger() def do_more_things(): print('done') @pyfile def module1(): # import_and_enable_debugger() import module2 def do_something(): module2.do_more_things() @pyfile def test_code(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() from module1 import do_something do_something() bp_line = 3 with DebugSession() as session: session.initialize( target=(run_as, test_code), start_method=start_method, ignore_unobserved=[Event('stopped')], ) session.set_breakpoints(module2, [bp_line]) session.start_debugging() session.wait_for_thread_stopped() modules = session.all_occurrences_of(Event('module')) modules = [(m.body['module']['name'], m.body['module']['path']) for m in modules] assert modules[:3] == [ ('module2', Path(module2)), ('module1', Path(module1)), ('__main__', Path(test_code)), ] session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit()
def test_log_point(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() a = 10 for i in range(1, a): print('value: %d' % i) bp_line = 5 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.send_request('setBreakpoints', arguments={ 'source': { 'path': code_to_debug }, 'breakpoints': [{ 'line': bp_line, 'logMessage': 'log: {a + i}' }], }).wait_for_response() session.start_debugging() session.wait_for_exit() assert session.get_stderr_as_string() == b'' output = session.all_occurrences_of( Event('output', ANY.dict_with({'category': 'stdout'}))) output_str = ''.join(o.body['output'] for o in output) logged = sorted( int(i) for i in re.findall(r"log:\s([0-9]*)", output_str)) values = sorted( int(i) for i in re.findall(r"value:\s([0-9]*)", output_str)) # NOTE: Due to https://github.com/Microsoft/ptvsd/issues/1028 we may not get # all output events. Once that is fixed we should check for the exact output # and log value assert len(logged) > 0 assert len(values) > 0
def test_conditional_breakpoint(pyfile, run_as, start_method, condition_key): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() for i in range(0, 10): print(i) expected = { 'condition_var': ('condition', 'i==5', '5', 1), 'hitCondition_#': ('hitCondition', '5', '4', 1), 'hitCondition_eq': ('hitCondition', '==5', '4', 1), 'hitCondition_gt': ('hitCondition', '>5', '5', 5), 'hitCondition_ge': ('hitCondition', '>=5', '4', 6), 'hitCondition_lt': ('hitCondition', '<5', '0', 4), 'hitCondition_le': ('hitCondition', '<=5', '0', 5), 'hitCondition_mod': ('hitCondition', '%3', '2', 3), } condition_type, condition, value, hits = expected[condition_key] bp_line = 4 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.send_request('setBreakpoints', arguments={ 'source': {'path': code_to_debug}, 'breakpoints': [{'line': bp_line, condition_type: condition}], }).wait_for_response() session.start_debugging() hit = session.wait_for_thread_stopped() frames = hit.stacktrace.body['stackFrames'] assert bp_line == frames[0]['line'] resp_scopes = session.send_request('scopes', arguments={ 'frameId': hit.frame_id }).wait_for_response() scopes = resp_scopes.body['scopes'] assert len(scopes) > 0 resp_variables = session.send_request('variables', arguments={ 'variablesReference': scopes[0]['variablesReference'] }).wait_for_response() variables = list(v for v in resp_variables.body['variables'] if v['name'] == 'i') assert variables == [ ANY.dict_with({'name': 'i', 'type': 'int', 'value': value, 'evaluateName': 'i'}) ] session.send_request('continue').wait_for_response(freeze=False) for i in range(1, hits): session.wait_for_thread_stopped() session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit()
def test_add_and_remove_breakpoint(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() for i in range(0, 10): print(i) import backchannel backchannel.read_json() bp_line = 4 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, use_backchannel=True, ) session.set_breakpoints(code_to_debug, [bp_line]) session.start_debugging() hit = session.wait_for_thread_stopped() frames = hit.stacktrace.body['stackFrames'] assert bp_line == frames[0]['line'] # remove breakpoints in file session.set_breakpoints(code_to_debug, []) session.send_request('continue').wait_for_response(freeze=False) session.wait_for_next( Event('output', ANY.dict_with({ 'category': 'stdout', 'output': '9' }))) session.write_json('done') session.wait_for_exit() output = session.all_occurrences_of( Event('output', ANY.dict_with({'category': 'stdout'}))) output = sorted( int(o.body['output'].strip()) for o in output if len(o.body['output'].strip()) > 0) assert list(range(0, 10)) == output
def test_debug_this_thread(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() import platform import ptvsd import threading def foo(x): ptvsd.debug_this_thread() event.set() #@bp return 0 event = threading.Event() if platform.system() == 'Windows': from ctypes import CFUNCTYPE, c_void_p, c_size_t, c_uint32, windll thread_func_p = CFUNCTYPE(c_uint32, c_void_p) thread_func = thread_func_p( foo) # must hold a reference to wrapper during the call assert windll.kernel32.CreateThread(c_void_p(0), c_size_t(0), thread_func, c_void_p(0), c_uint32(0), c_void_p(0)) elif platform.system() == 'Linux' or platform.system() == 'Darwin': from ctypes import CDLL, CFUNCTYPE, byref, c_void_p, c_ulong from ctypes.util import find_library libpthread = CDLL(find_library('libpthread')) thread_func_p = CFUNCTYPE(c_void_p, c_void_p) thread_func = thread_func_p( foo) # must hold a reference to wrapper during the call assert not libpthread.pthread_create(byref( c_ulong(0)), c_void_p(0), thread_func, c_void_p(0)) else: assert False event.wait() line_numbers = get_marked_line_numbers(code_to_debug) with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.set_breakpoints(code_to_debug, [line_numbers['bp']]) session.start_debugging() session.wait_for_thread_stopped() session.send_request('continue').wait_for_response() session.wait_for_exit()
def test_run(pyfile, run_as, start_method): @pyfile def code_to_debug(): import os import sys import backchannel from dbgimporter import import_and_enable_debugger import_and_enable_debugger() print('begin') assert backchannel.read_json() == 'continue' backchannel.write_json(os.path.abspath(sys.modules['ptvsd'].__file__)) print('end') with DebugSession() as session: session.initialize(target=(run_as, code_to_debug), start_method=start_method, use_backchannel=True) session.start_debugging() assert session.timeline.is_frozen process_event, = session.all_occurrences_of(Event('process')) assert process_event == Event( 'process', ANY.dict_with({ 'name': ANY if run_as == 'code' else ANY.such_that(lambda name: ( # There can be a difference in file extension (.py/.pyc/.pyo) on clean runs. name == code_to_debug or name == code_to_debug + 'c' or name == code_to_debug + 'o')), })) session.write_json('continue') ptvsd_path = session.read_json() expected_ptvsd_path = os.path.abspath(ptvsd.__file__) assert (ptvsd_path == expected_ptvsd_path or ptvsd_path == expected_ptvsd_path + 'c' or ptvsd_path == expected_ptvsd_path + 'o') session.wait_for_exit()
def test_completions_cases(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() a = 1 b = {"one": 1, "two": 2} c = 3 print([a, b, c]) bp_line = 6 bp_file = code_to_debug with DebugSession() as session: session.initialize( target=(run_as, bp_file), start_method=start_method, ignore_unobserved=[Event('continued')], ) session.set_breakpoints(bp_file, [bp_line]) session.start_debugging() hit = session.wait_for_thread_stopped() response = session.send_request('completions', arguments={ 'frameId': hit.frame_id, 'text': 'b.', 'column': 3, }).wait_for_response() labels = set(target['label'] for target in response.body['targets']) assert labels.issuperset(['get', 'items', 'keys', 'setdefault', 'update', 'values']) response = session.send_request('completions', arguments={ 'frameId': hit.frame_id, 'text': 'x = b.setdefault', 'column': 13, }).wait_for_response() assert response.body['targets'] == [ {'label': 'setdefault', 'length': 6, 'start': 6, 'type': 'function'}] response = session.send_request('completions', arguments={ 'frameId': hit.frame_id, 'text': 'not_there', 'column': 10, }).wait_for_response() assert not response.body['targets'] session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit()
def test_justmycode_frames(pyfile, run_as, start_method, jmc): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() print('break here') #@bp line_numbers = get_marked_line_numbers(code_to_debug) with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], debug_options=[] if jmc == 'jmcOn' else ['DebugStdLib']) bp_line = line_numbers['bp'] actual_bps = session.set_breakpoints(code_to_debug, [bp_line]) actual_bps = [bp['line'] for bp in actual_bps] session.start_debugging() hit = session.wait_for_thread_stopped() frames = hit.stacktrace.body['stackFrames'] assert frames[0] == ANY.dict_with({ 'line': bp_line, 'source': ANY.dict_with({'path': Path(code_to_debug)}) }) if jmc == 'jmcOn': assert len(frames) == 1 session.send_request('stepIn', { 'threadId': hit.thread_id }).wait_for_response() # 'step' should terminate the debuggee else: assert len(frames) >= 1 session.send_request('stepIn', { 'threadId': hit.thread_id }).wait_for_response() # 'step' should enter stdlib hit2 = session.wait_for_thread_stopped() frames2 = hit2.stacktrace.body['stackFrames'] assert frames2[0]['source']['path'] != Path(code_to_debug) # 'continue' should terminate the debuggee session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit()
def test_stack_format(pyfile, run_as, start_method, module, line): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() from test_module import do_something do_something() @pyfile def test_module(): # import_and_enable_debugger() def do_something(): print('break here') bp_line = 3 with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('stopped'), Event('continued')], ) session.set_breakpoints(test_module, [bp_line]) session.start_debugging() hit = session.wait_for_thread_stopped() resp_stacktrace = session.send_request('stackTrace', arguments={ 'threadId': hit.thread_id, 'format': {'module': module, 'line': line}, }).wait_for_response() assert resp_stacktrace.body['totalFrames'] > 0 frames = resp_stacktrace.body['stackFrames'] assert line == (frames[0]['name'].find(': ' + str(bp_line)) > -1) assert module == (frames[0]['name'].find('test_module') > -1) session.send_request('continue').wait_for_response(freeze=False) session.wait_for_exit()
def test_run(pyfile, run_as, start_method): @pyfile def code_to_debug(): import os import sys import backchannel from dbgimporter import import_and_enable_debugger import_and_enable_debugger() print('begin') assert backchannel.read_json() == 'continue' backchannel.write_json(os.path.abspath(sys.modules['ptvsd'].__file__)) print('end') with DebugSession() as session: session.initialize(target=(run_as, code_to_debug), start_method=start_method, use_backchannel=True) session.start_debugging() assert session.timeline.is_frozen process_event, = session.all_occurrences_of(Event('process')) assert process_event == Event( 'process', ANY.dict_with({ 'name': '-c' if run_as == 'code' else Regex(re.escape(code_to_debug) + r'(c|o)?$') })) session.write_json('continue') ptvsd_path = session.read_json() expected_ptvsd_path = os.path.abspath(ptvsd.__file__) assert re.match( re.escape(expected_ptvsd_path) + r'(c|o)?$', ptvsd_path) session.wait_for_exit()
def test_exceptions_and_exclude_rules(pyfile, run_as, start_method, scenario, exception_type): if exception_type == 'RuntimeError': @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() raise RuntimeError('unhandled error') # @raise_line elif exception_type == 'SysExit': @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import sys import_and_enable_debugger() sys.exit(1) # @raise_line else: raise AssertionError('Unexpected exception_type: %s' % (exception_type,)) if scenario == 'exclude_by_name': rules = [{'path': '**/' + os.path.basename(code_to_debug), 'include': False}] elif scenario == 'exclude_by_dir': rules = [{'path': os.path.dirname(code_to_debug), 'include': False}] else: raise AssertionError('Unexpected scenario: %s' % (scenario,)) with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], rules=rules, ) # TODO: The process returncode doesn't match the one returned from the DAP. # See: https://github.com/Microsoft/ptvsd/issues/1278 session.expected_returncode = ANY.int filters = ['raised', 'uncaught'] session.send_request('setExceptionBreakpoints', { 'filters': filters }).wait_for_response() session.start_debugging() # No exceptions should be seen. session.wait_for_exit()
def test_deep_stacks(pyfile, run_as, start_method): @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger import_and_enable_debugger() def deep_stack(level): if level <= 0: print('done') #@bp return level deep_stack(level - 1) deep_stack(100) line_numbers = get_marked_line_numbers(code_to_debug) with DebugSession() as session: session.initialize( target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], ) bp_line = line_numbers['bp'] actual_bps = session.set_breakpoints(code_to_debug, [bp_line]) actual_bps = [bp['line'] for bp in actual_bps] session.start_debugging() hit = session.wait_for_thread_stopped() full_frames = hit.stacktrace.body['stackFrames'] assert len(full_frames) > 100 # Construct stack from parts frames = [] start = 0 for _ in range(5): resp_stacktrace = session.send_request('stackTrace', arguments={ 'threadId': hit.thread_id, 'startFrame': start, 'levels': 25 }).wait_for_response() assert resp_stacktrace.body['totalFrames'] > 0 frames += resp_stacktrace.body['stackFrames'] start = len(frames) assert full_frames == frames session.send_request('continue').wait_for_response() session.wait_for_exit()