summaryrefslogtreecommitdiff
path: root/test/irb/command
diff options
context:
space:
mode:
Diffstat (limited to 'test/irb/command')
-rw-r--r--test/irb/command/test_custom_command.rb149
-rw-r--r--test/irb/command/test_force_exit.rb51
-rw-r--r--test/irb/command/test_help.rb75
-rw-r--r--test/irb/command/test_multi_irb_commands.rb50
-rw-r--r--test/irb/command/test_show_source.rb397
5 files changed, 722 insertions, 0 deletions
diff --git a/test/irb/command/test_custom_command.rb b/test/irb/command/test_custom_command.rb
new file mode 100644
index 0000000000..3a3ad11d5a
--- /dev/null
+++ b/test/irb/command/test_custom_command.rb
@@ -0,0 +1,149 @@
+# frozen_string_literal: true
+require "irb"
+
+require_relative "../helper"
+
+module TestIRB
+ class CustomCommandIntegrationTest < TestIRB::IntegrationTestCase
+ def test_command_registration_can_happen_after_irb_require
+ write_ruby <<~RUBY
+ require "irb"
+ require "irb/command"
+
+ class PrintCommand < IRB::Command::Base
+ category 'CommandTest'
+ description 'print_command'
+ def execute(*)
+ puts "Hello from PrintCommand"
+ end
+ end
+
+ IRB::Command.register(:print!, PrintCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "print!"
+ type "exit"
+ end
+
+ assert_include(output, "Hello from PrintCommand")
+ end
+
+ def test_command_registration_accepts_string_too
+ write_ruby <<~RUBY
+ require "irb/command"
+
+ class PrintCommand < IRB::Command::Base
+ category 'CommandTest'
+ description 'print_command'
+ def execute(*)
+ puts "Hello from PrintCommand"
+ end
+ end
+
+ IRB::Command.register("print!", PrintCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "print!"
+ type "exit"
+ end
+
+ assert_include(output, "Hello from PrintCommand")
+ end
+
+ def test_arguments_propagation
+ write_ruby <<~RUBY
+ require "irb/command"
+
+ class PrintArgCommand < IRB::Command::Base
+ category 'CommandTest'
+ description 'print_command_arg'
+ def execute(arg)
+ $nth_execution ||= 0
+ puts "\#{$nth_execution} arg=\#{arg.inspect}"
+ $nth_execution += 1
+ end
+ end
+
+ IRB::Command.register(:print_arg, PrintArgCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "print_arg"
+ type "print_arg \n"
+ type "print_arg a r g"
+ type "print_arg a r g \n"
+ type "exit"
+ end
+
+ assert_include(output, "0 arg=\"\"")
+ assert_include(output, "1 arg=\"\"")
+ assert_include(output, "2 arg=\"a r g\"")
+ assert_include(output, "3 arg=\"a r g\"")
+ end
+
+ def test_def_extend_command_still_works
+ write_ruby <<~RUBY
+ require "irb"
+
+ class FooBarCommand < IRB::Command::Base
+ category 'FooBarCategory'
+ description 'foobar_description'
+ def execute(*)
+ $nth_execution ||= 1
+ puts "\#{$nth_execution} FooBar executed"
+ $nth_execution += 1
+ end
+ end
+
+ IRB::ExtendCommandBundle.def_extend_command(:foobar, FooBarCommand, nil, [:fbalias, IRB::Command::OVERRIDE_ALL])
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "foobar"
+ type "fbalias"
+ type "help foobar"
+ type "exit"
+ end
+
+ assert_include(output, "1 FooBar executed")
+ assert_include(output, "2 FooBar executed")
+ assert_include(output, "foobar_description")
+ end
+
+ def test_no_meta_command_also_works
+ write_ruby <<~RUBY
+ require "irb/command"
+
+ class NoMetaCommand < IRB::Command::Base
+ def execute(*)
+ puts "This command does not override meta attributes"
+ end
+ end
+
+ IRB::Command.register(:no_meta, NoMetaCommand)
+
+ binding.irb
+ RUBY
+
+ output = run_ruby_file do
+ type "no_meta"
+ type "help no_meta"
+ type "exit"
+ end
+
+ assert_include(output, "This command does not override meta attributes")
+ assert_include(output, "No description provided.")
+ assert_not_include(output, "Maybe IRB bug")
+ end
+ end
+end
diff --git a/test/irb/command/test_force_exit.rb b/test/irb/command/test_force_exit.rb
new file mode 100644
index 0000000000..191a786872
--- /dev/null
+++ b/test/irb/command/test_force_exit.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: false
+require 'irb'
+
+require_relative "../helper"
+
+module TestIRB
+ class ForceExitTest < IntegrationTestCase
+ def test_forced_exit_finishes_process_immediately
+ write_ruby <<~'ruby'
+ puts "First line"
+ puts "Second line"
+ binding.irb
+ puts "Third line"
+ binding.irb
+ puts "Fourth line"
+ ruby
+
+ output = run_ruby_file do
+ type "123"
+ type "456"
+ type "exit!"
+ end
+
+ assert_match(/First line\r\n/, output)
+ assert_match(/Second line\r\n/, output)
+ assert_match(/irb\(main\):001> 123/, output)
+ assert_match(/irb\(main\):002> 456/, output)
+ refute_match(/Third line\r\n/, output)
+ refute_match(/Fourth line\r\n/, output)
+ end
+
+ def test_forced_exit_in_nested_sessions
+ write_ruby <<~'ruby'
+ def foo
+ binding.irb
+ end
+
+ binding.irb
+ binding.irb
+ ruby
+
+ output = run_ruby_file do
+ type "123"
+ type "foo"
+ type "exit!"
+ end
+
+ assert_match(/irb\(main\):001> 123/, output)
+ end
+ end
+end
diff --git a/test/irb/command/test_help.rb b/test/irb/command/test_help.rb
new file mode 100644
index 0000000000..b34832b022
--- /dev/null
+++ b/test/irb/command/test_help.rb
@@ -0,0 +1,75 @@
+require "tempfile"
+require_relative "../helper"
+
+module TestIRB
+ class HelpTest < IntegrationTestCase
+ def setup
+ super
+
+ write_rc <<~'RUBY'
+ IRB.conf[:USE_PAGER] = false
+ RUBY
+
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+ end
+
+ def test_help
+ out = run_ruby_file do
+ type "help"
+ type "exit"
+ end
+
+ assert_match(/List all available commands/, out)
+ assert_match(/Start the debugger of debug\.gem/, out)
+ end
+
+ def test_command_help
+ out = run_ruby_file do
+ type "help ls"
+ type "exit"
+ end
+
+ assert_match(/Usage: ls \[obj\]/, out)
+ end
+
+ def test_command_help_not_found
+ out = run_ruby_file do
+ type "help foo"
+ type "exit"
+ end
+
+ assert_match(/Can't find command `foo`\. Please check the command name and try again\./, out)
+ end
+
+ def test_show_cmds
+ out = run_ruby_file do
+ type "help"
+ type "exit"
+ end
+
+ assert_match(/List all available commands/, out)
+ assert_match(/Start the debugger of debug\.gem/, out)
+ end
+
+ def test_help_lists_user_aliases
+ out = run_ruby_file do
+ type "help"
+ type "exit"
+ end
+
+ assert_match(/\$\s+Alias for `show_source`/, out)
+ assert_match(/@\s+Alias for `whereami`/, out)
+ end
+
+ def test_help_lists_helper_methods
+ out = run_ruby_file do
+ type "help"
+ type "exit"
+ end
+
+ assert_match(/Helper methods\s+conf\s+Returns the current IRB context/, out)
+ end
+ end
+end
diff --git a/test/irb/command/test_multi_irb_commands.rb b/test/irb/command/test_multi_irb_commands.rb
new file mode 100644
index 0000000000..e313c0c5d2
--- /dev/null
+++ b/test/irb/command/test_multi_irb_commands.rb
@@ -0,0 +1,50 @@
+require "tempfile"
+require_relative "../helper"
+
+module TestIRB
+ class MultiIRBTest < IntegrationTestCase
+ def setup
+ super
+
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+ end
+
+ def test_jobs_command_with_print_deprecated_warning
+ out = run_ruby_file do
+ type "jobs"
+ type "exit"
+ end
+
+ assert_match(/Multi-irb commands are deprecated and will be removed in IRB 2\.0\.0\. Please use workspace commands instead\./, out)
+ assert_match(%r|If you have any use case for multi-irb, please leave a comment at https://github.com/ruby/irb/issues/653|, out)
+ assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out)
+ end
+
+ def test_irb_jobs_and_kill_commands
+ out = run_ruby_file do
+ type "irb"
+ type "jobs"
+ type "kill 1"
+ type "exit"
+ end
+
+ assert_match(/#0->irb on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out)
+ assert_match(/#1->irb#1 on main \(#<Thread:0x.+ run>: running\)/, out)
+ end
+
+ def test_irb_fg_jobs_and_kill_commands
+ out = run_ruby_file do
+ type "irb"
+ type "fg 0"
+ type "jobs"
+ type "kill 1"
+ type "exit"
+ end
+
+ assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out)
+ assert_match(/#1->irb#1 on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out)
+ end
+ end
+end
diff --git a/test/irb/command/test_show_source.rb b/test/irb/command/test_show_source.rb
new file mode 100644
index 0000000000..d014c78fc4
--- /dev/null
+++ b/test/irb/command/test_show_source.rb
@@ -0,0 +1,397 @@
+# frozen_string_literal: false
+require 'irb'
+
+require_relative "../helper"
+
+module TestIRB
+ class ShowSourceTest < IntegrationTestCase
+ def setup
+ super
+
+ write_rc <<~'RUBY'
+ IRB.conf[:USE_PAGER] = false
+ RUBY
+ end
+
+ def test_show_source
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source IRB.conf"
+ type "exit"
+ end
+
+ assert_match(%r[/irb\/init\.rb], out)
+ end
+
+ def test_show_source_alias
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "$ IRB.conf"
+ type "exit"
+ end
+
+ assert_match(%r[/irb\/init\.rb], out)
+ end
+
+ def test_show_source_with_missing_signature
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source foo"
+ type "exit"
+ end
+
+ assert_match(%r[Couldn't locate a definition for foo], out)
+ end
+
+ def test_show_source_with_missing_constant
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Foo"
+ type "exit"
+ end
+
+ assert_match(%r[Couldn't locate a definition for Foo], out)
+ end
+
+ def test_show_source_string
+ write_ruby <<~'RUBY'
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source 'IRB.conf'"
+ type "exit"
+ end
+
+ assert_match(%r[/irb\/init\.rb], out)
+ end
+
+ def test_show_source_method_s
+ write_ruby <<~RUBY
+ class Baz
+ def foo
+ end
+ end
+
+ class Bar < Baz
+ def foo
+ super
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Bar#foo -s"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end\r\n], out)
+ end
+
+ def test_show_source_method_s_with_incorrect_signature
+ write_ruby <<~RUBY
+ class Baz
+ def foo
+ end
+ end
+
+ class Bar < Baz
+ def foo
+ super
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Bar#fooo -s"
+ type "exit"
+ end
+
+ assert_match(%r[Error: Couldn't locate a super definition for Bar#fooo], out)
+ end
+
+ def test_show_source_private_method
+ write_ruby <<~RUBY
+ class Bar
+ private def foo
+ end
+ end
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Bar#foo"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:2\s+private def foo\r\n end\r\n], out)
+ end
+
+ def test_show_source_private_singleton_method
+ write_ruby <<~RUBY
+ class Bar
+ private def foo
+ end
+ end
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "bar = Bar.new"
+ type "show_source bar.foo"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:2\s+private def foo\r\n end\r\n], out)
+ end
+
+ def test_show_source_method_multiple_s
+ write_ruby <<~RUBY
+ class Baz
+ def foo
+ end
+ end
+
+ class Bar < Baz
+ def foo
+ super
+ end
+ end
+
+ class Bob < Bar
+ def foo
+ super
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Bob#foo -ss"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end\r\n], out)
+ end
+
+ def test_show_source_method_no_instance_method
+ write_ruby <<~RUBY
+ class Baz
+ end
+
+ class Bar < Baz
+ def foo
+ super
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Bar#foo -s"
+ type "exit"
+ end
+
+ assert_match(%r[Error: Couldn't locate a super definition for Bar#foo], out)
+ end
+
+ def test_show_source_method_exceeds_super_chain
+ write_ruby <<~RUBY
+ class Baz
+ def foo
+ end
+ end
+
+ class Bar < Baz
+ def foo
+ super
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Bar#foo -ss"
+ type "exit"
+ end
+
+ assert_match(%r[Error: Couldn't locate a super definition for Bar#foo], out)
+ end
+
+ def test_show_source_method_accidental_characters
+ write_ruby <<~'RUBY'
+ class Baz
+ def foo
+ end
+ end
+
+ class Bar < Baz
+ def foo
+ super
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source Bar#foo -sddddd"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end], out)
+ end
+
+ def test_show_source_receiver_super
+ write_ruby <<~RUBY
+ class Baz
+ def foo
+ end
+ end
+
+ class Bar < Baz
+ def foo
+ super
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "bar = Bar.new"
+ type "show_source bar.foo -s"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:2\s+def foo\r\n end], out)
+ end
+
+ def test_show_source_with_double_colons
+ write_ruby <<~RUBY
+ class Foo
+ end
+
+ class Foo
+ class Bar
+ end
+ end
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source ::Foo"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:1\s+class Foo\r\nend], out)
+
+ out = run_ruby_file do
+ type "show_source ::Foo::Bar"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:5\s+class Bar\r\n end], out)
+ end
+
+ def test_show_source_keep_script_lines
+ pend unless defined?(RubyVM.keep_script_lines)
+
+ write_ruby <<~RUBY
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "def foo; end"
+ type "show_source foo"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}\(irb\):1\s+def foo; end], out)
+ end
+
+ def test_show_source_unavailable_source
+ write_ruby <<~RUBY
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ type "RubyVM.keep_script_lines = false if defined?(RubyVM.keep_script_lines)"
+ type "def foo; end"
+ type "show_source foo"
+ type "exit"
+ end
+ assert_match(%r[#{@ruby_file.to_path}\(irb\):2\s+Source not available], out)
+ end
+
+ def test_show_source_shows_binary_source
+ write_ruby <<~RUBY
+ # io-console is an indirect dependency of irb
+ require "io/console"
+
+ binding.irb
+ RUBY
+
+ out = run_ruby_file do
+ # IO::ConsoleMode is defined in io-console gem's C extension
+ type "show_source IO::ConsoleMode"
+ type "exit"
+ end
+
+ # A safeguard to make sure the test subject is actually defined
+ refute_match(/NameError/, out)
+ assert_match(%r[Defined in binary file:.+io/console], out)
+ end
+
+ def test_show_source_with_constant_lookup
+ write_ruby <<~RUBY
+ X = 1
+ module M
+ Y = 1
+ Z = 2
+ end
+ class A
+ Z = 1
+ Array = 1
+ class B
+ include M
+ Object.new.instance_eval { binding.irb }
+ end
+ end
+ RUBY
+
+ out = run_ruby_file do
+ type "show_source X"
+ type "show_source Y"
+ type "show_source Z"
+ type "show_source Array"
+ type "exit"
+ end
+
+ assert_match(%r[#{@ruby_file.to_path}:1\s+X = 1], out)
+ assert_match(%r[#{@ruby_file.to_path}:3\s+Y = 1], out)
+ assert_match(%r[#{@ruby_file.to_path}:7\s+Z = 1], out)
+ assert_match(%r[#{@ruby_file.to_path}:8\s+Array = 1], out)
+ end
+ end
+end