Пример #1
0
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)  # @break

        for i in range(100):
            do_something(i)

    bp_line = get_marked_line_numbers(code_to_debug)['break']
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )
        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()
Пример #2
0
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,
        )

        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')
Пример #3
0
def test_ptvsd_systeminfo(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        a = 'hello'  # @bp1
        print(a)

    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,
        )

        session.set_breakpoints(code_to_debug, [line_numbers['bp1']])
        session.start_debugging()

        session.wait_for_thread_stopped()

        resp = session.send_request('ptvsd_systemInfo').wait_for_response()
        expected = _generate_system_info()
        assert resp.body == expected

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
Пример #4
0
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)
Пример #5
0
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()
Пример #6
0
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()
Пример #7
0
def test_crossfile_breakpoint(pyfile, run_as, start_method):
    @pyfile
    def script1():
        from dbgimporter import import_and_enable_debugger  # noqa

        def do_something():
            print('do something')  # @bp

    @pyfile
    def script2():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        import script1
        script1.do_something()  # @bp
        print('Done')

    bp_script1_line = get_marked_line_numbers(script1)['bp']
    bp_script2_line = get_marked_line_numbers(script2)['bp']
    with DebugSession() as session:
        session.initialize(
            target=(run_as, script2),
            start_method=start_method,
        )
        session.set_breakpoints(script1, lines=[bp_script1_line])
        session.set_breakpoints(script2, lines=[bp_script2_line])
        session.start_debugging()

        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert bp_script2_line == frames[0]['line']
        assert frames[0]['source']['path'] == Path(script2)

        session.send_request('continue').wait_for_response(freeze=False)
        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert bp_script1_line == frames[0]['line']
        assert frames[0]['source']['path'] == Path(script1)

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
Пример #8
0
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()
Пример #9
0
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,
        )

        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()
Пример #10
0
def test_error_in_condition(pyfile, run_as, start_method, error_name):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        def do_something_bad():
            raise ArithmeticError()

        for i in range(1, 10):  # @bp
            pass

    # NOTE: NameError in condition, is a special case. Pydevd is configured to skip
    # traceback for name errors. See https://github.com/Microsoft/ptvsd/issues/853
    # for more details. For all other errors we should be printing traceback.
    condition = {
        'NameError': ('x==5'),  # 'x' does not exist in the debuggee
        'OtherError': ('do_something_bad()==5')  # throws some error
    }

    bp_line = get_marked_line_numbers(code_to_debug)['bp']
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )
        session.send_request('setBreakpoints',
                             arguments={
                                 'source': {
                                     'path': code_to_debug
                                 },
                                 'breakpoints': [{
                                     'line':
                                     bp_line,
                                     'condition':
                                     condition[error_name],
                                 }],
                             }).wait_for_response()
        session.start_debugging()

        session.wait_for_exit()
        assert session.get_stdout_as_string() == b''
        if error_name == 'NameError':
            assert session.get_stderr_as_string().find(b'NameError') == -1
        else:
            assert session.get_stderr_as_string().find(b'ArithmeticError') > 0
Пример #11
0
def test_stop_on_entry(pyfile, run_as, start_method, with_bp):

    @pyfile
    def code_to_debug():
        import backchannel # @bp
        # 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'],
            use_backchannel=True,
        )
        if bool(with_bp):
            line_numbers = get_marked_line_numbers(code_to_debug)
            bp_line = line_numbers['bp']
            session.set_breakpoints(code_to_debug, [bp_line])

        session.start_debugging()

        if bool(with_bp):
            thread_stopped, resp_stacktrace, thread_id, _ = session.wait_for_thread_stopped(reason='breakpoint')
            frames = resp_stacktrace.body['stackFrames']
            assert frames[0]['line'] == 1
            assert frames[0]['source']['path'] == Path(code_to_debug)

            session.send_request('next', {'threadId': thread_id}).wait_for_response()
            thread_stopped, resp_stacktrace, thread_id, _ = session.wait_for_thread_stopped(reason='step')
            frames = resp_stacktrace.body['stackFrames']
            assert frames[0]['line'] == 3
            assert frames[0]['source']['path'] == Path(code_to_debug)
        else:
            thread_stopped, resp_stacktrace, tid, _ = session.wait_for_thread_stopped(reason='entry')
            frames = resp_stacktrace.body['stackFrames']
            assert frames[0]['line'] == 1
            assert frames[0]['source']['path'] == Path(code_to_debug)

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_termination()

        assert session.read_json() == 'done'

        session.wait_for_exit()
