require_relative 'helper' describe Pry do before do @str_output = StringIO.new end describe "Exotic object support" do # regression test for exotic object support it "Should not error when return value is a BasicObject instance" do ReplTester.start do input('BasicObject.new').should =~ /^=> # proc{ was_called = true }) expect(was_called).to eq false end it 'should notice when exceptions are raised' do was_called = false mock_pry("raise RuntimeError", :exception_handler => proc{ was_called = true }) expect(was_called).to eq true end it 'should not try to catch intended exceptions' do expect { mock_pry("raise SystemExit") }.to raise_error SystemExit # SIGTERM expect { mock_pry("raise SignalException.new(15)") }.to raise_error SignalException end describe "multi-line input" do it "works" do expect(mock_pry('x = ', '1 + 4')).to match(/5/) end it 'should suppress output if input ends in a ";" (multi-line)' do expect(mock_pry('def self.blah', ':test', 'end;')).to eq '' end describe "newline stripping from an empty string" do it "with double quotes" do expect(mock_pry('"', '"')).to match(%r|"\\n"|) expect(mock_pry('"', "\n", "\n", "\n", '"')).to match(%r|"\\n\\n\\n\\n"|) end it "with single quotes" do expect(mock_pry("'", "'")).to match(%r|"\\n"|) expect(mock_pry("'", "\n", "\n", "\n", "'")).to match(%r|"\\n\\n\\n\\n"|) end it "with fancy delimiters" do expect(mock_pry('%(', ')')).to match(%r|"\\n"|) expect(mock_pry('%|', "\n", "\n", '|')).to match(%r|"\\n\\n\\n"|) expect(mock_pry('%q[', "\n", "\n", ']')).to match(%r|"\\n\\n\\n"|) end end describe "newline stripping from an empty regexp" do it "with regular regexp delimiters" do expect(mock_pry('/', '/')).to match(%r{/\n/}) end it "with fancy delimiters" do expect(mock_pry('%r{', "\n", "\n", '}')).to match(%r{/\n\n\n/}) expect(mock_pry('%r<', "\n", '>')).to match(%r{/\n\n/}) end end describe "newline from an empty heredoc" do it "works" do expect(mock_pry('< input, :output => StringIO.new) expect(o.instance_variable_get(:@x)).to eq 10 end end describe "complete_expression?" do it "should not mutate the input!" do clean = "puts <<-FOO\nhi\nFOO\n" a = clean.dup Pry::Code.complete_expression?(a) expect(a).to eq clean end end describe "history arrays" do it 'sets _ to the last result' do t = pry_tester t.eval ":foo" expect(t.eval("_")).to eq :foo t.eval "42" expect(t.eval("_")).to eq 42 end it 'sets out to an array with the result' do t = pry_tester t.eval ":foo" t.eval "42" res = t.eval "_out_" expect(res).to be_a_kind_of Pry::HistoryArray expect(res[1..2]).to eq [:foo, 42] end it 'sets _in_ to an array with the entered lines' do t = pry_tester t.eval ":foo" t.eval "42" res = t.eval "_in_" expect(res).to be_a_kind_of Pry::HistoryArray expect(res[1..2]).to eq [":foo\n", "42\n"] end it 'uses 100 as the size of _in_ and _out_' do expect(pry_tester.eval("[_in_.max_size, _out_.max_size]")).to eq [100, 100] end it 'can change the size of the history arrays' do expect(pry_tester(:memory_size => 1000).eval("[_out_, _in_].map(&:max_size)")).to eq [1000, 1000] end it 'store exceptions' do mock_pry("foo!", "Pad.in = _in_[-1]; Pad.out = _out_[-1]") expect(Pad.in).to eq "foo!\n" expect(Pad.out).to be_a_kind_of NoMethodError end end describe "last_result" do it "should be set to the most recent value" do expect(pry_eval("2", "_ + 82")).to eq 84 end # This test needs mock_pry because the command retvals work by # replacing the eval_string, so _ won't be modified without Pry doing # a REPL loop. it "should be set to the result of a command with :keep_retval" do Pry::Commands.block_command '++', '', :keep_retval => true do |a| a.to_i + 1 end expect(mock_pry('++ 86', '++ #{_}')).to match(/88/) end it "should be preserved over an empty line" do expect(pry_eval("2 + 2", " ", "\t", " ", "_ + 92")).to eq 96 end it "should be preserved when evalling a command without :keep_retval" do expect(pry_eval("2 + 2", "ls -l", "_ + 96")).to eq 100 end end describe "nesting" do after do Pry.reset_defaults Pry.config.color = false end it 'should nest properly' do Pry.config.input = InputTester.new("cd 1", "cd 2", "cd 3", "\"nest:\#\{(_pry_.binding_stack.size - 1)\}\"", "exit-all") Pry.config.output = @str_output o = Object.new o.pry expect(@str_output.string).to match(/nest:3/) end end describe "defining methods" do it 'should define a method on the singleton class of an object when performing "def meth;end" inside the object' do [Object.new, {}, []].each do |val| pry_eval(val, 'def hello; end') expect(val.methods(false).map(&:to_sym).include?(:hello)).to eq true end end it 'should define an instance method on the module when performing "def meth;end" inside the module' do hello = Module.new pry_eval(hello, "def hello; end") expect(hello.instance_methods(false).map(&:to_sym).include?(:hello)).to eq true end it 'should define an instance method on the class when performing "def meth;end" inside the class' do hello = Class.new pry_eval(hello, "def hello; end") expect(hello.instance_methods(false).map(&:to_sym).include?(:hello)).to eq true end it 'should define a method on the class of an object when performing "def meth;end" inside an immediate value or Numeric' do [:test, 0, true, false, nil, (0.0 unless Pry::Helpers::BaseHelpers.jruby?)].each do |val| pry_eval(val, "def hello; end"); expect(val.class.instance_methods(false).map(&:to_sym).include?(:hello)).to eq true end end end describe "Object#pry" do after do Pry.reset_defaults Pry.config.color = false end it "should start a pry session on the receiver (first form)" do Pry.config.input = InputTester.new("self", "exit-all") str_output = StringIO.new Pry.config.output = str_output 20.pry expect(str_output.string).to match(/20/) end it "should start a pry session on the receiver (second form)" do Pry.config.input = InputTester.new("self", "exit-all") str_output = StringIO.new Pry.config.output = str_output pry 20 expect(str_output.string).to match(/20/) end it "should raise if more than two arguments are passed to Object#pry" do expect { pry(20, :quiet, :input => Readline) }.to raise_error ArgumentError end end describe "Pry.binding_for" do it 'should return TOPLEVEL_BINDING if parameter self is main' do _main_ = lambda { TOPLEVEL_BINDING.eval('self') } expect(Pry.binding_for(_main_.call).is_a?(Binding)).to eq true expect(Pry.binding_for(_main_.call)).to eq TOPLEVEL_BINDING expect(Pry.binding_for(_main_.call)).to eq Pry.binding_for(_main_.call) end end end end describe 'setting custom options' do it 'does not raise for unrecognized options' do expect { Pry.new(:custom_option => 'custom value') }.to_not raise_error end it 'correctly handles the :quiet option (#1261)' do instance = Pry.new(:quiet => true) expect(instance.quiet?).to eq true end end describe "a fresh instance" do it "should use `caller` as its backtrace" do location = "#{__FILE__}:#{__LINE__ + 1}"[1..-1] # omit leading . backtrace = Pry.new.backtrace expect(backtrace).not_to equal nil expect(backtrace.any? { |l| l.include?(location) }).to equal true end end end