diff --git a/test/helper.rb b/test/helper.rb index dda1f241..c0508ed7 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -27,6 +27,25 @@ class << Pry end end +class MockPryException + attr_accessor :bt_index + attr_accessor :backtrace + + def initialize(*backtrace) + @backtrace = backtrace + @bt_index = 0 + end + + def message + "mock exception" + end + + def bt_source_location_for(index) + backtrace[index] =~ /(.*):(\d+)/ + [$1, $2.to_i] + end +end + # are we on Jruby platform? def jruby? defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ @@ -136,6 +155,17 @@ class Pry end end +# Open a temp file and yield it to the block, closing it after +# @return [String] The path of the temp file +def temp_file + file = Tempfile.new("tmp") + yield file + file.flush + file.path +ensure + file.close +end + CommandTester = Pry::CommandSet.new do command "command1", "command 1 test" do diff --git a/test/test_default_commands/test_introspection.rb b/test/test_default_commands/test_introspection.rb index a0dff7b4..78dc426e 100644 --- a/test/test_default_commands/test_introspection.rb +++ b/test/test_default_commands/test_introspection.rb @@ -122,6 +122,55 @@ describe "Pry::DefaultCommands::Introspection" do end end + describe "with --ex NUM" do + before do + Pry.config.editor = proc do |file, line| + @__ex_file__ = file + @__ex_line__ = line + nil + end + end + + it 'should start editor on first level of backtrace when --ex used with no argument ' do + pry_instance = Pry.new(:input => StringIO.new("edit -n --ex"), :output => StringIO.new) + pry_instance.last_exception = MockPryException.new("a:1", "b:2", "c:3") + pry_instance.rep(self) + @__ex_file__.should == "a" + @__ex_line__.should == 1 + end + + it 'should start editor on first level of backtrace when --ex 0 used ' do + pry_instance = Pry.new(:input => StringIO.new("edit -n --ex 0"), :output => StringIO.new) + pry_instance.last_exception = MockPryException.new("a:1", "b:2", "c:3") + pry_instance.rep(self) + @__ex_file__.should == "a" + @__ex_line__.should == 1 + end + + it 'should start editor on second level of backtrace when --ex 1 used' do + pry_instance = Pry.new(:input => StringIO.new("edit -n --ex 1"), :output => StringIO.new) + pry_instance.last_exception = MockPryException.new("a:1", "b:2", "c:3") + pry_instance.rep(self) + @__ex_file__.should == "b" + @__ex_line__.should == 2 + end + + it 'should start editor on third level of backtrace when --ex 2 used' do + pry_instance = Pry.new(:input => StringIO.new("edit -n --ex 2"), :output => StringIO.new) + pry_instance.last_exception = MockPryException.new("a:1", "b:2", "c:3") + pry_instance.rep(self) + @__ex_file__.should == "c" + @__ex_line__.should == 3 + end + + it 'should display error message when backtrace level is out of bounds (using --ex 4)' do + pry_instance = Pry.new(:input => StringIO.new("edit -n --ex 4"), :output => str_output = StringIO.new) + pry_instance.last_exception = MockPryException.new("a:1", "b:2", "c:3") + pry_instance.rep(self) + str_output.string.should =~ /Exception has no associated file/ + end + end + describe "without FILE" do it "should edit the current expression if it's incomplete" do mock_pry("def a", "edit") @@ -169,7 +218,7 @@ describe "Pry::DefaultCommands::Introspection" do str_output.string.should =~ /def sample/ end - + it 'should output multiple methods\' sources' do str_output = StringIO.new redirect_pry_io(InputTester.new("show-method sample_method another_sample_method", "exit-all"), str_output) do diff --git a/test/test_default_commands/test_shell.rb b/test/test_default_commands/test_shell.rb index 33386170..1d6373c8 100644 --- a/test/test_default_commands/test_shell.rb +++ b/test/test_default_commands/test_shell.rb @@ -5,14 +5,87 @@ describe "Pry::DefaultCommands::Shell" do # this doesnt work so well on rbx due to differences in backtrace # so we currently skip rbx until we figure out a workaround - if !rbx? - it 'cat --ex should correctly display code that generated exception even if raised in repl' do - mock_pry("this raises error", "cat --ex").should =~ /\d+:(\s*) this raises error/ + describe "with --ex" do + if !rbx? + it 'cat --ex should correctly display code that generated exception even if raised in repl' do + mock_pry("this raises error", "cat --ex").should =~ /\d+:(\s*) this raises error/ + end + + it 'cat --ex should correctly display code that generated exception' do + mock_pry("broken_method", "cat --ex").should =~ /this method is broken/ + end + end + end + + describe "with --ex N" do + it 'should cat first level of backtrace when --ex used with no argument ' do + pry_instance = Pry.new(:input => StringIO.new("cat --ex"), :output => str_output = StringIO.new) + file_name = temp_file do |f| + f << "bt number 1" + end + pry_instance.last_exception = MockPryException.new("#{file_name}:1", "x", "x") + pry_instance.rep(self) + str_output.string.should =~ /bt number 1/ end - it 'cat --ex should correctly display code that generated exception' do - mock_pry("broken_method", "cat --ex").should =~ /this method is broken/ + it 'should cat first level of backtrace when --ex 0 used ' do + pry_instance = Pry.new(:input => StringIO.new("cat --ex 0"), :output => str_output = StringIO.new) + file_name = temp_file do |f| + f << "bt number 1" + end + pry_instance.last_exception = MockPryException.new("#{file_name}:1", "x", "x") + pry_instance.rep(self) + str_output.string.should =~ /bt number 1/ end + + it 'should cat second level of backtrace when --ex 1 used ' do + pry_instance = Pry.new(:input => StringIO.new("cat --ex 1"), :output => str_output = StringIO.new) + file_name = temp_file do |f| + f << "bt number 2" + end + pry_instance.last_exception = MockPryException.new("x", "#{file_name}:1", "x") + pry_instance.rep(self) + str_output.string.should =~ /bt number 2/ + end + + it 'should cat third level of backtrace when --ex 2 used ' do + pry_instance = Pry.new(:input => StringIO.new("cat --ex 2"), :output => str_output = StringIO.new) + file_name = temp_file do |f| + f << "bt number 3" + end + pry_instance.last_exception = MockPryException.new("x", "x", "#{file_name}:1") + pry_instance.rep(self) + str_output.string.should =~ /bt number 3/ + end + + it 'should show error when backtrace level out of bounds ' do + pry_instance = Pry.new(:input => StringIO.new("cat --ex 3"), :output => str_output = StringIO.new) + pry_instance.last_exception = MockPryException.new("x", "x", "x") + pry_instance.rep(self) + str_output.string.should =~ /No Exception or Exception has no associated file/ + end + + it 'each successive cat --ex should show the next level of backtrace, and going past the final level should return to the first' do + file_names = [] + file_names << temp_file { |f| f << "bt number 0" } + file_names << temp_file { |f| f << "bt number 1" } + file_names << temp_file { |f| f << "bt number 2" } + + pry_instance = Pry.new(:input => StringIO.new("cat --ex\n" * (file_names.size + 1)), + :output => str_output = StringIO.new) + + pry_instance.last_exception = MockPryException.new(*file_names.map { |f| "#{f}:1" }) + + file_names.each_with_index do |f, idx| + pry_instance.rep(self) + str_output.string.should =~ /bt number #{idx}/ + end + + str_output.reopen + pry_instance.rep(self) + str_output.string.should =~ /bt number 0/ + end + end end end