Пример #12
0
def test_reattach(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        import time
        import ptvsd
        import backchannel
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        ptvsd.break_into_debugger()
        print('first')  # @break1
        backchannel.write_json('continued')
        for _ in range(0, 100):
            time.sleep(0.1)
            ptvsd.break_into_debugger()
            print('second')  # @break2

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            use_backchannel=True,
            kill_ptvsd=False,
            skip_capture=True,
        )

        marked_line_numbers = get_marked_line_numbers(code_to_debug)

        session.start_debugging()
        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert marked_line_numbers['break1'] == frames[0]['line']
        session.send_request('disconnect').wait_for_response(freeze=False)
        session.wait_for_disconnect()
        assert session.read_json() == 'continued'

    # re-attach
    with session.connect_with_new_session(
            target=(run_as, code_to_debug), ) as session2:
        session2.start_debugging()
        hit = session2.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert marked_line_numbers['break2'] == frames[0]['line']
        session2.send_request('disconnect').wait_for_response(freeze=False)
        session2.wait_for_disconnect()
Пример #13
0
def test_client_ide_from_path_mapping_linux_backend(pyfile, tmpdir, run_as,
                                                    start_method,
                                                    invalid_os_type):
    '''
    Test simulating that the backend is on Linux and the client is on Windows
    (automatically detect it from the path mapping).
    '''
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        import backchannel
        import pydevd_file_utils
        backchannel.write_json({'ide_os': pydevd_file_utils._ide_os})
        print('done')  # @break_here

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
            use_backchannel=True,
            path_mappings=[{
                'localRoot': 'C:\\TEMP\\src',
                'remoteRoot': os.path.dirname(code_to_debug),
            }],
        )
        if invalid_os_type:
            session.debug_options.append('CLIENT_OS_TYPE=INVALID')
        bp_line = get_marked_line_numbers(code_to_debug)['break_here']
        session.set_breakpoints(
            'c:\\temp\\src\\' + os.path.basename(code_to_debug), [bp_line])
        session.start_debugging()
        hit = session.wait_for_thread_stopped('breakpoint')
        frames = hit.stacktrace.body['stackFrames']
        assert frames[0]['source'][
            'path'] == 'C:\\TEMP\\src\\' + os.path.basename(code_to_debug)

        json_read = session.read_json()
        assert json_read == {'ide_os': 'WINDOWS'}

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
Пример #14
0
def test_thread_count(pyfile, run_as, start_method, count):
    @pyfile
    def code_to_debug():
        import threading
        import time
        import sys
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        stop = False

        def worker(tid, offset):
            i = 0
            global stop
            while not stop:
                time.sleep(0.01)
                i += 1

        threads = []
        if sys.argv[1] != '1':
            for i in [111, 222]:
                thread = threading.Thread(target=worker,
                                          args=(i, len(threads)))
                threads.append(thread)
                thread.start()
        print('check here')  # @bp
        stop = True

    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,
            program_args=[str(count)],
        )
        session.set_breakpoints(code_to_debug, [line_numbers['bp']])
        session.start_debugging()
        session.wait_for_thread_stopped()
        resp_threads = session.send_request('threads').wait_for_response()

        assert len(resp_threads.body['threads']) == count

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
Пример #15
0
def test_exceptions_and_partial_exclude_rules(pyfile, run_as, start_method,
                                              scenario):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        import backchannel
        import sys
        json = backchannel.read_json()
        call_me_back_dir = json['call_me_back_dir']
        sys.path.append(call_me_back_dir)

        import call_me_back

        def call_func():
            raise RuntimeError('unhandled error')  # @raise_line

        call_me_back.call_me_back(call_func)  # @call_me_back_line
        print('done')

    line_numbers = get_marked_line_numbers(code_to_debug)
    call_me_back_dir = get_test_root('call_me_back')

    if scenario == 'exclude_code_to_debug':
        rules = [{
            'path': '**/' + os.path.basename(code_to_debug),
            'include': False
        }]
    elif scenario == 'exclude_callback_dir':
        rules = [{'path': call_me_back_dir, '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,
            use_backchannel=True,
            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()

        if scenario == 'exclude_code_to_debug':
            breakpoints = session.set_breakpoints(code_to_debug, [1])
            assert breakpoints == [{
                'verified':
                False,
                'message':
                ('Breakpoint in file excluded by filters.\n'
                 'Note: may be excluded because of "justMyCode" option (default == true).'
                 ),
                'source':
                ANY.dict_with({'path': Path(code_to_debug)}),
                'line':
                1
            }]

        session.start_debugging()
        session.write_json({'call_me_back_dir': call_me_back_dir})

        if scenario == 'exclude_code_to_debug':
            # Stop at handled
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            # We don't stop at the raise line but rather at the callback module which is
            # not excluded.
            assert len(frames) == 1
            assert frames[0] == ANY.dict_with({
                'line':
                2,
                'source':
                ANY.dict_with({
                    'path':
                    Path(os.path.join(call_me_back_dir, 'call_me_back.py'))
                })
            })
            # assert frames[1] == ANY.dict_with({ -- filtered out
            #     'line': line_numbers['call_me_back_line'],
            #     'source': ANY.dict_with({
            #         'path': Path(code_to_debug)
            #     })
            # })
            # 'continue' should terminate the debuggee
            session.send_request('continue').wait_for_response(freeze=False)

            # Note: does not stop at unhandled exception because raise was in excluded file.

        elif scenario == 'exclude_callback_dir':
            # Stop at handled raise_line
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert [(frame['name'], basename(frame['source']['path']))
                    for frame in frames] == [
                        ('call_func', 'code_to_debug.py'),
                        # ('call_me_back', 'call_me_back.py'), -- filtered out
                        ('<module>', 'code_to_debug.py'),
                    ]
            assert frames[0] == ANY.dict_with({
                'line':
                line_numbers['raise_line'],
                'source':
                ANY.dict_with({'path': Path(code_to_debug)})
            })
            session.send_request('continue').wait_for_response()

            # Stop at handled call_me_back_line
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert [(frame['name'], basename(frame['source']['path']))
                    for frame in frames] == [
                        ('<module>', 'code_to_debug.py'),
                    ]
            assert frames[0] == ANY.dict_with({
                'line':
                line_numbers['call_me_back_line'],
                'source':
                ANY.dict_with({'path': Path(code_to_debug)})
            })
            session.send_request('continue').wait_for_response()

            # Stop at unhandled
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert [(frame['name'], basename(frame['source']['path']))
                    for frame in frames] == [
                        ('call_func', 'code_to_debug.py'),
                        # ('call_me_back', 'call_me_back.py'), -- filtered out
                        ('<module>', 'code_to_debug.py'),
                    ]

            assert frames[0] == ANY.dict_with({
                'line':
                line_numbers['raise_line'],
                'source':
                ANY.dict_with({'path': Path(code_to_debug)})
            })
            session.send_request('continue').wait_for_response(freeze=False)
        else:
            raise AssertionError('Unexpected scenario: %s' % (scenario, ))

        session.wait_for_exit()
Пример #16
0
def test_step_multi_threads(pyfile, run_as, start_method, stepping_resumes_all_threads):

    @pyfile
    def code_to_debug():
        '''
        After breaking on the thread 1, thread 2 should pause waiting for the event1 to be set,
        so, when we step return on thread 1, the program should finish if all threads are resumed
        or should keep waiting for the thread 2 to run if only thread 1 is resumed.
        '''
        import threading
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        event0 = threading.Event()
        event1 = threading.Event()
        event2 = threading.Event()
        event3 = threading.Event()

        def _thread1():
            while not event0.is_set():
                event0.wait(timeout=.001)

            event1.set()  # @break_thread_1

            while not event2.is_set():
                event2.wait(timeout=.001)
            # Note: we can only get here if thread 2 is also released.

            event3.set()

        def _thread2():
            event0.set()

            while not event1.is_set():
                event1.wait(timeout=.001)

            event2.set()

            while not event3.is_set():
                event3.wait(timeout=.001)

        threads = [
            threading.Thread(target=_thread1, name='thread1'),
            threading.Thread(target=_thread2, name='thread2'),
        ]
        for t in threads:
            t.start()

        for t in threads:
            t.join()

    line_numbers = get_marked_line_numbers(code_to_debug)
    with DebugSession() as session:
        session.stepping_resumes_all_threads = stepping_resumes_all_threads
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )
        session.set_breakpoints(code_to_debug, [line_numbers['break_thread_1']])
        session.start_debugging()
        _thread_stopped, _resp_stacktrace, thread_id, _ = session.wait_for_thread_stopped()
        resp_threads = session.send_request('threads').wait_for_response()
        assert len(resp_threads.body['threads']) == 3
        thread_name_to_id = dict((t['name'], t['id']) for t in resp_threads.body['threads'])
        assert thread_id == thread_name_to_id['thread1']

        if stepping_resumes_all_threads or stepping_resumes_all_threads is None:
            # stepping_resumes_all_threads == None means we should use default (which is to
            # resume all threads) -- in which case stepping out will exit the program.
            session.send_request('stepOut', {'threadId': thread_id}).wait_for_response(freeze=False)

        else:
            session.send_request('stepOut', {'threadId': thread_id}).wait_for_response()
            # Wait a second and check that threads are still there.
            time.sleep(1)

            resp_stacktrace = session.send_request('stackTrace', arguments={
                'threadId': thread_name_to_id['thread1'],
            }).wait_for_response()
            assert '_thread1' in [x['name'] for x in resp_stacktrace.body['stackFrames']]

            resp_stacktrace = session.send_request('stackTrace', arguments={
                'threadId': thread_name_to_id['thread2'],
            }).wait_for_response()
            assert '_thread2' in [x['name'] for x in resp_stacktrace.body['stackFrames']]

            session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
Пример #17
0
def test_with_path_mappings(pyfile, tmpdir, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        def full_function():
            # Note that this function is not called, it's there just to make the mapping explicit.
            print('cell1 line 2')  # @map_to_cell1_line_2
            print('cell1 line 3')  # @map_to_cell1_line_3

            print('cell2 line 2')  # @map_to_cell2_line_2
            print('cell2 line 3')  # @map_to_cell2_line_3

        def strip_lines(s):
            return '\n'.join([line.strip() for line in s.splitlines()])

        def create_code():
            cell1_code = compile(
                strip_lines(''' # line 1
            a = 1  # line 2
            b = 2  # line 3
            '''), '<cell1>', 'exec')

            cell2_code = compile(
                strip_lines('''# line 1
            c = 3  # line 2
            d = 4  # line 3
            '''), '<cell2>', 'exec')

            return {'cell1': cell1_code, 'cell2': cell2_code}

        code = create_code()
        exec(code['cell1'], {})
        exec(code['cell1'], {})

        exec(code['cell2'], {})
        exec(code['cell2'], {})
        print('ok')

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )

        marked_line_numbers = get_marked_line_numbers(code_to_debug)
        map_to_cell_1_line2 = marked_line_numbers['map_to_cell1_line_2']
        map_to_cell_2_line2 = marked_line_numbers['map_to_cell2_line_2']

        source_entry = code_to_debug
        if sys.platform == 'win32':
            # Check if it matches even not normalized.
            source_entry = code_to_debug[0].lower() + code_to_debug[1:].upper()
            source_entry = source_entry.replace('\\', '/')

        # Set breakpoints first and the map afterwards to make sure that it's reapplied.
        session.set_breakpoints(code_to_debug, [map_to_cell_1_line2])

        session.send_request('setPydevdSourceMap',
                             arguments={
                                 'source': {
                                     'path': source_entry
                                 },
                                 'pydevdSourceMaps': [
                                     {
                                         'line': map_to_cell_1_line2,
                                         'endLine': map_to_cell_1_line2 + 1,
                                         'runtimeSource': {
                                             'path': '<cell1>'
                                         },
                                         'runtimeLine': 2,
                                     },
                                     {
                                         'line': map_to_cell_2_line2,
                                         'endLine': map_to_cell_2_line2 + 1,
                                         'runtimeSource': {
                                             'path': '<cell2>'
                                         },
                                         'runtimeLine': 2,
                                     },
                                 ],
                             }).wait_for_response()

        session.start_debugging()
        hit = session.wait_for_thread_stopped('breakpoint')

        frames = hit.stacktrace.body['stackFrames']
        assert frames[0]['source']['path'] == Path(code_to_debug)

        session.set_breakpoints(code_to_debug, [map_to_cell_2_line2])
        # Leave only the cell2 mapping.
        session.send_request('setPydevdSourceMap',
                             arguments={
                                 'source': {
                                     'path': source_entry
                                 },
                                 'pydevdSourceMaps': [
                                     {
                                         'line': map_to_cell_2_line2,
                                         'endLine': map_to_cell_2_line2 + 1,
                                         'runtimeSource': {
                                             'path': '<cell2>'
                                         },
                                         'runtimeLine': 2,
                                     },
                                 ],
                             }).wait_for_response()

        session.send_request('continue').wait_for_response()

        hit = session.wait_for_thread_stopped('breakpoint')

        # Remove the cell2 mapping so that it doesn't stop again.
        session.send_request('setPydevdSourceMap',
                             arguments={
                                 'source': {
                                     'path': source_entry
                                 },
                                 'pydevdSourceMaps': [
                                     {
                                         'line': map_to_cell_1_line2,
                                         'endLine': map_to_cell_1_line2 + 1,
                                         'runtimeSource': {
                                             'path': '<cell1>'
                                         },
                                         'runtimeLine': 2,
                                     },
                                 ],
                             }).wait_for_response()

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
Пример #18
0
def test_invalid_breakpoints(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        b = True
        while b:        #@bp1-expected
            pass        #@bp1-requested
            break

        print()         #@bp2-expected
        [               #@bp2-requested
            1, 2, 3,    #@bp3-expected
        ]               #@bp3-requested

        # Python 2.7 only.
        print()         #@bp4-expected
        print(1,        #@bp4-requested-1
              2, 3,     #@bp4-requested-2
              4, 5, 6)

    line_numbers = get_marked_line_numbers(code_to_debug)
    from tests.helpers import print
    print(line_numbers)

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
        )

        requested_bps = [
            line_numbers['bp1-requested'],
            line_numbers['bp2-requested'],
            line_numbers['bp3-requested'],
        ]
        if sys.version_info < (3,):
            requested_bps += [
                line_numbers['bp4-requested-1'],
                line_numbers['bp4-requested-2'],
            ]

        actual_bps = session.set_breakpoints(code_to_debug, requested_bps)
        actual_bps = [bp['line'] for bp in actual_bps]

        expected_bps = [
            line_numbers['bp1-expected'],
            line_numbers['bp2-expected'],
            line_numbers['bp3-expected'],
        ]
        if sys.version_info < (3,):
            expected_bps += [
                line_numbers['bp4-expected'],
                line_numbers['bp4-expected'],
            ]

        assert expected_bps == actual_bps

        # Now let's make sure that we hit all of the expected breakpoints,
        # and stop where we expect them to be.

        session.start_debugging()

        # If there's multiple breakpoints on the same line, we only stop once,
        # so remove duplicates first.
        expected_bps = sorted(set(expected_bps))

        while expected_bps:
            hit = session.wait_for_thread_stopped()
            frames = hit.stacktrace.body['stackFrames']
            line = frames[0]['line']
            assert line == expected_bps[0]
            del expected_bps[0]
            session.send_request('continue').wait_for_response()
        assert not expected_bps

        session.wait_for_exit()
Пример #19
0
def test_vsc_exception_options_raise_without_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_without_except():
            raise ArithmeticError('bad code')  # @exception_line

        raise_without_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'),
                               Event('stopped')],
            expected_returncode=ANY.int,
        )
        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)

            # NOTE: debugger stops at each frame if raised and is uncaught
            # This behavior can be changed by updating 'notify_on_handled_exceptions'
            # setting we send to pydevd to notify only once. In our test code, we have
            # two frames, hence two stops.
            session.wait_for_thread_stopped(reason='exception')
            session.send_request('continue').wait_for_response(freeze=False)

        if uncaught == 'uncaughtOn':
            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()

            expected = ANY.dict_with({
                'exceptionId':
                ANY.such_that(lambda s: s.endswith('ArithmeticError')),
                'description':
                'bad code',
                'breakMode':
                'unhandled',  # Only difference from previous expected is breakMode.
                'details':
                ANY.dict_with({
                    'typeName':
                    ANY.such_that(lambda s: s.endswith('ArithmeticError')),
                    'message':
                    'bad code',
                    'source':
                    Path(code_to_debug),
                }),
            })

            assert resp_exc_info.body == expected
            session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
