pry/spec/command_integration_spec.rb

591 lines
16 KiB
Ruby

# frozen_string_literal: true
describe "commands" do
before do
@str_output = StringIO.new
@o = Object.new
# Shortcuts. They save a lot of typing.
@bs1 = "Pad.bs1 = pry_instance.binding_stack.dup"
@bs2 = "Pad.bs2 = pry_instance.binding_stack.dup"
@bs3 = "Pad.bs3 = pry_instance.binding_stack.dup"
@self = "Pad.self = self"
@command_tester = Pry::CommandSet.new do
command "command1", "command 1 test" do
output.puts "command1"
end
command "command2", "command 2 test" do |arg|
output.puts arg
end
end
Pad.bong = "bong"
end
after do
Pad.clear
Pry.reset_defaults
end
describe "alias_command" do
it 'should make an aliasd command behave like its original' do
set = Pry::CommandSet.new do
command "test-command" do
output.puts "testing 1, 2, 3"
end
alias_command "test-alias", "test-command"
end
pry_tester(commands: set).tap do |t|
expect(t.eval('test-command')).to eq t.eval('test-alias')
end
end
it 'should pass on arguments to original' do
set = Pry::CommandSet.new do
command "test-command" do |*args|
output.puts "testing #{args.join(' ')}"
end
alias_command "test-alias", "test-command"
end
t = pry_tester(commands: set)
t.process_command "test-alias hello baby duck"
expect(t.last_output).to match(/testing hello baby duck/)
end
it 'should pass option arguments to original' do
set = Pry::CommandSet.new do
import Pry::Commands
alias_command "test-alias", "ls"
end
obj = Class.new { @x = 10 }
t = pry_tester(obj, commands: set)
t.process_command "test-alias -i"
expect(t.last_output).to match(/@x/)
end
it 'should pass option arguments to original with additional parameters' do
set = Pry::CommandSet.new do
import Pry::Commands
alias_command "test-alias", "ls -M"
end
obj = Class.new { @x = Class.new { define_method(:plymouth) {} } }
t = pry_tester(obj, commands: set)
t.process_command "test-alias @x"
expect(t.last_output).to match(/plymouth/)
end
it 'should be able to alias a regex command' do
set = Pry::CommandSet.new do
command(/du.k/) do
output.puts "ducky"
end
alias_command "test-alias", "duck"
end
t = pry_tester(commands: set)
t.process_command "test-alias"
expect(t.last_output).to match(/ducky/)
end
it 'should be able to make the alias a regex' do
set = Pry::CommandSet.new do
command(/du.k/) do
output.puts "ducky"
end
alias_command(/test-ali.s/, "duck")
end
redirect_pry_io(InputTester.new("test-alias"), out1 = StringIO.new) do
Pry.start self, commands: set
end
expect(out1.string).to match(/ducky/)
end
end
describe "Pry::Command#run" do
it 'should allow running of commands with following whitespace' do
set = Pry::CommandSet.new do
import Pry::Commands
command "test-run" do
run "cd / "
end
end
redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run",
@self, @bs2, "exit-all")) do
Pry.start(@o, commands: set)
end
expect(Pad.bs1.size).to eq 7
expect(Pad.self).to eq @o
expect(Pad.bs2.size).to eq 1
end
it 'should allow running of cd command when contained in a single string' do
set = Pry::CommandSet.new do
import Pry::Commands
command "test-run" do
run "cd /"
end
end
redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run",
@self, @bs2, "exit-all")) do
Pry.start(@o, commands: set)
end
expect(Pad.bs1.size).to eq 7
expect(Pad.self).to eq @o
expect(Pad.bs2.size).to eq 1
end
it 'should allow running of cd command when split into array' do
set = Pry::CommandSet.new do
import Pry::Commands
command "test-run" do
run "cd", "/"
end
end
redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run",
@self, @bs2, "exit-all")) do
Pry.start(@o, commands: set)
end
expect(Pad.bs1.size).to eq 7
expect(Pad.self).to eq @o
expect(Pad.bs2.size).to eq 1
end
it 'should run a command from within a command' do
klass = Pry::CommandSet.new do
command "v" do
output.puts "v command"
end
command "run_v" do
run "v"
end
end
expect(pry_tester(commands: klass).eval('run_v')).to match(/v command/)
end
it 'should run a regex command from within a command' do
klass = Pry::CommandSet.new do
command(/v(.*)?/) do |arg|
output.puts "v #{arg}"
end
command "run_v" do
run "vbaby"
end
end
expect(pry_tester(commands: klass).eval('run_v')).to match(/v baby/)
end
it 'should run a command from within a command with arguments' do
klass = Pry::CommandSet.new do
command(/v(\w+)/) do |arg1, arg2|
output.puts "v #{arg1} #{arg2}"
end
command "run_v_explicit_parameter" do
run "vbaby", "param"
end
command "run_v_embedded_parameter" do
run "vbaby param"
end
end
%w[run_v_explicit_parameter run_v_embedded_parameter].each do |cmd|
expect(pry_tester(commands: klass).eval(cmd)).to match(/v baby param/)
end
end
end
describe "Pry#run_command" do
it 'should run a command that modifies the passed in eval_string' do
p = Pry.new(output: @str_output)
p.eval "def hello\npeter pan\n"
p.run_command "amend-line !"
expect(p.eval_string).to match(/def hello/)
expect(p.eval_string).not_to match(/peter pan/)
end
it 'should run a command in the context of a session' do
pry_tester(Object.new).tap do |t|
t.eval "@session_ivar = 10", "pry_instance.run_command('ls')"
expect(t.last_output).to match(/@session_ivar/)
end
end
end
it 'should interpolate ruby code into commands' do
set = Pry::CommandSet.new do
command "hello", "", keep_retval: true do |arg|
arg
end
end
# rubocop:disable Lint/InterpolationCheck
expect(pry_tester(commands: set).eval('hello #{Pad.bong}')).to match(/bong/)
# rubocop:enable Lint/InterpolationCheck
end
# bug fix for https://github.com/pry/pry/issues/170
it(
"doesn't choke on complex string interpolation when checking if ruby code " \
"is a command"
) do
redirect_pry_io(
# rubocop:disable Lint/InterpolationCheck
InputTester.new('/#{Regexp.escape(File.expand_path("."))}/'),
# rubocop:enable Lint/InterpolationCheck
@str_output
) do
pry
end
expect(@str_output.string).not_to match(/SyntaxError/)
end
it 'should NOT interpolate ruby code into commands if :interpolate => false' do
set = Pry::CommandSet.new do
command "hello", "", keep_retval: true, interpolate: false do |arg|
arg
end
end
# rubocop:disable Lint/InterpolationCheck
expect(pry_tester(commands: set).eval('hello #{Pad.bong}'))
.to match(/Pad\.bong/)
# rubocop:enable Lint/InterpolationCheck
end
it 'should NOT try to interpolate pure ruby code (no commands) ' do
# rubocop:disable Lint/InterpolationCheck
# These should raise RuntimeError instead of NameError
expect { pry_eval 'raise \'#{aggy}\'' }.to raise_error RuntimeError
expect { pry_eval 'raise #{aggy}' }.to raise_error RuntimeError
expect(pry_eval('format \'#{my_var}\'')).to eq "\#{my_var}"
# rubocop:enable Lint/InterpolationCheck
end
it 'should create a command with a space in its name zzz' do
set = Pry::CommandSet.new do
command "hello baby", "" do
output.puts "hello baby command"
end
end
expect(pry_tester(commands: set).eval('hello baby'))
.to match(/hello baby command/)
end
it 'should create a command with a space in its name and pass an argument' do
set = Pry::CommandSet.new do
command "hello baby", "" do |arg|
output.puts "hello baby command #{arg}"
end
end
expect(pry_tester(commands: set).eval('hello baby john'))
.to match(/hello baby command john/)
end
it 'should create a regex command and be able to invoke it' do
set = Pry::CommandSet.new do
command(/hello(.)/, "") do
c = captures.first
output.puts "hello#{c}"
end
end
expect(pry_tester(commands: set).eval('hello1')).to match(/hello1/)
end
it(
'creates a regex command and passes captures into the args list ' \
'before regular arguments'
) do
set = Pry::CommandSet.new do
command(/hello(.)/, "") do |c1, a1|
output.puts "hello #{c1} #{a1}"
end
end
expect(pry_tester(commands: set).eval('hello1 baby')).to match(/hello 1 baby/)
end
it 'should create a regex command and interpolate the captures' do
set = Pry::CommandSet.new do
command(/hello (.*)/, "") do |c1|
output.puts "hello #{c1}"
end
end
bong = "bong"
expect(pry_tester(binding, commands: set).eval("hello #{bong}"))
.to match(/hello #{bong}/)
end
it 'should create a regex command and arg_string should be interpolated' do
set = Pry::CommandSet.new do
command(/hello(\w+)/, "") do |c1, a1, a2, a3|
output.puts "hello #{c1} #{a1} #{a2} #{a3}"
end
end
bing = 'bing'
bong = 'bong'
bang = 'bang'
expect(pry_tester(binding, commands: set)
.eval("hellojohn #{bing} #{bong} #{bang}"))
.to match(/hello john #{bing} #{bong} #{bang}/)
end
it 'if a regex capture is missing it should be nil' do
set = Pry::CommandSet.new do
command(/hello(.)?/, "") do |c1, a1|
output.puts "hello #{c1.inspect} #{a1}"
end
end
expect(pry_tester(commands: set).eval('hello baby')).to match(/hello nil baby/)
end
it(
'creates a command in a nested context and that command should ' \
'be accessible from the parent'
) do
tester = pry_tester(Object.new)
expect(tester.eval(*<<-RUBY.split("\n"))).to match(/instance variables:\s+@x/m)
@x = nil
cd 7
pry_instance.commands.instance_eval { command('bing') { |arg| run arg } }
cd ..
bing ls
RUBY
end
it 'should define a command that keeps its return value' do
klass = Pry::CommandSet.new do
command "hello", "", keep_retval: true do
:kept_hello
end
end
t = pry_tester(commands: klass)
t.eval("hello\n")
expect(t.last_command_result).to eq :kept_hello
end
it 'should define a command that does NOT keep its return value' do
klass = Pry::CommandSet.new do
command "hello", "", keep_retval: false do
:kept_hello
end
end
t = pry_tester(commands: klass)
expect(t.eval("hello\n")).to eq ''
expect(t.last_command_result).to eq Pry::Command::VOID_VALUE
end
it 'should define a command that keeps its return value even when nil' do
klass = Pry::CommandSet.new do
command "hello", "", keep_retval: true do
nil
end
end
t = pry_tester(commands: klass)
t.eval("hello\n")
expect(t.last_command_result).to eq nil
end
it(
'should define a command that keeps its return value but does not ' \
'return when value is void'
) do
klass = Pry::CommandSet.new do
command "hello", "", keep_retval: true do
void
end
end
expect(pry_tester(commands: klass).eval("hello\n").empty?).to eq true
end
it(
"a command (with :keep_retval => false) that replaces eval_string with a " \
"valid expression doesn't have the expression value suppressed"
) do
klass = Pry::CommandSet.new do
command "hello", "" do
eval_string.replace("6")
end
end
redirect_pry_io(InputTester.new('def yo', 'hello'), @str_output) do
Pry.start self, commands: klass
end
expect(@str_output.string).to match(/6/)
end
it(
'a command (with :keep_retval => true) that replaces eval_string with ' \
'a valid expression overwrites the eval_string with the return value'
) do
klass = Pry::CommandSet.new do
command "hello", "", keep_retval: true do
7
end
end
expect(pry_tester(commands: klass).eval("def yo", "hello")).to eq 7
end
it(
'a command that return a value in a multi-line expression clears ' \
'the expression and return the value'
) do
klass = Pry::CommandSet.new do
command "hello", "", keep_retval: true do
5
end
end
expect(pry_tester(commands: klass).eval("def yo", "hello\n")).to eq 5
end
it 'should set the commands default, and the default should be overridable' do
klass = Pry::CommandSet.new do
command "hello" do
output.puts "hello world"
end
end
other_klass = Pry::CommandSet.new do
command "goodbye", "" do
output.puts "goodbye world"
end
end
Pry.config.commands = klass
expect(pry_tester.eval("hello")).to eq "hello world\n"
expect(pry_tester(commands: other_klass).eval("goodbye")).to eq "goodbye world\n"
end
it 'should inherit commands from Pry::Commands' do
klass = Pry::CommandSet.new Pry::Commands do
command "v" do
end
end
expect(klass.to_hash.include?("nesting")).to eq true
expect(klass.to_hash.include?("jump-to")).to eq true
expect(klass.to_hash.include?("cd")).to eq true
expect(klass.to_hash.include?("v")).to eq true
end
it 'should change description of a command using desc' do
klass = Pry::CommandSet.new do
import Pry::Commands
end
orig = klass["help"].description
klass.instance_eval do
desc "help", "blah"
end
commands = klass.to_hash
expect(commands["help"].description).not_to eq orig
expect(commands["help"].description).to eq "blah"
end
it(
'enables an inherited method to access opts, output and target, ' \
'due to instance_exec'
) do
klass = Pry::CommandSet.new do
command "v" do
output.puts target.eval('self').to_s
end
end
child_klass = Pry::CommandSet.new klass do
end
mock_pry(Pry.binding_for('john'), "v", print: proc {}, commands: child_klass,
output: @str_output)
expect(@str_output.string).to eq "john\n"
end
it 'should import commands from another command object' do
klass = Pry::CommandSet.new do
import_from Pry::Commands, "ls", "jump-to"
end
expect(klass.to_hash.include?("ls")).to eq true
expect(klass.to_hash.include?("jump-to")).to eq true
end
it 'should delete some inherited commands when using delete method' do
klass = Pry::CommandSet.new Pry::Commands do
command "v" do
end
delete "show-doc", "show-method"
delete "ls"
end
commands = klass.to_hash
expect(commands.include?("nesting")).to eq true
expect(commands.include?("jump-to")).to eq true
expect(commands.include?("cd")).to eq true
expect(commands.include?("v")).to eq true
expect(commands.include?("show-doc")).to eq false
expect(commands.include?("show-method")).to eq false
expect(commands.include?("ls")).to eq false
end
it 'should override some inherited commands' do
klass = Pry::CommandSet.new Pry::Commands do
command "jump-to" do
output.puts "jump-to the music"
end
command "help" do
output.puts "help to the music"
end
end
t = pry_tester(commands: klass)
expect(t.eval('jump-to')).to eq "jump-to the music\n"
expect(t.eval('help')).to eq "help to the music\n"
end
it 'should run a command with no parameter' do
expect(pry_tester(commands: @command_tester).eval('command1'))
.to eq "command1\n"
end
it 'should run a command with one parameter' do
expect(pry_tester(commands: @command_tester).eval('command2 horsey'))
.to eq "horsey\n"
end
end