diff options
Diffstat (limited to 'test/irb')
25 files changed, 0 insertions, 7128 deletions
diff --git a/test/irb/command/test_force_exit.rb b/test/irb/command/test_force_exit.rb deleted file mode 100644 index 9e86c644d6..0000000000 --- a/test/irb/command/test_force_exit.rb +++ /dev/null @@ -1,63 +0,0 @@ -# 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 - - def test_forced_exit_out_of_irb_session - write_ruby <<~'ruby' - at_exit { puts 'un' + 'reachable' } - binding.irb - exit! # this will call exit! method overrided by command - ruby - output = run_ruby_file do - type "exit" - end - assert_not_include(output, 'unreachable') - end - end -end diff --git a/test/irb/command/test_help.rb b/test/irb/command/test_help.rb deleted file mode 100644 index c82c43a4c5..0000000000 --- a/test/irb/command/test_help.rb +++ /dev/null @@ -1,66 +0,0 @@ -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 - end -end diff --git a/test/irb/command/test_show_source.rb b/test/irb/command/test_show_source.rb deleted file mode 100644 index d014c78fc4..0000000000 --- a/test/irb/command/test_show_source.rb +++ /dev/null @@ -1,397 +0,0 @@ -# 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 diff --git a/test/irb/helper.rb b/test/irb/helper.rb deleted file mode 100644 index 1614b42adb..0000000000 --- a/test/irb/helper.rb +++ /dev/null @@ -1,219 +0,0 @@ -require "test/unit" -require "pathname" -require "rubygems" - -begin - require_relative "../lib/helper" - require_relative "../lib/envutil" -rescue LoadError # ruby/ruby defines helpers differently -end - -begin - require "pty" -rescue LoadError # some platforms don't support PTY -end - -module IRB - class InputMethod; end -end - -module TestIRB - RUBY_3_4 = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0.dev") - class TestCase < Test::Unit::TestCase - class TestInputMethod < ::IRB::InputMethod - attr_reader :list, :line_no - - def initialize(list = []) - @line_no = 0 - @list = list - end - - def gets - @list[@line_no]&.tap {@line_no += 1} - end - - def eof? - @line_no >= @list.size - end - - def encoding - Encoding.default_external - end - - def reset - @line_no = 0 - end - end - - def ruby_core? - !Pathname(__dir__).join("../../", "irb.gemspec").exist? - end - - def save_encodings - @default_encoding = [Encoding.default_external, Encoding.default_internal] - @stdio_encodings = [STDIN, STDOUT, STDERR].map {|io| [io.external_encoding, io.internal_encoding] } - end - - def restore_encodings - EnvUtil.suppress_warning do - Encoding.default_external, Encoding.default_internal = *@default_encoding - [STDIN, STDOUT, STDERR].zip(@stdio_encodings) do |io, encs| - io.set_encoding(*encs) - end - end - end - - def without_rdoc(&block) - ::Kernel.send(:alias_method, :irb_original_require, :require) - - ::Kernel.define_method(:require) do |name| - raise LoadError, "cannot load such file -- rdoc (test)" if name.match?("rdoc") || name.match?(/^rdoc\/.*/) - ::Kernel.send(:irb_original_require, name) - end - - yield - ensure - EnvUtil.suppress_warning { - ::Kernel.send(:alias_method, :require, :irb_original_require) - ::Kernel.undef_method :irb_original_require - } - end - end - - class IntegrationTestCase < TestCase - LIB = File.expand_path("../../lib", __dir__) - TIMEOUT_SEC = 3 - - def setup - @envs = {} - @tmpfiles = [] - - unless defined?(PTY) - omit "Integration tests require PTY." - end - - if ruby_core? - omit "This test works only under ruby/irb" - end - - write_rc <<~RUBY - IRB.conf[:USE_PAGER] = false - RUBY - end - - def teardown - @tmpfiles.each do |tmpfile| - File.unlink(tmpfile) - end - end - - def run_ruby_file(&block) - cmd = [EnvUtil.rubybin, "-I", LIB, @ruby_file.to_path] - tmp_dir = Dir.mktmpdir - - @commands = [] - lines = [] - - yield - - # Test should not depend on user's irbrc file - @envs["HOME"] ||= tmp_dir - @envs["XDG_CONFIG_HOME"] ||= tmp_dir - @envs["IRBRC"] = nil unless @envs.key?("IRBRC") - - PTY.spawn(@envs.merge("TERM" => "dumb"), *cmd) do |read, write, pid| - Timeout.timeout(TIMEOUT_SEC) do - while line = safe_gets(read) - lines << line - - # means the breakpoint is triggered - if line.match?(/binding\.irb/) - while command = @commands.shift - write.puts(command) - end - end - end - end - ensure - read.close - write.close - kill_safely(pid) - end - - lines.join - rescue Timeout::Error - message = <<~MSG - Test timedout. - - #{'=' * 30} OUTPUT #{'=' * 30} - #{lines.map { |l| " #{l}" }.join} - #{'=' * 27} END OF OUTPUT #{'=' * 27} - MSG - assert_block(message) { false } - ensure - FileUtils.remove_entry tmp_dir - end - - # read.gets could raise exceptions on some platforms - # https://github.com/ruby/ruby/blob/master/ext/pty/pty.c#L721-L728 - def safe_gets(read) - read.gets - rescue Errno::EIO - nil - end - - def kill_safely pid - return if wait_pid pid, TIMEOUT_SEC - - Process.kill :TERM, pid - return if wait_pid pid, 0.2 - - Process.kill :KILL, pid - Process.waitpid(pid) - rescue Errno::EPERM, Errno::ESRCH - end - - def wait_pid pid, sec - total_sec = 0.0 - wait_sec = 0.001 # 1ms - - while total_sec < sec - if Process.waitpid(pid, Process::WNOHANG) == pid - return true - end - sleep wait_sec - total_sec += wait_sec - wait_sec *= 2 - end - - false - rescue Errno::ECHILD - true - end - - def type(command) - @commands << command - end - - def write_ruby(program) - @ruby_file = Tempfile.create(%w{irb- .rb}) - @tmpfiles << @ruby_file - @ruby_file.write(program) - @ruby_file.close - end - - def write_rc(content) - # Append irbrc content if a tempfile for it already exists - if @irbrc - @irbrc = File.open(@irbrc, "a") - else - @irbrc = Tempfile.new('irbrc') - @tmpfiles << @irbrc - end - - @irbrc.write(content) - @irbrc.close - @envs['IRBRC'] = @irbrc.path - end - end -end diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb deleted file mode 100644 index 72e036eab7..0000000000 --- a/test/irb/test_color.rb +++ /dev/null @@ -1,274 +0,0 @@ -# frozen_string_literal: false -require 'irb/color' -require 'stringio' - -require_relative "helper" - -module TestIRB - class ColorTest < TestCase - CLEAR = "\e[0m" - BOLD = "\e[1m" - UNDERLINE = "\e[4m" - REVERSE = "\e[7m" - RED = "\e[31m" - GREEN = "\e[32m" - YELLOW = "\e[33m" - BLUE = "\e[34m" - MAGENTA = "\e[35m" - CYAN = "\e[36m" - - def setup - super - if IRB.respond_to?(:conf) - @colorize, IRB.conf[:USE_COLORIZE] = IRB.conf[:USE_COLORIZE], true - end - end - - def teardown - if instance_variable_defined?(:@colorize) - IRB.conf[:USE_COLORIZE] = @colorize - end - super - end - - def test_colorize - text = "text" - { - [:BOLD] => "#{BOLD}#{text}#{CLEAR}", - [:UNDERLINE] => "#{UNDERLINE}#{text}#{CLEAR}", - [:REVERSE] => "#{REVERSE}#{text}#{CLEAR}", - [:RED] => "#{RED}#{text}#{CLEAR}", - [:GREEN] => "#{GREEN}#{text}#{CLEAR}", - [:YELLOW] => "#{YELLOW}#{text}#{CLEAR}", - [:BLUE] => "#{BLUE}#{text}#{CLEAR}", - [:MAGENTA] => "#{MAGENTA}#{text}#{CLEAR}", - [:CYAN] => "#{CYAN}#{text}#{CLEAR}", - }.each do |seq, result| - assert_equal_with_term(result, text, seq: seq) - - assert_equal_with_term(text, text, seq: seq, tty: false) - assert_equal_with_term(text, text, seq: seq, colorable: false) - assert_equal_with_term(result, text, seq: seq, tty: false, colorable: true) - end - end - - def test_colorize_code - # Common behaviors. Warn parser error, but do not warn compile error. - tests = { - "1" => "#{BLUE}#{BOLD}1#{CLEAR}", - "2.3" => "#{MAGENTA}#{BOLD}2.3#{CLEAR}", - "7r" => "#{BLUE}#{BOLD}7r#{CLEAR}", - "8i" => "#{BLUE}#{BOLD}8i#{CLEAR}", - "['foo', :bar]" => "[#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}#{BOLD}'#{CLEAR}, #{YELLOW}:#{CLEAR}#{YELLOW}bar#{CLEAR}]", - "class A; end" => "#{GREEN}class#{CLEAR} #{BLUE}#{BOLD}#{UNDERLINE}A#{CLEAR}; #{GREEN}end#{CLEAR}", - "def self.foo; bar; end" => "#{GREEN}def#{CLEAR} #{CYAN}#{BOLD}self#{CLEAR}.#{BLUE}#{BOLD}foo#{CLEAR}; bar; #{GREEN}end#{CLEAR}", - 'erb = ERB.new("a#{nil}b", trim_mode: "-")' => "erb = #{BLUE}#{BOLD}#{UNDERLINE}ERB#{CLEAR}.new(#{RED}#{BOLD}\"#{CLEAR}#{RED}a#{CLEAR}#{RED}\#{#{CLEAR}#{CYAN}#{BOLD}nil#{CLEAR}#{RED}}#{CLEAR}#{RED}b#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}, #{MAGENTA}trim_mode:#{CLEAR} #{RED}#{BOLD}\"#{CLEAR}#{RED}-#{CLEAR}#{RED}#{BOLD}\"#{CLEAR})", - "# comment" => "#{BLUE}#{BOLD}# comment#{CLEAR}", - "def f;yield(hello);end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}f#{CLEAR};#{GREEN}yield#{CLEAR}(hello);#{GREEN}end#{CLEAR}", - '"##@var]"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}\##{CLEAR}#{RED}\##{CLEAR}@var#{RED}]#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}", - '"foo#{a} #{b}"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}foo#{CLEAR}#{RED}\#{#{CLEAR}a#{RED}}#{CLEAR}#{RED} #{CLEAR}#{RED}\#{#{CLEAR}b#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}", - '/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e#{RED}}#{CLEAR}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}", - "'a\nb'" => "#{RED}#{BOLD}'#{CLEAR}#{RED}a#{CLEAR}\n#{RED}b#{CLEAR}#{RED}#{BOLD}'#{CLEAR}", - "%[str]" => "#{RED}#{BOLD}%[#{CLEAR}#{RED}str#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "%Q[str]" => "#{RED}#{BOLD}%Q[#{CLEAR}#{RED}str#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "%q[str]" => "#{RED}#{BOLD}%q[#{CLEAR}#{RED}str#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "%x[cmd]" => "#{RED}#{BOLD}%x[#{CLEAR}#{RED}cmd#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "%r[reg]" => "#{RED}#{BOLD}%r[#{CLEAR}#{RED}reg#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "%w[a b]" => "#{RED}#{BOLD}%w[#{CLEAR}#{RED}a#{CLEAR} #{RED}b#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "%W[a b]" => "#{RED}#{BOLD}%W[#{CLEAR}#{RED}a#{CLEAR} #{RED}b#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "%s[a b]" => "#{YELLOW}%s[#{CLEAR}#{YELLOW}a b#{CLEAR}#{YELLOW}]#{CLEAR}", - "%i[c d]" => "#{YELLOW}%i[#{CLEAR}#{YELLOW}c#{CLEAR}#{YELLOW} #{CLEAR}#{YELLOW}d#{CLEAR}#{YELLOW}]#{CLEAR}", - "%I[c d]" => "#{YELLOW}%I[#{CLEAR}#{YELLOW}c#{CLEAR}#{YELLOW} #{CLEAR}#{YELLOW}d#{CLEAR}#{YELLOW}]#{CLEAR}", - "{'a': 1}" => "{#{RED}#{BOLD}'#{CLEAR}#{RED}a#{CLEAR}#{RED}#{BOLD}':#{CLEAR} #{BLUE}#{BOLD}1#{CLEAR}}", - ":Struct" => "#{YELLOW}:#{CLEAR}#{YELLOW}Struct#{CLEAR}", - '"#{}"' => "#{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR}#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}", - ':"a#{}b"' => "#{YELLOW}:\"#{CLEAR}#{YELLOW}a#{CLEAR}#{YELLOW}\#{#{CLEAR}#{YELLOW}}#{CLEAR}#{YELLOW}b#{CLEAR}#{YELLOW}\"#{CLEAR}", - ':"a#{ def b; end; \'c\' + "#{ :d }" }e"' => "#{YELLOW}:\"#{CLEAR}#{YELLOW}a#{CLEAR}#{YELLOW}\#{#{CLEAR} #{GREEN}def#{CLEAR} #{BLUE}#{BOLD}b#{CLEAR}; #{GREEN}end#{CLEAR}; #{RED}#{BOLD}'#{CLEAR}#{RED}c#{CLEAR}#{RED}#{BOLD}'#{CLEAR} + #{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR} #{YELLOW}:#{CLEAR}#{YELLOW}d#{CLEAR} #{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR} #{YELLOW}}#{CLEAR}#{YELLOW}e#{CLEAR}#{YELLOW}\"#{CLEAR}", - "[__FILE__, __LINE__, __ENCODING__]" => "[#{CYAN}#{BOLD}__FILE__#{CLEAR}, #{CYAN}#{BOLD}__LINE__#{CLEAR}, #{CYAN}#{BOLD}__ENCODING__#{CLEAR}]", - ":self" => "#{YELLOW}:#{CLEAR}#{YELLOW}self#{CLEAR}", - ":class" => "#{YELLOW}:#{CLEAR}#{YELLOW}class#{CLEAR}", - "[:end, 2]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}end#{CLEAR}, #{BLUE}#{BOLD}2#{CLEAR}]", - "[:>, 3]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}>#{CLEAR}, #{BLUE}#{BOLD}3#{CLEAR}]", - "[:`, 4]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}`#{CLEAR}, #{BLUE}#{BOLD}4#{CLEAR}]", - ":Hello ? world : nil" => "#{YELLOW}:#{CLEAR}#{YELLOW}Hello#{CLEAR} ? world : #{CYAN}#{BOLD}nil#{CLEAR}", - 'raise "foo#{bar}baz"' => "raise #{RED}#{BOLD}\"#{CLEAR}#{RED}foo#{CLEAR}#{RED}\#{#{CLEAR}bar#{RED}}#{CLEAR}#{RED}baz#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}", - '["#{obj.inspect}"]' => "[#{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR}obj.inspect#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}]", - 'URI.parse "#{}"' => "#{BLUE}#{BOLD}#{UNDERLINE}URI#{CLEAR}.parse #{RED}#{BOLD}\"#{CLEAR}#{RED}\#{#{CLEAR}#{RED}}#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}", - "begin\nrescue\nend" => "#{GREEN}begin#{CLEAR}\n#{GREEN}rescue#{CLEAR}\n#{GREEN}end#{CLEAR}", - "foo %w[bar]" => "foo #{RED}#{BOLD}%w[#{CLEAR}#{RED}bar#{CLEAR}#{RED}#{BOLD}]#{CLEAR}", - "foo %i[bar]" => "foo #{YELLOW}%i[#{CLEAR}#{YELLOW}bar#{CLEAR}#{YELLOW}]#{CLEAR}", - "foo :@bar, baz, :@@qux, :$quux" => "foo #{YELLOW}:#{CLEAR}#{YELLOW}@bar#{CLEAR}, baz, #{YELLOW}:#{CLEAR}#{YELLOW}@@qux#{CLEAR}, #{YELLOW}:#{CLEAR}#{YELLOW}$quux#{CLEAR}", - "`echo`" => "#{RED}#{BOLD}`#{CLEAR}#{RED}echo#{CLEAR}#{RED}#{BOLD}`#{CLEAR}", - "\t" => "\t", # not ^I - "foo(*%W(bar))" => "foo(*#{RED}#{BOLD}%W(#{CLEAR}#{RED}bar#{CLEAR}#{RED}#{BOLD})#{CLEAR})", - "$stdout" => "#{GREEN}#{BOLD}$stdout#{CLEAR}", - "__END__" => "#{GREEN}__END__#{CLEAR}", - "foo\n__END__\nbar" => "foo\n#{GREEN}__END__#{CLEAR}\nbar", - "foo\n<<A\0\0bar\nA\nbaz" => "foo\n#{RED}<<A#{CLEAR}^@^@bar\n#{RED}A#{CLEAR}\nbaz", - "<<A+1\nA" => "#{RED}<<A#{CLEAR}+#{BLUE}#{BOLD}1#{CLEAR}\n#{RED}A#{CLEAR}", - } - - tests.merge!({ - "4.5.6" => "#{MAGENTA}#{BOLD}4.5#{CLEAR}#{RED}#{REVERSE}.6#{CLEAR}", - "\e[0m\n" => "#{RED}#{REVERSE}^[#{CLEAR}[#{BLUE}#{BOLD}0#{CLEAR}#{RED}#{REVERSE}m#{CLEAR}\n", - "<<EOS\nhere\nEOS" => "#{RED}<<EOS#{CLEAR}\n#{RED}here#{CLEAR}\n#{RED}EOS#{CLEAR}", - }) - - # specific to Ruby 3.0+ - if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') - tests.merge!({ - "[1]]]\u0013" => "[#{BLUE}#{BOLD}1#{CLEAR}]#{RED}#{REVERSE}]#{CLEAR}#{RED}#{REVERSE}]#{CLEAR}#{RED}#{REVERSE}^S#{CLEAR}", - }) - tests.merge!({ - "def req(true) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}true#{CLEAR}) #{RED}#{REVERSE}end#{CLEAR}", - "nil = 1" => "#{RED}#{REVERSE}nil#{CLEAR} = #{BLUE}#{BOLD}1#{CLEAR}", - "alias $x $1" => "#{GREEN}alias#{CLEAR} #{GREEN}#{BOLD}$x#{CLEAR} #{RED}#{REVERSE}$1#{CLEAR}", - "class bad; end" => "#{GREEN}class#{CLEAR} #{RED}#{REVERSE}bad#{CLEAR}; #{GREEN}end#{CLEAR}", - "def req(@a) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}@a#{CLEAR}) #{GREEN}end#{CLEAR}", - }) - if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.2.0') - tests.merge!({ - "def req(true) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}true#{CLEAR}#{RED}#{REVERSE})#{CLEAR} #{RED}#{REVERSE}end#{CLEAR}", - }) - end - else - tests.merge!({ - "[1]]]\u0013" => "[#{BLUE}#{BOLD}1#{CLEAR}]#{RED}#{REVERSE}]#{CLEAR}]^S", - "def req(true) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}true#{CLEAR}) end", - "nil = 1" => "#{CYAN}#{BOLD}nil#{CLEAR} = #{BLUE}#{BOLD}1#{CLEAR}", - "alias $x $1" => "#{GREEN}alias#{CLEAR} #{GREEN}#{BOLD}$x#{CLEAR} $1", - "class bad; end" => "#{GREEN}class#{CLEAR} bad; #{GREEN}end#{CLEAR}", - "def req(@a) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(@a) #{GREEN}end#{CLEAR}", - }) - end - - tests.each do |code, result| - assert_equal_with_term(result, code, complete: true) - assert_equal_with_term(result, code, complete: false) - - assert_equal_with_term(code, code, complete: true, tty: false) - assert_equal_with_term(code, code, complete: false, tty: false) - - assert_equal_with_term(code, code, complete: true, colorable: false) - - assert_equal_with_term(code, code, complete: false, colorable: false) - - assert_equal_with_term(result, code, complete: true, tty: false, colorable: true) - - assert_equal_with_term(result, code, complete: false, tty: false, colorable: true) - end - end - - def test_colorize_code_with_local_variables - code = "a /(b +1)/i" - result_without_lvars = "a #{RED}#{BOLD}/#{CLEAR}#{RED}(b +1)#{CLEAR}#{RED}#{BOLD}/i#{CLEAR}" - result_with_lvar = "a /(b #{BLUE}#{BOLD}+1#{CLEAR})/i" - result_with_lvars = "a /(b +#{BLUE}#{BOLD}1#{CLEAR})/i" - - assert_equal_with_term(result_without_lvars, code) - assert_equal_with_term(result_with_lvar, code, local_variables: ['a']) - assert_equal_with_term(result_with_lvars, code, local_variables: ['a', 'b']) - end - - def test_colorize_code_complete_true - # `complete: true` behaviors. Warn end-of-file. - { - "'foo' + 'bar" => "#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}#{BOLD}'#{CLEAR} + #{RED}#{BOLD}'#{CLEAR}#{RED}#{REVERSE}bar#{CLEAR}", - "('foo" => "(#{RED}#{BOLD}'#{CLEAR}#{RED}#{REVERSE}foo#{CLEAR}", - }.each do |code, result| - assert_equal_with_term(result, code, complete: true) - - assert_equal_with_term(code, code, complete: true, tty: false) - - assert_equal_with_term(code, code, complete: true, colorable: false) - - assert_equal_with_term(result, code, complete: true, tty: false, colorable: true) - end - end - - def test_colorize_code_complete_false - # `complete: false` behaviors. Do not warn end-of-file. - { - "'foo' + 'bar" => "#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}#{BOLD}'#{CLEAR} + #{RED}#{BOLD}'#{CLEAR}#{RED}bar#{CLEAR}", - "('foo" => "(#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}", - }.each do |code, result| - assert_equal_with_term(result, code, complete: false) - - assert_equal_with_term(code, code, complete: false, tty: false) - - assert_equal_with_term(code, code, complete: false, colorable: false) - - assert_equal_with_term(result, code, complete: false, tty: false, colorable: true) - end - end - - def test_inspect_colorable - { - 1 => true, - 2.3 => true, - ['foo', :bar] => true, - (a = []; a << a; a) => false, - (h = {}; h[h] = h; h) => false, - { a: 4 } => true, - /reg/ => true, - (1..3) => true, - Object.new => false, - Struct => true, - Test => true, - Struct.new(:a) => false, - Struct.new(:a).new(1) => false, - }.each do |object, result| - assert_equal(result, IRB::Color.inspect_colorable?(object), "Case: inspect_colorable?(#{object.inspect})") - end - end - - private - - def with_term(tty: true) - stdout = $stdout - io = StringIO.new - def io.tty?; true; end if tty - $stdout = io - - env = ENV.to_h.dup - ENV['TERM'] = 'xterm-256color' - - yield - ensure - $stdout = stdout - ENV.replace(env) if env - end - - def assert_equal_with_term(result, code, seq: nil, tty: true, **opts) - actual = with_term(tty: tty) do - if seq - IRB::Color.colorize(code, seq, **opts) - else - IRB::Color.colorize_code(code, **opts) - end - end - message = -> { - args = [code.dump] - args << seq.inspect if seq - opts.each {|kwd, val| args << "#{kwd}: #{val}"} - "Case: colorize#{seq ? "" : "_code"}(#{args.join(', ')})\nResult: #{humanized_literal(actual)}" - } - assert_equal(result, actual, message) - end - - def humanized_literal(str) - str - .gsub(CLEAR, '@@@{CLEAR}') - .gsub(BOLD, '@@@{BOLD}') - .gsub(UNDERLINE, '@@@{UNDERLINE}') - .gsub(REVERSE, '@@@{REVERSE}') - .gsub(RED, '@@@{RED}') - .gsub(GREEN, '@@@{GREEN}') - .gsub(YELLOW, '@@@{YELLOW}') - .gsub(BLUE, '@@@{BLUE}') - .gsub(MAGENTA, '@@@{MAGENTA}') - .gsub(CYAN, '@@@{CYAN}') - .dump.gsub(/@@@/, '#') - end - end -end diff --git a/test/irb/test_color_printer.rb b/test/irb/test_color_printer.rb deleted file mode 100644 index c2c624d868..0000000000 --- a/test/irb/test_color_printer.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: false -require 'irb/color_printer' -require 'stringio' - -require_relative "helper" - -module TestIRB - class ColorPrinterTest < TestCase - CLEAR = "\e[0m" - BOLD = "\e[1m" - RED = "\e[31m" - GREEN = "\e[32m" - BLUE = "\e[34m" - CYAN = "\e[36m" - - def setup - super - if IRB.respond_to?(:conf) - @colorize, IRB.conf[:USE_COLORIZE] = IRB.conf[:USE_COLORIZE], true - end - @get_screen_size = Reline.method(:get_screen_size) - Reline.instance_eval { undef :get_screen_size } - def Reline.get_screen_size - [36, 80] - end - end - - def teardown - Reline.instance_eval { undef :get_screen_size } - Reline.define_singleton_method(:get_screen_size, @get_screen_size) - if instance_variable_defined?(:@colorize) - IRB.conf[:USE_COLORIZE] = @colorize - end - super - end - - IRBTestColorPrinter = Struct.new(:a) - - def test_color_printer - { - 1 => "#{BLUE}#{BOLD}1#{CLEAR}\n", - "a\nb" => %[#{RED}#{BOLD}"#{CLEAR}#{RED}a\\nb#{CLEAR}#{RED}#{BOLD}"#{CLEAR}\n], - IRBTestColorPrinter.new('test') => "#{GREEN}#<struct TestIRB::ColorPrinterTest::IRBTestColorPrinter#{CLEAR} a#{GREEN}=#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}#{RED}test#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}#{GREEN}>#{CLEAR}\n", - Ripper::Lexer.new('1').scan => "[#{GREEN}#<Ripper::Lexer::Elem:#{CLEAR} on_int@1:0 END token: #{RED}#{BOLD}\"#{CLEAR}#{RED}1#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}#{GREEN}>#{CLEAR}]\n", - Class.new{define_method(:pretty_print){|q| q.text("[__FILE__, __LINE__, __ENCODING__]")}}.new => "[#{CYAN}#{BOLD}__FILE__#{CLEAR}, #{CYAN}#{BOLD}__LINE__#{CLEAR}, #{CYAN}#{BOLD}__ENCODING__#{CLEAR}]\n", - }.each do |object, result| - actual = with_term { IRB::ColorPrinter.pp(object, '') } - assert_equal(result, actual, "Case: IRB::ColorPrinter.pp(#{object.inspect}, '')") - end - end - - private - - def with_term - stdout = $stdout - io = StringIO.new - def io.tty?; true; end - $stdout = io - - env = ENV.to_h.dup - ENV['TERM'] = 'xterm-256color' - - yield - ensure - $stdout = stdout - ENV.replace(env) if env - end - end -end diff --git a/test/irb/test_command.rb b/test/irb/test_command.rb deleted file mode 100644 index 03fdd37855..0000000000 --- a/test/irb/test_command.rb +++ /dev/null @@ -1,1043 +0,0 @@ -# frozen_string_literal: false -require "irb" - -require_relative "helper" - -module TestIRB - class CommandTestCase < TestCase - def setup - @pwd = Dir.pwd - @tmpdir = File.join(Dir.tmpdir, "test_reline_config_#{$$}") - begin - Dir.mkdir(@tmpdir) - rescue Errno::EEXIST - FileUtils.rm_rf(@tmpdir) - Dir.mkdir(@tmpdir) - end - Dir.chdir(@tmpdir) - @home_backup = ENV["HOME"] - ENV["HOME"] = @tmpdir - @xdg_config_home_backup = ENV.delete("XDG_CONFIG_HOME") - save_encodings - IRB.instance_variable_get(:@CONF).clear - IRB.instance_variable_set(:@existing_rc_name_generators, nil) - @is_win = (RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/) - end - - def teardown - ENV["XDG_CONFIG_HOME"] = @xdg_config_home_backup - ENV["HOME"] = @home_backup - Dir.chdir(@pwd) - FileUtils.rm_rf(@tmpdir) - restore_encodings - end - - def execute_lines(*lines, conf: {}, main: self, irb_path: nil) - capture_output do - IRB.init_config(nil) - IRB.conf[:VERBOSE] = false - IRB.conf[:PROMPT_MODE] = :SIMPLE - IRB.conf[:USE_PAGER] = false - IRB.conf.merge!(conf) - input = TestInputMethod.new(lines) - irb = IRB::Irb.new(IRB::WorkSpace.new(main), input) - irb.context.return_format = "=> %s\n" - irb.context.irb_path = irb_path if irb_path - IRB.conf[:MAIN_CONTEXT] = irb.context - irb.eval_input - end - end - end - - class FrozenObjectTest < CommandTestCase - def test_calling_command_on_a_frozen_main - main = Object.new.freeze - - out, err = execute_lines( - "irb_info", - main: main - ) - assert_empty(err) - assert_match(/RUBY_PLATFORM/, out) - end - end - - class InfoTest < CommandTestCase - def setup - super - @locals_backup = ENV.delete("LANG"), ENV.delete("LC_ALL") - end - - def teardown - super - ENV["LANG"], ENV["LC_ALL"] = @locals_backup - end - - def test_irb_info_multiline - FileUtils.touch("#{@tmpdir}/.inputrc") - FileUtils.touch("#{@tmpdir}/.irbrc") - FileUtils.touch("#{@tmpdir}/_irbrc") - - out, err = execute_lines( - "irb_info", - conf: { USE_MULTILINE: true, USE_SINGLELINE: false } - ) - - expected = %r{ - Ruby\sversion:\s.+\n - IRB\sversion:\sirb\s.+\n - InputMethod:\sAbstract\sInputMethod\n - Completion: .+\n - \.irbrc\spaths:.*\.irbrc.*_irbrc\n - RUBY_PLATFORM:\s.+\n - East\sAsian\sAmbiguous\sWidth:\s\d\n - #{@is_win ? 'Code\spage:\s\d+\n' : ''} - }x - - assert_empty err - assert_match expected, out - end - - def test_irb_info_singleline - FileUtils.touch("#{@tmpdir}/.inputrc") - FileUtils.touch("#{@tmpdir}/.irbrc") - - out, err = execute_lines( - "irb_info", - conf: { USE_MULTILINE: false, USE_SINGLELINE: true } - ) - - expected = %r{ - Ruby\sversion:\s.+\n - IRB\sversion:\sirb\s.+\n - InputMethod:\sAbstract\sInputMethod\n - Completion: .+\n - \.irbrc\spaths:\s.+\n - RUBY_PLATFORM:\s.+\n - East\sAsian\sAmbiguous\sWidth:\s\d\n - #{@is_win ? 'Code\spage:\s\d+\n' : ''} - }x - - assert_empty err - assert_match expected, out - end - - def test_irb_info_multiline_without_rc_files - inputrc_backup = ENV["INPUTRC"] - ENV["INPUTRC"] = "unknown_inpurc" - ext_backup = IRB::IRBRC_EXT - IRB.__send__(:remove_const, :IRBRC_EXT) - IRB.const_set(:IRBRC_EXT, "unknown_ext") - - out, err = execute_lines( - "irb_info", - conf: { USE_MULTILINE: true, USE_SINGLELINE: false } - ) - - expected = %r{ - Ruby\sversion:\s.+\n - IRB\sversion:\sirb\s.+\n - InputMethod:\sAbstract\sInputMethod\n - Completion: .+\n - RUBY_PLATFORM:\s.+\n - East\sAsian\sAmbiguous\sWidth:\s\d\n - #{@is_win ? 'Code\spage:\s\d+\n' : ''} - }x - - assert_empty err - assert_match expected, out - ensure - ENV["INPUTRC"] = inputrc_backup - IRB.__send__(:remove_const, :IRBRC_EXT) - IRB.const_set(:IRBRC_EXT, ext_backup) - end - - def test_irb_info_singleline_without_rc_files - inputrc_backup = ENV["INPUTRC"] - ENV["INPUTRC"] = "unknown_inpurc" - ext_backup = IRB::IRBRC_EXT - IRB.__send__(:remove_const, :IRBRC_EXT) - IRB.const_set(:IRBRC_EXT, "unknown_ext") - - out, err = execute_lines( - "irb_info", - conf: { USE_MULTILINE: false, USE_SINGLELINE: true } - ) - - expected = %r{ - Ruby\sversion:\s.+\n - IRB\sversion:\sirb\s.+\n - InputMethod:\sAbstract\sInputMethod\n - Completion: .+\n - RUBY_PLATFORM:\s.+\n - East\sAsian\sAmbiguous\sWidth:\s\d\n - #{@is_win ? 'Code\spage:\s\d+\n' : ''} - }x - - assert_empty err - assert_match expected, out - ensure - ENV["INPUTRC"] = inputrc_backup - IRB.__send__(:remove_const, :IRBRC_EXT) - IRB.const_set(:IRBRC_EXT, ext_backup) - end - - def test_irb_info_lang - FileUtils.touch("#{@tmpdir}/.inputrc") - FileUtils.touch("#{@tmpdir}/.irbrc") - ENV["LANG"] = "ja_JP.UTF-8" - ENV["LC_ALL"] = "en_US.UTF-8" - - out, err = execute_lines( - "irb_info", - conf: { USE_MULTILINE: true, USE_SINGLELINE: false } - ) - - expected = %r{ - Ruby\sversion: .+\n - IRB\sversion:\sirb .+\n - InputMethod:\sAbstract\sInputMethod\n - Completion: .+\n - \.irbrc\spaths: .+\n - RUBY_PLATFORM: .+\n - LANG\senv:\sja_JP\.UTF-8\n - LC_ALL\senv:\sen_US\.UTF-8\n - East\sAsian\sAmbiguous\sWidth:\s\d\n - }x - - assert_empty err - assert_match expected, out - end - end - - class CustomCommandTestCase < CommandTestCase - def setup - @commands_backup = IRB::Command.commands - IRB::ExtendCommandBundle.class_variable_set(:@@command_override_policies, nil) - end - - def teardown - IRB::ExtendCommandBundle.class_variable_set(:@@command_override_policies, nil) - IRB::Command.instance_variable_set(:@commands, @commands_backup) - end - end - - class CommandArgTest < CustomCommandTestCase - class PrintArgCommand < IRB::Command::Base - category 'CommandTest' - description 'print_command_arg' - def execute(arg) - puts "arg=#{arg.inspect}" - end - end - - def test_arg - IRB::Command._register_with_aliases(:print_arg, PrintArgCommand, [:pa, IRB::ExtendCommandBundle::OVERRIDE_ALL]) - out, err = execute_lines("print_arg\n") - assert_empty err - assert_include(out, 'arg=""') - - out, err = execute_lines("print_arg \n") - assert_empty err - assert_include(out, 'arg=""') - - out, err = execute_lines("print_arg a r g\n") - assert_empty err - assert_include(out, 'arg="a r g"') - - out, err = execute_lines("print_arg a r g \n") - assert_empty err - assert_include(out, 'arg="a r g"') - - out, err = execute_lines("pa a r g \n") - assert_empty err - assert_include(out, 'arg="a r g"') - end - end - - class ExtendCommandBundleCompatibilityTest < CustomCommandTestCase - class FooBarCommand < IRB::Command::Base - category 'FooBarCategory' - description 'foobar_description' - def execute(_arg) - puts "FooBar executed" - end - end - - def test_def_extend_command - IRB::Command._register_with_aliases(:foobar, FooBarCommand, [:fbalias, IRB::ExtendCommandBundle::OVERRIDE_ALL]) - out, err = execute_lines("foobar\n") - assert_empty err - assert_include(out, "FooBar executed") - - out, err = execute_lines("fbalias\n") - assert_empty err - assert_include(out, "FooBar executed") - - out, err = execute_lines("show_cmds\n") - assert_include(out, "FooBarCategory") - assert_include(out, "foobar_description") - end - end - - class MeasureTest < CommandTestCase - def test_measure - conf = { - PROMPT: { - DEFAULT: { - PROMPT_I: '> ', - PROMPT_S: '> ', - PROMPT_C: '> ' - } - }, - PROMPT_MODE: :DEFAULT, - MEASURE: false - } - - c = Class.new(Object) - out, err = execute_lines( - "measure\n", - "3\n", - "measure :off\n", - "3\n", - "measure :on\n", - "3\n", - "measure :off\n", - "3\n", - conf: conf, - main: c - ) - - assert_empty err - assert_match(/\A(TIME is added\.\n=> nil\nprocessing time: .+\n=> 3\n=> nil\n=> 3\n){2}/, out) - assert_empty(c.class_variables) - end - - def test_measure_keeps_previous_value - conf = { - PROMPT: { - DEFAULT: { - PROMPT_I: '> ', - PROMPT_S: '> ', - PROMPT_C: '> ' - } - }, - PROMPT_MODE: :DEFAULT, - MEASURE: false - } - - c = Class.new(Object) - out, err = execute_lines( - "measure\n", - "3\n", - "_\n", - conf: conf, - main: c - ) - - assert_empty err - assert_match(/\ATIME is added\.\n=> nil\nprocessing time: .+\n=> 3\nprocessing time: .+\n=> 3/, out) - assert_empty(c.class_variables) - end - - def test_measure_enabled_by_rc - conf = { - PROMPT: { - DEFAULT: { - PROMPT_I: '> ', - PROMPT_S: '> ', - PROMPT_C: '> ' - } - }, - PROMPT_MODE: :DEFAULT, - MEASURE: true - } - - out, err = execute_lines( - "3\n", - "measure :off\n", - "3\n", - conf: conf, - ) - - assert_empty err - assert_match(/\Aprocessing time: .+\n=> 3\n=> nil\n=> 3\n/, out) - end - - def test_measure_enabled_by_rc_with_custom - measuring_proc = proc { |line, line_no, &block| - time = Time.now - result = block.() - puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE] - result - } - conf = { - PROMPT: { - DEFAULT: { - PROMPT_I: '> ', - PROMPT_S: '> ', - PROMPT_C: '> ' - } - }, - PROMPT_MODE: :DEFAULT, - MEASURE: true, - MEASURE_PROC: { CUSTOM: measuring_proc } - } - - out, err = execute_lines( - "3\n", - "measure :off\n", - "3\n", - conf: conf, - ) - assert_empty err - assert_match(/\Acustom processing time: .+\n=> 3\n=> nil\n=> 3\n/, out) - end - - def test_measure_with_custom - measuring_proc = proc { |line, line_no, &block| - time = Time.now - result = block.() - puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE] - result - } - conf = { - PROMPT: { - DEFAULT: { - PROMPT_I: '> ', - PROMPT_S: '> ', - PROMPT_C: '> ' - } - }, - PROMPT_MODE: :DEFAULT, - MEASURE: false, - MEASURE_PROC: { CUSTOM: measuring_proc } - } - out, err = execute_lines( - "3\n", - "measure\n", - "3\n", - "measure :off\n", - "3\n", - conf: conf - ) - - assert_empty err - assert_match(/\A=> 3\nCUSTOM is added\.\n=> nil\ncustom processing time: .+\n=> 3\n=> nil\n=> 3\n/, out) - end - - def test_measure_toggle - conf = { - PROMPT: { - DEFAULT: { - PROMPT_I: '> ', - PROMPT_S: '> ', - PROMPT_C: '> ' - } - }, - PROMPT_MODE: :DEFAULT, - MEASURE: false, - MEASURE_PROC: { - FOO: proc { |&block| puts 'foo'; block.call }, - BAR: proc { |&block| puts 'bar'; block.call } - } - } - out, err = execute_lines( - "measure :foo\n", - "1\n", - "measure :on, :bar\n", - "2\n", - "measure :off, :foo\n", - "3\n", - "measure :off, :bar\n", - "4\n", - conf: conf - ) - - assert_empty err - assert_match(/\AFOO is added\.\n=> nil\nfoo\n=> 1\nBAR is added\.\n=> nil\nbar\nfoo\n=> 2\n=> nil\nbar\n=> 3\n=> nil\n=> 4\n/, out) - end - - def test_measure_with_proc_warning - conf = { - PROMPT: { - DEFAULT: { - PROMPT_I: '> ', - PROMPT_S: '> ', - PROMPT_C: '> ' - } - }, - PROMPT_MODE: :DEFAULT, - MEASURE: false, - } - c = Class.new(Object) - out, err = execute_lines( - "3\n", - "measure do\n", - "3\n", - conf: conf, - main: c - ) - - assert_match(/to add custom measure/, err) - assert_match(/\A=> 3\n=> nil\n=> 3\n/, out) - assert_empty(c.class_variables) - end - end - - class IrbSourceTest < CommandTestCase - def test_irb_source - File.write("#{@tmpdir}/a.rb", "a = 'hi'\n") - out, err = execute_lines( - "a = 'bug17564'\n", - "a\n", - "irb_source '#{@tmpdir}/a.rb'\n", - "a\n", - ) - assert_empty err - assert_pattern_list([ - /=> "bug17564"\n/, - /=> "bug17564"\n/, - / => "hi"\n/, - / => nil\n/, - /=> "hi"\n/, - ], out) - end - - def test_irb_source_without_argument - out, err = execute_lines( - "irb_source\n", - ) - assert_empty err - assert_match(/Please specify the file name./, out) - end - end - - class IrbLoadTest < CommandTestCase - def test_irb_load - File.write("#{@tmpdir}/a.rb", "a = 'hi'\n") - out, err = execute_lines( - "a = 'bug17564'\n", - "a\n", - "irb_load '#{@tmpdir}/a.rb'\n", - "a\n", - ) - assert_empty err - assert_pattern_list([ - /=> "bug17564"\n/, - /=> "bug17564"\n/, - / => "hi"\n/, - / => nil\n/, - /=> "bug17564"\n/, - ], out) - end - - def test_irb_load_without_argument - out, err = execute_lines( - "irb_load\n", - ) - - assert_empty err - assert_match(/Please specify the file name./, out) - end - end - - class WorkspaceCommandTestCase < CommandTestCase - def setup - super - # create Foo under the test class's namespace so it doesn't pollute global namespace - self.class.class_eval <<~RUBY - class Foo; end - RUBY - end - end - - class CwwsTest < WorkspaceCommandTestCase - def test_cwws_returns_the_current_workspace_object - out, err = execute_lines( - "cwws", - "self.class" - ) - - assert_empty err - assert_include(out, self.class.name) - end - end - - class PushwsTest < WorkspaceCommandTestCase - def test_pushws_switches_to_new_workspace_and_pushes_the_current_one_to_the_stack - out, err = execute_lines( - "pushws #{self.class}::Foo.new", - "self.class", - "popws", - "self.class" - ) - assert_empty err - - assert_match(/=> #{self.class}::Foo\n/, out) - assert_match(/=> #{self.class}\n$/, out) - end - - def test_pushws_extends_the_new_workspace_with_command_bundle - out, err = execute_lines( - "pushws Object.new", - "self.singleton_class.ancestors" - ) - assert_empty err - assert_include(out, "IRB::ExtendCommandBundle") - end - - def test_pushws_prints_workspace_stack_when_no_arg_is_given - out, err = execute_lines( - "pushws", - ) - assert_empty err - assert_include(out, "[#<TestIRB::PushwsTe...>]") - end - - def test_pushws_without_argument_swaps_the_top_two_workspaces - out, err = execute_lines( - "pushws #{self.class}::Foo.new", - "self.class", - "pushws", - "self.class" - ) - assert_empty err - assert_match(/=> #{self.class}::Foo\n/, out) - assert_match(/=> #{self.class}\n$/, out) - end - end - - class WorkspacesTest < WorkspaceCommandTestCase - def test_workspaces_returns_the_stack_of_workspaces - out, err = execute_lines( - "pushws #{self.class}::Foo.new\n", - "workspaces", - ) - - assert_empty err - assert_match(/\[#<TestIRB::Workspac...>, #<TestIRB::Workspac...>\]\n/, out) - end - end - - class PopwsTest < WorkspaceCommandTestCase - def test_popws_replaces_the_current_workspace_with_the_previous_one - out, err = execute_lines( - "pushws Foo.new\n", - "popws\n", - "cwws\n", - "_.class", - ) - assert_empty err - assert_include(out, "=> #{self.class}") - end - - def test_popws_prints_help_message_if_the_workspace_is_empty - out, err = execute_lines( - "popws\n", - ) - assert_empty err - assert_match(/\[#<TestIRB::PopwsTes...>\]\n/, out) - end - end - - class ChwsTest < WorkspaceCommandTestCase - def test_chws_replaces_the_current_workspace - out, err = execute_lines( - "chws #{self.class}::Foo.new\n", - "cwws\n", - "_.class", - ) - assert_empty err - assert_include(out, "=> #{self.class}::Foo") - end - - def test_chws_does_nothing_when_receiving_no_argument - out, err = execute_lines( - "chws\n", - "cwws\n", - "_.class", - ) - assert_empty err - assert_include(out, "=> #{self.class}") - end - end - - class WhereamiTest < CommandTestCase - def test_whereami - out, err = execute_lines( - "whereami\n", - ) - assert_empty err - assert_match(/^From: .+ @ line \d+ :\n/, out) - end - - def test_whereami_alias - out, err = execute_lines( - "@\n", - ) - assert_empty err - assert_match(/^From: .+ @ line \d+ :\n/, out) - end - end - - class LsTest < CommandTestCase - def test_ls - out, err = execute_lines( - "class P\n", - " def m() end\n", - " def m2() end\n", - "end\n", - - "class C < P\n", - " def m1() end\n", - " def m2() end\n", - "end\n", - - "module M\n", - " def m1() end\n", - " def m3() end\n", - "end\n", - - "module M2\n", - " include M\n", - " def m4() end\n", - "end\n", - - "obj = C.new\n", - "obj.instance_variable_set(:@a, 1)\n", - "obj.extend M2\n", - "def obj.m5() end\n", - "ls obj\n", - ) - - assert_empty err - assert_match(/^instance variables:\s+@a\n/m, out) - assert_match(/P#methods:\s+m\n/m, out) - assert_match(/C#methods:\s+m2\n/m, out) - assert_match(/M#methods:\s+m1\s+m3\n/m, out) - assert_match(/M2#methods:\s+m4\n/m, out) - assert_match(/C.methods:\s+m5\n/m, out) - end - - def test_ls_class - out, err = execute_lines( - "module M1\n", - " def m2; end\n", - " def m3; end\n", - "end\n", - - "class C1\n", - " def m1; end\n", - " def m2; end\n", - "end\n", - - "class C2 < C1\n", - " include M1\n", - " def m3; end\n", - " def m4; end\n", - " def self.m3; end\n", - " def self.m5; end\n", - "end\n", - "ls C2" - ) - - assert_empty err - assert_match(/C2.methods:\s+m3\s+m5\n/, out) - assert_match(/C2#methods:\s+m3\s+m4\n.*M1#methods:\s+m2\n.*C1#methods:\s+m1\n/, out) - assert_not_match(/Module#methods/, out) - assert_not_match(/Class#methods/, out) - end - - def test_ls_module - out, err = execute_lines( - "module M1\n", - " def m1; end\n", - " def m2; end\n", - "end\n", - - "module M2\n", - " include M1\n", - " def m1; end\n", - " def m3; end\n", - " def self.m4; end\n", - "end\n", - "ls M2" - ) - - assert_empty err - assert_match(/M2\.methods:\s+m4\n/, out) - assert_match(/M2#methods:\s+m1\s+m3\n.*M1#methods:\s+m2\n/, out) - assert_not_match(/Module#methods/, out) - end - - def test_ls_instance - out, err = execute_lines( - "class Foo; def bar; end; end\n", - "ls Foo.new" - ) - - assert_empty err - assert_match(/Foo#methods:\s+bar/, out) - # don't duplicate - assert_not_match(/Foo#methods:\s+bar\n.*Foo#methods/, out) - end - - def test_ls_grep - out, err = execute_lines("ls 42\n") - assert_empty err - assert_match(/times/, out) - assert_match(/polar/, out) - - [ - "ls 42, grep: /times/\n", - "ls 42 -g times\n", - "ls 42 -G times\n", - ].each do |line| - out, err = execute_lines(line) - assert_empty err - assert_match(/times/, out) - assert_not_match(/polar/, out) - end - end - - def test_ls_grep_empty - out, err = execute_lines("ls\n") - assert_empty err - assert_match(/assert/, out) - assert_match(/refute/, out) - - [ - "ls grep: /assert/\n", - "ls -g assert\n", - "ls -G assert\n", - ].each do |line| - out, err = execute_lines(line) - assert_empty err - assert_match(/assert/, out) - assert_not_match(/refute/, out) - end - end - - def test_ls_with_no_singleton_class - out, err = execute_lines( - "ls 42", - ) - assert_empty err - assert_match(/Comparable#methods:\s+/, out) - assert_match(/Numeric#methods:\s+/, out) - assert_match(/Integer#methods:\s+/, out) - end - end - - class ShowDocTest < CommandTestCase - def test_show_doc - out, err = execute_lines( - "show_doc String#gsub\n", - "\n", - ) - - # the former is what we'd get without document content installed, like on CI - # the latter is what we may get locally - possible_rdoc_output = [/Nothing known about String#gsub/, /gsub\(pattern\)/] - assert_not_include err, "[Deprecation]" - assert(possible_rdoc_output.any? { |output| output.match?(out) }, "Expect the `show_doc` command to match one of the possible outputs. Got:\n#{out}") - ensure - # this is the only way to reset the redefined method without coupling the test with its implementation - EnvUtil.suppress_warning { load "irb/command/help.rb" } - end - - def test_show_doc_without_rdoc - out, err = without_rdoc do - execute_lines( - "show_doc String#gsub\n", - "\n", - ) - end - - # if it fails to require rdoc, it only returns the command object - assert_match(/=> nil\n/, out) - assert_include(err, "Can't display document because `rdoc` is not installed.\n") - ensure - # this is the only way to reset the redefined method without coupling the test with its implementation - EnvUtil.suppress_warning { load "irb/command/help.rb" } - end - end - - class EditTest < CommandTestCase - def setup - @original_visual = ENV["VISUAL"] - @original_editor = ENV["EDITOR"] - # noop the command so nothing gets executed - ENV["VISUAL"] = ": code" - ENV["EDITOR"] = ": code2" - end - - def teardown - ENV["VISUAL"] = @original_visual - ENV["EDITOR"] = @original_editor - end - - def test_edit_without_arg - out, err = execute_lines( - "edit", - irb_path: __FILE__ - ) - - assert_empty err - assert_match("path: #{__FILE__}", out) - assert_match("command: ': code'", out) - end - - def test_edit_without_arg_and_non_existing_irb_path - out, err = execute_lines( - "edit", - irb_path: '/path/to/file.rb(irb)' - ) - - assert_empty err - assert_match(/Can not find file: \/path\/to\/file\.rb\(irb\)/, out) - end - - def test_edit_with_path - out, err = execute_lines( - "edit #{__FILE__}" - ) - - assert_empty err - assert_match("path: #{__FILE__}", out) - assert_match("command: ': code'", out) - end - - def test_edit_with_non_existing_path - out, err = execute_lines( - "edit test_cmd_non_existing_path.rb" - ) - - assert_empty err - assert_match(/Can not find file: test_cmd_non_existing_path\.rb/, out) - end - - def test_edit_with_constant - out, err = execute_lines( - "edit IRB::Irb" - ) - - assert_empty err - assert_match(/path: .*\/lib\/irb\.rb/, out) - assert_match("command: ': code'", out) - end - - def test_edit_with_class_method - out, err = execute_lines( - "edit IRB.start" - ) - - assert_empty err - assert_match(/path: .*\/lib\/irb\.rb/, out) - assert_match("command: ': code'", out) - end - - def test_edit_with_instance_method - out, err = execute_lines( - "edit IRB::Irb#run" - ) - - assert_empty err - assert_match(/path: .*\/lib\/irb\.rb/, out) - assert_match("command: ': code'", out) - end - - def test_edit_with_editor_env_var - ENV.delete("VISUAL") - - out, err = execute_lines( - "edit", - irb_path: __FILE__ - ) - - assert_empty err - assert_match("path: #{__FILE__}", out) - assert_match("command: ': code2'", out) - end - end - - class HistoryCmdTest < CommandTestCase - def teardown - TestInputMethod.send(:remove_const, "HISTORY") if defined?(TestInputMethod::HISTORY) - super - end - - def test_history - TestInputMethod.const_set("HISTORY", %w[foo bar baz]) - - out, err = without_rdoc do - execute_lines("history") - end - - assert_include(out, <<~EOF) - 2: baz - 1: bar - 0: foo - EOF - assert_empty err - end - - def test_multiline_history_with_truncation - TestInputMethod.const_set("HISTORY", ["foo", "bar", <<~INPUT]) - [].each do |x| - puts x - end - INPUT - - out, err = without_rdoc do - execute_lines("hist") - end - - assert_include(out, <<~EOF) - 2: [].each do |x| - puts x - ... - 1: bar - 0: foo - EOF - assert_empty err - end - - def test_history_grep - TestInputMethod.const_set("HISTORY", ["foo", "bar", <<~INPUT]) - [].each do |x| - puts x - end - INPUT - - out, err = without_rdoc do - execute_lines("hist -g each\n") - end - - assert_include(out, <<~EOF) - 2: [].each do |x| - puts x - ... - EOF - assert_empty err - end - - end - - class HelperMethodInsallTest < CommandTestCase - def test_helper_method_install - IRB::ExtendCommandBundle.module_eval do - def foobar - "test_helper_method_foobar" - end - end - - out, err = execute_lines("foobar.upcase") - assert_empty err - assert_include(out, '=> "TEST_HELPER_METHOD_FOOBAR"') - ensure - IRB::ExtendCommandBundle.remove_method :foobar - end - end -end diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb deleted file mode 100644 index 5fe7952b3d..0000000000 --- a/test/irb/test_completion.rb +++ /dev/null @@ -1,311 +0,0 @@ -# frozen_string_literal: false -require "pathname" -require "irb" - -require_relative "helper" - -module TestIRB - class CompletionTest < TestCase - def completion_candidates(target, bind) - IRB::RegexpCompletor.new.completion_candidates('', target, '', bind: bind) - end - - def doc_namespace(target, bind) - IRB::RegexpCompletor.new.doc_namespace('', target, '', bind: bind) - end - - class CommandCompletionTest < CompletionTest - def test_command_completion - assert_include(IRB::RegexpCompletor.new.completion_candidates('', 'show_s', '', bind: binding), 'show_source') - assert_not_include(IRB::RegexpCompletor.new.completion_candidates(';', 'show_s', '', bind: binding), 'show_source') - end - end - - class MethodCompletionTest < CompletionTest - def test_complete_string - assert_include(completion_candidates("'foo'.up", binding), "'foo'.upcase") - # completing 'foo bar'.up - assert_include(completion_candidates("bar'.up", binding), "bar'.upcase") - assert_equal("String.upcase", doc_namespace("'foo'.upcase", binding)) - end - - def test_complete_regexp - assert_include(completion_candidates("/foo/.ma", binding), "/foo/.match") - # completing /foo bar/.ma - assert_include(completion_candidates("bar/.ma", binding), "bar/.match") - assert_equal("Regexp.match", doc_namespace("/foo/.match", binding)) - end - - def test_complete_array - assert_include(completion_candidates("[].an", binding), "[].any?") - assert_equal("Array.any?", doc_namespace("[].any?", binding)) - end - - def test_complete_hash_and_proc - # hash - assert_include(completion_candidates("{}.an", binding), "{}.any?") - assert_equal(["Hash.any?", "Proc.any?"], doc_namespace("{}.any?", binding)) - - # proc - assert_include(completion_candidates("{}.bin", binding), "{}.binding") - assert_equal(["Hash.binding", "Proc.binding"], doc_namespace("{}.binding", binding)) - end - - def test_complete_numeric - assert_include(completion_candidates("1.positi", binding), "1.positive?") - assert_equal("Integer.positive?", doc_namespace("1.positive?", binding)) - - assert_include(completion_candidates("1r.positi", binding), "1r.positive?") - assert_equal("Rational.positive?", doc_namespace("1r.positive?", binding)) - - assert_include(completion_candidates("0xFFFF.positi", binding), "0xFFFF.positive?") - assert_equal("Integer.positive?", doc_namespace("0xFFFF.positive?", binding)) - - assert_empty(completion_candidates("1i.positi", binding)) - end - - def test_complete_symbol - assert_include(completion_candidates(":foo.to_p", binding), ":foo.to_proc") - assert_equal("Symbol.to_proc", doc_namespace(":foo.to_proc", binding)) - end - - def test_complete_class - assert_include(completion_candidates("String.ne", binding), "String.new") - assert_equal("String.new", doc_namespace("String.new", binding)) - end - end - - class RequireComepletionTest < CompletionTest - def test_complete_require - candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding) - %w['irb/init 'irb/ruby-lex].each do |word| - assert_include candidates, word - end - # Test cache - candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding) - %w['irb/init 'irb/ruby-lex].each do |word| - assert_include candidates, word - end - # Test string completion not disturbed by require completion - candidates = IRB::RegexpCompletor.new.completion_candidates("'string ", "'.", "", bind: binding) - assert_include candidates, "'.upcase" - end - - def test_complete_require_with_pathname_in_load_path - temp_dir = Dir.mktmpdir - File.write(File.join(temp_dir, "foo.rb"), "test") - test_path = Pathname.new(temp_dir) - $LOAD_PATH << test_path - - candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding) - assert_include candidates, "'foo" - ensure - $LOAD_PATH.pop if test_path - FileUtils.remove_entry(temp_dir) if temp_dir - end - - def test_complete_require_with_string_convertable_in_load_path - temp_dir = Dir.mktmpdir - File.write(File.join(temp_dir, "foo.rb"), "test") - object = Object.new - object.define_singleton_method(:to_s) { temp_dir } - $LOAD_PATH << object - - candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding) - assert_include candidates, "'foo" - ensure - $LOAD_PATH.pop if object - FileUtils.remove_entry(temp_dir) if temp_dir - end - - def test_complete_require_with_malformed_object_in_load_path - object = Object.new - def object.to_s; raise; end - $LOAD_PATH << object - - assert_nothing_raised do - IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding) - end - ensure - $LOAD_PATH.pop if object - end - - def test_complete_require_library_name_first - # Test that library name is completed first with subdirectories - candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding) - assert_equal "'irb", candidates.first - end - - def test_complete_require_relative - candidates = Dir.chdir(__dir__ + "/../..") do - IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding) - end - %w['lib/irb/init 'lib/irb/ruby-lex].each do |word| - assert_include candidates, word - end - # Test cache - candidates = Dir.chdir(__dir__ + "/../..") do - IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding) - end - %w['lib/irb/init 'lib/irb/ruby-lex].each do |word| - assert_include candidates, word - end - end - end - - class VariableCompletionTest < CompletionTest - def test_complete_variable - # Bug fix issues https://github.com/ruby/irb/issues/368 - # Variables other than `str_example` and `@str_example` are defined to ensure that irb completion does not cause unintended behavior - str_example = '' - @str_example = '' - private_methods = '' - methods = '' - global_variables = '' - local_variables = '' - instance_variables = '' - - # suppress "assigned but unused variable" warning - str_example.clear - @str_example.clear - private_methods.clear - methods.clear - global_variables.clear - local_variables.clear - instance_variables.clear - - assert_include(completion_candidates("str_examp", binding), "str_example") - assert_equal("String", doc_namespace("str_example", binding)) - assert_equal("String.to_s", doc_namespace("str_example.to_s", binding)) - - assert_include(completion_candidates("@str_examp", binding), "@str_example") - assert_equal("String", doc_namespace("@str_example", binding)) - assert_equal("String.to_s", doc_namespace("@str_example.to_s", binding)) - end - - def test_complete_sort_variables - xzy, xzy_1, xzy2 = '', '', '' - - xzy.clear - xzy_1.clear - xzy2.clear - - candidates = completion_candidates("xz", binding) - assert_equal(%w[xzy xzy2 xzy_1], candidates) - end - end - - class ConstantCompletionTest < CompletionTest - class Foo - B3 = 1 - B1 = 1 - B2 = 1 - end - - def test_complete_constants - assert_equal(["Foo"], completion_candidates("Fo", binding)) - assert_equal(["Foo::B1", "Foo::B2", "Foo::B3"], completion_candidates("Foo::B", binding)) - assert_equal(["Foo::B1.positive?"], completion_candidates("Foo::B1.pos", binding)) - - assert_equal(["::Forwardable"], completion_candidates("::Fo", binding)) - assert_equal("Forwardable", doc_namespace("::Forwardable", binding)) - end - end - - def test_not_completing_empty_string - assert_equal([], completion_candidates("", binding)) - assert_equal([], completion_candidates(" ", binding)) - assert_equal([], completion_candidates("\t", binding)) - assert_equal(nil, doc_namespace("", binding)) - end - - def test_complete_symbol - symbols = %w"UTF-16LE UTF-7".map do |enc| - "K".force_encoding(enc).to_sym - rescue - end - symbols += [:aiueo, :"aiu eo"] - candidates = completion_candidates(":a", binding) - assert_include(candidates, ":aiueo") - assert_not_include(candidates, ":aiu eo") - assert_empty(completion_candidates(":irb_unknown_symbol_abcdefg", binding)) - # Do not complete empty symbol for performance reason - assert_empty(completion_candidates(":", binding)) - end - - def test_complete_invalid_three_colons - assert_empty(completion_candidates(":::A", binding)) - assert_empty(completion_candidates(":::", binding)) - end - - def test_complete_absolute_constants_with_special_characters - assert_empty(completion_candidates("::A:", binding)) - assert_empty(completion_candidates("::A.", binding)) - assert_empty(completion_candidates("::A(", binding)) - assert_empty(completion_candidates("::A)", binding)) - assert_empty(completion_candidates("::A[", binding)) - end - - def test_complete_reserved_words - candidates = completion_candidates("de", binding) - %w[def defined?].each do |word| - assert_include candidates, word - end - - candidates = completion_candidates("__", binding) - %w[__ENCODING__ __LINE__ __FILE__].each do |word| - assert_include candidates, word - end - end - - def test_complete_methods - obj = Object.new - obj.singleton_class.class_eval { - def public_hoge; end - private def private_hoge; end - - # Support for overriding #methods etc. - def methods; end - def private_methods; end - def global_variables; end - def local_variables; end - def instance_variables; end - } - bind = obj.instance_exec { binding } - - assert_include(completion_candidates("public_hog", bind), "public_hoge") - assert_include(doc_namespace("public_hoge", bind), "public_hoge") - - assert_include(completion_candidates("private_hog", bind), "private_hoge") - assert_include(doc_namespace("private_hoge", bind), "private_hoge") - end - end - - class DeprecatedInputCompletorTest < TestCase - def setup - save_encodings - @verbose, $VERBOSE = $VERBOSE, nil - IRB.init_config(nil) - IRB.conf[:VERBOSE] = false - IRB.conf[:MAIN_CONTEXT] = IRB::Context.new(IRB::WorkSpace.new(binding)) - end - - def teardown - restore_encodings - $VERBOSE = @verbose - end - - def test_completion_proc - assert_include(IRB::InputCompletor::CompletionProc.call('1.ab'), '1.abs') - assert_include(IRB::InputCompletor::CompletionProc.call('1.ab', '', ''), '1.abs') - end - - def test_retrieve_completion_data - assert_include(IRB::InputCompletor.retrieve_completion_data('1.ab'), '1.abs') - assert_equal(IRB::InputCompletor.retrieve_completion_data('1.abs', doc_namespace: true), 'Integer.abs') - bind = eval('a = 1; binding') - assert_include(IRB::InputCompletor.retrieve_completion_data('a.ab', bind: bind), 'a.abs') - assert_equal(IRB::InputCompletor.retrieve_completion_data('a.abs', bind: bind, doc_namespace: true), 'Integer.abs') - end - end -end diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb deleted file mode 100644 index aff4b5b67c..0000000000 --- a/test/irb/test_context.rb +++ /dev/null @@ -1,721 +0,0 @@ -# frozen_string_literal: false -require 'tempfile' -require 'irb' - -require_relative "helper" - -module TestIRB - class ContextTest < TestCase - def setup - IRB.init_config(nil) - IRB.conf[:USE_SINGLELINE] = false - IRB.conf[:VERBOSE] = false - IRB.conf[:USE_PAGER] = false - workspace = IRB::WorkSpace.new(Object.new) - @context = IRB::Context.new(nil, workspace, TestInputMethod.new) - - @get_screen_size = Reline.method(:get_screen_size) - Reline.instance_eval { undef :get_screen_size } - def Reline.get_screen_size - [36, 80] - end - save_encodings - end - - def teardown - Reline.instance_eval { undef :get_screen_size } - Reline.define_singleton_method(:get_screen_size, @get_screen_size) - restore_encodings - end - - - def test_eval_input - verbose, $VERBOSE = $VERBOSE, nil - input = TestInputMethod.new([ - "raise 'Foo'\n", - "_\n", - "0\n", - "_\n", - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - out, err = capture_output do - irb.eval_input - end - assert_empty err - - expected_output = - if RUBY_3_4 - [ - :*, /\(irb\):1:in '<main>': Foo \(RuntimeError\)\n/, - :*, /#<RuntimeError: Foo>\n/, - :*, /0$/, - :*, /0$/, - /\s*/ - ] - else - [ - :*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/, - :*, /#<RuntimeError: Foo>\n/, - :*, /0$/, - :*, /0$/, - /\s*/ - ] - end - - assert_pattern_list(expected_output, out) - ensure - $VERBOSE = verbose - end - - def test_eval_input_raise2x - input = TestInputMethod.new([ - "raise 'Foo'\n", - "raise 'Bar'\n", - "_\n", - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - out, err = capture_output do - irb.eval_input - end - assert_empty err - expected_output = - if RUBY_3_4 - [ - :*, /\(irb\):1:in '<main>': Foo \(RuntimeError\)\n/, - :*, /\(irb\):2:in '<main>': Bar \(RuntimeError\)\n/, - :*, /#<RuntimeError: Bar>\n/, - ] - else - [ - :*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/, - :*, /\(irb\):2:in `<main>': Bar \(RuntimeError\)\n/, - :*, /#<RuntimeError: Bar>\n/, - ] - end - assert_pattern_list(expected_output, out) - end - - def test_prompt_n_deprecation - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), TestInputMethod.new) - - _, err = capture_output do - irb.context.prompt_n = "foo" - irb.context.prompt_n - end - - assert_include err, "IRB::Context#prompt_n is deprecated" - assert_include err, "IRB::Context#prompt_n= is deprecated" - end - - def test_output_to_pipe - require 'stringio' - input = TestInputMethod.new(["n=1"]) - input.instance_variable_set(:@stdout, StringIO.new) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - irb.context.echo_on_assignment = :truncate - irb.context.prompt_mode = :DEFAULT - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal "=> 1\n", out - end - - { - successful: [ - [false, "class Foo < Struct.new(:bar); end; Foo.new(123)\n", /#<struct bar=123>/], - [:p, "class Foo < Struct.new(:bar); end; Foo.new(123)\n", /#<struct bar=123>/], - [true, "class Foo < Struct.new(:bar); end; Foo.new(123)\n", /#<struct #<Class:.*>::Foo bar=123>/], - [:yaml, "123", /--- 123\n/], - [:marshal, "123", Marshal.dump(123)], - ], - failed: [ - [false, "BasicObject.new", /#<NoMethodError: undefined method (`|')to_s' for/], - [:p, "class Foo; undef inspect ;end; Foo.new", /#<NoMethodError: undefined method (`|')inspect' for/], - [:yaml, "BasicObject.new", /#<NoMethodError: undefined method (`|')inspect' for/], - [:marshal, "[Object.new, Class.new]", /#<TypeError: can't dump anonymous class #<Class:/] - ] - }.each do |scenario, cases| - cases.each do |inspect_mode, input, expected| - define_method "test_#{inspect_mode}_inspect_mode_#{scenario}" do - verbose, $VERBOSE = $VERBOSE, nil - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), TestInputMethod.new([input])) - irb.context.inspect_mode = inspect_mode - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_match(expected, out) - ensure - $VERBOSE = verbose - end - end - end - - def test_object_inspection_handles_basic_object - verbose, $VERBOSE = $VERBOSE, nil - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), TestInputMethod.new(["BasicObject.new"])) - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_not_match(/NoMethodError/, out) - assert_match(/#<BasicObject:.*>/, out) - ensure - $VERBOSE = verbose - end - - def test_object_inspection_falls_back_to_kernel_inspect_when_errored - verbose, $VERBOSE = $VERBOSE, nil - main = Object.new - main.singleton_class.module_eval <<~RUBY - class Foo - def inspect - raise "foo" - end - end - RUBY - - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new(["Foo.new"])) - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_match(/An error occurred when inspecting the object: #<RuntimeError: foo>/, out) - assert_match(/Result of Kernel#inspect: #<#<Class:.*>::Foo:/, out) - ensure - $VERBOSE = verbose - end - - def test_object_inspection_prints_useful_info_when_kernel_inspect_also_errored - verbose, $VERBOSE = $VERBOSE, nil - main = Object.new - main.singleton_class.module_eval <<~RUBY - class Foo - def initialize - # Kernel#inspect goes through instance variables with #inspect - # So this will cause Kernel#inspect to fail - @foo = BasicObject.new - end - - def inspect - raise "foo" - end - end - RUBY - - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new(["Foo.new"])) - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_match(/An error occurred when inspecting the object: #<RuntimeError: foo>/, out) - assert_match(/An error occurred when running Kernel#inspect: #<NoMethodError: undefined method (`|')inspect' for/, out) - ensure - $VERBOSE = verbose - end - - def test_default_config - assert_equal(true, @context.use_autocomplete?) - end - - def test_echo_on_assignment - input = TestInputMethod.new([ - "a = 1\n", - "a\n", - "a, b = 2, 3\n", - "a\n", - "b\n", - "b = 4\n", - "_\n" - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - irb.context.return_format = "=> %s\n" - - # The default - irb.context.echo = true - irb.context.echo_on_assignment = false - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> 1\n=> 2\n=> 3\n=> 4\n", out) - - # Everything is output, like before echo_on_assignment was introduced - input.reset - irb.context.echo = true - irb.context.echo_on_assignment = true - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> 1\n=> 1\n=> [2, 3]\n=> 2\n=> 3\n=> 4\n=> 4\n", out) - - # Nothing is output when echo is false - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = false - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - - # Nothing is output when echo is false even if echo_on_assignment is true - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = true - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - end - - def test_omit_on_assignment - input = TestInputMethod.new([ - "a = [1] * 100\n", - "a\n", - ]) - value = [1] * 100 - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - irb.context.return_format = "=> %s\n" - - irb.context.echo = true - irb.context.echo_on_assignment = false - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> \n#{value.pretty_inspect}", out) - - input.reset - irb.context.echo = true - irb.context.echo_on_assignment = :truncate - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> \n#{value.pretty_inspect[0..3]}...\n=> \n#{value.pretty_inspect}", out) - - input.reset - irb.context.echo = true - irb.context.echo_on_assignment = true - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> \n#{value.pretty_inspect}=> \n#{value.pretty_inspect}", out) - - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = false - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = :truncate - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = true - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - end - - def test_omit_multiline_on_assignment - without_colorize do - input = TestInputMethod.new([ - "class A; def inspect; ([?* * 1000] * 3).join(%{\\n}); end; end; a = A.new\n", - "a\n" - ]) - value = ([?* * 1000] * 3).join(%{\n}) - value_first_line = (?* * 1000).to_s - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - irb.context.return_format = "=> %s\n" - - irb.context.echo = true - irb.context.echo_on_assignment = false - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> \n#{value}\n", out) - irb.context.evaluate_expression('A.remove_method(:inspect)', 0) - - input.reset - irb.context.echo = true - irb.context.echo_on_assignment = :truncate - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> #{value_first_line[0..(input.winsize.last - 9)]}...\n=> \n#{value}\n", out) - irb.context.evaluate_expression('A.remove_method(:inspect)', 0) - - input.reset - irb.context.echo = true - irb.context.echo_on_assignment = true - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> \n#{value}\n=> \n#{value}\n", out) - irb.context.evaluate_expression('A.remove_method(:inspect)', 0) - - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = false - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - irb.context.evaluate_expression('A.remove_method(:inspect)', 0) - - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = :truncate - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - irb.context.evaluate_expression('A.remove_method(:inspect)', 0) - - input.reset - irb.context.echo = false - irb.context.echo_on_assignment = true - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("", out) - irb.context.evaluate_expression('A.remove_method(:inspect)', 0) - end - end - - def test_echo_on_assignment_conf - # Default - IRB.conf[:ECHO] = nil - IRB.conf[:ECHO_ON_ASSIGNMENT] = nil - without_colorize do - input = TestInputMethod.new() - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - - assert(irb.context.echo?, "echo? should be true by default") - assert_equal(:truncate, irb.context.echo_on_assignment?, "echo_on_assignment? should be :truncate by default") - - # Explicitly set :ECHO to false - IRB.conf[:ECHO] = false - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - - refute(irb.context.echo?, "echo? should be false when IRB.conf[:ECHO] is set to false") - assert_equal(:truncate, irb.context.echo_on_assignment?, "echo_on_assignment? should be :truncate by default") - - # Explicitly set :ECHO_ON_ASSIGNMENT to true - IRB.conf[:ECHO] = nil - IRB.conf[:ECHO_ON_ASSIGNMENT] = false - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - - assert(irb.context.echo?, "echo? should be true by default") - refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to false") - end - end - - def test_multiline_output_on_default_inspector - main = Object.new - def main.inspect - "abc\ndef" - end - - without_colorize do - input = TestInputMethod.new([ - "self" - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(main), input) - irb.context.return_format = "=> %s\n" - - # The default - irb.context.newline_before_multiline_output = true - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> \nabc\ndef\n", - out) - - # No newline before multiline output - input.reset - irb.context.newline_before_multiline_output = false - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("=> abc\ndef\n", out) - end - end - - def test_default_return_format - IRB.conf[:PROMPT][:MY_PROMPT] = { - :PROMPT_I => "%03n> ", - :PROMPT_S => "%03n> ", - :PROMPT_C => "%03n> " - # without :RETURN - # :RETURN => "%s\n" - } - IRB.conf[:PROMPT_MODE] = :MY_PROMPT - input = TestInputMethod.new([ - "3" - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_equal("3\n", - out) - end - - def test_eval_input_with_exception - pend if RUBY_ENGINE == 'truffleruby' - verbose, $VERBOSE = $VERBOSE, nil - input = TestInputMethod.new([ - "def hoge() fuga; end; def fuga() raise; end; hoge\n", - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - out, err = capture_output do - irb.eval_input - end - assert_empty err - expected_output = - if RUBY_3_4 - [ - :*, /\(irb\):1:in 'fuga': unhandled exception\n/, - :*, /\tfrom \(irb\):1:in 'hoge'\n/, - :*, /\tfrom \(irb\):1:in '<main>'\n/, - :* - ] - elsif RUBY_VERSION < '3.0.0' && STDOUT.tty? - [ - :*, /Traceback \(most recent call last\):\n/, - :*, /\t 2: from \(irb\):1:in `<main>'\n/, - :*, /\t 1: from \(irb\):1:in `hoge'\n/, - :*, /\(irb\):1:in `fuga': unhandled exception\n/, - ] - else - [ - :*, /\(irb\):1:in `fuga': unhandled exception\n/, - :*, /\tfrom \(irb\):1:in `hoge'\n/, - :*, /\tfrom \(irb\):1:in `<main>'\n/, - :* - ] - end - assert_pattern_list(expected_output, out) - ensure - $VERBOSE = verbose - end - - def test_eval_input_with_invalid_byte_sequence_exception - verbose, $VERBOSE = $VERBOSE, nil - input = TestInputMethod.new([ - %Q{def hoge() fuga; end; def fuga() raise "A\\xF3B"; end; hoge\n}, - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - out, err = capture_output do - irb.eval_input - end - assert_empty err - expected_output = - if RUBY_3_4 - [ - :*, /\(irb\):1:in 'fuga': A\\xF3B \(RuntimeError\)\n/, - :*, /\tfrom \(irb\):1:in 'hoge'\n/, - :*, /\tfrom \(irb\):1:in '<main>'\n/, - :* - ] - elsif RUBY_VERSION < '3.0.0' && STDOUT.tty? - [ - :*, /Traceback \(most recent call last\):\n/, - :*, /\t 2: from \(irb\):1:in `<main>'\n/, - :*, /\t 1: from \(irb\):1:in `hoge'\n/, - :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/, - ] - else - [ - :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/, - :*, /\tfrom \(irb\):1:in `hoge'\n/, - :*, /\tfrom \(irb\):1:in `<main>'\n/, - :* - ] - end - - assert_pattern_list(expected_output, out) - ensure - $VERBOSE = verbose - end - - def test_eval_input_with_long_exception - pend if RUBY_ENGINE == 'truffleruby' - verbose, $VERBOSE = $VERBOSE, nil - nesting = 20 - generated_code = '' - nesting.times do |i| - generated_code << "def a#{i}() a#{i + 1}; end; " - end - generated_code << "def a#{nesting}() raise; end; a0\n" - input = TestInputMethod.new([ - generated_code - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - out, err = capture_output do - irb.eval_input - end - assert_empty err - if RUBY_VERSION < '3.0.0' && STDOUT.tty? - expected = [ - :*, /Traceback \(most recent call last\):\n/, - :*, /\t... \d+ levels...\n/, - :*, /\t16: from \(irb\):1:in (`|')a4'\n/, - :*, /\t15: from \(irb\):1:in (`|')a5'\n/, - :*, /\t14: from \(irb\):1:in (`|')a6'\n/, - :*, /\t13: from \(irb\):1:in (`|')a7'\n/, - :*, /\t12: from \(irb\):1:in (`|')a8'\n/, - :*, /\t11: from \(irb\):1:in (`|')a9'\n/, - :*, /\t10: from \(irb\):1:in (`|')a10'\n/, - :*, /\t 9: from \(irb\):1:in (`|')a11'\n/, - :*, /\t 8: from \(irb\):1:in (`|')a12'\n/, - :*, /\t 7: from \(irb\):1:in (`|')a13'\n/, - :*, /\t 6: from \(irb\):1:in (`|')a14'\n/, - :*, /\t 5: from \(irb\):1:in (`|')a15'\n/, - :*, /\t 4: from \(irb\):1:in (`|')a16'\n/, - :*, /\t 3: from \(irb\):1:in (`|')a17'\n/, - :*, /\t 2: from \(irb\):1:in (`|')a18'\n/, - :*, /\t 1: from \(irb\):1:in (`|')a19'\n/, - :*, /\(irb\):1:in (`|')a20': unhandled exception\n/, - ] - else - expected = [ - :*, /\(irb\):1:in (`|')a20': unhandled exception\n/, - :*, /\tfrom \(irb\):1:in (`|')a19'\n/, - :*, /\tfrom \(irb\):1:in (`|')a18'\n/, - :*, /\tfrom \(irb\):1:in (`|')a17'\n/, - :*, /\tfrom \(irb\):1:in (`|')a16'\n/, - :*, /\tfrom \(irb\):1:in (`|')a15'\n/, - :*, /\tfrom \(irb\):1:in (`|')a14'\n/, - :*, /\tfrom \(irb\):1:in (`|')a13'\n/, - :*, /\tfrom \(irb\):1:in (`|')a12'\n/, - :*, /\tfrom \(irb\):1:in (`|')a11'\n/, - :*, /\tfrom \(irb\):1:in (`|')a10'\n/, - :*, /\tfrom \(irb\):1:in (`|')a9'\n/, - :*, /\tfrom \(irb\):1:in (`|')a8'\n/, - :*, /\tfrom \(irb\):1:in (`|')a7'\n/, - :*, /\tfrom \(irb\):1:in (`|')a6'\n/, - :*, /\tfrom \(irb\):1:in (`|')a5'\n/, - :*, /\tfrom \(irb\):1:in (`|')a4'\n/, - :*, /\t... \d+ levels...\n/, - ] - end - assert_pattern_list(expected, out) - ensure - $VERBOSE = verbose - end - - def test_prompt_main_escape - main = Struct.new(:to_s).new("main\a\t\r\n") - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new) - assert_equal("irb(main )>", irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1)) - end - - def test_prompt_main_inspect_escape - main = Struct.new(:inspect).new("main\\n\nmain") - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new) - assert_equal("irb(main\\n main)>", irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1)) - end - - def test_prompt_main_truncate - main = Struct.new(:to_s).new("a" * 100) - def main.inspect; to_s.inspect; end - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new) - assert_equal('irb(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa...)>', irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1)) - assert_equal('irb("aaaaaaaaaaaaaaaaaaaaaaaaaaaa...)>', irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1)) - end - - def test_prompt_main_raise - main = Object.new - def main.to_s; raise TypeError; end - def main.inspect; raise ArgumentError; end - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new) - assert_equal("irb(!TypeError)>", irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1)) - assert_equal("irb(!ArgumentError)>", irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1)) - end - - def test_lineno - input = TestInputMethod.new([ - "\n", - "__LINE__\n", - "__LINE__\n", - "\n", - "\n", - "__LINE__\n", - ]) - irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) - out, err = capture_output do - irb.eval_input - end - assert_empty err - assert_pattern_list([ - :*, /\b2\n/, - :*, /\b3\n/, - :*, /\b6\n/, - ], out) - end - - def test_irb_path_setter - @context.irb_path = __FILE__ - assert_equal(__FILE__, @context.irb_path) - assert_equal("#{__FILE__}(irb)", @context.instance_variable_get(:@eval_path)) - @context.irb_path = 'file/does/not/exist' - assert_equal('file/does/not/exist', @context.irb_path) - assert_equal('file/does/not/exist', @context.instance_variable_get(:@eval_path)) - @context.irb_path = "#{__FILE__}(irb)" - assert_equal("#{__FILE__}(irb)", @context.irb_path) - assert_equal("#{__FILE__}(irb)", @context.instance_variable_get(:@eval_path)) - end - - def test_build_completor - verbose, $VERBOSE = $VERBOSE, nil - original_completor = IRB.conf[:COMPLETOR] - IRB.conf[:COMPLETOR] = :regexp - assert_equal 'IRB::RegexpCompletor', @context.send(:build_completor).class.name - IRB.conf[:COMPLETOR] = :unknown - assert_equal 'IRB::RegexpCompletor', @context.send(:build_completor).class.name - # :type is tested in test_type_completor.rb - ensure - $VERBOSE = verbose - IRB.conf[:COMPLETOR] = original_completor - end - - private - - def without_colorize - original_value = IRB.conf[:USE_COLORIZE] - IRB.conf[:USE_COLORIZE] = false - yield - ensure - IRB.conf[:USE_COLORIZE] = original_value - end - end -end diff --git a/test/irb/test_debugger_integration.rb b/test/irb/test_debugger_integration.rb deleted file mode 100644 index 839a0d43f0..0000000000 --- a/test/irb/test_debugger_integration.rb +++ /dev/null @@ -1,462 +0,0 @@ -# frozen_string_literal: true - -require "tempfile" -require "tmpdir" - -require_relative "helper" - -module TestIRB - class DebuggerIntegrationTest < IntegrationTestCase - def setup - super - - if RUBY_ENGINE == 'truffleruby' - omit "This test runs with ruby/debug, which doesn't work with truffleruby" - end - - @envs.merge!("NO_COLOR" => "true", "RUBY_DEBUG_HISTORY_FILE" => '') - end - - def test_backtrace - write_ruby <<~'RUBY' - def foo - binding.irb - end - foo - RUBY - - output = run_ruby_file do - type "backtrace" - type "exit!" - end - - assert_match(/irb\(main\):001> backtrace/, output) - assert_match(/Object#foo at #{@ruby_file.to_path}/, output) - end - - def test_debug - write_ruby <<~'ruby' - binding.irb - puts "hello" - ruby - - output = run_ruby_file do - type "debug" - type "next" - type "continue" - end - - assert_match(/irb\(main\):001> debug/, output) - assert_match(/irb:rdbg\(main\):002> next/, output) - assert_match(/=> 2\| puts "hello"/, output) - end - - def test_debug_command_only_runs_once - write_ruby <<~'ruby' - binding.irb - ruby - - output = run_ruby_file do - type "debug" - type "debug" - type "continue" - end - - assert_match(/irb\(main\):001> debug/, output) - assert_match(/irb:rdbg\(main\):002> debug/, output) - assert_match(/IRB is already running with a debug session/, output) - end - - def test_next - write_ruby <<~'ruby' - binding.irb - puts "hello" - ruby - - output = run_ruby_file do - type "next" - type "continue" - end - - assert_match(/irb\(main\):001> next/, output) - assert_match(/=> 2\| puts "hello"/, output) - end - - def test_break - write_ruby <<~'RUBY' - binding.irb - puts "Hello" - RUBY - - output = run_ruby_file do - type "break 2" - type "continue" - type "continue" - end - - assert_match(/irb\(main\):001> break/, output) - assert_match(/=> 2\| puts "Hello"/, output) - end - - def test_delete - write_ruby <<~'RUBY' - binding.irb - puts "Hello" - binding.irb - puts "World" - RUBY - - output = run_ruby_file do - type "break 4" - type "continue" - type "delete 0" - type "continue" - end - - assert_match(/irb:rdbg\(main\):003> delete/, output) - assert_match(/deleted: #0 BP - Line/, output) - end - - def test_step - write_ruby <<~'RUBY' - def foo - puts "Hello" - end - binding.irb - foo - RUBY - - output = run_ruby_file do - type "step" - type "step" - type "continue" - end - - assert_match(/irb\(main\):001> step/, output) - assert_match(/=> 5\| foo/, output) - assert_match(/=> 2\| puts "Hello"/, output) - end - - def test_long_stepping - write_ruby <<~'RUBY' - class Foo - def foo(num) - bar(num + 10) - end - - def bar(num) - num - end - end - - binding.irb - Foo.new.foo(100) - RUBY - - output = run_ruby_file do - type "step" - type "step" - type "step" - type "step" - type "num" - type "continue" - end - - assert_match(/irb\(main\):001> step/, output) - assert_match(/irb:rdbg\(main\):002> step/, output) - assert_match(/irb:rdbg\(#<Foo:.*>\):003> step/, output) - assert_match(/irb:rdbg\(#<Foo:.*>\):004> step/, output) - assert_match(/irb:rdbg\(#<Foo:.*>\):005> num/, output) - assert_match(/=> 110/, output) - end - - def test_continue - write_ruby <<~'RUBY' - binding.irb - puts "Hello" - binding.irb - puts "World" - RUBY - - output = run_ruby_file do - type "continue" - type "continue" - end - - assert_match(/irb\(main\):001> continue/, output) - assert_match(/=> 3: binding.irb/, output) - assert_match(/irb:rdbg\(main\):002> continue/, output) - end - - def test_finish - write_ruby <<~'RUBY' - def foo - binding.irb - puts "Hello" - end - foo - RUBY - - output = run_ruby_file do - type "finish" - type "continue" - end - - assert_match(/irb\(main\):001> finish/, output) - assert_match(/=> 4\| end/, output) - end - - def test_info - write_ruby <<~'RUBY' - def foo - a = "He" + "llo" - binding.irb - end - foo - RUBY - - output = run_ruby_file do - type "info" - type "continue" - end - - assert_match(/irb\(main\):001> info/, output) - assert_match(/%self = main/, output) - assert_match(/a = "Hello"/, output) - end - - def test_catch - write_ruby <<~'RUBY' - binding.irb - 1 / 0 - RUBY - - output = run_ruby_file do - type "catch ZeroDivisionError" - type "continue" - type "continue" - end - - assert_match(/irb\(main\):001> catch/, output) - assert_match(/Stop by #0 BP - Catch "ZeroDivisionError"/, output) - end - - def test_exit - write_ruby <<~'RUBY' - binding.irb - puts "hello" - RUBY - - output = run_ruby_file do - type "next" - type "exit" - end - - assert_match(/irb\(main\):001> next/, output) - end - - def test_quit - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "next" - type "quit!" - end - - assert_match(/irb\(main\):001> next/, output) - end - - def test_prompt_line_number_continues - write_ruby <<~'ruby' - binding.irb - puts "Hello" - puts "World" - ruby - - output = run_ruby_file do - type "123" - type "456" - type "next" - type "info" - type "next" - type "continue" - end - - assert_match(/irb\(main\):003> next/, output) - assert_match(/irb:rdbg\(main\):004> info/, output) - assert_match(/irb:rdbg\(main\):005> next/, output) - end - - def test_prompt_irb_name_is_kept - write_rc <<~RUBY - IRB.conf[:IRB_NAME] = "foo" - RUBY - - write_ruby <<~'ruby' - binding.irb - puts "Hello" - ruby - - output = run_ruby_file do - type "next" - type "continue" - end - - assert_match(/foo\(main\):001> next/, output) - assert_match(/foo:rdbg\(main\):002> continue/, output) - end - - def test_irb_commands_are_available_after_moving_around_with_the_debugger - write_ruby <<~'ruby' - class Foo - def bar - puts "bar" - end - end - - binding.irb - Foo.new.bar - ruby - - output = run_ruby_file do - # Due to the way IRB defines its commands, moving into the Foo instance from main is necessary for proper testing. - type "next" - type "step" - type "irb_info" - type "continue" - end - - assert_include(output, "InputMethod: RelineInputMethod") - end - - def test_help_command_is_delegated_to_the_debugger - write_ruby <<~'ruby' - binding.irb - ruby - - output = run_ruby_file do - type "debug" - type "help" - type "continue" - end - - assert_include(output, "### Frame control") - end - - def test_help_display_different_content_when_debugger_is_enabled - write_ruby <<~'ruby' - binding.irb - ruby - - output = run_ruby_file do - type "debug" - type "help" - type "continue" - end - - # IRB's commands should still be listed - assert_match(/help\s+List all available commands/, output) - # debug gem's commands should be appended at the end - assert_match(/Debugging \(from debug\.gem\)\s+### Control flow/, output) - end - - def test_input_is_evaluated_in_the_context_of_the_current_thread - write_ruby <<~'ruby' - current_thread = Thread.current - binding.irb - ruby - - output = run_ruby_file do - type "debug" - type '"Threads match: #{current_thread == Thread.current}"' - type "continue" - end - - assert_match(/irb\(main\):001> debug/, output) - assert_match(/Threads match: true/, output) - end - - def test_irb_switches_debugger_interface_if_debug_was_already_activated - write_ruby <<~'ruby' - require 'debug' - class Foo - def bar - puts "bar" - end - end - - binding.irb - Foo.new.bar - ruby - - output = run_ruby_file do - # Due to the way IRB defines its commands, moving into the Foo instance from main is necessary for proper testing. - type "next" - type "step" - type 'irb_info' - type "continue" - end - - assert_match(/irb\(main\):001> next/, output) - assert_include(output, "InputMethod: RelineInputMethod") - end - - def test_debugger_cant_be_activated_while_multi_irb_is_active - write_ruby <<~'ruby' - binding.irb - a = 1 - ruby - - output = run_ruby_file do - type "jobs" - type "next" - type "exit" - end - - assert_match(/irb\(main\):001> jobs/, output) - assert_include(output, "Can't start the debugger when IRB is running in a multi-IRB session.") - end - - def test_multi_irb_commands_are_not_available_after_activating_the_debugger - write_ruby <<~'ruby' - binding.irb - a = 1 - ruby - - output = run_ruby_file do - type "next" - type "jobs" - type "continue" - end - - assert_match(/irb\(main\):001> next/, output) - assert_include(output, "Multi-IRB commands are not available when the debugger is enabled.") - end - - def test_irb_passes_empty_input_to_debugger_to_repeat_the_last_command - write_ruby <<~'ruby' - binding.irb - puts "foo" - puts "bar" - puts "baz" - ruby - - output = run_ruby_file do - type "next" - type "" - # Test that empty input doesn't repeat expressions - type "123" - type "" - type "next" - type "" - type "" - end - - assert_include(output, "=> 2\| puts \"foo\"") - assert_include(output, "=> 3\| puts \"bar\"") - assert_include(output, "=> 4\| puts \"baz\"") - end - end -end diff --git a/test/irb/test_eval_history.rb b/test/irb/test_eval_history.rb deleted file mode 100644 index 54913ceff5..0000000000 --- a/test/irb/test_eval_history.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true -require "irb" - -require_relative "helper" - -module TestIRB - class EvalHistoryTest < TestCase - def setup - save_encodings - IRB.instance_variable_get(:@CONF).clear - end - - def teardown - restore_encodings - end - - def execute_lines(*lines, conf: {}, main: self, irb_path: nil) - IRB.init_config(nil) - IRB.conf[:VERBOSE] = false - IRB.conf[:PROMPT_MODE] = :SIMPLE - IRB.conf[:USE_PAGER] = false - IRB.conf.merge!(conf) - input = TestInputMethod.new(lines) - irb = IRB::Irb.new(IRB::WorkSpace.new(main), input) - irb.context.return_format = "=> %s\n" - irb.context.irb_path = irb_path if irb_path - IRB.conf[:MAIN_CONTEXT] = irb.context - capture_output do - irb.eval_input - end - end - - def test_eval_history_is_disabled_by_default - out, err = execute_lines( - "a = 1", - "__" - ) - - assert_empty(err) - assert_match(/undefined local variable or method (`|')__'/, out) - end - - def test_eval_history_can_be_retrieved_with_double_underscore - out, err = execute_lines( - "a = 1", - "__", - conf: { EVAL_HISTORY: 5 } - ) - - assert_empty(err) - assert_match("=> 1\n" + "=> 1 1\n", out) - end - - def test_eval_history_respects_given_limit - out, err = execute_lines( - "'foo'\n", - "'bar'\n", - "'baz'\n", - "'xyz'\n", - "__", - conf: { EVAL_HISTORY: 4 } - ) - - assert_empty(err) - # Because eval_history injects `__` into the history AND decide to ignore it, we only get <limit> - 1 results - assert_match("2 \"bar\"\n" + "3 \"baz\"\n" + "4 \"xyz\"\n", out) - end - end -end diff --git a/test/irb/test_evaluation.rb b/test/irb/test_evaluation.rb deleted file mode 100644 index adb69b2067..0000000000 --- a/test/irb/test_evaluation.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require "tempfile" - -require_relative "helper" - -module TestIRB - class EchoingTest < IntegrationTestCase - def test_irb_echos_by_default - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "123123" - type "exit" - end - - assert_include(output, "=> 123123") - end - - def test_irb_doesnt_echo_line_with_semicolon - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "123123;" - type "123123 ;" - type "123123; " - type <<~RUBY - if true - 123123 - end; - RUBY - type "'evaluation ends'" - type "exit" - end - - assert_include(output, "=> \"evaluation ends\"") - assert_not_include(output, "=> 123123") - end - end -end diff --git a/test/irb/test_history.rb b/test/irb/test_history.rb deleted file mode 100644 index 63be35fdaa..0000000000 --- a/test/irb/test_history.rb +++ /dev/null @@ -1,491 +0,0 @@ -# frozen_string_literal: false -require 'irb' -require 'readline' -require "tempfile" - -require_relative "helper" - -return if RUBY_PLATFORM.match?(/solaris|mswin|mingw/i) - -module TestIRB - class HistoryTest < TestCase - def setup - @original_verbose, $VERBOSE = $VERBOSE, nil - @tmpdir = Dir.mktmpdir("test_irb_history_") - @backup_home = ENV["HOME"] - @backup_xdg_config_home = ENV.delete("XDG_CONFIG_HOME") - @backup_irbrc = ENV.delete("IRBRC") - @backup_default_external = Encoding.default_external - ENV["HOME"] = @tmpdir - IRB.instance_variable_set(:@existing_rc_name_generators, nil) - end - - def teardown - IRB.instance_variable_set(:@existing_rc_name_generators, nil) - ENV["HOME"] = @backup_home - ENV["XDG_CONFIG_HOME"] = @backup_xdg_config_home - ENV["IRBRC"] = @backup_irbrc - Encoding.default_external = @backup_default_external - $VERBOSE = @original_verbose - FileUtils.rm_rf(@tmpdir) - end - - class TestInputMethodWithRelineHistory < TestInputMethod - # When IRB.conf[:USE_MULTILINE] is true, IRB::RelineInputMethod uses Reline::History - HISTORY = Reline::History.new(Reline.core.config) - - include IRB::HistorySavingAbility - end - - class TestInputMethodWithReadlineHistory < TestInputMethod - # When IRB.conf[:USE_MULTILINE] is false, IRB::ReadlineInputMethod uses Readline::HISTORY - HISTORY = Readline::HISTORY - - include IRB::HistorySavingAbility - end - - def test_history_save_1 - omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) - IRB.conf[:SAVE_HISTORY] = 1 - assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT) - exit - EXPECTED_HISTORY - 1 - 2 - 3 - 4 - INITIAL_HISTORY - 5 - exit - INPUT - end - - def test_history_save_100 - omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) - IRB.conf[:SAVE_HISTORY] = 100 - assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT) - 1 - 2 - 3 - 4 - 5 - exit - EXPECTED_HISTORY - 1 - 2 - 3 - 4 - INITIAL_HISTORY - 5 - exit - INPUT - end - - def test_history_save_bignum - omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) - IRB.conf[:SAVE_HISTORY] = 10 ** 19 - assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT) - 1 - 2 - 3 - 4 - 5 - exit - EXPECTED_HISTORY - 1 - 2 - 3 - 4 - INITIAL_HISTORY - 5 - exit - INPUT - end - - def test_history_save_minus_as_infinity - omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) - IRB.conf[:SAVE_HISTORY] = -1 # infinity - assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT) - 1 - 2 - 3 - 4 - 5 - exit - EXPECTED_HISTORY - 1 - 2 - 3 - 4 - INITIAL_HISTORY - 5 - exit - INPUT - end - - def test_history_concurrent_use_reline - omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) - IRB.conf[:SAVE_HISTORY] = 1 - history_concurrent_use_for_input_method(TestInputMethodWithRelineHistory) - end - - def test_history_concurrent_use_readline - omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) - IRB.conf[:SAVE_HISTORY] = 1 - history_concurrent_use_for_input_method(TestInputMethodWithReadlineHistory) - end - - def test_history_concurrent_use_not_present - IRB.conf[:LC_MESSAGES] = IRB::Locale.new - IRB.conf[:SAVE_HISTORY] = 1 - io = TestInputMethodWithRelineHistory.new - io.class::HISTORY.clear - io.load_history - io.class::HISTORY << 'line1' - io.class::HISTORY << 'line2' - - history_file = IRB.rc_file("_history") - assert_not_send [File, :file?, history_file] - File.write(history_file, "line0\n") - io.save_history - assert_equal(%w"line0 line1 line2", File.read(history_file).split) - end - - def test_history_different_encodings - IRB.conf[:SAVE_HISTORY] = 2 - Encoding.default_external = Encoding::US_ASCII - locale = IRB::Locale.new("C") - assert_history(<<~EXPECTED_HISTORY.encode(Encoding::US_ASCII), <<~INITIAL_HISTORY.encode(Encoding::UTF_8), <<~INPUT, locale: locale) - ???? - exit - EXPECTED_HISTORY - 😀 - INITIAL_HISTORY - exit - INPUT - end - - def test_history_does_not_raise_when_history_file_directory_does_not_exist - backup_history_file = IRB.conf[:HISTORY_FILE] - IRB.conf[:SAVE_HISTORY] = 1 - IRB.conf[:HISTORY_FILE] = "fake/fake/fake/history_file" - io = TestInputMethodWithRelineHistory.new - - assert_warn(/history file does not exist/) do - io.save_history - end - - # assert_warn reverts $VERBOSE to EnvUtil.original_verbose, which is true in some cases - # We want to keep $VERBOSE as nil until teardown is called - # TODO: check if this is an assert_warn issue - $VERBOSE = nil - ensure - IRB.conf[:HISTORY_FILE] = backup_history_file - end - - def test_no_home_no_history_file_does_not_raise_history_save - ENV['HOME'] = nil - io = TestInputMethodWithRelineHistory.new - assert_nil(IRB.rc_file('_history')) - assert_nothing_raised do - io.load_history - io.save_history - end - end - - private - - def history_concurrent_use_for_input_method(input_method) - assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT, input_method) do |history_file| - exit - 5 - exit - EXPECTED_HISTORY - 1 - 2 - 3 - 4 - INITIAL_HISTORY - 5 - exit - INPUT - assert_history(<<~EXPECTED_HISTORY2, <<~INITIAL_HISTORY2, <<~INPUT2, input_method) - exit - EXPECTED_HISTORY2 - 1 - 2 - 3 - 4 - INITIAL_HISTORY2 - 5 - exit - INPUT2 - File.utime(File.atime(history_file), File.mtime(history_file) + 2, history_file) - end - end - - def assert_history(expected_history, initial_irb_history, input, input_method = TestInputMethodWithRelineHistory, locale: IRB::Locale.new) - IRB.conf[:LC_MESSAGES] = locale - actual_history = nil - history_file = IRB.rc_file("_history") - ENV["HOME"] = @tmpdir - File.open(history_file, "w") do |f| - f.write(initial_irb_history) - end - - io = input_method.new - io.class::HISTORY.clear - io.load_history - if block_given? - previous_history = [] - io.class::HISTORY.each { |line| previous_history << line } - yield history_file - io.class::HISTORY.clear - previous_history.each { |line| io.class::HISTORY << line } - end - input.split.each { |line| io.class::HISTORY << line } - io.save_history - - io.load_history - File.open(history_file, "r") do |f| - actual_history = f.read - end - assert_equal(expected_history, actual_history, <<~MESSAGE) - expected: - #{expected_history} - but actual: - #{actual_history} - MESSAGE - end - - def with_temp_stdio - Tempfile.create("test_readline_stdin") do |stdin| - Tempfile.create("test_readline_stdout") do |stdout| - yield stdin, stdout - end - end - end - end - - class IRBHistoryIntegrationTest < IntegrationTestCase - def test_history_saving_with_debug - write_history "" - - write_ruby <<~'RUBY' - def foo - end - - binding.irb - - foo - RUBY - - output = run_ruby_file do - type "'irb session'" - type "next" - type "'irb:debug session'" - type "step" - type "irb_info" - type "puts Reline::HISTORY.to_a.to_s" - type "q!" - end - - assert_include(output, "InputMethod: RelineInputMethod") - # check that in-memory history is preserved across sessions - assert_include output, %q( - ["'irb session'", "next", "'irb:debug session'", "step", "irb_info", "puts Reline::HISTORY.to_a.to_s"] - ).strip - - assert_equal <<~HISTORY, @history_file.open.read - 'irb session' - next - 'irb:debug session' - step - irb_info - puts Reline::HISTORY.to_a.to_s - q! - HISTORY - end - - def test_history_saving_with_debug_without_prior_history - tmpdir = Dir.mktmpdir("test_irb_history_") - # Intentionally not creating the file so we test the reset counter logic - history_file = File.join(tmpdir, "irb_history") - - write_rc <<~RUBY - IRB.conf[:HISTORY_FILE] = "#{history_file}" - RUBY - - write_ruby <<~'RUBY' - def foo - end - - binding.irb - - foo - RUBY - - output = run_ruby_file do - type "'irb session'" - type "next" - type "'irb:debug session'" - type "step" - type "irb_info" - type "puts Reline::HISTORY.to_a.to_s" - type "q!" - end - - assert_include(output, "InputMethod: RelineInputMethod") - # check that in-memory history is preserved across sessions - assert_include output, %q( - ["'irb session'", "next", "'irb:debug session'", "step", "irb_info", "puts Reline::HISTORY.to_a.to_s"] - ).strip - - assert_equal <<~HISTORY, File.read(history_file) - 'irb session' - next - 'irb:debug session' - step - irb_info - puts Reline::HISTORY.to_a.to_s - q! - HISTORY - ensure - FileUtils.rm_rf(tmpdir) - end - - def test_history_saving_with_nested_sessions - write_history "" - - write_ruby <<~'RUBY' - def foo - binding.irb - end - - binding.irb - RUBY - - run_ruby_file do - type "'outer session'" - type "foo" - type "'inner session'" - type "exit" - type "'outer session again'" - type "exit" - end - - assert_equal <<~HISTORY, @history_file.open.read - 'outer session' - foo - 'inner session' - exit - 'outer session again' - exit - HISTORY - end - - def test_nested_history_saving_from_inner_session_with_exit! - write_history "" - - write_ruby <<~'RUBY' - def foo - binding.irb - end - - binding.irb - RUBY - - run_ruby_file do - type "'outer session'" - type "foo" - type "'inner session'" - type "exit!" - end - - assert_equal <<~HISTORY, @history_file.open.read - 'outer session' - foo - 'inner session' - exit! - HISTORY - end - - def test_nested_history_saving_from_outer_session_with_exit! - write_history "" - - write_ruby <<~'RUBY' - def foo - binding.irb - end - - binding.irb - RUBY - - run_ruby_file do - type "'outer session'" - type "foo" - type "'inner session'" - type "exit" - type "'outer session again'" - type "exit!" - end - - assert_equal <<~HISTORY, @history_file.open.read - 'outer session' - foo - 'inner session' - exit - 'outer session again' - exit! - HISTORY - end - - def test_history_saving_with_nested_sessions_and_prior_history - write_history <<~HISTORY - old_history_1 - old_history_2 - old_history_3 - HISTORY - - write_ruby <<~'RUBY' - def foo - binding.irb - end - - binding.irb - RUBY - - run_ruby_file do - type "'outer session'" - type "foo" - type "'inner session'" - type "exit" - type "'outer session again'" - type "exit" - end - - assert_equal <<~HISTORY, @history_file.open.read - old_history_1 - old_history_2 - old_history_3 - 'outer session' - foo - 'inner session' - exit - 'outer session again' - exit - HISTORY - end - - private - - def write_history(history) - @history_file = Tempfile.new('irb_history') - @history_file.write(history) - @history_file.close - write_rc <<~RUBY - IRB.conf[:HISTORY_FILE] = "#{@history_file.path}" - RUBY - end - end -end diff --git a/test/irb/test_init.rb b/test/irb/test_init.rb deleted file mode 100644 index f11d7398c8..0000000000 --- a/test/irb/test_init.rb +++ /dev/null @@ -1,310 +0,0 @@ -# frozen_string_literal: false -require "irb" -require "fileutils" - -require_relative "helper" - -module TestIRB - class InitTest < TestCase - def setup - # IRBRC is for RVM... - @backup_env = %w[HOME XDG_CONFIG_HOME IRBRC].each_with_object({}) do |env, hash| - hash[env] = ENV.delete(env) - end - ENV["HOME"] = @tmpdir = File.realpath(Dir.mktmpdir("test_irb_init_#{$$}")) - end - - def reset_rc_name_generators - IRB.instance_variable_set(:@existing_rc_name_generators, nil) - end - - def teardown - ENV.update(@backup_env) - FileUtils.rm_rf(@tmpdir) - IRB.conf.delete(:SCRIPT) - reset_rc_name_generators - end - - def test_setup_with_argv_preserves_global_argv - argv = ["foo", "bar"] - with_argv(argv) do - IRB.setup(eval("__FILE__"), argv: %w[-f]) - assert_equal argv, ARGV - end - end - - def test_setup_with_minimum_argv_does_not_change_dollar0 - orig = $0.dup - IRB.setup(eval("__FILE__"), argv: %w[-f]) - assert_equal orig, $0 - end - - def test_rc_files - tmpdir = @tmpdir - Dir.chdir(tmpdir) do - home = ENV['HOME'] = "#{tmpdir}/home" - xdg_config_home = ENV['XDG_CONFIG_HOME'] = "#{tmpdir}/xdg" - reset_rc_name_generators - assert_empty(IRB.irbrc_files) - assert_equal("#{home}/.irb_history", IRB.rc_file('_history')) - FileUtils.mkdir_p(home) - FileUtils.mkdir_p("#{xdg_config_home}/irb") - FileUtils.mkdir_p("#{home}/.config/irb") - reset_rc_name_generators - assert_empty(IRB.irbrc_files) - assert_equal("#{xdg_config_home}/irb/irb_history", IRB.rc_file('_history')) - home_irbrc = "#{home}/.irbrc" - config_irbrc = "#{home}/.config/irb/irbrc" - xdg_config_irbrc = "#{xdg_config_home}/irb/irbrc" - [home_irbrc, config_irbrc, xdg_config_irbrc].each do |file| - FileUtils.touch(file) - end - current_dir_irbrcs = %w[.irbrc irbrc _irbrc $irbrc].map { |file| "#{tmpdir}/#{file}" } - current_dir_irbrcs.each { |file| FileUtils.touch(file) } - reset_rc_name_generators - assert_equal([xdg_config_irbrc, home_irbrc, *current_dir_irbrcs], IRB.irbrc_files) - assert_equal(xdg_config_irbrc.sub(/rc$/, '_history'), IRB.rc_file('_history')) - ENV['XDG_CONFIG_HOME'] = nil - reset_rc_name_generators - assert_equal([home_irbrc, config_irbrc, *current_dir_irbrcs], IRB.irbrc_files) - assert_equal(home_irbrc.sub(/rc$/, '_history'), IRB.rc_file('_history')) - ENV['XDG_CONFIG_HOME'] = '' - reset_rc_name_generators - assert_equal([home_irbrc, config_irbrc] + current_dir_irbrcs, IRB.irbrc_files) - assert_equal(home_irbrc.sub(/rc$/, '_history'), IRB.rc_file('_history')) - ENV['XDG_CONFIG_HOME'] = xdg_config_home - ENV['IRBRC'] = "#{tmpdir}/.irbrc" - reset_rc_name_generators - assert_equal([ENV['IRBRC'], xdg_config_irbrc, home_irbrc] + (current_dir_irbrcs - [ENV['IRBRC']]), IRB.irbrc_files) - assert_equal(ENV['IRBRC'] + '_history', IRB.rc_file('_history')) - ENV['IRBRC'] = ENV['HOME'] = ENV['XDG_CONFIG_HOME'] = nil - reset_rc_name_generators - assert_equal(current_dir_irbrcs, IRB.irbrc_files) - assert_nil(IRB.rc_file('_history')) - end - end - - def test_duplicated_rc_files - tmpdir = @tmpdir - Dir.chdir(tmpdir) do - ENV['XDG_CONFIG_HOME'] = "#{ENV['HOME']}/.config" - FileUtils.mkdir_p("#{ENV['XDG_CONFIG_HOME']}/irb") - env_irbrc = ENV['IRBRC'] = "#{tmpdir}/_irbrc" - xdg_config_irbrc = "#{ENV['XDG_CONFIG_HOME']}/irb/irbrc" - home_irbrc = "#{ENV['HOME']}/.irbrc" - current_dir_irbrc = "#{tmpdir}/irbrc" - [env_irbrc, xdg_config_irbrc, home_irbrc, current_dir_irbrc].each do |file| - FileUtils.touch(file) - end - reset_rc_name_generators - assert_equal([env_irbrc, xdg_config_irbrc, home_irbrc, current_dir_irbrc], IRB.irbrc_files) - end - end - - def test_sigint_restore_default - pend "This test gets stuck on Solaris for unknown reason; contribution is welcome" if RUBY_PLATFORM =~ /solaris/ - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - # IRB should restore SIGINT handler - status = assert_in_out_err(bundle_exec + %w[-W0 -rirb -e Signal.trap("SIGINT","DEFAULT");binding.irb;loop{Process.kill("SIGINT",$$)} -- -f --], "exit\n", //, //) - Process.kill("SIGKILL", status.pid) if !status.exited? && !status.stopped? && !status.signaled? - end - - def test_sigint_restore_block - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - # IRB should restore SIGINT handler - status = assert_in_out_err(bundle_exec + %w[-W0 -rirb -e x=false;Signal.trap("SIGINT"){x=true};binding.irb;loop{Process.kill("SIGINT",$$);if(x);break;end} -- -f --], "exit\n", //, //) - Process.kill("SIGKILL", status.pid) if !status.exited? && !status.stopped? && !status.signaled? - end - - def test_no_color_environment_variable - orig_no_color = ENV['NO_COLOR'] - orig_use_colorize = IRB.conf[:USE_COLORIZE] - IRB.conf[:USE_COLORIZE] = true - - assert IRB.conf[:USE_COLORIZE] - - ENV['NO_COLOR'] = 'true' - IRB.setup(__FILE__) - refute IRB.conf[:USE_COLORIZE] - - ENV['NO_COLOR'] = '' - IRB.setup(__FILE__) - assert IRB.conf[:USE_COLORIZE] - - ENV['NO_COLOR'] = nil - IRB.setup(__FILE__) - assert IRB.conf[:USE_COLORIZE] - ensure - ENV['NO_COLOR'] = orig_no_color - IRB.conf[:USE_COLORIZE] = orig_use_colorize - end - - def test_use_autocomplete_environment_variable - orig_use_autocomplete_env = ENV['IRB_USE_AUTOCOMPLETE'] - orig_use_autocomplete_conf = IRB.conf[:USE_AUTOCOMPLETE] - - ENV['IRB_USE_AUTOCOMPLETE'] = nil - IRB.setup(__FILE__) - assert IRB.conf[:USE_AUTOCOMPLETE] - - ENV['IRB_USE_AUTOCOMPLETE'] = '' - IRB.setup(__FILE__) - assert IRB.conf[:USE_AUTOCOMPLETE] - - ENV['IRB_USE_AUTOCOMPLETE'] = 'false' - IRB.setup(__FILE__) - refute IRB.conf[:USE_AUTOCOMPLETE] - - ENV['IRB_USE_AUTOCOMPLETE'] = 'true' - IRB.setup(__FILE__) - assert IRB.conf[:USE_AUTOCOMPLETE] - ensure - ENV["IRB_USE_AUTOCOMPLETE"] = orig_use_autocomplete_env - IRB.conf[:USE_AUTOCOMPLETE] = orig_use_autocomplete_conf - end - - def test_completor_environment_variable - orig_use_autocomplete_env = ENV['IRB_COMPLETOR'] - orig_use_autocomplete_conf = IRB.conf[:COMPLETOR] - - ENV['IRB_COMPLETOR'] = nil - IRB.setup(__FILE__) - assert_equal(:regexp, IRB.conf[:COMPLETOR]) - - ENV['IRB_COMPLETOR'] = 'regexp' - IRB.setup(__FILE__) - assert_equal(:regexp, IRB.conf[:COMPLETOR]) - - ENV['IRB_COMPLETOR'] = 'type' - IRB.setup(__FILE__) - assert_equal(:type, IRB.conf[:COMPLETOR]) - - ENV['IRB_COMPLETOR'] = 'regexp' - IRB.setup(__FILE__, argv: ['--type-completor']) - assert_equal :type, IRB.conf[:COMPLETOR] - - ENV['IRB_COMPLETOR'] = 'type' - IRB.setup(__FILE__, argv: ['--regexp-completor']) - assert_equal :regexp, IRB.conf[:COMPLETOR] - ensure - ENV['IRB_COMPLETOR'] = orig_use_autocomplete_env - IRB.conf[:COMPLETOR] = orig_use_autocomplete_conf - end - - def test_completor_setup_with_argv - orig_completor_conf = IRB.conf[:COMPLETOR] - - # Default is :regexp - IRB.setup(__FILE__, argv: []) - assert_equal :regexp, IRB.conf[:COMPLETOR] - - IRB.setup(__FILE__, argv: ['--type-completor']) - assert_equal :type, IRB.conf[:COMPLETOR] - - IRB.setup(__FILE__, argv: ['--regexp-completor']) - assert_equal :regexp, IRB.conf[:COMPLETOR] - ensure - IRB.conf[:COMPLETOR] = orig_completor_conf - end - - def test_noscript - argv = %w[--noscript -- -f] - IRB.setup(eval("__FILE__"), argv: argv) - assert_nil IRB.conf[:SCRIPT] - assert_equal(['-f'], argv) - - argv = %w[--noscript -- a] - IRB.setup(eval("__FILE__"), argv: argv) - assert_nil IRB.conf[:SCRIPT] - assert_equal(['a'], argv) - - argv = %w[--noscript a] - IRB.setup(eval("__FILE__"), argv: argv) - assert_nil IRB.conf[:SCRIPT] - assert_equal(['a'], argv) - - argv = %w[--script --noscript a] - IRB.setup(eval("__FILE__"), argv: argv) - assert_nil IRB.conf[:SCRIPT] - assert_equal(['a'], argv) - - argv = %w[--noscript --script a] - IRB.setup(eval("__FILE__"), argv: argv) - assert_equal('a', IRB.conf[:SCRIPT]) - assert_equal([], argv) - end - - def test_dash - argv = %w[-] - IRB.setup(eval("__FILE__"), argv: argv) - assert_equal('-', IRB.conf[:SCRIPT]) - assert_equal([], argv) - - argv = %w[-- -] - IRB.setup(eval("__FILE__"), argv: argv) - assert_equal('-', IRB.conf[:SCRIPT]) - assert_equal([], argv) - - argv = %w[-- - -f] - IRB.setup(eval("__FILE__"), argv: argv) - assert_equal('-', IRB.conf[:SCRIPT]) - assert_equal(['-f'], argv) - end - - def test_option_tracer - argv = %w[--tracer] - IRB.setup(eval("__FILE__"), argv: argv) - assert_equal(true, IRB.conf[:USE_TRACER]) - end - - private - - def with_argv(argv) - orig = ARGV.dup - ARGV.replace(argv) - yield - ensure - ARGV.replace(orig) - end - end - - class InitIntegrationTest < IntegrationTestCase - def test_load_error_in_rc_file_is_warned - write_rc <<~'IRBRC' - require "file_that_does_not_exist" - IRBRC - - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "'foobar'" - type "exit" - end - - # IRB session should still be started - assert_includes output, "foobar" - assert_includes output, 'cannot load such file -- file_that_does_not_exist (LoadError)' - end - - def test_normal_errors_in_rc_file_is_warned - write_rc <<~'IRBRC' - raise "I'm an error" - IRBRC - - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "'foobar'" - type "exit" - end - - # IRB session should still be started - assert_includes output, "foobar" - assert_includes output, 'I\'m an error (RuntimeError)' - end - end -end diff --git a/test/irb/test_input_method.rb b/test/irb/test_input_method.rb deleted file mode 100644 index ce317b4b32..0000000000 --- a/test/irb/test_input_method.rb +++ /dev/null @@ -1,173 +0,0 @@ -# frozen_string_literal: false - -require "irb" -require "rdoc" -require_relative "helper" - -module TestIRB - class InputMethodTest < TestCase - def setup - @conf_backup = IRB.conf.dup - IRB.conf[:LC_MESSAGES] = IRB::Locale.new - save_encodings - end - - def teardown - IRB.conf.replace(@conf_backup) - restore_encodings - # Reset Reline configuration overridden by RelineInputMethod. - Reline.instance_variable_set(:@core, nil) - end - end - - class RelineInputMethodTest < InputMethodTest - def test_initialization - Reline.completion_proc = nil - Reline.dig_perfect_match_proc = nil - IRB::RelineInputMethod.new(IRB::RegexpCompletor.new) - - assert_nil Reline.completion_append_character - assert_equal '', Reline.completer_quote_characters - assert_equal IRB::InputMethod::BASIC_WORD_BREAK_CHARACTERS, Reline.basic_word_break_characters - assert_not_nil Reline.completion_proc - assert_not_nil Reline.dig_perfect_match_proc - end - - def test_initialization_without_use_autocomplete - original_show_doc_proc = Reline.dialog_proc(:show_doc)&.dialog_proc - empty_proc = Proc.new {} - Reline.add_dialog_proc(:show_doc, empty_proc) - - IRB.conf[:USE_AUTOCOMPLETE] = false - - IRB::RelineInputMethod.new(IRB::RegexpCompletor.new) - - refute Reline.autocompletion - assert_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc - ensure - Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT) - end - - def test_initialization_with_use_autocomplete - original_show_doc_proc = Reline.dialog_proc(:show_doc)&.dialog_proc - empty_proc = Proc.new {} - Reline.add_dialog_proc(:show_doc, empty_proc) - - IRB.conf[:USE_AUTOCOMPLETE] = true - - IRB::RelineInputMethod.new(IRB::RegexpCompletor.new) - - assert Reline.autocompletion - assert_not_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc - ensure - Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT) - end - - def test_initialization_with_use_autocomplete_but_without_rdoc - original_show_doc_proc = Reline.dialog_proc(:show_doc)&.dialog_proc - empty_proc = Proc.new {} - Reline.add_dialog_proc(:show_doc, empty_proc) - - IRB.conf[:USE_AUTOCOMPLETE] = true - - without_rdoc do - IRB::RelineInputMethod.new(IRB::RegexpCompletor.new) - end - - assert Reline.autocompletion - # doesn't register show_doc dialog - assert_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc - ensure - Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT) - end - end - - class DisplayDocumentTest < InputMethodTest - def setup - super - @driver = RDoc::RI::Driver.new(use_stdout: true) - end - - def display_document(target, bind, driver = nil) - input_method = IRB::RelineInputMethod.new(IRB::RegexpCompletor.new) - input_method.instance_variable_set(:@rdoc_ri_driver, driver) if driver - input_method.instance_variable_set(:@completion_params, ['', target, '', bind]) - input_method.display_document(target) - end - - def test_perfectly_matched_namespace_triggers_document_display - omit unless has_rdoc_content? - - out, err = capture_output do - display_document("String", binding, @driver) - end - - assert_empty(err) - - assert_include(out, " S\bSt\btr\bri\bin\bng\bg") - end - - def test_perfectly_matched_multiple_namespaces_triggers_document_display - result = nil - out, err = capture_output do - result = display_document("{}.nil?", binding, @driver) - end - - assert_empty(err) - - # check if there're rdoc contents (e.g. CI doesn't generate them) - if has_rdoc_content? - # if there's rdoc content, we can verify by checking stdout - # rdoc generates control characters for formatting method names - assert_include(out, "P\bPr\bro\boc\bc.\b.n\bni\bil\bl?\b?") # Proc.nil? - assert_include(out, "H\bHa\bas\bsh\bh.\b.n\bni\bil\bl?\b?") # Hash.nil? - else - # this is a hacky way to verify the rdoc rendering code path because CI doesn't have rdoc content - # if there are multiple namespaces to be rendered, PerfectMatchedProc renders the result with a document - # which always returns the bytes rendered, even if it's 0 - assert_equal(0, result) - end - end - - def test_not_matched_namespace_triggers_nothing - result = nil - out, err = capture_output do - result = display_document("Stri", binding, @driver) - end - - assert_empty(err) - assert_empty(out) - assert_nil(result) - end - - def test_perfect_matching_stops_without_rdoc - result = nil - - out, err = capture_output do - without_rdoc do - result = display_document("String", binding) - end - end - - assert_empty(err) - assert_not_match(/from ruby core/, out) - assert_nil(result) - end - - def test_perfect_matching_handles_nil_namespace - out, err = capture_output do - # symbol literal has `nil` doc namespace so it's a good test subject - assert_nil(display_document(":aiueo", binding, @driver)) - end - - assert_empty(err) - assert_empty(out) - end - - private - - def has_rdoc_content? - File.exist?(RDoc::RI::Paths::BASE) - end - end -end diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb deleted file mode 100644 index 84b9ee3644..0000000000 --- a/test/irb/test_irb.rb +++ /dev/null @@ -1,806 +0,0 @@ -# frozen_string_literal: true -require "irb" - -require_relative "helper" - -module TestIRB - class InputTest < IntegrationTestCase - def test_symbol_aliases_are_handled_correctly - write_ruby <<~'RUBY' - class Foo - end - binding.irb - RUBY - - output = run_ruby_file do - type "$ Foo" - type "exit!" - end - - assert_include output, "From: #{@ruby_file.path}:1" - end - - def test_symbol_aliases_are_handled_correctly_with_singleline_mode - write_rc <<~RUBY - IRB.conf[:USE_SINGLELINE] = true - RUBY - - write_ruby <<~'RUBY' - class Foo - end - binding.irb - RUBY - - output = run_ruby_file do - type "irb_info" - type "$ Foo" - type "exit!" - end - - # Make sure it's tested in singleline mode - assert_include output, "InputMethod: ReadlineInputMethod" - assert_include output, "From: #{@ruby_file.path}:1" - end - - def test_underscore_stores_last_result - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "1 + 1" - type "_ + 10" - type "exit!" - end - - assert_include output, "=> 12" - end - - def test_evaluate_with_encoding_error_without_lineno - if RUBY_ENGINE == 'truffleruby' - omit "Remove me after https://github.com/ruby/prism/issues/2129 is addressed and adopted in TruffleRuby" - end - - if RUBY_VERSION >= "3.4." - omit "Now raises SyntaxError" - end - - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type %q[:"\xAE"] - type "exit!" - end - - assert_include output, 'invalid symbol in encoding UTF-8 :"\xAE"' - # EncodingError would be wrapped with ANSI escape sequences, so we assert it separately - assert_include output, "EncodingError" - end - - def test_evaluate_still_emits_warning - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type %q[def foo; END {}; end] - type "exit!" - end - - assert_include output, '(irb):1: warning: END in method; use at_exit' - end - - def test_symbol_aliases_dont_affect_ruby_syntax - write_ruby <<~'RUBY' - $foo = "It's a foo" - @bar = "It's a bar" - binding.irb - RUBY - - output = run_ruby_file do - type "$foo" - type "@bar" - type "exit!" - end - - assert_include output, "=> \"It's a foo\"" - assert_include output, "=> \"It's a bar\"" - end - - def test_empty_input_echoing_behaviour - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "" - type " " - type "exit" - end - - assert_not_match(/irb\(main\):001> (\r*\n)?=> nil/, output) - assert_match(/irb\(main\):002> (\r*\n)?=> nil/, output) - end - end - - class IrbIOConfigurationTest < TestCase - Row = Struct.new(:content, :current_line_spaces, :new_line_spaces, :indent_level) - - class MockIO_AutoIndent - attr_reader :calculated_indent - - def initialize(*params) - @params = params - end - - def auto_indent(&block) - @calculated_indent = block.call(*@params) - end - end - - class MockIO_DynamicPrompt - attr_reader :prompt_list - - def initialize(params, &assertion) - @params = params - end - - def dynamic_prompt(&block) - @prompt_list = block.call(@params) - end - end - - def setup - save_encodings - @irb = build_irb - end - - def teardown - restore_encodings - end - - class AutoIndentationTest < IrbIOConfigurationTest - def test_auto_indent - input_with_correct_indents = [ - [%q(def each_top_level_statement), 0, 2], - [%q( initialize_input), 2, 2], - [%q( catch(:TERM_INPUT) do), 2, 4], - [%q( loop do), 4, 6], - [%q( begin), 6, 8], - [%q( prompt), 8, 8], - [%q( unless l = lex), 8, 10], - [%q( throw :TERM_INPUT if @line == ''), 10, 10], - [%q( else), 8, 10], - [%q( @line_no += l.count("\n")), 10, 10], - [%q( next if l == "\n"), 10, 10], - [%q( @line.concat l), 10, 10], - [%q( if @code_block_open or @ltype or @continue or @indent > 0), 10, 12], - [%q( next), 12, 12], - [%q( end), 10, 10], - [%q( end), 8, 8], - [%q( if @line != "\n"), 8, 10], - [%q( @line.force_encoding(@io.encoding)), 10, 10], - [%q( yield @line, @exp_line_no), 10, 10], - [%q( end), 8, 8], - [%q( break if @io.eof?), 8, 8], - [%q( @line = ''), 8, 8], - [%q( @exp_line_no = @line_no), 8, 8], - [%q( ), nil, 8], - [%q( @indent = 0), 8, 8], - [%q( rescue TerminateLineInput), 6, 8], - [%q( initialize_input), 8, 8], - [%q( prompt), 8, 8], - [%q( end), 6, 6], - [%q( end), 4, 4], - [%q( end), 2, 2], - [%q(end), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_braces_on_their_own_line - input_with_correct_indents = [ - [%q(if true), 0, 2], - [%q( [), 2, 4], - [%q( ]), 2, 2], - [%q(end), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_multiple_braces_in_a_line - input_with_correct_indents = [ - [%q([[[), 0, 6], - [%q( ]), 4, 4], - [%q( ]), 2, 2], - [%q(]), 0, 0], - [%q([<<FOO]), 0, 0], - [%q(hello), 0, 0], - [%q(FOO), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_a_closed_brace_and_not_closed_brace_in_a_line - input_with_correct_indents = [ - [%q(p() {), 0, 2], - [%q(}), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_symbols - input_with_correct_indents = [ - [%q(:a), 0, 0], - [%q(:A), 0, 0], - [%q(:+), 0, 0], - [%q(:@@a), 0, 0], - [%q(:@a), 0, 0], - [%q(:$a), 0, 0], - [%q(:def), 0, 0], - [%q(:`), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_incomplete_coding_magic_comment - input_with_correct_indents = [ - [%q(#coding:u), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_incomplete_encoding_magic_comment - input_with_correct_indents = [ - [%q(#encoding:u), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_incomplete_emacs_coding_magic_comment - input_with_correct_indents = [ - [%q(# -*- coding: u), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_incomplete_vim_coding_magic_comment - input_with_correct_indents = [ - [%q(# vim:set fileencoding=u), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_mixed_rescue - input_with_correct_indents = [ - [%q(def m), 0, 2], - [%q( begin), 2, 4], - [%q( begin), 4, 6], - [%q( x = a rescue 4), 6, 6], - [%q( y = [(a rescue 5)]), 6, 6], - [%q( [x, y]), 6, 6], - [%q( rescue => e), 4, 6], - [%q( raise e rescue 8), 6, 6], - [%q( end), 4, 4], - [%q( rescue), 2, 4], - [%q( raise rescue 11), 4, 4], - [%q( end), 2, 2], - [%q(rescue => e), 0, 2], - [%q( raise e rescue 14), 2, 2], - [%q(end), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_oneliner_method_definition - input_with_correct_indents = [ - [%q(class A), 0, 2], - [%q( def foo0), 2, 4], - [%q( 3), 4, 4], - [%q( end), 2, 2], - [%q( def foo1()), 2, 4], - [%q( 3), 4, 4], - [%q( end), 2, 2], - [%q( def foo2(a, b)), 2, 4], - [%q( a + b), 4, 4], - [%q( end), 2, 2], - [%q( def foo3 a, b), 2, 4], - [%q( a + b), 4, 4], - [%q( end), 2, 2], - [%q( def bar0() = 3), 2, 2], - [%q( def bar1(a) = a), 2, 2], - [%q( def bar2(a, b) = a + b), 2, 2], - [%q( def bar3() = :s), 2, 2], - [%q( def bar4() = Time.now), 2, 2], - [%q(end), 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents) - end - - def test_tlambda - input_with_correct_indents = [ - [%q(if true), 0, 2, 1], - [%q( -> {), 2, 4, 2], - [%q( }), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_corresponding_syntax_to_keyword_do_in_class - input_with_correct_indents = [ - [%q(class C), 0, 2, 1], - [%q( while method_name do), 2, 4, 2], - [%q( 3), 4, 4, 2], - [%q( end), 2, 2, 1], - [%q( foo do), 2, 4, 2], - [%q( 3), 4, 4, 2], - [%q( end), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_corresponding_syntax_to_keyword_do - input_with_correct_indents = [ - [%q(while i > 0), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(while true), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(while ->{i > 0}.call), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(while ->{true}.call), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(while i > 0 do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(while true do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(while ->{i > 0}.call do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(while ->{true}.call do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(foo do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(foo true do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(foo ->{true} do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - [%q(foo ->{i > 0} do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_corresponding_syntax_to_keyword_for - input_with_correct_indents = [ - [%q(for i in [1]), 0, 2, 1], - [%q( puts i), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_corresponding_syntax_to_keyword_for_with_do - input_with_correct_indents = [ - [%q(for i in [1] do), 0, 2, 1], - [%q( puts i), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_typing_incomplete_include_interpreted_as_keyword_in - input_with_correct_indents = [ - [%q(module E), 0, 2, 1], - [%q(end), 0, 0, 0], - [%q(class A), 0, 2, 1], - [%q( in), 2, 2, 1] # scenario typing `include E` - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - - end - - def test_bracket_corresponding_to_times - input_with_correct_indents = [ - [%q(3.times { |i|), 0, 2, 1], - [%q( puts i), 2, 2, 1], - [%q(}), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_do_corresponding_to_times - input_with_correct_indents = [ - [%q(3.times do |i|), 0, 2, 1], - [%q( puts i), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_bracket_corresponding_to_loop - input_with_correct_indents = [ - ['loop {', 0, 2, 1], - [' 3', 2, 2, 1], - ['}', 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_do_corresponding_to_loop - input_with_correct_indents = [ - [%q(loop do), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_embdoc_indent - input_with_correct_indents = [ - [%q(=begin), 0, 0, 0], - [%q(a), 0, 0, 0], - [%q( b), 1, 1, 0], - [%q(=end), 0, 0, 0], - [%q(if 1), 0, 2, 1], - [%q( 2), 2, 2, 1], - [%q(=begin), 0, 0, 0], - [%q(a), 0, 0, 0], - [%q( b), 1, 1, 0], - [%q(=end), 0, 2, 1], - [%q( 3), 2, 2, 1], - [%q(end), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_heredoc_with_indent - if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7.0') - pend 'This test needs Ripper::Lexer#scan to take broken tokens' - end - input_with_correct_indents = [ - [%q(<<~Q+<<~R), 0, 2, 1], - [%q(a), 2, 2, 1], - [%q(a), 2, 2, 1], - [%q( b), 2, 2, 1], - [%q( b), 2, 2, 1], - [%q( Q), 0, 2, 1], - [%q( c), 4, 4, 1], - [%q( c), 4, 4, 1], - [%q( R), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_oneliner_def_in_multiple_lines - input_with_correct_indents = [ - [%q(def a()=[), 0, 2, 1], - [%q( 1,), 2, 2, 1], - [%q(].), 0, 0, 0], - [%q(to_s), 0, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_broken_heredoc - input_with_correct_indents = [ - [%q(def foo), 0, 2, 1], - [%q( <<~Q), 2, 4, 2], - [%q( Qend), 4, 4, 2], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_pasted_code_keep_base_indent_spaces - input_with_correct_indents = [ - [%q( def foo), 0, 6, 1], - [%q( if bar), 6, 10, 2], - [%q( [1), 10, 12, 3], - [%q( ]+[["a), 10, 14, 4], - [%q(b" + `c), 0, 14, 4], - [%q(d` + /e), 0, 14, 4], - [%q(f/ + :"g), 0, 14, 4], - [%q(h".tap do), 0, 16, 5], - [%q( 1), 16, 16, 5], - [%q( end), 14, 14, 4], - [%q( ]), 12, 12, 3], - [%q( ]), 10, 10, 2], - [%q( end), 8, 6, 1], - [%q( end), 4, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_pasted_code_keep_base_indent_spaces_with_heredoc - input_with_correct_indents = [ - [%q( def foo), 0, 6, 1], - [%q( if bar), 6, 10, 2], - [%q( [1), 10, 12, 3], - [%q( ]+[["a), 10, 14, 4], - [%q(b" + <<~A + <<-B + <<C), 0, 16, 5], - [%q( a#{), 16, 18, 6], - [%q( 1), 18, 18, 6], - [%q( }), 16, 16, 5], - [%q( A), 14, 16, 5], - [%q( b#{), 16, 18, 6], - [%q( 1), 18, 18, 6], - [%q( }), 16, 16, 5], - [%q( B), 14, 0, 0], - [%q(c#{), 0, 2, 1], - [%q(1), 2, 2, 1], - [%q(}), 0, 0, 0], - [%q(C), 0, 14, 4], - [%q( ]), 12, 12, 3], - [%q( ]), 10, 10, 2], - [%q( end), 8, 6, 1], - [%q( end), 4, 0, 0], - ] - - assert_rows_with_correct_indents(input_with_correct_indents, assert_indent_level: true) - end - - def test_heredoc_keep_indent_spaces - (1..4).each do |indent| - row = Row.new(' ' * indent, nil, [4, indent].max, 2) - lines = ['def foo', ' <<~Q', row.content] - assert_row_indenting(lines, row) - assert_indent_level(lines, row.indent_level) - end - end - - private - - def assert_row_indenting(lines, row) - actual_current_line_spaces = calculate_indenting(lines, false) - - error_message = <<~MSG - Incorrect spaces calculation for line: - - ``` - > #{lines.last} - ``` - - All lines: - - ``` - #{lines.join("\n")} - ``` - MSG - assert_equal(row.current_line_spaces, actual_current_line_spaces, error_message) - - error_message = <<~MSG - Incorrect spaces calculation for line after the current line: - - ``` - #{lines.last} - > - ``` - - All lines: - - ``` - #{lines.join("\n")} - ``` - MSG - actual_next_line_spaces = calculate_indenting(lines, true) - assert_equal(row.new_line_spaces, actual_next_line_spaces, error_message) - end - - def assert_rows_with_correct_indents(rows_with_spaces, assert_indent_level: false) - lines = [] - rows_with_spaces.map do |row| - row = Row.new(*row) - lines << row.content - assert_row_indenting(lines, row) - - if assert_indent_level - assert_indent_level(lines, row.indent_level) - end - end - end - - def assert_indent_level(lines, expected) - code = lines.map { |l| "#{l}\n" }.join # code should end with "\n" - _tokens, opens, _ = @irb.scanner.check_code_state(code, local_variables: []) - indent_level = @irb.scanner.calc_indent_level(opens) - error_message = "Calculated the wrong number of indent level for:\n #{lines.join("\n")}" - assert_equal(expected, indent_level, error_message) - end - - def calculate_indenting(lines, add_new_line) - lines = lines + [""] if add_new_line - last_line_index = lines.length - 1 - byte_pointer = lines.last.length - - mock_io = MockIO_AutoIndent.new(lines, last_line_index, byte_pointer, add_new_line) - @irb.context.auto_indent_mode = true - @irb.context.io = mock_io - @irb.configure_io - - mock_io.calculated_indent - end - end - - class DynamicPromptTest < IrbIOConfigurationTest - def test_endless_range_at_end_of_line - input_with_prompt = [ - ['001:0: :> ', %q(a = 3..)], - ['002:0: :> ', %q()], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def test_heredoc_with_embexpr - input_with_prompt = [ - ['001:0:":* ', %q(<<A+%W[#{<<B)], - ['002:0:":* ', %q(#{<<C+%W[)], - ['003:0:":* ', %q(a)], - ['004:2:]:* ', %q(C)], - ['005:2:]:* ', %q(a)], - ['006:0:":* ', %q(]})], - ['007:0:":* ', %q(})], - ['008:0:":* ', %q(A)], - ['009:2:]:* ', %q(B)], - ['010:1:]:* ', %q(})], - ['011:0: :> ', %q(])], - ['012:0: :> ', %q()], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def test_heredoc_prompt_with_quotes - input_with_prompt = [ - ["001:1:':* ", %q(<<~'A')], - ["002:1:':* ", %q(#{foobar})], - ["003:0: :> ", %q(A)], - ["004:1:`:* ", %q(<<~`A`)], - ["005:1:`:* ", %q(whoami)], - ["006:0: :> ", %q(A)], - ['007:1:":* ', %q(<<~"A")], - ['008:1:":* ', %q(foobar)], - ['009:0: :> ', %q(A)], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def test_backtick_method - input_with_prompt = [ - ['001:0: :> ', %q(self.`(arg))], - ['002:0: :> ', %q()], - ['003:0: :> ', %q(def `(); end)], - ['004:0: :> ', %q()], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def test_dynamic_prompt - input_with_prompt = [ - ['001:1: :* ', %q(def hoge)], - ['002:1: :* ', %q( 3)], - ['003:0: :> ', %q(end)], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def test_dynamic_prompt_with_double_newline_breaking_code - input_with_prompt = [ - ['001:1: :* ', %q(if true)], - ['002:2: :* ', %q(%)], - ['003:1: :* ', %q(;end)], - ['004:1: :* ', %q(;hello)], - ['005:0: :> ', %q(end)], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def test_dynamic_prompt_with_multiline_literal - input_with_prompt = [ - ['001:1: :* ', %q(if true)], - ['002:2:]:* ', %q( %w[)], - ['003:2:]:* ', %q( a)], - ['004:1: :* ', %q( ])], - ['005:1: :* ', %q( b)], - ['006:2:]:* ', %q( %w[)], - ['007:2:]:* ', %q( c)], - ['008:1: :* ', %q( ])], - ['009:0: :> ', %q(end)], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def test_dynamic_prompt_with_blank_line - input_with_prompt = [ - ['001:1:]:* ', %q(%w[)], - ['002:1:]:* ', %q()], - ['003:0: :> ', %q(])], - ] - - assert_dynamic_prompt(input_with_prompt) - end - - def assert_dynamic_prompt(input_with_prompt) - expected_prompt_list, lines = input_with_prompt.transpose - def @irb.generate_prompt(opens, continue, line_offset) - ltype = @scanner.ltype_from_open_tokens(opens) - indent = @scanner.calc_indent_level(opens) - continue = opens.any? || continue - line_no = @line_no + line_offset - '%03d:%01d:%1s:%s ' % [line_no, indent, ltype, continue ? '*' : '>'] - end - io = MockIO_DynamicPrompt.new(lines) - @irb.context.io = io - @irb.configure_io - - error_message = <<~EOM - Expected dynamic prompt: - #{expected_prompt_list.join("\n")} - - Actual dynamic prompt: - #{io.prompt_list.join("\n")} - EOM - assert_equal(expected_prompt_list, io.prompt_list, error_message) - end - end - - private - - def build_binding - Object.new.instance_eval { binding } - end - - def build_irb - IRB.init_config(nil) - workspace = IRB::WorkSpace.new(build_binding) - - IRB.conf[:VERBOSE] = false - IRB::Irb.new(workspace, TestInputMethod.new) - end - end -end diff --git a/test/irb/test_locale.rb b/test/irb/test_locale.rb deleted file mode 100644 index 930a38834c..0000000000 --- a/test/irb/test_locale.rb +++ /dev/null @@ -1,118 +0,0 @@ -require "irb" -require "stringio" - -require_relative "helper" - -module TestIRB - class LocaleTestCase < TestCase - def test_initialize_with_en - locale = IRB::Locale.new("en_US.UTF-8") - - assert_equal("en", locale.lang) - assert_equal("US", locale.territory) - assert_equal("UTF-8", locale.encoding.name) - assert_equal(nil, locale.modifier) - end - - def test_initialize_with_ja - locale = IRB::Locale.new("ja_JP.UTF-8") - - assert_equal("ja", locale.lang) - assert_equal("JP", locale.territory) - assert_equal("UTF-8", locale.encoding.name) - assert_equal(nil, locale.modifier) - end - - def test_initialize_with_legacy_ja_encoding_ujis - original_stderr = $stderr - $stderr = StringIO.new - - locale = IRB::Locale.new("ja_JP.ujis") - - assert_equal("ja", locale.lang) - assert_equal("JP", locale.territory) - assert_equal(Encoding::EUC_JP, locale.encoding) - assert_equal(nil, locale.modifier) - - assert_include $stderr.string, "ja_JP.ujis is obsolete. use ja_JP.EUC-JP" - ensure - $stderr = original_stderr - end - - def test_initialize_with_legacy_ja_encoding_euc - original_stderr = $stderr - $stderr = StringIO.new - - locale = IRB::Locale.new("ja_JP.euc") - - assert_equal("ja", locale.lang) - assert_equal("JP", locale.territory) - assert_equal(Encoding::EUC_JP, locale.encoding) - assert_equal(nil, locale.modifier) - - assert_include $stderr.string, "ja_JP.euc is obsolete. use ja_JP.EUC-JP" - ensure - $stderr = original_stderr - end - - %w(IRB_LANG LC_MESSAGES LC_ALL LANG).each do |env_var| - define_method "test_initialize_with_#{env_var.downcase}" do - original_values = { - "IRB_LANG" => ENV["IRB_LANG"], - "LC_MESSAGES" => ENV["LC_MESSAGES"], - "LC_ALL" => ENV["LC_ALL"], - "LANG" => ENV["LANG"], - } - - ENV["IRB_LANG"] = ENV["LC_MESSAGES"] = ENV["LC_ALL"] = ENV["LANG"] = nil - ENV[env_var] = "zh_TW.UTF-8" - - locale = IRB::Locale.new - - assert_equal("zh", locale.lang) - assert_equal("TW", locale.territory) - assert_equal("UTF-8", locale.encoding.name) - assert_equal(nil, locale.modifier) - ensure - original_values.each do |key, value| - ENV[key] = value - end - end - end - - def test_load - # reset Locale's internal cache - IRB::Locale.class_variable_set(:@@loaded, []) - # Because error.rb files define the same class, loading them causes method redefinition warnings. - original_verbose = $VERBOSE - $VERBOSE = nil - - jp_local = IRB::Locale.new("ja_JP.UTF-8") - jp_local.load("irb/error.rb") - msg = IRB::CantReturnToNormalMode.new.message - assert_equal("Normalモードに戻れません.", msg) - - # reset Locale's internal cache - IRB::Locale.class_variable_set(:@@loaded, []) - - en_local = IRB::Locale.new("en_US.UTF-8") - en_local.load("irb/error.rb") - msg = IRB::CantReturnToNormalMode.new.message - assert_equal("Can't return to normal mode.", msg) - ensure - # before turning warnings back on, load the error.rb file again to avoid warnings in other tests - IRB::Locale.new.load("irb/error.rb") - $VERBOSE = original_verbose - end - - def test_find - jp_local = IRB::Locale.new("ja_JP.UTF-8") - path = jp_local.find("irb/error.rb") - assert_include(path, "/lib/irb/lc/ja/error.rb") - - en_local = IRB::Locale.new("en_US.UTF-8") - path = en_local.find("irb/error.rb") - assert_include(path, "/lib/irb/lc/error.rb") - end - end -end diff --git a/test/irb/test_nesting_parser.rb b/test/irb/test_nesting_parser.rb deleted file mode 100644 index 2482d40081..0000000000 --- a/test/irb/test_nesting_parser.rb +++ /dev/null @@ -1,341 +0,0 @@ -# frozen_string_literal: false -require 'irb' - -require_relative "helper" - -module TestIRB - class NestingParserTest < TestCase - def setup - save_encodings - end - - def teardown - restore_encodings - end - - def parse_by_line(code) - IRB::NestingParser.parse_by_line(IRB::RubyLex.ripper_lex_without_warning(code)) - end - - def test_open_tokens - code = <<~'EOS' - class A - def f - if true - tap do - { - x: " - #{p(1, 2, 3 - EOS - opens = IRB::NestingParser.open_tokens(IRB::RubyLex.ripper_lex_without_warning(code)) - assert_equal(%w[class def if do { " #{ (], opens.map(&:tok)) - end - - def test_parse_by_line - code = <<~EOS - (((((1+2 - ).to_s())).tap do ((( - EOS - _tokens, prev_opens, next_opens, min_depth = parse_by_line(code).last - assert_equal(%w[( ( ( ( (], prev_opens.map(&:tok)) - assert_equal(%w[( ( do ( ( (], next_opens.map(&:tok)) - assert_equal(2, min_depth) - end - - def test_ruby_syntax - code = <<~'EOS' - class A - 1 if 2 - 1 while 2 - 1 until 2 - 1 unless 2 - 1 rescue 2 - begin; rescue; ensure; end - tap do; rescue; ensure; end - class B; end - module C; end - def f; end - def `; end - def f() = 1 - %(); %w[]; %q(); %r{}; %i[] - "#{1}"; ''; /#{1}/; `#{1}` - :sym; :"sym"; :+; :`; :if - [1, 2, 3] - { x: 1, y: 2 } - (a, (*b, c), d), e = 1, 2, 3 - ->(a){}; ->(a) do end - -> a = -> b = :do do end do end - if 1; elsif 2; else; end - unless 1; end - while 1; end - until 1; end - for i in j; end - case 1; when 2; end - puts(1, 2, 3) - loop{|i|} - loop do |i| end - end - EOS - line_results = parse_by_line(code) - assert_equal(code.lines.size, line_results.size) - class_open, *inner_line_results, class_close = line_results - assert_equal(['class'], class_open[2].map(&:tok)) - inner_line_results.each {|result| assert_equal(['class'], result[2].map(&:tok)) } - assert_equal([], class_close[2].map(&:tok)) - end - - def test_multiline_string - code = <<~EOS - " - aaa - bbb - " - <<A - aaa - bbb - A - EOS - line_results = parse_by_line(code) - assert_equal(code.lines.size, line_results.size) - string_content_line, string_opens = line_results[1] - assert_equal("\naaa\nbbb\n", string_content_line.first.first.tok) - assert_equal("aaa\n", string_content_line.first.last) - assert_equal(['"'], string_opens.map(&:tok)) - heredoc_content_line, heredoc_opens = line_results[6] - assert_equal("aaa\nbbb\n", heredoc_content_line.first.first.tok) - assert_equal("bbb\n", heredoc_content_line.first.last) - assert_equal(['<<A'], heredoc_opens.map(&:tok)) - _line, _prev_opens, next_opens, _min_depth = line_results.last - assert_equal([], next_opens) - end - - def test_backslash_continued_nested_symbol - code = <<~'EOS' - x = <<A, :\ - heredoc #{ - here - } - A - =begin - embdoc - =end - # comment - - if # this is symbol :if - while - EOS - line_results = parse_by_line(code) - assert_equal(%w[: <<A #{], line_results[2][2].map(&:tok)) - assert_equal(%w[while], line_results.last[2].map(&:tok)) - end - - def test_oneliner_def - code = <<~EOC - if true - # normal oneliner def - def f = 1 - def f() = 1 - def f(*) = 1 - # keyword, backtick, op - def * = 1 - def ` = 1 - def if = 1 - def *() = 1 - def `() = 1 - def if() = 1 - # oneliner def with receiver - def a.* = 1 - def $a.* = 1 - def @a.` = 1 - def A.` = 1 - def ((a;b;c)).*() = 1 - def ((a;b;c)).if() = 1 - def ((a;b;c)).end() = 1 - # multiline oneliner def - def f = - 1 - def f() - = - 1 - # oneliner def with comment and embdoc - def # comment - =begin - embdoc - =end - ((a;b;c)) - . # comment - =begin - embdoc - =end - f (*) # comment - =begin - embdoc - =end - = - 1 - # nested oneliner def - def f(x = def f() = 1) = def f() = 1 - EOC - _tokens, _prev_opens, next_opens, min_depth = parse_by_line(code).last - assert_equal(['if'], next_opens.map(&:tok)) - assert_equal(1, min_depth) - end - - def test_heredoc_embexpr - code = <<~'EOS' - <<A+<<B+<<C+(<<D+(<<E) - #{ - <<~F+"#{<<~G} - #{ - here - } - F - G - " - } - A - B - C - D - E - ) - EOS - line_results = parse_by_line(code) - last_opens = line_results.last[-2] - assert_equal([], last_opens) - _tokens, _prev_opens, next_opens, _min_depth = line_results[4] - assert_equal(%w[( <<E <<D <<C <<B <<A #{ " <<~G <<~F #{], next_opens.map(&:tok)) - end - - def test_for_in - code = <<~EOS - for i in j - here - end - for i in j do - here - end - for i in - j do - here - end - for - # comment - i in j do - here - end - for (a;b;c).d in (a;b;c) do - here - end - for i in :in + :do do - here - end - for i in -> do end do - here - end - EOS - line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include?('here') } - assert_equal(7, line_results.size) - line_results.each do |_tokens, _prev_opens, next_opens, _min_depth| - assert_equal(['for'], next_opens.map(&:tok)) - end - end - - def test_while_until - base_code = <<~'EOS' - while_or_until true - here - end - while_or_until a < c - here - end - while_or_until true do - here - end - while_or_until - # comment - (a + b) < - # comment - c do - here - end - while_or_until :\ - do do - here - end - while_or_until def do; end == :do do - here - end - while_or_until -> do end do - here - end - EOS - %w[while until].each do |keyword| - code = base_code.gsub('while_or_until', keyword) - line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include?('here') } - assert_equal(7, line_results.size) - line_results.each do |_tokens, _prev_opens, next_opens, _min_depth| - assert_equal([keyword], next_opens.map(&:tok) ) - end - end - end - - def test_undef_alias - codes = [ - 'undef foo', - 'alias foo bar', - 'undef !', - 'alias + -', - 'alias $a $b', - 'undef do', - 'alias do do', - 'undef :do', - 'alias :do :do', - 'undef :"#{alias do do}"', - 'alias :"#{undef do}" do', - 'alias do :"#{undef do}"' - ] - code_with_comment = <<~EOS - undef # - # - do # - alias # - # - do # - # - do # - EOS - code_with_heredoc = <<~EOS - <<~A; alias - A - :"#{<<~A}" - A - do - EOS - [*codes, code_with_comment, code_with_heredoc].each do |code| - opens = IRB::NestingParser.open_tokens(IRB::RubyLex.ripper_lex_without_warning('(' + code + "\nif")) - assert_equal(%w[( if], opens.map(&:tok)) - end - end - - def test_case_in - if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7.0') - pend 'This test requires ruby version that supports case-in syntax' - end - code = <<~EOS - case 1 - in 1 - here - in - 2 - here - end - EOS - line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include?('here') } - assert_equal(2, line_results.size) - line_results.each do |_tokens, _prev_opens, next_opens, _min_depth| - assert_equal(['in'], next_opens.map(&:tok)) - end - end - end -end diff --git a/test/irb/test_option.rb b/test/irb/test_option.rb deleted file mode 100644 index fec31f384f..0000000000 --- a/test/irb/test_option.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: false -require_relative "helper" - -module TestIRB - class OptionTest < TestCase - def test_end_of_option - bug4117 = '[ruby-core:33574]' - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - status = assert_in_out_err(bundle_exec + %w[-W0 -rirb -e IRB.start(__FILE__) -- -f --], "", //, [], bug4117) - assert(status.success?, bug4117) - end - end -end diff --git a/test/irb/test_raise_exception.rb b/test/irb/test_raise_exception.rb deleted file mode 100644 index 44a5ae87e1..0000000000 --- a/test/irb/test_raise_exception.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: false -require "tmpdir" - -require_relative "helper" - -module TestIRB - class RaiseExceptionTest < TestCase - def test_raise_exception_with_nil_backtrace - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, /#<Exception: foo>/, []) - raise Exception.new("foo").tap {|e| def e.backtrace; nil; end } -IRB - end - - def test_raise_exception_with_message_exception - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - expected = /#<Exception: foo>\nbacktraces are hidden because bar was raised when processing them/ - assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, expected, []) - e = Exception.new("foo") - def e.message; raise 'bar'; end - raise e -IRB - end - - def test_raise_exception_with_message_inspect_exception - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - expected = /Uninspectable exception occurred/ - assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, expected, []) - e = Exception.new("foo") - def e.message; raise; end - def e.inspect; raise; end - raise e -IRB - end - - def test_raise_exception_with_invalid_byte_sequence - pend if RUBY_ENGINE == 'truffleruby' || /mswin|mingw/ =~ RUBY_PLATFORM - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<~IRB, /A\\xF3B \(StandardError\)/, []) - raise StandardError, "A\\xf3B" - IRB - end - - def test_raise_exception_with_different_encoding_containing_invalid_byte_sequence - backup_home = ENV["HOME"] - Dir.mktmpdir("test_irb_raise_no_backtrace_exception_#{$$}") do |tmpdir| - ENV["HOME"] = tmpdir - - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - File.open("#{tmpdir}/euc.rb", 'w') do |f| - f.write(<<~EOF) - # encoding: euc-jp - - def raise_euc_with_invalid_byte_sequence - raise "\xA4\xA2\\xFF" - end - EOF - end - env = {} - %w(LC_MESSAGES LC_ALL LC_CTYPE LANG).each {|n| env[n] = "ja_JP.UTF-8" } - # TruffleRuby warns when the locale does not exist - env['TRUFFLERUBYOPT'] = "#{ENV['TRUFFLERUBYOPT']} --log.level=SEVERE" if RUBY_ENGINE == 'truffleruby' - args = [env] + bundle_exec + %W[-rirb -C #{tmpdir} -W0 -e IRB.start(__FILE__) -- -f --] - error = /raise_euc_with_invalid_byte_sequence': あ\\xFF \(RuntimeError\)/ - assert_in_out_err(args, <<~IRB, error, [], encoding: "UTF-8") - require_relative 'euc' - raise_euc_with_invalid_byte_sequence - IRB - end - ensure - ENV["HOME"] = backup_home - end - end -end diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb deleted file mode 100644 index 4e406a8ce0..0000000000 --- a/test/irb/test_ruby_lex.rb +++ /dev/null @@ -1,242 +0,0 @@ -# frozen_string_literal: true -require "irb" - -require_relative "helper" - -module TestIRB - class RubyLexTest < TestCase - def setup - save_encodings - end - - def teardown - restore_encodings - end - - def test_interpolate_token_with_heredoc_and_unclosed_embexpr - code = <<~'EOC' - ①+<<A-② - #{③*<<B/④ - #{⑤&<<C|⑥ - EOC - ripper_tokens = Ripper.tokenize(code) - rubylex_tokens = IRB::RubyLex.ripper_lex_without_warning(code) - # Assert no missing part - assert_equal(code, rubylex_tokens.map(&:tok).join) - # Assert ripper tokens are not removed - ripper_tokens.each do |tok| - assert(rubylex_tokens.any? { |t| t.tok == tok && t.tok != :on_ignored_by_ripper }) - end - # Assert interpolated token position - rubylex_tokens.each do |t| - row, col = t.pos - assert_equal t.tok, code.lines[row - 1].byteslice(col, t.tok.bytesize) - end - end - - def test_local_variables_dependent_code - lines = ["a /1#/ do", "2"] - assert_indent_level(lines, 1) - assert_code_block_open(lines, true) - assert_indent_level(lines, 0, local_variables: ['a']) - assert_code_block_open(lines, false, local_variables: ['a']) - end - - def test_literal_ends_with_space - assert_code_block_open(['% a'], true) - assert_code_block_open(['% a '], false) - end - - def test_literal_ends_with_newline - assert_code_block_open(['%'], true) - assert_code_block_open(['%', ''], false) - end - - def test_should_continue - assert_should_continue(['a'], false) - assert_should_continue(['/a/'], false) - assert_should_continue(['a;'], false) - assert_should_continue(['<<A', 'A'], false) - assert_should_continue(['a...'], false) - assert_should_continue(['a\\'], true) - assert_should_continue(['a.'], true) - assert_should_continue(['a+'], true) - assert_should_continue(['a; #comment', '', '=begin', 'embdoc', '=end', ''], false) - assert_should_continue(['a+ #comment', '', '=begin', 'embdoc', '=end', ''], true) - end - - def test_code_block_open_with_should_continue - # syntax ok - assert_code_block_open(['a'], false) # continue: false - assert_code_block_open(['a\\'], true) # continue: true - - # recoverable syntax error code is not terminated - assert_code_block_open(['a+'], true) - - # unrecoverable syntax error code is terminated - assert_code_block_open(['.; a+'], false) - - # other syntax error that failed to determine if it is recoverable or not - assert_code_block_open(['@; a'], false) - assert_code_block_open(['@; a+'], true) - assert_code_block_open(['@; (a'], true) - end - - def test_broken_percent_literal - tokens = IRB::RubyLex.ripper_lex_without_warning('%wwww') - pos_to_index = {} - tokens.each_with_index { |t, i| - assert_nil(pos_to_index[t.pos], "There is already another token in the position of #{t.inspect}.") - pos_to_index[t.pos] = i - } - end - - def test_broken_percent_literal_in_method - tokens = IRB::RubyLex.ripper_lex_without_warning(<<~EOC.chomp) - def foo - %wwww - end - EOC - pos_to_index = {} - tokens.each_with_index { |t, i| - assert_nil(pos_to_index[t.pos], "There is already another token in the position of #{t.inspect}.") - pos_to_index[t.pos] = i - } - end - - def test_unterminated_code - ['do', '<<A'].each do |code| - tokens = IRB::RubyLex.ripper_lex_without_warning(code) - assert_equal(code, tokens.map(&:tok).join, "Cannot reconstruct code from tokens") - error_tokens = tokens.map(&:event).grep(/error/) - assert_empty(error_tokens, 'Error tokens must be ignored if there is corresponding non-error token') - end - end - - def test_unterminated_heredoc_string_literal - ['<<A;<<B', "<<A;<<B\n", "%W[\#{<<A;<<B", "%W[\#{<<A;<<B\n"].each do |code| - tokens = IRB::RubyLex.ripper_lex_without_warning(code) - string_literal = IRB::NestingParser.open_tokens(tokens).last - assert_equal('<<A', string_literal&.tok) - end - end - - def test_indent_level_with_heredoc_and_embdoc - reference_code = <<~EOC.chomp - if true - hello - p( - ) - EOC - code_with_heredoc = <<~EOC.chomp - if true - <<~A - A - p( - ) - EOC - code_with_embdoc = <<~EOC.chomp - if true - =begin - =end - p( - ) - EOC - expected = 1 - assert_indent_level(reference_code.lines, expected) - assert_indent_level(code_with_heredoc.lines, expected) - assert_indent_level(code_with_embdoc.lines, expected) - end - - def test_assignment_expression - ruby_lex = IRB::RubyLex.new - - [ - "foo = bar", - "@foo = bar", - "$foo = bar", - "@@foo = bar", - "::Foo = bar", - "a::Foo = bar", - "Foo = bar", - "foo.bar = 1", - "foo[1] = bar", - "foo += bar", - "foo -= bar", - "foo ||= bar", - "foo &&= bar", - "foo, bar = 1, 2", - "foo.bar=(1)", - "foo; foo = bar", - "foo; foo = bar; ;\n ;", - "foo\nfoo = bar", - ].each do |exp| - assert( - ruby_lex.assignment_expression?(exp, local_variables: []), - "#{exp.inspect}: should be an assignment expression" - ) - end - - [ - "foo", - "foo.bar", - "foo[0]", - "foo = bar; foo", - "foo = bar\nfoo", - ].each do |exp| - refute( - ruby_lex.assignment_expression?(exp, local_variables: []), - "#{exp.inspect}: should not be an assignment expression" - ) - end - end - - def test_assignment_expression_with_local_variable - ruby_lex = IRB::RubyLex.new - code = "a /1;x=1#/" - refute(ruby_lex.assignment_expression?(code, local_variables: []), "#{code}: should not be an assignment expression") - assert(ruby_lex.assignment_expression?(code, local_variables: [:a]), "#{code}: should be an assignment expression") - refute(ruby_lex.assignment_expression?("", local_variables: [:a]), "empty code should not be an assignment expression") - end - - def test_initialising_the_old_top_level_ruby_lex - assert_in_out_err(["--disable-gems", "-W:deprecated"], <<~RUBY, [], /warning: constant ::RubyLex is deprecated/) - require "irb" - ::RubyLex.new(nil) - RUBY - end - - private - - def assert_indent_level(lines, expected, local_variables: []) - indent_level, _continue, _code_block_open = check_state(lines, local_variables: local_variables) - error_message = "Calculated the wrong number of indent level for:\n #{lines.join("\n")}" - assert_equal(expected, indent_level, error_message) - end - - def assert_should_continue(lines, expected, local_variables: []) - _indent_level, continue, _code_block_open = check_state(lines, local_variables: local_variables) - error_message = "Wrong result of should_continue for:\n #{lines.join("\n")}" - assert_equal(expected, continue, error_message) - end - - def assert_code_block_open(lines, expected, local_variables: []) - if RUBY_ENGINE == 'truffleruby' - omit "Remove me after https://github.com/ruby/prism/issues/2129 is addressed and adopted in TruffleRuby" - end - - _indent_level, _continue, code_block_open = check_state(lines, local_variables: local_variables) - error_message = "Wrong result of code_block_open for:\n #{lines.join("\n")}" - assert_equal(expected, code_block_open, error_message) - end - - def check_state(lines, local_variables: []) - code = lines.map { |l| "#{l}\n" }.join # code should end with "\n" - ruby_lex = IRB::RubyLex.new - tokens, opens, terminated = ruby_lex.check_code_state(code, local_variables: local_variables) - indent_level = ruby_lex.calc_indent_level(opens) - continue = ruby_lex.should_continue?(tokens) - [indent_level, continue, !terminated] - end - end -end diff --git a/test/irb/test_tracer.rb b/test/irb/test_tracer.rb deleted file mode 100644 index 540f8be131..0000000000 --- a/test/irb/test_tracer.rb +++ /dev/null @@ -1,90 +0,0 @@ -# frozen_string_literal: false -require 'tempfile' -require 'irb' - -require_relative "helper" - -module TestIRB - class ContextWithTracerIntegrationTest < IntegrationTestCase - def setup - super - - omit "Tracer gem is not available when running on TruffleRuby" if RUBY_ENGINE == "truffleruby" - - @envs.merge!("NO_COLOR" => "true") - end - - def example_ruby_file - <<~'RUBY' - class Foo - def self.foo - 100 - end - end - - def bar(obj) - obj.foo - end - - binding.irb - RUBY - end - - def test_use_tracer_enabled_when_gem_is_unavailable - write_rc <<~RUBY - # Simulate the absence of the tracer gem - ::Kernel.send(:alias_method, :irb_original_require, :require) - - ::Kernel.define_method(:require) do |name| - raise LoadError, "cannot load such file -- tracer (test)" if name.match?("tracer") - ::Kernel.send(:irb_original_require, name) - end - - IRB.conf[:USE_TRACER] = true - RUBY - - write_ruby example_ruby_file - - output = run_ruby_file do - type "bar(Foo)" - type "exit" - end - - assert_include(output, "Tracer extension of IRB is enabled but tracer gem wasn't found.") - end - - def test_use_tracer_enabled_when_gem_is_available - write_rc <<~RUBY - IRB.conf[:USE_TRACER] = true - RUBY - - write_ruby example_ruby_file - - output = run_ruby_file do - type "bar(Foo)" - type "exit" - end - - assert_include(output, "Object#bar at") - assert_include(output, "Foo.foo at") - assert_include(output, "Foo.foo #=> 100") - assert_include(output, "Object#bar #=> 100") - - # Test that the tracer output does not include IRB's own files - assert_not_include(output, "irb/workspace.rb") - end - - def test_use_tracer_is_disabled_by_default - write_ruby example_ruby_file - - output = run_ruby_file do - type "bar(Foo)" - type "exit" - end - - assert_not_include(output, "#depth:") - assert_not_include(output, "Foo.foo") - end - - end -end diff --git a/test/irb/test_type_completor.rb b/test/irb/test_type_completor.rb deleted file mode 100644 index 5ed8988b34..0000000000 --- a/test/irb/test_type_completor.rb +++ /dev/null @@ -1,88 +0,0 @@ -# frozen_string_literal: true - -# Run test only when Ruby >= 3.0 and repl_type_completor is available -return unless RUBY_VERSION >= '3.0.0' -return if RUBY_ENGINE == 'truffleruby' # needs endless method definition -begin - require 'repl_type_completor' -rescue LoadError - return -end - -require 'irb' -require 'tempfile' -require_relative './helper' - -module TestIRB - class TypeCompletorTest < TestCase - DummyContext = Struct.new(:irb_path) - - def setup - ReplTypeCompletor.load_rbs unless ReplTypeCompletor.rbs_loaded? - context = DummyContext.new('(irb)') - @completor = IRB::TypeCompletor.new(context) - end - - def empty_binding - binding - end - - def assert_completion(preposing, target, binding: empty_binding, include: nil, exclude: nil) - raise ArgumentError if include.nil? && exclude.nil? - candidates = @completor.completion_candidates(preposing, target, '', bind: binding) - assert ([*include] - candidates).empty?, "Expected #{candidates} to include #{include}" if include - assert (candidates & [*exclude]).empty?, "Expected #{candidates} not to include #{exclude}" if exclude - end - - def assert_doc_namespace(preposing, target, namespace, binding: empty_binding) - @completor.completion_candidates(preposing, target, '', bind: binding) - assert_equal namespace, @completor.doc_namespace(preposing, target, '', bind: binding) - end - - def test_type_completion - bind = eval('num = 1; binding') - assert_completion('num.times.map(&:', 'ab', binding: bind, include: 'abs') - assert_doc_namespace('num.chr.', 'upcase', 'String#upcase', binding: bind) - end - - def test_inspect - assert_match(/\AReplTypeCompletor.*\z/, @completor.inspect) - end - - def test_empty_completion - candidates = @completor.completion_candidates('(', ')', '', bind: binding) - assert_equal [], candidates - assert_doc_namespace('(', ')', nil) - end - - def test_command_completion - assert_include(@completor.completion_candidates('', 'show_s', '', bind: binding), 'show_source') - assert_not_include(@completor.completion_candidates(';', 'show_s', '', bind: binding), 'show_source') - end - end - - class TypeCompletorIntegrationTest < IntegrationTestCase - def test_type_completor - write_rc <<~RUBY - IRB.conf[:COMPLETOR] = :type - RUBY - - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "irb_info" - type "sleep 0.01 until ReplTypeCompletor.rbs_loaded?" - type "completor = IRB.CurrentContext.io.instance_variable_get(:@completor);" - type "n = 10" - type "puts completor.completion_candidates 'a = n.abs;', 'a.b', '', bind: binding" - type "puts completor.doc_namespace 'a = n.chr;', 'a.encoding', '', bind: binding" - type "exit!" - end - assert_match(/Completion: Autocomplete, ReplTypeCompletor/, output) - assert_match(/a\.bit_length/, output) - assert_match(/String#encoding/, output) - end - end -end diff --git a/test/irb/test_workspace.rb b/test/irb/test_workspace.rb deleted file mode 100644 index 199ce95a37..0000000000 --- a/test/irb/test_workspace.rb +++ /dev/null @@ -1,127 +0,0 @@ -# frozen_string_literal: false -require 'tempfile' -require 'irb' -require 'irb/workspace' -require 'irb/color' - -require_relative "helper" - -module TestIRB - class WorkSpaceTest < TestCase - def test_code_around_binding - IRB.conf[:USE_COLORIZE] = false - Tempfile.create('irb') do |f| - code = <<~RUBY - # 1 - # 2 - IRB::WorkSpace.new(binding) # 3 - # 4 - # 5 - RUBY - f.print(code) - f.close - - workspace = eval(code, binding, f.path) - assert_equal(<<~EOS, without_term { workspace.code_around_binding }) - - From: #{f.path} @ line 3 : - - 1: # 1 - 2: # 2 - => 3: IRB::WorkSpace.new(binding) # 3 - 4: # 4 - 5: # 5 - - EOS - end - ensure - IRB.conf.delete(:USE_COLORIZE) - end - - def test_code_around_binding_with_existing_unreadable_file - pend 'chmod cannot make file unreadable on windows' if windows? - pend 'skipped in root privilege' if Process.uid == 0 - - Tempfile.create('irb') do |f| - code = "IRB::WorkSpace.new(binding)\n" - f.print(code) - f.close - - File.chmod(0, f.path) - - workspace = eval(code, binding, f.path) - assert_equal(nil, workspace.code_around_binding) - end - end - - def test_code_around_binding_with_script_lines__ - IRB.conf[:USE_COLORIZE] = false - with_script_lines do |script_lines| - Tempfile.create('irb') do |f| - code = "IRB::WorkSpace.new(binding)\n" - script_lines[f.path] = code.split(/^/) - - workspace = eval(code, binding, f.path) - assert_equal(<<~EOS, without_term { workspace.code_around_binding }) - - From: #{f.path} @ line 1 : - - => 1: IRB::WorkSpace.new(binding) - - EOS - end - end - ensure - IRB.conf.delete(:USE_COLORIZE) - end - - def test_code_around_binding_on_irb - workspace = eval("IRB::WorkSpace.new(binding)", binding, "(irb)") - assert_equal(nil, workspace.code_around_binding) - end - - - def test_toplevel_binding_local_variables - bug17623 = '[ruby-core:102468]' - bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - top_srcdir = "#{__dir__}/../.." - irb_path = nil - %w[exe libexec].find do |dir| - irb_path = "#{top_srcdir}/#{dir}/irb" - File.exist?(irb_path) - end or omit 'irb command not found' - assert_in_out_err(bundle_exec + ['-W0', "-C#{top_srcdir}", '-e', <<~RUBY, '--', '-f', '--'], 'binding.local_variables', /\[:_\]/, [], bug17623) - version = 'xyz' # typical rubygems loading file - load('#{irb_path}') - RUBY - end - - private - - def with_script_lines - script_lines = nil - debug_lines = {} - Object.class_eval do - if defined?(SCRIPT_LINES__) - script_lines = SCRIPT_LINES__ - remove_const :SCRIPT_LINES__ - end - const_set(:SCRIPT_LINES__, debug_lines) - end - yield debug_lines - ensure - Object.class_eval do - remove_const :SCRIPT_LINES__ - const_set(:SCRIPT_LINES__, script_lines) if script_lines - end - end - - def without_term - env = ENV.to_h.dup - ENV.delete('TERM') - yield - ensure - ENV.replace(env) - end - end -end diff --git a/test/irb/yamatanooroti/test_rendering.rb b/test/irb/yamatanooroti/test_rendering.rb deleted file mode 100644 index 44e07a3a12..0000000000 --- a/test/irb/yamatanooroti/test_rendering.rb +++ /dev/null @@ -1,517 +0,0 @@ -require 'irb' - -begin - require 'yamatanooroti' -rescue LoadError, NameError - # On Ruby repository, this test suite doesn't run because Ruby repo doesn't - # have the yamatanooroti gem. - return -end - -class IRB::RenderingTest < Yamatanooroti::TestCase - def setup - @original_term = ENV['TERM'] - @home_backup = ENV['HOME'] - @xdg_config_home_backup = ENV['XDG_CONFIG_HOME'] - ENV['TERM'] = "xterm-256color" - @pwd = Dir.pwd - suffix = '%010d' % Random.rand(0..65535) - @tmpdir = File.join(File.expand_path(Dir.tmpdir), "test_irb_#{$$}_#{suffix}") - begin - Dir.mkdir(@tmpdir) - rescue Errno::EEXIST - FileUtils.rm_rf(@tmpdir) - Dir.mkdir(@tmpdir) - end - @irbrc_backup = ENV['IRBRC'] - @irbrc_file = ENV['IRBRC'] = File.join(@tmpdir, 'temporaty_irbrc') - File.unlink(@irbrc_file) if File.exist?(@irbrc_file) - ENV['HOME'] = File.join(@tmpdir, 'home') - ENV['XDG_CONFIG_HOME'] = File.join(@tmpdir, 'xdg_config_home') - end - - def teardown - FileUtils.rm_rf(@tmpdir) - ENV['IRBRC'] = @irbrc_backup - ENV['TERM'] = @original_term - ENV['HOME'] = @home_backup - ENV['XDG_CONFIG_HOME'] = @xdg_config_home_backup - end - - def test_launch - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write(<<~EOC) - 'Hello, World!' - EOC - close - assert_screen(<<~EOC) - start IRB - irb(main):001> 'Hello, World!' - => "Hello, World!" - irb(main):002> - EOC - end - - def test_configuration_file_is_skipped_with_dash_f - write_irbrc <<~'LINES' - puts '.irbrc file should be ignored when -f is used' - LINES - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: '') - write(<<~EOC) - 'Hello, World!' - EOC - close - assert_screen(<<~EOC) - irb(main):001> 'Hello, World!' - => "Hello, World!" - irb(main):002> - EOC - end - - def test_configuration_file_is_skipped_with_dash_f_for_nested_sessions - write_irbrc <<~'LINES' - puts '.irbrc file should be ignored when -f is used' - LINES - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: '') - write(<<~EOC) - 'Hello, World!' - binding.irb - exit! - EOC - close - assert_screen(<<~EOC) - irb(main):001> 'Hello, World!' - => "Hello, World!" - irb(main):002> binding.irb - irb(main):003> exit! - irb(main):001> - EOC - end - - def test_nomultiline - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb --nomultiline}, startup_message: 'start IRB') - write(<<~EOC) - if true - if false - a = "hello - world" - puts a - end - end - EOC - close - assert_screen(<<~EOC) - start IRB - irb(main):001> if true - irb(main):002* if false - irb(main):003* a = "hello - irb(main):004" world" - irb(main):005* puts a - irb(main):006* end - irb(main):007* end - => nil - irb(main):008> - EOC - end - - def test_multiline_paste - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write(<<~EOC) - class A - def inspect; '#<A>'; end - def a; self; end - def b; true; end - end - - a = A.new - - a - .a - .b - .itself - EOC - close - assert_screen(<<~EOC) - start IRB - irb(main):001* class A - irb(main):002* def inspect; '#<A>'; end - irb(main):003* def a; self; end - irb(main):004* def b; true; end - irb(main):005> end - => :b - irb(main):006> - irb(main):007> a = A.new - => #<A> - irb(main):008> - irb(main):009> a - irb(main):010> .a - irb(main):011> .b - irb(main):012> .itself - => true - irb(main):013> - EOC - end - - def test_evaluate_each_toplevel_statement_by_multiline_paste - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write(<<~EOC) - class A - def inspect; '#<A>'; end - def b; self; end - def c; true; end - end - - a = A.new - - a - .b - # aaa - .c - - (a) - &.b() - - class A def b; self; end; def c; true; end; end; - a = A.new - a - .b - # aaa - .c - (a) - &.b() - .itself - EOC - close - assert_screen(<<~EOC) - start IRB - irb(main):001* class A - irb(main):002* def inspect; '#<A>'; end - irb(main):003* def b; self; end - irb(main):004* def c; true; end - irb(main):005> end - => :c - irb(main):006> - irb(main):007> a = A.new - => #<A> - irb(main):008> - irb(main):009> a - irb(main):010> .b - irb(main):011> # aaa - irb(main):012> .c - => true - irb(main):013> - irb(main):014> (a) - irb(main):015> &.b() - => #<A> - irb(main):016> - irb(main):017> class A def b; self; end; def c; true; end; end; - irb(main):018> a = A.new - => #<A> - irb(main):019> a - irb(main):020> .b - irb(main):021> # aaa - irb(main):022> .c - => true - irb(main):023> (a) - irb(main):024> &.b() - irb(main):025> .itself - => #<A> - irb(main):026> - EOC - end - - def test_symbol_with_backtick - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write(<<~EOC) - :` - EOC - close - assert_screen(<<~EOC) - start IRB - irb(main):001> :` - => :` - irb(main):002> - EOC - end - - def test_autocomplete_with_multiple_doc_namespaces - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(3, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("{}.__id_") - write("\C-i") - sleep 0.2 - close - screen = result.join("\n").sub(/\n*\z/, "\n") - assert_match(/start\ IRB\nirb\(main\):001> {}\.__id__\n }\.__id__(?:Press )?/, screen) - end - - def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right - rdoc_dir = File.join(@tmpdir, 'rdoc') - system("bundle exec rdoc -r -o #{rdoc_dir}") - write_irbrc <<~LINES - IRB.conf[:EXTRA_DOC_DIRS] = ['#{rdoc_dir}'] - IRB.conf[:PROMPT][:MY_PROMPT] = { - :PROMPT_I => "%03n> ", - :PROMPT_S => "%03n> ", - :PROMPT_C => "%03n> " - } - IRB.conf[:PROMPT_MODE] = :MY_PROMPT - puts 'start IRB' - LINES - start_terminal(4, 19, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("IR") - write("\C-i") - sleep 0.2 - close - - # This is because on macOS we display different shortcut for displaying the full doc - # 'O' is for 'Option' and 'A' is for 'Alt' - if RUBY_PLATFORM =~ /darwin/ - assert_screen(<<~EOC) - start IRB - 001> IRB - IRBPress Opti - IRB - EOC - else - assert_screen(<<~EOC) - start IRB - 001> IRB - IRBPress Alt+ - IRB - EOC - end - end - - def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left - rdoc_dir = File.join(@tmpdir, 'rdoc') - system("bundle exec rdoc -r -o #{rdoc_dir}") - write_irbrc <<~LINES - IRB.conf[:EXTRA_DOC_DIRS] = ['#{rdoc_dir}'] - IRB.conf[:PROMPT][:MY_PROMPT] = { - :PROMPT_I => "%03n> ", - :PROMPT_S => "%03n> ", - :PROMPT_C => "%03n> " - } - IRB.conf[:PROMPT_MODE] = :MY_PROMPT - puts 'start IRB' - LINES - start_terminal(4, 12, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("IR") - write("\C-i") - sleep 0.2 - close - assert_screen(<<~EOC) - start IRB - 001> IRB - PressIRB - IRB - EOC - end - - def test_assignment_expression_truncate - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - # Assignment expression code that turns into non-assignment expression after evaluation - code = "a /'/i if false; a=1; x=1000.times.to_a#'.size" - write(code + "\n") - close - assert_screen(<<~EOC) - start IRB - irb(main):001> #{code} - => - [0, - ... - irb(main):002> - EOC - end - - def test_ctrl_c_is_handled - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - # Assignment expression code that turns into non-assignment expression after evaluation - write("\C-c") - close - assert_screen(<<~EOC) - start IRB - irb(main):001> - ^C - irb(main):001> - EOC - end - - def test_show_cmds_with_pager_can_quit_with_ctrl_c - write_irbrc <<~'LINES' - puts 'start IRB' - LINES - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("help\n") - write("G") # move to the end of the screen - write("\C-c") # quit pager - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - # IRB::Abort should be rescued - assert_not_match(/IRB::Abort/, screen) - # IRB should resume - assert_match(/foobar/, screen) - end - - def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_total_length - write_irbrc <<~'LINES' - puts 'start IRB' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("IRB::Pager.page_content('a' * (80 * 8))\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - assert_match(/a{80}/, screen) - # because pager is invoked, foobar will not be evaluated - assert_not_match(/foobar/, screen) - end - - def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_screen_height - write_irbrc <<~'LINES' - puts 'start IRB' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("IRB::Pager.page_content('a\n' * 8)\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - assert_match(/(a\n){8}/, screen) - # because pager is invoked, foobar will not be evaluated - assert_not_match(/foobar/, screen) - end - - def test_pager_page_content_doesnt_page_output_when_it_fits_in_the_screen - write_irbrc <<~'LINES' - puts 'start IRB' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("IRB::Pager.page_content('a' * (80 * 7))\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - assert_match(/a{80}/, screen) - # because pager is not invoked, foobar will be evaluated - assert_match(/foobar/, screen) - end - - def test_long_evaluation_output_is_paged - write_irbrc <<~'LINES' - puts 'start IRB' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("'a' * 80 * 11\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - assert_match(/(a{80}\n){8}/, screen) - # because pager is invoked, foobar will not be evaluated - assert_not_match(/foobar/, screen) - end - - def test_long_evaluation_output_is_preserved_after_paging - write_irbrc <<~'LINES' - puts 'start IRB' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') - write("'a' * 80 * 11\n") - write("q") # quit pager - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - # confirm pager has exited - assert_match(/foobar/, screen) - # confirm output is preserved - assert_match(/(a{80}\n){6}/, screen) - end - - def test_debug_integration_hints_debugger_commands - write_irbrc <<~'LINES' - IRB.conf[:USE_COLORIZE] = false - LINES - script = Tempfile.create(["debug", ".rb"]) - script.write <<~RUBY - puts 'start IRB' - binding.irb - RUBY - script.close - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: 'start IRB') - write("debug\n") - write("pp 1\n") - write("pp 1") - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - # submitted input shouldn't contain hint - assert_include(screen, "irb:rdbg(main):002> pp 1\n") - # unsubmitted input should contain hint - assert_include(screen, "irb:rdbg(main):003> pp 1 # debug command\n") - ensure - File.unlink(script) if script - end - - def test_debug_integration_doesnt_hint_non_debugger_commands - write_irbrc <<~'LINES' - IRB.conf[:USE_COLORIZE] = false - LINES - script = Tempfile.create(["debug", ".rb"]) - script.write <<~RUBY - puts 'start IRB' - binding.irb - RUBY - script.close - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: 'start IRB') - write("debug\n") - write("foo") - close - - screen = result.join("\n").sub(/\n*\z/, "\n") - assert_include(screen, "irb:rdbg(main):002> foo\n") - ensure - File.unlink(script) if script - end - - private - - def write_irbrc(content) - File.open(@irbrc_file, 'w') do |f| - f.write content - end - end -end |