Пример #20
0
def test_exception_stack(pyfile, run_as, start_method, max_frames):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        def do_something(n):
            if n <= 0:
                raise ArithmeticError('bad code')  # @unhandled
            do_something2(n - 1)

        def do_something2(n):
            do_something(n - 1)

        do_something(100)

    if max_frames == 'all':
        # trace back compresses repeated text
        min_expected_lines = 100
        max_expected_lines = 220
        args = {'maxExceptionStackFrames': 0}
    elif max_frames == 'default':
        # default is all frames
        min_expected_lines = 100
        max_expected_lines = 220
        args = {}
    else:
        min_expected_lines = 10
        max_expected_lines = 21
        args = {'maxExceptionStackFrames': 10}

    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')],
            expected_returncode=ANY.int,
            args=args,
        )
        session.send_request('setExceptionBreakpoints', {
            'filters': ['uncaught']
        }).wait_for_response()
        session.start_debugging()

        hit = session.wait_for_thread_stopped(reason='exception')
        frames = hit.stacktrace.body['stackFrames']
        assert frames[0]['line'] == line_numbers['unhandled']

        resp_exc_info = session.send_request('exceptionInfo', {
            'threadId': hit.thread_id
        }).wait_for_response()

        expected = ANY.dict_with({
            'exceptionId':
            Regex('ArithmeticError'),
            'description':
            'bad code',
            'breakMode':
            'unhandled',
            'details':
            ANY.dict_with({
                'typeName': Regex('ArithmeticError'),
                'message': 'bad code',
                'source': Path(code_to_debug),
            }),
        })
        assert resp_exc_info.body == expected
        stack_str = resp_exc_info.body['details']['stackTrace']
        stack_line_count = len(stack_str.split('\n'))
        assert min_expected_lines <= stack_line_count <= max_expected_lines

        session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
