def test_basic_debugger(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["f"])); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) self.run(interp, """ function f() { } """) def c1(): assert c.read() == Message("echo", ["stop breakpoint f"]) ok(c) assert c.read() == Message(">", None) c.write(Message("continue", None)); ok(c) thread.start_new_thread(c1, ()) self.run(interp, "f();") assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_serialize_with_calls(self): source = """<? function f($a) { return $a + 4; } echo f(3); ?>""" space = getspace() bc = compile_php('<input>', source, space) dump = bc.serialize(space) bc2 = unserialize(dump, space) interp = MockInterpreter(space) interp.run_main(space, bc2) assert space.int_w(interp.output[0]) == 3 + 4
def test_call_args(self): space = ObjSpace() interp = MockInterpreter(space) sin = interp.locate_function("sin") w_res = space.call_args(sin, [space.wrap(1.2)]) assert space.float_w(w_res) == math.sin(1.2) max = interp.locate_function("max") w_res = space.call_args( max, [space.wrap(2), space.wrap(15), space.wrap(3)]) assert space.int_w(w_res) == 15 w_res = space.call_args( max, [W_Reference(space.wrap(2)), space.wrap(15), space.wrap(3)]) assert space.int_w(w_res) == 15 str_repeat = interp.locate_function("str_repeat") w_res = space.call_args(str_repeat, [space.newstr("a"), space.wrap(3)]) assert space.str_w(w_res) == "aaa" source = """<?php function f($a, $b) { return $a + 10 * $b; } """ bc = compile_php('<input>', source, space, interp) interp.run_main(space, bc) f = interp.locate_function("f") w_res = space.call_args(f, [space.wrap(1), space.wrap(2)]) assert space.int_w(w_res) == 21
def test_serialize_array_constants(self): source = """<? $a = array("a", "b"); $b = array("a"=>"b"); echo $a[1]; echo $b["a"]; ?>""" space = getspace() bc = compile_php('<input>', source, space) dump = bc.serialize(space) bc2 = unserialize(dump, space) interp = MockInterpreter(space) interp.run_main(space, bc2) assert space.str_w(interp.output[0]) == "b" assert space.str_w(interp.output[1]) == "b"
def test_serialize_with_classes(self): source = """<? class X { function __construct() { $this->x = 3; } } $x = new X(); echo $x->x; ?>""" space = getspace() bc = compile_php('<input>', source, space) dump = bc.serialize(space) bc2 = unserialize(dump, space) interp = MockInterpreter(space) interp.run_main(space, bc2) assert space.int_w(interp.output[0]) == 3
def test_empty_backtrace(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("backtrace", None)); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) self.run(interp, "") assert c.read() == Message(">", None) assert c.read() == Message("warn", ["empty backtrace"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_basic_serialize(self): source = "<? $a = 3; var_dump($a);?>" space = getspace() bc = compile_php('<input>', source, space) dump = bc.serialize(space) bc2 = unserialize(dump, space) assert bc.dump() == bc2.dump() assert space.int_w(bc2.consts[0]) == 3 assert bc2.name == bc.name assert bc2.filename == bc.filename assert bc2.startlineno == bc.startlineno assert bc2.sourcelines == bc.sourcelines assert bc.names == bc2.names assert bc.varnames == bc2.varnames interp = MockInterpreter(space) interp.run_main(space, bc2) assert interp.output[0] == 'int(3)\n'
def test_call_args(self): space = ObjSpace() interp = MockInterpreter(space) sin = interp.locate_function("sin") w_res = space.call_args(sin, [space.wrap(1.2)]) assert space.float_w(w_res) == math.sin(1.2) max = interp.locate_function("max") w_res = space.call_args(max, [space.wrap(2), space.wrap(15), space.wrap(3)]) assert space.int_w(w_res) == 15 w_res = space.call_args(max, [W_Reference(space.wrap(2)), space.wrap(15), space.wrap(3)]) assert space.int_w(w_res) == 15 str_repeat = interp.locate_function("str_repeat") w_res = space.call_args(str_repeat, [space.newstr("a"), space.wrap(3)]) assert space.str_w(w_res) == "aaa" source = """<?php function f($a, $b) { return $a + 10 * $b; } """ bc = compile_php('<input>', source, space, interp) interp.run_main(space, bc) f = interp.locate_function("f") w_res = space.call_args(f, [space.wrap(1), space.wrap(2)]) assert space.int_w(w_res) == 21
def test_step_enter_leave(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("step", None)); ok(c); ok(c) c.write(Message("step", None)); ok(c) c.write(Message("step", None)); ok(c); ok(c) c.write(Message("backtrace", None)); ok(c) c.write(Message("step", None)); ok(c); ok(c); ok(c); ok(c) c.write(Message("step", None)); ok(c); ok(c); ok(c) c.write(Message("step", None)); ok(c); ok(c) c.write(Message("continue", None)); ok(c); ok(c) interp.debugger.run_debugger_loop(interp) interp.echo = interp.print_expr # <= hack self.run(interp, """ function F() { echo 'fff'; } F(); F(); F(); """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter <main>"]) assert c.read() == Message("linechange", ["<input>", "2", "<main>", "function F() {"]) assert c.read() == Message(">", None) assert c.read() == Message("linechange", ["<input>", "5", "<main>", "F(); F();"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter F"]) assert c.read() == Message("linechange", ["<input>", "3", "F", " echo 'fff';"]) assert c.read() == Message(">", None) exp_traceback = ["<input>", "F", "3", " echo 'fff';", "<input>", "<main>", "5", "F(); F();"] assert c.read() == Message("traceback", exp_traceback) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['string(3) "fff"']) assert c.read() == Message("echo", ["leave F"]) assert c.read() == Message("echo", ["enter F"]) assert c.read() == Message("linechange", ["<input>", "3", "F", " echo 'fff';"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['string(3) "fff"']) assert c.read() == Message("echo", ["leave F"]) assert c.read() == Message("linechange", ["<input>", "6", "<main>", "F();"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter F"]) assert c.read() == Message("linechange", ["<input>", "3", "F", " echo 'fff';"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert c.read() == Message("echo", ['string(3) "fff"']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_step_precise_position(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("step", None)); ok(c); ok(c) c.write(Message("step", None)); ok(c) c.write(Message("step", None)); ok(c); ok(c) c.write(Message("continue", None)); ok(c); ok(c) interp.debugger.run_debugger_loop(interp) interp.echo = interp.print_expr # <= hack self.run(interp, """ $a = 5; echo 'foobar'; echo 'baz'; """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter <main>"]) assert c.read() == Message("linechange", ["<input>", "2", "<main>", "$a = 5;"]) assert c.read() == Message(">", None) assert c.read() == Message("linechange", ["<input>", "3", "<main>", "echo 'foobar';"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['string(6) "foobar"']) assert c.read() == Message("linechange", ["<input>", "4", "<main>", "echo 'baz';"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert c.read() == Message("echo", ['string(3) "baz"']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_next_is_step_if_not_a_call(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("next", None)) ok(c) ok(c) c.write(Message("next", None)) ok(c) ok(c) c.write(Message("continue", None)) ok(c) interp.debugger.run_debugger_loop(interp) interp.echo = interp.print_expr # <= hack self.run(interp, """ echo 'fff'; $a = 5; """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter <main>"]) assert c.read() == Message("linechange", ["<input>", "2", "<main>", "echo 'fff';"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['string(3) "fff"']) assert c.read() == Message("linechange", ["<input>", "3", "<main>", "$a = 5;"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_next_skips_all_nested_calls(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("next", None)); ok(c); ok(c) c.write(Message("next", None)); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) interp.echo = interp.print_expr # <= hack self.run(interp, """ function F() { return G(); } function G() { return 42; } $a = F(); $a++; """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter <main>"]) assert c.read() == Message("linechange", ["<input>", "8", "<main>", "$a = F();"]) assert c.read() == Message(">", None) assert c.read() == Message("linechange", ["<input>", "9", "<main>", "$a++;"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_next_passes_over_calls_on_the_same_line(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("next", None)); ok(c); ok(c) c.write(Message("next", None)); ok(c); ok(c); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) interp.echo = interp.print_expr # <= hack self.run(interp, """ function F() { echo 'fff'; } F(); F(); $a = 5; """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter <main>"]) assert c.read() == Message("linechange", ["<input>", "5", "<main>", "F(); F();"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['string(3) "fff"']) assert c.read() == Message("echo", ['string(3) "fff"']) assert c.read() == Message("linechange", ["<input>", "6", "<main>", "$a = 5;"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_basic_debugger(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["f"])) ok(c) c.write(Message("continue", None)) ok(c) interp.debugger.run_debugger_loop(interp) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) self.run(interp, """ function f() { } """) def c1(): assert c.read() == Message("echo", ["stop breakpoint f"]) ok(c) assert c.read() == Message(">", None) c.write(Message("continue", None)) ok(c) thread.start_new_thread(c1, ()) self.run(interp, "f();") assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_eval(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["f"])); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) self.run(interp, """ function f($a, $b, $x) { } """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) ok(c) c.write(Message("eval", ["$x"])); ok(c) c.write(Message("backtrace", None)); ok(c) c.write(Message("continue", None)); ok(c) self.run(interp, """ f(1, 2, 3); """) assert c.read() == Message("echo", ["stop breakpoint f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["int(3)"]) assert c.read() == Message(">", None) exp_traceback = ["<input>", "f", "2", "function f($a, $b, $x) {", "<input>", "<main>", "2", "f(1, 2, 3);"] msg = c.read() assert msg == Message("traceback", exp_traceback) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_class_breakpoint_and_traceback(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["klass::method"])); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) def c1(): assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set klass::method"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) assert c.read() == Message("echo", ["stop breakpoint klass::method"]) ok(c) assert c.read() == Message(">", None) c.write(Message("eval", ["$x"])); ok(c) c.write(Message("continue", None)); ok(c) thread.start_new_thread(c1, ()) self.run(interp, """ class klass { function method($x) { } } $x = new klass(); $x->method(13); """) assert c.read() == Message("echo", ["int(13)"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_next_skips_all_nested_calls(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("next", None)); ok(c); ok(c) c.write(Message("next", None)); ok(c) c.write(Message("next", None)); ok(c) c.write(Message("next", None)); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) interp.echo = interp.print_expr # <= hack self.run(interp, """ function F() { return G(); } function G() { return 42; } $a = F(); $a++; """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter <main>"]) assert c.read() == Message("linechange", ["<input>", "2", "<main>", "function F() {"]) assert c.read() == Message(">", None) assert c.read() == Message("linechange", ["<input>", "5", "<main>", "function G() {"]) assert c.read() == Message(">", None) assert c.read() == Message("linechange", ["<input>", "8", "<main>", "$a = F();"]) assert c.read() == Message(">", None) assert c.read() == Message("linechange", ["<input>", "9", "<main>", "$a++;"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_eval(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["f"])) ok(c) c.write(Message("continue", None)) ok(c) interp.debugger.run_debugger_loop(interp) self.run(interp, """ function f($a, $b, $x) { } """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) ok(c) c.write(Message("eval", ["$x"])) ok(c) c.write(Message("backtrace", None)) ok(c) c.write(Message("continue", None)) ok(c) self.run(interp, """ f(1, 2, 3); """) assert c.read() == Message("echo", ["stop breakpoint f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["int(3)"]) assert c.read() == Message(">", None) exp_traceback = [ "<input>", "f", "2", "function f($a, $b, $x) {", "<input>", "<main>", "2", "f(1, 2, 3);" ] msg = c.read() assert msg == Message("traceback", exp_traceback) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_class_breakpoint_and_traceback(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["klass::method"])) ok(c) c.write(Message("continue", None)) ok(c) interp.debugger.run_debugger_loop(interp) def c1(): assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set klass::method"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) assert c.read() == Message("echo", ["stop breakpoint klass::method"]) ok(c) assert c.read() == Message(">", None) c.write(Message("eval", ["$x"])) ok(c) c.write(Message("continue", None)) ok(c) thread.start_new_thread(c1, ()) self.run( interp, """ class klass { function method($x) { } } $x = new klass(); $x->method(13); """) assert c.read() == Message("echo", ["int(13)"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def test_next_passes_over_calls_on_the_same_line(self): space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("next", None)); ok(c); ok(c) c.write(Message("next", None)); ok(c) c.write(Message("next", None)); ok(c); ok(c); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) interp.echo = interp.print_expr # <= hack self.run(interp, """ function F() { echo 'fff'; } F(); F(); $a = 5; """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["enter <main>"]) assert c.read() == Message("linechange", ["<input>", "2", "<main>", "function F() {"]) assert c.read() == Message(">", None) assert c.read() == Message("linechange", ["<input>", "5", "<main>", "F(); F();"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['string(3) "fff"']) assert c.read() == Message("echo", ['string(3) "fff"']) assert c.read() == Message("linechange", ["<input>", "6", "<main>", "$a = 5;"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def run_source(self, source, expected_warnings=[]): output_w = MockInterpreter.run_source(self, source) space = self.space output = [space.str_w(v) for v in output_w] return ''.join(output)
def test_line_start_offset(): space = ObjSpace() MockInterpreter(space) bc = compile_php('<input>', 'Hi there\n', space) assert bc.startlineno == 1
def test_next_step(self): pytest.xfail() space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["f"])) ok(c) c.write(Message("continue", None)) ok(c) interp.debugger.run_debugger_loop(interp) def c1(): assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) assert c.read() == Message("echo", ["stop breakpoint f"]) ok(c) assert c.read() == Message(">", None) c.write(Message("eval", ["$a"])) assert c.read() == Message("echo", ["int(1)"]) ok(c) assert c.read() == Message(">", None) c.write(Message("next", None)) assert c.read() == Message( "linechange", ["<input>", "3", "f", " $z = $a + $b + $c;"]) ok(c) assert c.read() == Message(">", None) c.write(Message("next", None)) assert c.read() == Message( "linechange", ["<input>", "4", "f", " $a = $z - 3 + g();"]) ok(c) assert c.read() == Message(">", None) c.write(Message("eval", ["$z"])) assert c.read() == Message("echo", ["int(6)"]) ok(c) assert c.read() == Message(">", None) c.write(Message("step", None)) assert c.read() == Message("echo", ["enter g"]) ok(c) assert c.read() == Message("linechange", ["<input>", "8", "g", " return 13;"]) ok(c) c.write(Message("continue", None)) ok(c) thread.start_new_thread(c1, ()) self.run( interp, """ function f($a, $b, $c) { $z = $a + $b + $c; $a = $z - 3 + g(); return $a; } function g() { return 13; } f(1, 2, 3); """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()
def run_bytecode(self, bc, expected_warnings=None): output_w = MockInterpreter.run_bytecode(self, bc) space = self.space output = [space.str_w(v) for v in output_w] return ''.join(output)
def test_next_step(self): pytest.xfail() space = ObjSpace() interp = MockInterpreter(space) interp.setup_debugger(self.read_fd1, self.write_fd2) c = Connection(self.read_fd2, self.write_fd1) c.write(Message("force_breakpoint", ["f"])); ok(c) c.write(Message("continue", None)); ok(c) interp.debugger.run_debugger_loop(interp) def c1(): assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Breakpoint set f"]) assert c.read() == Message(">", None) assert c.read() == Message("echo", ["Continuing"]) assert c.read() == Message("echo", ["stop breakpoint f"]) ok(c) assert c.read() == Message(">", None) c.write(Message("eval", ["$a"])) assert c.read() == Message("echo", ["int(1)"]) ok(c) assert c.read() == Message(">", None) c.write(Message("next", None)) assert c.read() == Message("linechange", ["<input>", "3", "f", " $z = $a + $b + $c;"]) ok(c) assert c.read() == Message(">", None) c.write(Message("next", None)) assert c.read() == Message("linechange", ["<input>", "4", "f", " $a = $z - 3 + g();"]) ok(c) assert c.read() == Message(">", None) c.write(Message("eval", ["$z"])) assert c.read() == Message("echo", ["int(6)"]) ok(c) assert c.read() == Message(">", None) c.write(Message("step", None)) assert c.read() == Message("echo", ["enter g"]) ok(c) assert c.read() == Message("linechange", ["<input>", "8", "g", " return 13;"]) ok(c) c.write(Message("continue", None)) ok(c) thread.start_new_thread(c1, ()) self.run(interp, """ function f($a, $b, $c) { $z = $a + $b + $c; $a = $z - 3 + g(); return $a; } function g() { return 13; } f(1, 2, 3); """) assert c.read() == Message(">", None) assert c.read() == Message("echo", ['Continuing']) assert not c.more_pending_messages() assert not interp.debugger.conn.more_pending_messages() assert not interp.msgs interp.shutdown()