1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00

Rewrite cd tests to drive pry instance directly

This commit is contained in:
Ryan Fitzgerald 2012-07-23 04:03:05 -04:00
parent 6fd797d302
commit 62a684b9d9
5 changed files with 166 additions and 210 deletions

View file

@ -66,9 +66,16 @@ class Pry
# Restore old stack to its initial values. # Restore old stack to its initial values.
state.old_stack = old_stack state.old_stack = old_stack
output.puts "Bad object path: #{arg_string.chomp}. Failed trying to resolve: #{context}" msg = [
output.puts e.inspect "Bad object path: #{arg_string}.",
return "Failed trying to resolve: #{context}.",
e.inspect
].join(' ')
CommandError.new(msg).tap do |err|
err.set_backtrace e.backtrace
raise err
end
end end
end end

View file

@ -196,7 +196,6 @@ class Pry
exec_hook :before_session, output, target, self exec_hook :before_session, output, target, self
set_last_result(nil, target) set_last_result(nil, target)
@input_array << nil # add empty input so _in_ and _out_ match @input_array << nil # add empty input so _in_ and _out_ match
binding_stack.push target binding_stack.push target
@ -272,10 +271,7 @@ class Pry
exec_hook :before_eval, code, self exec_hook :before_eval, code, self
result = target.eval(code, Pry.eval_path, Pry.current_line) result = evaluate_ruby(code, target)
set_last_result(result, target, code)
result
rescue RescuableException => e rescue RescuableException => e
self.last_exception = e self.last_exception = e
e e
@ -320,6 +316,15 @@ class Pry
eval_string eval_string
end end
def evaluate_ruby(code, target = binding_stack.last)
target = Pry.binding_for(target)
inject_sticky_locals(target)
target.eval(code, Pry.eval_path, Pry.current_line).tap do |result|
set_last_result(result, target, code)
end
end
# Output the result or pass to an exception handler (if result is an exception). # Output the result or pass to an exception handler (if result is an exception).
def show_result(result) def show_result(result)
if last_result_is_exception? if last_result_is_exception?
@ -419,7 +424,7 @@ class Pry
# @param [String] eval_string The cumulative lines of input. # @param [String] eval_string The cumulative lines of input.
# @param [Binding] target The target of the Pry session. # @param [Binding] target The target of the Pry session.
# @return [Boolean] `true` if `val` is a command, `false` otherwise # @return [Boolean] `true` if `val` is a command, `false` otherwise
def process_command(val, eval_string, target) def process_command(val, eval_string = '', target = TOPLEVEL_BINDING)
result = commands.process_line(val, { result = commands.process_line(val, {
:target => target, :target => target,
:output => output, :output => output,

View file

@ -125,7 +125,6 @@ def redirect_pry_io(new_in, new_out = StringIO.new)
end end
def mock_pry(*args) def mock_pry(*args)
args.flatten! args.flatten!
binding = args.first.is_a?(Binding) ? args.shift : binding() binding = args.first.is_a?(Binding) ? args.shift : binding()

View file

@ -1,290 +1,248 @@
require 'helper' require 'helper'
module CdTestHelpers
def binding_stack
evaluate_ruby '_pry_.binding_stack.dup'
end
def assert_binding_stack(other)
binding_stack.map { |b| b.eval('self') }.should == other
end
def command_state
evaluate_ruby '_pry_.command_state["cd"]'
end
def old_stack
evaluate_ruby '_pry_.command_state["cd"].old_stack.dup'
end
def evaluate_self
evaluate_ruby 'self'
end
def process_commands(*args)
args.flatten.each do |cmd|
@pry.process_command cmd
end
end
def evaluate_ruby(ruby)
@pry.evaluate_ruby ruby
end
end
describe 'Pry::DefaultCommands::Cd' do describe 'Pry::DefaultCommands::Cd' do
before do before do
extend CdTestHelpers
@o, @obj = Object.new, Object.new @o, @obj = Object.new, Object.new
@obj.instance_variable_set(:@x, 66) @obj.instance_variable_set(:@x, 66)
@obj.instance_variable_set(:@y, 79) @obj.instance_variable_set(:@y, 79)
@o.instance_variable_set(:@obj, @obj) @o.instance_variable_set(:@obj, @obj)
# Shortcuts. They save a lot of typing. @pry = Pry.new
@bs1 = "Pad.bs1 = _pry_.binding_stack.dup" @pry.binding_stack << Pry.binding_for(@o)
@bs2 = "Pad.bs2 = _pry_.binding_stack.dup"
@bs3 = "Pad.bs3 = _pry_.binding_stack.dup"
@os1 = "Pad.os1 = _pry_.command_state['cd'].old_stack.dup"
@os2 = "Pad.os2 = _pry_.command_state['cd'].old_stack.dup"
@self = "Pad.self = self"
@inner = "Pad.inner = self"
@outer = "Pad.outer = self"
end
after do
Pad.clear
end end
describe 'state' do describe 'state' do
it 'should not to be set up in fresh instance' do it 'should not to be set up in fresh instance' do
redirect_pry_io(InputTester.new(@os1, "exit-all")) do command_state.should.be.nil
Pry.start(@o)
end
Pad.os1.should == nil
end end
end end
describe 'old stack toggling with `cd -`' do describe 'old stack toggling with `cd -`' do
describe 'in fresh pry instance' do describe 'in fresh pry instance' do
it 'should not toggle when there is no old stack' do it 'should not toggle when there is no old stack' do
redirect_pry_io(InputTester.new("cd -", @bs1, "cd -", 2.times do
@bs2, "exit-all")) do process_commands 'cd -'
Pry.start(@o) assert_binding_stack [@o]
end end
Pad.bs1.map { |v| v.eval("self") }.should == [@o]
Pad.bs2.map { |v| v.eval("self") }.should == [@o]
end end
end end
describe 'when an error was raised' do describe 'when an error was raised' do
it 'should ensure cd @ raises SyntaxError' do it 'should not toggle and should keep correct stacks' do
mock_pry("cd @").should =~ /SyntaxError/ proc {
end process_commands 'cd @'
}.should.raise(Pry::CommandError)
it 'should not toggle and should keep correct old stack' do old_stack.should == []
redirect_pry_io(InputTester.new("cd @", @os1, "cd -", @os2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.os1.should == [] process_commands 'cd -'
Pad.os2.should == [] old_stack.should == []
end assert_binding_stack [@o]
it 'should not toggle and should keep correct current binding stack' do
redirect_pry_io(InputTester.new("cd @", @bs1, "cd -", @bs2, "exit-all")) do
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o]
Pad.bs2.map { |v| v.eval("self") }.should == [@o]
end end
end end
describe 'when using simple cd syntax' do describe 'when using simple cd syntax' do
it 'should toggle' do it 'should toggle' do
redirect_pry_io(InputTester.new("cd :mon_dogg", "cd -", @bs1, process_commands 'cd :mon_dogg', 'cd -'
"cd -", @bs2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o] process_commands 'cd -'
Pad.bs2.map { |v| v.eval("self") }.should == [@o, :mon_dogg] assert_binding_stack [@o, :mon_dogg]
end end
end end
describe "when using complex cd syntax" do describe "when using complex cd syntax" do
it 'should toggle with a complex path (simple case)' do it 'should toggle with a complex path (simple case)' do
redirect_pry_io(InputTester.new("cd 1/2/3", "cd -", @bs1, process_commands 'cd 1/2/3', 'cd -'
"cd -", @bs2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o] process_commands 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, 1, 2, 3] assert_binding_stack [@o, 1, 2, 3]
end end
it 'should toggle with a complex path (more complex case)' do it 'should toggle with a complex path (more complex case)' do
redirect_pry_io(InputTester.new("cd 1/2/3", "cd ../4", "cd -", process_commands 'cd 1/2/3', 'cd ../4', 'cd -'
@bs1, "cd -", @bs2, "exit-all")) do assert_binding_stack [@o, 1, 2, 3]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o, 1, 2, 3] process_commands 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, 1, 2, 4] assert_binding_stack [@o, 1, 2, 4]
end end
end end
describe 'series of cd calls' do describe 'series of cd calls' do
it 'should toggle with fuzzy `cd -` calls' do it 'should toggle with fuzzy `cd -` calls' do
redirect_pry_io(InputTester.new("cd :mon_dogg", "cd -", "cd 42", "cd -", process_commands 'cd :mon_dogg', 'cd -', 'cd 42', 'cd -'
@bs1, "cd -", @bs2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o] process_commands 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, 42] assert_binding_stack [@o, 42]
end end
end end
describe 'when using cd ..' do describe 'when using cd ..' do
it 'should toggle with a simple path' do it 'should toggle with a simple path' do
redirect_pry_io(InputTester.new("cd :john_dogg", "cd ..", @bs1, process_commands 'cd :john_dogg', 'cd ..'
"cd -", @bs2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o] process_commands 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, :john_dogg] assert_binding_stack [@o, :john_dogg]
end end
it 'should toggle with a complex path' do it 'should toggle with a complex path' do
redirect_pry_io(InputTester.new("cd 1/2/3/../4", "cd -", @bs1, process_commands 'cd 1/2/3/../4', 'cd -'
"cd -", @bs2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o] process_commands 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, 1, 2, 4] assert_binding_stack [@o, 1, 2, 4]
end end
end end
describe 'when using cd ::' do describe 'when using cd ::' do
it 'should toggle' do it 'should toggle' do
redirect_pry_io(InputTester.new("cd ::", "cd -", @bs1, process_commands 'cd ::', 'cd -'
"cd -", @bs2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o] process_commands 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, TOPLEVEL_BINDING.eval("self")] assert_binding_stack [@o, TOPLEVEL_BINDING.eval('self')]
end end
end end
describe 'when using cd /' do describe 'when using cd /' do
it 'should toggle' do it 'should toggle' do
redirect_pry_io(InputTester.new("cd /", "cd -", @bs1, "cd :john_dogg", process_commands 'cd /', 'cd -'
"cd /", "cd -", @bs2, "exit-all")) do assert_binding_stack [@o]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o] process_commands 'cd :john_dogg', 'cd /', 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, :john_dogg] assert_binding_stack [@o, :john_dogg]
end end
end end
describe 'when using ^D (Control-D) key press' do describe 'when using ^D (Control-D) key press' do
before do
@control_d = "Pry::DEFAULT_CONTROL_D_HANDLER.call('', _pry_)"
end
it 'should keep correct old binding' do it 'should keep correct old binding' do
redirect_pry_io(InputTester.new("cd :john_dogg", "cd :mon_dogg", process_commands 'cd :john_dogg', 'cd :mon_dogg', 'cd :kyr_dogg'
"cd :kyr_dogg", @control_d, @bs1, evaluate_ruby 'Pry::DEFAULT_CONTROL_D_HANDLER.call("", _pry_)'
"cd -", @bs2, "cd -", @bs3, "exit-all")) do assert_binding_stack [@o, :john_dogg, :mon_dogg]
Pry.start(@o)
end
Pad.bs1.map { |v| v.eval('self') }.should == [@o, :john_dogg, :mon_dogg] process_commands 'cd -'
Pad.bs2.map { |v| v.eval('self') }.should == [@o, :john_dogg, :mon_dogg, :kyr_dogg] assert_binding_stack [@o, :john_dogg, :mon_dogg, :kyr_dogg]
Pad.bs3.map { |v| v.eval('self') }.should == [@o, :john_dogg, :mon_dogg]
process_commands 'cd -'
assert_binding_stack [@o, :john_dogg, :mon_dogg]
end end
end end
end end
it 'should cd into simple input' do it 'should cd into simple input' do
redirect_pry_io(InputTester.new("cd :mon_ouie", @inner, "exit-all")) do process_commands 'cd :mon_ouie'
Pry.start(@o) evaluate_self.should == :mon_ouie
end
Pad.inner.should == :mon_ouie
end end
it 'should break out of session with cd ..' do it 'should break out of session with cd ..' do
redirect_pry_io(InputTester.new("cd :inner", @inner, "cd ..", @outer, "exit-all")) do process_commands 'cd :outer', 'cd :inner'
Pry.start(:outer) evaluate_self.should == :inner
end
Pad.inner.should == :inner process_commands 'cd ..'
Pad.outer.should == :outer evaluate_self.should == :outer
end end
it "should not leave the REPL session when given 'cd ..'" do it "should not leave the REPL session when given 'cd ..'" do
redirect_pry_io(InputTester.new("cd ..", @self, "exit-all")) do process_commands 'cd ..'
Pry.start(@o) evaluate_self.should == @o
end
Pad.self.should == @o
end end
it 'should break out to outer-most session with cd /' do it 'should break out to outer-most session with cd /' do
redirect_pry_io(InputTester.new("cd :inner", @inner, "cd 5", "Pad.five = self", process_commands 'cd :inner'
"cd /", @outer, "exit-all")) do evaluate_self.should == :inner
Pry.start(:outer)
end
Pad.inner.should == :inner process_commands 'cd 5'
Pad.five.should == 5 evaluate_self.should == 5
Pad.outer.should == :outer
process_commands 'cd /'
evaluate_self.should == @o
end end
it 'should break out to outer-most session with just cd (no args)' do it 'should break out to outer-most session with just cd (no args)' do
redirect_pry_io(InputTester.new("cd :inner", @inner, "cd 5", "Pad.five = self", process_commands 'cd :inner'
"cd", @outer, "exit-all")) do evaluate_self.should == :inner
Pry.start(:outer)
end
Pad.inner.should == :inner process_commands 'cd 5'
Pad.five.should == 5 evaluate_self.should == 5
Pad.outer.should == :outer
process_commands 'cd'
evaluate_self.should == @o
end end
it 'should cd into an object and its ivar using cd obj/@ivar syntax' do it 'should cd into an object and its ivar using cd obj/@ivar syntax' do
redirect_pry_io(InputTester.new("cd @obj/@x", @bs1, "exit-all")) do process_commands 'cd @obj/@x'
Pry.start(@o) assert_binding_stack [@o, @obj, 66]
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o, @obj, 66]
end end
it 'should cd into an object and its ivar using cd obj/@ivar/ syntax (note following /)' do it 'should cd into an object and its ivar using cd obj/@ivar/ syntax (note following /)' do
redirect_pry_io(InputTester.new("cd @obj/@x/", @bs1, "exit-all")) do process_commands 'cd @obj/@x/'
Pry.start(@o) assert_binding_stack [@o, @obj, 66]
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o, @obj, 66]
end end
it 'should cd into previous object and its local using cd ../local syntax' do it 'should cd into previous object and its local using cd ../local syntax' do
redirect_pry_io(InputTester.new("cd @obj", "local = :local", "cd @x", process_commands 'cd @obj'
"cd ../local", @bs1, "exit-all")) do evaluate_ruby 'local = :local'
Pry.start(@o) process_commands 'cd @x', 'cd ../local'
end assert_binding_stack [@o, @obj, :local]
Pad.bs1.map { |v| v.eval("self") }.should == [@o, @obj, :local]
end end
it 'should cd into an object and its ivar and back again using cd obj/@ivar/.. syntax' do it 'should cd into an object and its ivar and back again using cd obj/@ivar/.. syntax' do
redirect_pry_io(InputTester.new("cd @obj/@x/..", @bs1, "exit-all")) do process_commands 'cd @obj/@x/..'
Pry.start(@o) assert_binding_stack [@o, @obj]
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o, @obj]
end end
it 'should cd into an object and its ivar and back and then into another ivar using cd obj/@ivar/../@y syntax' do it 'should cd into an object and its ivar and back and then into another ivar using cd obj/@ivar/../@y syntax' do
redirect_pry_io(InputTester.new("cd @obj/@x/../@y", @bs1, "exit-all")) do process_commands 'cd @obj/@x/../@y'
Pry.start(@o) assert_binding_stack [@o, @obj, 79]
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o, @obj, 79]
end end
it 'should cd back to top-level and then into another ivar using cd /@ivar/ syntax' do it 'should cd back to top-level and then into another ivar using cd /@ivar/ syntax' do
redirect_pry_io(InputTester.new("@z = 20", "cd @obj/@x/", "cd /@z", evaluate_ruby '@z = 20'
@bs1, "exit-all")) do process_commands 'cd @obj/@x/', 'cd /@z'
Pry.start(@o) assert_binding_stack [@o, 20]
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o, 20]
end end
it 'should start a session on TOPLEVEL_BINDING with cd ::' do it 'should start a session on TOPLEVEL_BINDING with cd ::' do
redirect_pry_io(InputTester.new("cd ::", @self, "exit-all")) do process_commands 'cd ::'
Pry.start(@o) evaluate_self.should == TOPLEVEL_BINDING.eval('self')
end
Pad.self.should == TOPLEVEL_BINDING.eval("self")
end end
it 'should cd into complex input (with spaces)' do it 'should cd into complex input (with spaces)' do
@ -292,30 +250,23 @@ describe 'Pry::DefaultCommands::Cd' do
:mon_ouie :mon_ouie
end end
redirect_pry_io(InputTester.new("cd hello 1, 2, 3", @self, "exit-all")) do process_commands 'cd hello 1, 2, 3'
Pry.start(@o) evaluate_self.should == :mon_ouie
end
Pad.self.should == :mon_ouie
end end
it 'should not cd into complex input when it encounters an exception' do it 'should not cd into complex input when it encounters an exception' do
redirect_pry_io(InputTester.new("cd 1/2/swoop_a_doop/3", proc {
@bs1, "exit-all")) do process_commands 'cd 1/2/swoop_a_doop/3'
Pry.start(@o) }.should.raise(Pry::CommandError)
end
Pad.bs1.map { |v| v.eval("self") }.should == [@o] assert_binding_stack [@o]
end end
# Regression test for ticket #516. # Regression test for ticket #516.
#it 'should be able to cd into the Object BasicObject.' do # FIXME: This is actually broken.
# mock_pry('cd BasicObject.new').should.not =~ /\Aundefined method `__binding__'/ # it 'should be able to cd into the Object BasicObject' do
#end # proc {
# process_commands 'cd BasicObject.new'
# Regression test for ticket #516 # }.should.not.raise
# Possibly move higher up. # end
it 'should not fail with undefined BasicObject#is_a?' do
mock_pry('cd BasicObject.new').should.not =~ /undefined method `is_a\?'/
end
end end

View file

@ -138,17 +138,11 @@ describe "Sticky locals (_file_ and friends)" do
end end
it 'should provide different values for successive block invocations' do it 'should provide different values for successive block invocations' do
o = Object.new pry = Pry.new
pi = Pry.new pry.add_sticky_local(:test_local) { rand }
v = [1, 2] value1 = pry.evaluate_ruby 'test_local'
pi.add_sticky_local(:test_local) { v.shift } value2 = pry.evaluate_ruby 'test_local'
pi.input = InputTester.new("@value1 = test_local", value1.should.not == value2
"@value2 = test_local", "exit-all")
pi.output = StringIO.new
pi.repl(o)
o.instance_variable_get(:@value1).should == 1
o.instance_variable_get(:@value2).should == 2
end end
end end