Пример #21
0
def test_hex_numbers(pyfile, run_as, start_method):

    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        a = 100
        b = [1, 10, 100]
        c = {10: 10, 100: 100, 1000: 1000}
        d = {(1, 10, 100): (10000, 100000, 100000)}
        print((a, b, c, d))  # @bp

    line_numbers = get_marked_line_numbers(code_to_debug)
    print(line_numbers)

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )
        session.set_breakpoints(code_to_debug, [line_numbers['bp']])
        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'],
            'format': {'hex': True}
        }).wait_for_response()
        variables = list(v for v in resp_variables.body['variables']
                         if v['name'] in ('a', 'b', 'c', 'd'))
        a, b, c, d = sorted(variables, key=lambda v: v['name'])
        assert a == ANY.dict_with({
            'name': 'a',
            'value': "0x64",
            'type': 'int',
            'evaluateName': 'a',
            'variablesReference': 0,
        })

        assert b == ANY.dict_with({
            'name': 'b',
            'value': "[0x1, 0xa, 0x64]",
            'type': 'list',
            'evaluateName': 'b',
            'variablesReference': ANY.dap_id,
        })

        resp_variables = session.send_request('variables', arguments={
            'variablesReference': b['variablesReference'],
            'format': {'hex': True}
        }).wait_for_response()
        b_children = resp_variables.body['variables']
        assert b_children == [
            {'name': '0x0', 'value': '0x1', 'type': 'int', 'evaluateName': 'b[0]', 'variablesReference': 0, },
            {'name': '0x1', 'value': '0xa', 'type': 'int', 'evaluateName': 'b[1]', 'variablesReference': 0, },
            {'name': '0x2', 'value': '0x64', 'type': 'int', 'evaluateName': 'b[2]', 'variablesReference': 0, },
            {'name': '__len__', 'value': '0x3', 'type': 'int', 'evaluateName': 'len(b)', 'variablesReference': 0, 'presentationHint': {'attributes': ['readOnly']}, },
        ]

        assert c == ANY.dict_with({
            'name': 'c',
            'value': '{0xa: 0xa, 0x64: 0x64, 0x3e8: 0x3e8}',
            'type': 'dict',
            'evaluateName': 'c',
            'variablesReference': ANY.dap_id,
        })

        resp_variables = session.send_request('variables', arguments={
            'variablesReference': c['variablesReference'],
            'format': {'hex': True}
        }).wait_for_response()
        c_children = resp_variables.body['variables']
        assert c_children == [
            {'name': '0x3e8', 'value': '0x3e8', 'type': 'int', 'evaluateName': 'c[1000]', 'variablesReference': 0, },
            {'name': '0x64', 'value': '0x64', 'type': 'int', 'evaluateName': 'c[100]', 'variablesReference': 0, },
            {'name': '0xa', 'value': '0xa', 'type': 'int', 'evaluateName': 'c[10]', 'variablesReference': 0, },
            {'name': '__len__', 'value': '0x3', 'type': 'int', 'evaluateName': 'len(c)', 'variablesReference': 0, 'presentationHint': {'attributes': ['readOnly']}, }
        ]

        assert d == ANY.dict_with({
            'name': 'd',
            'value': '{(0x1, 0xa, 0x64): (0x2710, 0x186a0, 0x186a0)}',
            'type': 'dict',
            'evaluateName': 'd',
            'variablesReference': ANY.dap_id,
        })
        resp_variables = session.send_request('variables', arguments={
            'variablesReference': d['variablesReference'],
            'format': {'hex': True}
        }).wait_for_response()
        d_children = resp_variables.body['variables']
        assert d_children == [
            {'name': '(0x1, 0xa, 0x64)', 'value': '(0x2710, 0x186a0, 0x186a0)', 'type': 'tuple', 'evaluateName': 'd[(1, 10, 100)]', 'variablesReference': ANY.dap_id},
            {'name': '__len__', 'value': '0x1', 'type': 'int', 'evaluateName': 'len(d)', 'variablesReference': 0, 'presentationHint': {'attributes': ['readOnly']}, }
        ]

        resp_variables = session.send_request('variables', arguments={
            'variablesReference': d_children[0]['variablesReference'],
            'format': {'hex': True}
        }).wait_for_response()
        d_child_of_child = resp_variables.body['variables']
        assert d_child_of_child == [
            {'name': '0x0', 'value': '0x2710', 'type': 'int', 'evaluateName': 'd[(1, 10, 100)][0]', 'variablesReference': 0, },
            {'name': '0x1', 'value': '0x186a0', 'type': 'int', 'evaluateName': 'd[(1, 10, 100)][1]', 'variablesReference': 0, },
            {'name': '0x2', 'value': '0x186a0', 'type': 'int', 'evaluateName': 'd[(1, 10, 100)][2]', 'variablesReference': 0, },
            {'name': '__len__', 'value': '0x3', 'type': 'int', 'evaluateName': 'len(d[(1, 10, 100)])', 'variablesReference': 0, 'presentationHint': {'attributes': ['readOnly']}, }
        ]

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
Пример #22
0
def test_systemexit(pyfile, run_as, start_method, raised, uncaught, zero,
                    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, ))
        try:
            sys.exit(exit_code)  # @handled
        except SystemExit:
            pass
        sys.exit(exit_code)  # @unhandled

    line_numbers = get_marked_line_numbers(code_to_debug)

    filters = []
    if raised:
        filters += ['raised']
    if uncaught:
        filters += ['uncaught']

    with DebugSession() as session:
        session.program_args = [repr(exit_code)]
        if zero:
            session.debug_options += ['BreakOnSystemExitZero']
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
            expected_returncode=ANY.int,
        )
        session.send_request('setExceptionBreakpoints', {
            'filters': filters
        }).wait_for_response()
        session.start_debugging()

        # When breaking on raised exceptions, we'll stop on both lines,
        # unless it's SystemExit(0) and we asked to ignore that.
        if raised and (zero or exit_code != 0):
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert frames[0]['line'] == line_numbers['handled']
            session.send_request('continue').wait_for_response(freeze=False)

            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert frames[0]['line'] == line_numbers['unhandled']
            session.send_request('continue').wait_for_response(freeze=False)

        # When breaking on uncaught exceptions, we'll stop on the second line,
        # unless it's SystemExit(0) and we asked to ignore that.
        # Note that if both raised and uncaught filters are set, there will be
        # two stop for the second line - one for exception being raised, and one
        # for it unwinding the stack without finding a handler. The block above
        # takes care of the first stop, so here we just take care of the second.
        if uncaught and (zero or exit_code != 0):
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert frames[0]['line'] == line_numbers['unhandled']
            session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
Пример #23
0
def test_tracing(pyfile, start_method, run_as):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        import ptvsd

        def func(expected_tracing):
            assert ptvsd.tracing() == expected_tracing, (
                "inside func({0!r})".format(expected_tracing)
            )
            print(1)  # @inner1

            # Test nested change/restore. Going from False to True only works entirely
            # correctly on Python 3.6+; on earlier versions, if tracing wasn't enabled
            # when the function is entered, re-enabling it later will not cause the
            # breakpoints in this function to light up. However, it will allow hitting
            # breakpoints in functions called from here.

            def inner2():
                print(2)  # @inner2

            with ptvsd.tracing(not expected_tracing):
                assert ptvsd.tracing() != expected_tracing, "inside with-statement"
                inner2()
            assert ptvsd.tracing() == expected_tracing, "after with-statement"

            print(3)  # @inner3

        assert ptvsd.tracing(), "before tracing(False)"
        ptvsd.tracing(False)
        assert not ptvsd.tracing(), "after tracing(False)"

        print(0)  # @outer1
        func(False)

        ptvsd.tracing(True)
        assert ptvsd.tracing(), "after tracing(True)"

        print(0)  # @outer2
        func(True)

    line_numbers = get_marked_line_numbers(code_to_debug)
    print(line_numbers)

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
            env={'PTVSD_USE_CONTINUED': '1'},
        )

        session.set_breakpoints(code_to_debug, line_numbers.values())
        session.start_debugging()

        stop = session.wait_for_thread_stopped()
        frame = stop.stacktrace.body['stackFrames'][0]
        assert frame == ANY.dict_with({
            "line": line_numbers["inner2"],
        })

        session.send_request('continue').wait_for_response()

        stop = session.wait_for_thread_stopped()
        frame = stop.stacktrace.body['stackFrames'][0]
        assert frame == ANY.dict_with({
            "line": line_numbers["outer2"],
        })

        session.send_request('continue').wait_for_response()

        stop = session.wait_for_thread_stopped()
        frame = stop.stacktrace.body['stackFrames'][0]
        assert frame == ANY.dict_with({
            "line": line_numbers["inner1"],
        })

        session.send_request('continue').wait_for_response()

        stop = session.wait_for_thread_stopped()
        frame = stop.stacktrace.body['stackFrames'][0]
        assert frame == ANY.dict_with({
            "line": line_numbers["inner3"],
        })

        session.send_request('continue').wait_for_response()
        session.wait_for_exit()
Пример #24
0
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])  # @break

    line_numbers = get_marked_line_numbers(code_to_debug)
    bp_line = line_numbers['break']
    bp_file = code_to_debug

    with DebugSession() as session:
        session.initialize(
            target=(run_as, bp_file),
            start_method=start_method,
        )
        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']

        # Check errors
        with pytest.raises(RequestFailure) as request_failure:
            response = session.send_request(
                'completions',
                arguments={
                    'frameId': 9999999,  # frameId not available.
                    'text': 'not_there',
                    'column': 10,
                }).wait_for_response()
        assert 'Wrong ID sent from the client:' in request_failure.value.message

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
Пример #25
0
def test_set_next_statement(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        def func():
            print(1)  # @inner1
            print(2)  # @inner2

        print(3)  # @outer3
        func()

    line_numbers = get_marked_line_numbers(code_to_debug)
    print(line_numbers)

    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['inner1']])
        session.start_debugging()

        stop = session.wait_for_thread_stopped()
        frames = stop.stacktrace.body['stackFrames']
        line = frames[0]['line']
        assert line == line_numbers['inner1']

        targets = session.send_request('gotoTargets', {
            'source': {
                'path': code_to_debug
            },
            'line': line_numbers['outer3'],
        }).wait_for_response().body['targets']

        assert targets == [{
            'id': ANY.num,
            'label': ANY.str,
            'line': line_numbers['outer3']
        }]
        outer3_target = targets[0]['id']

        with pytest.raises(Exception):
            session.send_request('goto', {
                'threadId': stop.thread_id,
                'targetId': outer3_target,
            }).wait_for_response()

        targets = session.send_request('gotoTargets', {
            'source': {
                'path': code_to_debug
            },
            'line': line_numbers['inner2'],
        }).wait_for_response().body['targets']

        assert targets == [{
            'id': ANY.num,
            'label': ANY.str,
            'line': line_numbers['inner2'],
        }]
        inner2_target = targets[0]['id']

        session.send_request('goto', {
            'threadId': stop.thread_id,
            'targetId': inner2_target,
        }).wait_for_response()

        session.wait_for_next(Event('continued'))

        stop = session.wait_for_thread_stopped(reason='goto')
        frames = stop.stacktrace.body['stackFrames']
        line = frames[0]['line']
        assert line == line_numbers['inner2']

        session.send_request('continue').wait_for_response()
        session.wait_for_exit()
Пример #26
0
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  # @in_do_something

        def someFunction(someVar):
            someVariable = someVar
            return SomeClass(someVariable).do_someting()  # @in_some_function

        someFunction('value')
        print('done')  # @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')],
        )

        line_numbers = get_marked_line_numbers(code_to_debug)
        session.set_breakpoints(code_to_debug, [line_numbers[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()
Пример #27
0
def test_raise_exception_options(pyfile, run_as, start_method, exceptions,
                                 break_mode):

    if break_mode in ('never', 'unhandled', 'userUnhandled'):

        @pyfile
        def code_to_debug():
            from dbgimporter import import_and_enable_debugger
            import_and_enable_debugger()
            raise AssertionError()  # @AssertionError

        if break_mode == 'never':
            expect_exceptions = []

        elif 'AssertionError' in exceptions or not exceptions:
            # Only AssertionError is raised in this use-case.
            expect_exceptions = ['AssertionError']

        else:
            expect_exceptions = []

    else:
        expect_exceptions = exceptions[:]
        if not expect_exceptions:
            # Deal with the Python Exceptions category
            expect_exceptions = [
                'RuntimeError', 'AssertionError', 'IndexError'
            ]

        @pyfile
        def code_to_debug():
            from dbgimporter import import_and_enable_debugger
            import_and_enable_debugger()
            try:
                raise RuntimeError()  # @RuntimeError
            except RuntimeError:
                pass
            try:
                raise AssertionError()  # @AssertionError
            except AssertionError:
                pass
            try:
                raise IndexError()  # @IndexError
            except IndexError:
                pass

    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'),
                               Event('stopped')],
            expected_returncode=ANY.int,
        )
        path = [
            {
                'names': ['Python Exceptions']
            },
        ]
        if exceptions:
            path.append({'names': exceptions})
        session.send_request(
            'setExceptionBreakpoints',
            {
                'filters': [],  # Unused when exceptionOptions is passed.
                'exceptionOptions': [{
                    'path': path,
                    'breakMode':
                    break_mode,  # Can be "never", "always", "unhandled", "userUnhandled"
                }],
            }).wait_for_response()
        session.start_debugging()

        for expected_exception in expect_exceptions:
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert frames[0]['source']['path'].endswith('code_to_debug.py')
            assert frames[0]['line'] == line_numbers[expected_exception]
            session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
Пример #28
0
def test_return_values(pyfile, run_as, start_method):

    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        class MyClass(object):

            def do_something(self):
                return 'did something'

        def my_func():
            return 'did more things'

        MyClass().do_something()  # @bp
        my_func()
        print('done')

    line_numbers = get_marked_line_numbers(code_to_debug)
    print(line_numbers)

    expected1 = ANY.dict_with({
        'name': '(return) MyClass.do_something',
        'value': "'did something'",
        'type': 'str',
        'presentationHint': ANY.dict_with({
            'attributes': ANY.such_that(lambda x: 'readOnly' in x)
        }),
    })

    expected2 = ANY.dict_with({
        'name': '(return) my_func',
        'value': "'did more things'",
        'type': 'str',
        'presentationHint': ANY.dict_with({
            'attributes': ANY.such_that(lambda x: 'readOnly' in x)
        }),
    })

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            debug_options=['ShowReturnValue'],
        )
        session.set_breakpoints(code_to_debug, [line_numbers['bp']])
        session.start_debugging()
        hit = session.wait_for_thread_stopped()

        session.send_request('next', {'threadId': hit.thread_id}).wait_for_response()
        hit = session.wait_for_thread_stopped(reason='step')

        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'].startswith('(return)')
        )

        assert variables == [expected1]

        session.send_request('next', {'threadId': hit.thread_id}).wait_for_response()
        hit = session.wait_for_thread_stopped(reason='step')

        # Scope should not have changed so use the same scope
        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'].startswith('(return)')
        )

        assert variables == [expected1, expected2]

        session.send_request('continue').wait_for_response()
        session.wait_for_exit()