diff options
Diffstat (limited to 'test')
53 files changed, 0 insertions, 16175 deletions
diff --git a/test/irb/command/test_cd.rb b/test/irb/command/test_cd.rb deleted file mode 100644 index 10f77f6691..0000000000 --- a/test/irb/command/test_cd.rb +++ /dev/null @@ -1,84 +0,0 @@ -require "tempfile" -require_relative "../helper" - -module TestIRB - class CDTest < IntegrationTestCase - def setup - super - - write_ruby <<~'RUBY' - class Foo - class Bar - def bar - "this is bar" - end - end - - def foo - "this is foo" - end - end - - class BO < BasicObject - def baz - "this is baz" - end - end - - binding.irb - RUBY - end - - def test_cd - out = run_ruby_file do - type "cd Foo" - type "ls" - type "cd Bar" - type "ls" - type "cd .." - type "exit" - end - - assert_match(/irb\(Foo\):002>/, out) - assert_match(/Foo#methods: foo/, out) - assert_match(/irb\(Foo::Bar\):004>/, out) - assert_match(/Bar#methods: bar/, out) - assert_match(/irb\(Foo\):006>/, out) - end - - def test_cd_basic_object_or_frozen - out = run_ruby_file do - type "cd BO.new" - type "cd 1" - type "cd Object.new.freeze" - type "exit" - end - - assert_match(/irb\(#<BO:.+\):002>/, out) - assert_match(/irb\(1\):003>/, out) - assert_match(/irb\(#<Object:.+\):004>/, out) - end - - def test_cd_moves_top_level_with_no_args - out = run_ruby_file do - type "cd Foo" - type "cd Bar" - type "cd" - type "exit" - end - - assert_match(/irb\(Foo::Bar\):003>/, out) - assert_match(/irb\(main\):004>/, out) - end - - def test_cd_with_error - out = run_ruby_file do - type "cd Baz" - type "exit" - end - - assert_match(/Error: uninitialized constant Baz/, out) - assert_match(/irb\(main\):002>/, out) # the context should not change - end - end -end diff --git a/test/irb/command/test_command_aliasing.rb b/test/irb/command/test_command_aliasing.rb deleted file mode 100644 index 4ecc88c0aa..0000000000 --- a/test/irb/command/test_command_aliasing.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -require "tempfile" -require_relative "../helper" - -module TestIRB - class CommandAliasingTest < IntegrationTestCase - def setup - super - write_rc <<~RUBY - IRB.conf[:COMMAND_ALIASES] = { - :c => :conf, # alias to helper method - :f => :foo - } - RUBY - - write_ruby <<~'RUBY' - binding.irb - RUBY - end - - def test_aliasing_to_helper_method_triggers_warning - out = run_ruby_file do - type "c" - type "exit" - end - assert_include(out, "Using command alias `c` for helper method `conf` is not supported.") - assert_not_include(out, "Maybe IRB bug!") - end - - def test_alias_to_non_existent_command_triggers_warning - message = "You're trying to use command alias `f` for command `foo`, but `foo` does not exist." - out = run_ruby_file do - type "f" - type "exit" - end - assert_include(out, message) - assert_not_include(out, "Maybe IRB bug!") - - # Local variables take precedence over command aliases - out = run_ruby_file do - type "f = 123" - type "f" - type "exit" - end - assert_not_include(out, message) - assert_not_include(out, "Maybe IRB bug!") - end - end -end diff --git a/test/irb/command/test_copy.rb b/test/irb/command/test_copy.rb deleted file mode 100644 index 505812a1de..0000000000 --- a/test/irb/command/test_copy.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -require 'irb' - -require_relative "../helper" - -module TestIRB - class CopyTest < IntegrationTestCase - def setup - super - @envs['IRB_COPY_COMMAND'] = "#{EnvUtil.rubybin} -e \"puts 'foo' + STDIN.read\"" - end - - def test_copy_with_pbcopy - write_ruby <<~'ruby' - class Answer - def initialize(answer) - @answer = answer - end - end - - binding.irb - ruby - - output = run_ruby_file do - type "copy Answer.new(42)" - type "exit" - end - - assert_match(/foo#<Answer:0x[0-9a-f]+ @answer=42/, output) - assert_match(/Copied to system clipboard/, output) - end - - # copy puts 5 should: - # - Print value to the console - # - Copy nil to clipboard, since that is what the puts call evaluates to - def test_copy_when_expression_has_side_effects - write_ruby <<~'ruby' - binding.irb - ruby - - output = run_ruby_file do - type "copy puts 42" - type "exit" - end - - assert_match(/^42\r\n/, output) - assert_match(/foonil/, output) - assert_match(/Copied to system clipboard/, output) - refute_match(/foo42/, output) - end - - def test_copy_when_copy_command_is_invalid - @envs['IRB_COPY_COMMAND'] = "lulz" - - write_ruby <<~'ruby' - binding.irb - ruby - - output = run_ruby_file do - type "copy 42" - type "exit" - end - - assert_match(/No such file or directory - lulz/, output) - assert_match(/Is IRB\.conf\[:COPY_COMMAND\] set to a bad value/, output) - refute_match(/Copied to system clipboard/, output) - end - end -end diff --git a/test/irb/command/test_custom_command.rb b/test/irb/command/test_custom_command.rb deleted file mode 100644 index 13f412c210..0000000000 --- a/test/irb/command/test_custom_command.rb +++ /dev/null @@ -1,194 +0,0 @@ -# frozen_string_literal: true -require "irb" - -require_relative "../helper" - -module TestIRB - class CustomCommandIntegrationTest < TestIRB::IntegrationTestCase - def test_command_registration_can_happen_after_irb_require - write_ruby <<~RUBY - require "irb" - require "irb/command" - - class PrintCommand < IRB::Command::Base - category 'CommandTest' - description 'print_command' - def execute(*) - puts "Hello from PrintCommand" - end - end - - IRB::Command.register(:print!, PrintCommand) - - binding.irb - RUBY - - output = run_ruby_file do - type "print!" - type "exit" - end - - assert_include(output, "Hello from PrintCommand") - end - - def test_command_registration_accepts_string_too - write_ruby <<~RUBY - require "irb/command" - - class PrintCommand < IRB::Command::Base - category 'CommandTest' - description 'print_command' - def execute(*) - puts "Hello from PrintCommand" - end - end - - IRB::Command.register("print!", PrintCommand) - - binding.irb - RUBY - - output = run_ruby_file do - type "print!" - type "exit" - end - - assert_include(output, "Hello from PrintCommand") - end - - def test_arguments_propagation - write_ruby <<~RUBY - require "irb/command" - - class PrintArgCommand < IRB::Command::Base - category 'CommandTest' - description 'print_command_arg' - def execute(arg) - $nth_execution ||= 0 - puts "\#{$nth_execution} arg=\#{arg.inspect}" - $nth_execution += 1 - end - end - - IRB::Command.register(:print_arg, PrintArgCommand) - - binding.irb - RUBY - - output = run_ruby_file do - type "print_arg" - type "print_arg \n" - type "print_arg a r g" - type "print_arg a r g \n" - type "exit" - end - - assert_include(output, "0 arg=\"\"") - assert_include(output, "1 arg=\"\"") - assert_include(output, "2 arg=\"a r g\"") - assert_include(output, "3 arg=\"a r g\"") - end - - def test_def_extend_command_still_works - write_ruby <<~RUBY - require "irb" - - class FooBarCommand < IRB::Command::Base - category 'FooBarCategory' - description 'foobar_description' - def execute(*) - $nth_execution ||= 1 - puts "\#{$nth_execution} FooBar executed" - $nth_execution += 1 - end - end - - IRB::ExtendCommandBundle.def_extend_command(:foobar, FooBarCommand, nil, [:fbalias, IRB::Command::OVERRIDE_ALL]) - - binding.irb - RUBY - - output = run_ruby_file do - type "foobar" - type "fbalias" - type "help foobar" - type "exit" - end - - assert_include(output, "1 FooBar executed") - assert_include(output, "2 FooBar executed") - assert_include(output, "foobar_description") - end - - def test_no_meta_command_also_works - write_ruby <<~RUBY - require "irb/command" - - class NoMetaCommand < IRB::Command::Base - def execute(*) - puts "This command does not override meta attributes" - end - end - - IRB::Command.register(:no_meta, NoMetaCommand) - - binding.irb - RUBY - - output = run_ruby_file do - type "no_meta" - type "help no_meta" - type "exit" - end - - assert_include(output, "This command does not override meta attributes") - assert_include(output, "No description provided.") - assert_not_include(output, "Maybe IRB bug") - end - - def test_command_name_local_variable - write_ruby <<~RUBY - require "irb/command" - - class FooBarCommand < IRB::Command::Base - category 'CommandTest' - description 'test' - def execute(arg) - puts "arg=\#{arg.inspect}" - end - end - - IRB::Command.register(:foo_bar, FooBarCommand) - - binding.irb - RUBY - - output = run_ruby_file do - type "binding.irb" - type "foo_bar == 1 || 1" - type "foo_bar =~ /2/ || 2" - type "exit" - type "binding.irb" - type "foo_bar = '3'; foo_bar" - type "foo_bar == 4 || '4'" - type "foo_bar =~ /5/ || '5'" - type "exit" - type "binding.irb" - type "foo_bar ||= '6'; foo_bar" - type "foo_bar == 7 || '7'" - type "foo_bar =~ /8/ || '8'" - type "exit" - type "exit" - end - - assert_include(output, 'arg="== 1 || 1"') - assert_include(output, 'arg="=~ /2/ || 2"') - assert_include(output, '=> "3"') - assert_include(output, '=> "4"') - assert_include(output, '=> "5"') - assert_include(output, '=> "6"') - assert_include(output, '=> "7"') - assert_include(output, '=> "8"') - end - end -end diff --git a/test/irb/command/test_disable_irb.rb b/test/irb/command/test_disable_irb.rb deleted file mode 100644 index 14a20043d5..0000000000 --- a/test/irb/command/test_disable_irb.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: false -require 'irb' - -require_relative "../helper" - -module TestIRB - class DisableIRBTest < IntegrationTestCase - def test_disable_irb_disable_further_irb_breakpoints - 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 "disable_irb" - end - - assert_match(/First line\r\n/, output) - assert_match(/Second line\r\n/, output) - assert_match(/Third line\r\n/, output) - assert_match(/Fourth line\r\n/, output) - end - end -end diff --git a/test/irb/command/test_force_exit.rb b/test/irb/command/test_force_exit.rb deleted file mode 100644 index 191a786872..0000000000 --- a/test/irb/command/test_force_exit.rb +++ /dev/null @@ -1,51 +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 - end -end diff --git a/test/irb/command/test_help.rb b/test/irb/command/test_help.rb deleted file mode 100644 index b34832b022..0000000000 --- a/test/irb/command/test_help.rb +++ /dev/null @@ -1,75 +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 - - def test_help_lists_helper_methods - out = run_ruby_file do - type "help" - type "exit" - end - - assert_match(/Helper methods\s+conf\s+Returns the current IRB context/, out) - end - end -end diff --git a/test/irb/command/test_multi_irb_commands.rb b/test/irb/command/test_multi_irb_commands.rb deleted file mode 100644 index e313c0c5d2..0000000000 --- a/test/irb/command/test_multi_irb_commands.rb +++ /dev/null @@ -1,50 +0,0 @@ -require "tempfile" -require_relative "../helper" - -module TestIRB - class MultiIRBTest < IntegrationTestCase - def setup - super - - write_ruby <<~'RUBY' - binding.irb - RUBY - end - - def test_jobs_command_with_print_deprecated_warning - out = run_ruby_file do - type "jobs" - type "exit" - end - - assert_match(/Multi-irb commands are deprecated and will be removed in IRB 2\.0\.0\. Please use workspace commands instead\./, out) - assert_match(%r|If you have any use case for multi-irb, please leave a comment at https://github.com/ruby/irb/issues/653|, out) - assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out) - end - - def test_irb_jobs_and_kill_commands - out = run_ruby_file do - type "irb" - type "jobs" - type "kill 1" - type "exit" - end - - assert_match(/#0->irb on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out) - assert_match(/#1->irb#1 on main \(#<Thread:0x.+ run>: running\)/, out) - end - - def test_irb_fg_jobs_and_kill_commands - out = run_ruby_file do - type "irb" - type "fg 0" - type "jobs" - type "kill 1" - type "exit" - end - - assert_match(/#0->irb on main \(#<Thread:0x.+ run>: running\)/, out) - assert_match(/#1->irb#1 on main \(#<Thread:0x.+ sleep_forever>: stop\)/, out) - end - end -end diff --git a/test/irb/command/test_show_source.rb b/test/irb/command/test_show_source.rb deleted file mode 100644 index a4227231e4..0000000000 --- a/test/irb/command/test_show_source.rb +++ /dev/null @@ -1,410 +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_with_eval_error - write_ruby <<~'RUBY' - binding.irb - RUBY - - out = run_ruby_file do - type "show_source raise(Exception).itself" - type "exit" - end - - assert_match(%r[Couldn't locate a definition for raise\(Exception\)\.itself], 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 ea2c6ef16a..0000000000 --- a/test/irb/helper.rb +++ /dev/null @@ -1,234 +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 setup_envs(home:) - @backup_home = ENV["HOME"] - ENV["HOME"] = home - @backup_xdg_config_home = ENV.delete("XDG_CONFIG_HOME") - @backup_irbrc = ENV.delete("IRBRC") - end - - def teardown_envs - ENV["HOME"] = @backup_home - ENV["XDG_CONFIG_HOME"] = @backup_xdg_config_home - ENV["IRBRC"] = @backup_irbrc - 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") - - envs_for_spawn = @envs.merge('TERM' => 'dumb', 'TEST_IRB_FORCE_INTERACTIVE' => 'true') - - PTY.spawn(envs_for_spawn, *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{irbtest- .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 5529e29042..0000000000 --- a/test/irb/test_color.rb +++ /dev/null @@ -1,275 +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" => Reline::Unicode.escape_for_print("\t") == ' ' ? ' ' : "\t", # not ^I - "foo(*%W(bar))" => "foo(*#{RED}#{BOLD}%W(#{CLEAR}#{RED}bar#{CLEAR}#{RED}#{BOLD})#{CLEAR})", - "$stdout" => "#{GREEN}#{BOLD}$stdout#{CLEAR}", - "$&" => "#{GREEN}#{BOLD}$&#{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} #{GREEN}#{BOLD}$1#{CLEAR}", - "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 95d08e19e3..0000000000 --- a/test/irb/test_color_printer.rb +++ /dev/null @@ -1,82 +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 - - def test_colorization_disabled - { - 1 => "1\n", - "a\nb" => %["a\\nb"\n], - IRBTestColorPrinter.new('test') => "#<struct TestIRB::ColorPrinterTest::IRBTestColorPrinter a=\"test\">\n", - Ripper::Lexer.new('1').scan => "[#<Ripper::Lexer::Elem: on_int@1:0 END token: \"1\">]\n", - Class.new{define_method(:pretty_print){|q| q.text("[__FILE__, __LINE__, __ENCODING__]")}}.new => "[__FILE__, __LINE__, __ENCODING__]\n", - }.each do |object, result| - actual = with_term { IRB::ColorPrinter.pp(object, '', colorize: false) } - 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 ec2d1f92df..0000000000 --- a/test/irb/test_command.rb +++ /dev/null @@ -1,1001 +0,0 @@ -# frozen_string_literal: false -require "irb" - -require_relative "helper" - -module TestIRB - # In case when RDoc becomes a bundled gem, we may not be able to load it when running tests - # in ruby/ruby - HAS_RDOC = begin - require "rdoc" - true - rescue LoadError - false - end - - 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) - setup_envs(home: @tmpdir) - 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 - teardown_envs - 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 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\.\nprocessing time: .+\n=> 3\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\.\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=> 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=> 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\.\ncustom processing time: .+\n=> 3\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\.\nfoo\n=> 1\nBAR is added\.\nbar\nfoo\n=> 2\nbar\n=> 3\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=> 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/, - / => "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/, - / => "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" - ) - - assert_empty err - assert_include(out, "Current workspace: #{self}") - 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", - "self.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", - "self.class\n" - ) - assert_empty err - assert_include(out, "Current workspace: #<#{self.class.name}::Foo") - assert_include(out, "=> #{self.class}::Foo") - end - - def test_chws_does_nothing_when_receiving_no_argument - out, err = execute_lines( - "chws\n", - ) - assert_empty err - assert_include(out, "Current workspace: #{self}") - 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_eval_error - [ - "ls raise(Exception,'foo')\n", - "ls raise(Exception,'foo'), grep: /./\n", - "ls Integer, grep: raise(Exception,'foo')\n", - ].each do |line| - out, err = execute_lines(line) - assert_empty err - assert_match(/Exception: foo/, out) - assert_not_match(/Maybe IRB bug!/, 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 - if HAS_RDOC - def test_show_doc - out, err = execute_lines("show_doc String#gsub") - - # 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_ri - out, err = execute_lines("ri String#gsub") - - # 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 `ri` 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 - end - - def test_show_doc_without_rdoc - _, err = without_rdoc do - execute_lines("show_doc String#gsub") - end - - 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_not_include(out, <<~EOF) - foo - EOF - assert_not_include(out, <<~EOF) - bar - 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 c9a0eafa3d..0000000000 --- a/test/irb/test_completion.rb +++ /dev/null @@ -1,317 +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 - completor = IRB::RegexpCompletor.new - binding.eval("some_var = 1") - # completion for help command's argument should only include command names - assert_include(completor.completion_candidates('help ', 's', '', bind: binding), 'show_source') - assert_not_include(completor.completion_candidates('help ', 's', '', bind: binding), 'some_var') - - 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 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 c44c8e0573..0000000000 --- a/test/irb/test_context.rb +++ /dev/null @@ -1,737 +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("=> \n#{value_first_line[0, input.winsize.last]}...\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_basic_object - main = BasicObject.new - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new) - assert_match(/irb\(#<BasicObject:.+\)/, irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1)) - assert_match(/irb\(#<BasicObject:.+\)/, 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_prompt_format - main = 'main' - irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new) - assert_equal('%% main %m %main %%m >', irb.send(:format_prompt, '%%%% %m %%m %%%m %%%%m %l', '>', 1, 1)) - assert_equal('42,%i, 42,%3i,042,%03i', irb.send(:format_prompt, '%i,%%i,%3i,%%3i,%03i,%%03i', nil, 42, 1)) - assert_equal('42,%n, 42,%3n,042,%03n', irb.send(:format_prompt, '%n,%%n,%3n,%%3n,%03n,%%03n', nil, 1, 42)) - 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] = nil - assert_match(/IRB::(Regexp|Type)Completor/, @context.send(:build_completor).class.name) - 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 45ffb2a52e..0000000000 --- a/test/irb/test_debugger_integration.rb +++ /dev/null @@ -1,513 +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_debug_command_can_only_be_called_from_binding_irb - write_ruby <<~'ruby' - require "irb" - # trick test framework - puts "binding.irb" - IRB.start - ruby - - output = run_ruby_file do - type "debug" - type "exit" - end - - assert_include(output, "Debugging commands are only available when IRB is started with binding.irb") - 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 "he" + "llo" - RUBY - - output = run_ruby_file do - type "debug" - type "exit" - end - - assert_match(/irb:rdbg\(main\):002>/, output) - assert_match(/hello/, output) - end - - def test_force_exit - write_ruby <<~'RUBY' - binding.irb - puts "he" + "llo" - RUBY - - output = run_ruby_file do - type "debug" - type "exit!" - end - - assert_match(/irb:rdbg\(main\):002>/, output) - assert_not_match(/hello/, output) - end - - def test_quit - write_ruby <<~'RUBY' - binding.irb - puts "he" + "llo" - RUBY - - output = run_ruby_file do - type "debug" - type "quit!" - end - - assert_match(/irb:rdbg\(main\):002>/, output) - assert_not_match(/hello/, 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_irb_command_can_check_local_variables - write_ruby <<~'ruby' - binding.irb - ruby - - output = run_ruby_file do - type "debug" - type 'foobar = IRB' - type "show_source foobar.start" - type "show_source = 'Foo'" - type "show_source + 'Bar'" - type "continue" - end - assert_include(output, "def start(ap_path = nil)") - assert_include(output, '"FooBar"') - 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_helper_method.rb b/test/irb/test_helper_method.rb deleted file mode 100644 index a3e2c43b2f..0000000000 --- a/test/irb/test_helper_method.rb +++ /dev/null @@ -1,135 +0,0 @@ -# frozen_string_literal: true -require "irb" - -require_relative "helper" - -module TestIRB - class HelperMethodTestCase < TestCase - def setup - $VERBOSE = nil - @verbosity = $VERBOSE - save_encodings - IRB.instance_variable_get(:@CONF).clear - end - - def teardown - $VERBOSE = @verbosity - 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.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.conf[:USE_PAGER] = false - capture_output do - irb.eval_input - end - end - end - - module TestHelperMethod - class ConfTest < HelperMethodTestCase - def test_conf_returns_the_context_object - out, err = execute_lines("conf.ap_name") - - assert_empty err - assert_include out, "=> \"irb\"" - end - end - end - - class HelperMethodIntegrationTest < IntegrationTestCase - def test_arguments_propogation - write_ruby <<~RUBY - require "irb/helper_method" - - class MyHelper < IRB::HelperMethod::Base - description "This is a test helper" - - def execute( - required_arg, optional_arg = nil, *splat_arg, required_keyword_arg:, - optional_keyword_arg: nil, **double_splat_arg, &block_arg - ) - puts [required_arg, optional_arg, splat_arg, required_keyword_arg, optional_keyword_arg, double_splat_arg, block_arg.call].to_s - end - end - - IRB::HelperMethod.register(:my_helper, MyHelper) - - binding.irb - RUBY - - output = run_ruby_file do - type <<~INPUT - my_helper( - "required", "optional", "splat", required_keyword_arg: "required", - optional_keyword_arg: "optional", a: 1, b: 2 - ) { "block" } - INPUT - type "exit" - end - - optional = {a: 1, b: 2} - assert_include(output, %[["required", "optional", ["splat"], "required", "optional", #{optional.inspect}, "block"]]) - end - - def test_helper_method_injection_can_happen_after_irb_require - write_ruby <<~RUBY - require "irb" - - class MyHelper < IRB::HelperMethod::Base - description "This is a test helper" - - def execute - puts "Hello from MyHelper" - end - end - - IRB::HelperMethod.register(:my_helper, MyHelper) - - binding.irb - RUBY - - output = run_ruby_file do - type "my_helper" - type "exit" - end - - assert_include(output, 'Hello from MyHelper') - end - - def test_helper_method_instances_are_memoized - write_ruby <<~RUBY - require "irb/helper_method" - - class MyHelper < IRB::HelperMethod::Base - description "This is a test helper" - - def execute(val) - @val ||= val - end - end - - IRB::HelperMethod.register(:my_helper, MyHelper) - - binding.irb - RUBY - - output = run_ruby_file do - type "my_helper(100)" - type "my_helper(200)" - type "exit" - end - - assert_include(output, '=> 100') - assert_not_include(output, '=> 200') - end - end -end diff --git a/test/irb/test_history.rb b/test/irb/test_history.rb deleted file mode 100644 index 0171bb0eca..0000000000 --- a/test/irb/test_history.rb +++ /dev/null @@ -1,573 +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 - @conf_backup = IRB.conf.dup - @original_verbose, $VERBOSE = $VERBOSE, nil - @tmpdir = Dir.mktmpdir("test_irb_history_") - setup_envs(home: @tmpdir) - IRB.conf[:LC_MESSAGES] = IRB::Locale.new - save_encodings - IRB.instance_variable_set(:@existing_rc_name_generators, nil) - end - - def teardown - IRB.conf.replace(@conf_backup) - IRB.instance_variable_set(:@existing_rc_name_generators, nil) - teardown_envs - restore_encodings - $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_dont_save - omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) - IRB.conf[:SAVE_HISTORY] = nil - assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT) - 1 - 2 - EXPECTED_HISTORY - 1 - 2 - INITIAL_HISTORY - 3 - exit - INPUT - 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[: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 - IRB.conf[:LC_MESSAGES] = IRB::Locale.new("en_US.ASCII") - IRB.__send__(:set_encoding, Encoding::US_ASCII.name, override: false) - assert_history(<<~EXPECTED_HISTORY.encode(Encoding::US_ASCII), <<~INITIAL_HISTORY.encode(Encoding::UTF_8), <<~INPUT) - ???? - 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(/ensure the folder exists/i) 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) - 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_can_be_disabled_with_false - write_history "" - write_rc <<~RUBY - IRB.conf[:SAVE_HISTORY] = false - RUBY - - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "puts 'foo' + 'bar'" - type "exit" - end - - assert_include(output, "foobar") - assert_equal "", @history_file.open.read - end - - def test_history_saving_accepts_true - write_history "" - write_rc <<~RUBY - IRB.conf[:SAVE_HISTORY] = true - RUBY - - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "puts 'foo' + 'bar'" - type "exit" - end - - assert_include(output, "foobar") - assert_equal <<~HISTORY, @history_file.open.read - puts 'foo' + 'bar' - exit - HISTORY - end - - 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 - - def test_direct_debug_session_loads_history - @envs['RUBY_DEBUG_IRB_CONSOLE'] = "1" - write_history <<~HISTORY - old_history_1 - old_history_2 - old_history_3 - HISTORY - - write_ruby <<~'RUBY' - require 'debug' - debugger - binding.irb # needed to satisfy run_ruby_file - RUBY - - output = run_ruby_file do - type "history" - type "puts 'foo'" - type "history" - type "exit!" - end - - assert_include(output, "irb:rdbg(main):002") # assert that we're in an irb:rdbg session - assert_include(output, "5: history") - assert_include(output, "4: puts 'foo'") - assert_include(output, "3: history") - assert_include(output, "2: old_history_3") - assert_include(output, "1: old_history_2") - assert_include(output, "0: old_history_1") - 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 f34f692f09..0000000000 --- a/test/irb/test_init.rb +++ /dev/null @@ -1,408 +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_copy_command_environment_variable - orig_copy_command_env = ENV['IRB_COPY_COMMAND'] - orig_copy_command_conf = IRB.conf[:COPY_COMMAND] - - ENV['IRB_COPY_COMMAND'] = nil - IRB.setup(__FILE__) - refute IRB.conf[:COPY_COMMAND] - - ENV['IRB_COPY_COMMAND'] = '' - IRB.setup(__FILE__) - assert_equal('', IRB.conf[:COPY_COMMAND]) - - ENV['IRB_COPY_COMMAND'] = 'blah' - IRB.setup(__FILE__) - assert_equal('blah', IRB.conf[:COPY_COMMAND]) - ensure - ENV['IRB_COPY_COMMAND'] = orig_copy_command_env - IRB.conf[:COPY_COMMAND] = orig_copy_command_conf - end - - def test_completor_environment_variable - orig_use_autocomplete_env = ENV['IRB_COMPLETOR'] - orig_use_autocomplete_conf = IRB.conf[:COMPLETOR] - - # Default value is nil: auto-detect - ENV['IRB_COMPLETOR'] = nil - IRB.setup(__FILE__) - assert_equal(nil, 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] - orig_completor_env = ENV['IRB_COMPLETOR'] - ENV['IRB_COMPLETOR'] = nil - - # Default value is nil: auto-detect - IRB.setup(__FILE__, argv: []) - assert_equal nil, 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 - ENV['IRB_COMPLETOR'] = orig_completor_env - 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 ConfigValidationTest < TestCase - def setup - # To prevent the test from using the user's .irbrc file - @home = Dir.mktmpdir - setup_envs(home: @home) - super - end - - def teardown - super - teardown_envs - File.unlink(@irbrc) - Dir.rmdir(@home) - IRB.instance_variable_set(:@existing_rc_name_generators, nil) - end - - def test_irb_name_converts_non_string_values_to_string - assert_no_irb_validation_error(<<~'RUBY') - IRB.conf[:IRB_NAME] = :foo - RUBY - - assert_equal "foo", IRB.conf[:IRB_NAME] - end - - def test_irb_rc_name_only_takes_callable_objects - assert_irb_validation_error(<<~'RUBY', "IRB.conf[:IRB_RC] should be a callable object. Got :foo.") - IRB.conf[:IRB_RC] = :foo - RUBY - end - - def test_back_trace_limit_only_accepts_integers - assert_irb_validation_error(<<~'RUBY', "IRB.conf[:BACK_TRACE_LIMIT] should be an integer. Got \"foo\".") - IRB.conf[:BACK_TRACE_LIMIT] = "foo" - RUBY - end - - def test_prompt_only_accepts_hash - assert_irb_validation_error(<<~'RUBY', "IRB.conf[:PROMPT] should be a Hash. Got \"foo\".") - IRB.conf[:PROMPT] = "foo" - RUBY - end - - def test_eval_history_only_accepts_integers - assert_irb_validation_error(<<~'RUBY', "IRB.conf[:EVAL_HISTORY] should be an integer. Got \"foo\".") - IRB.conf[:EVAL_HISTORY] = "foo" - RUBY - end - - private - - def assert_irb_validation_error(rc_content, error_message) - write_rc rc_content - - assert_raise_with_message(TypeError, error_message) do - IRB.setup(__FILE__) - end - end - - def assert_no_irb_validation_error(rc_content) - write_rc rc_content - - assert_nothing_raised do - IRB.setup(__FILE__) - end - end - - def write_rc(content) - @irbrc = Tempfile.new('irbrc') - @irbrc.write(content) - @irbrc.close - ENV['IRBRC'] = @irbrc.path - end - end - - class InitIntegrationTest < IntegrationTestCase - def setup - super - - write_ruby <<~'RUBY' - binding.irb - RUBY - end - - def test_load_error_in_rc_file_is_warned - write_rc <<~'IRBRC' - require "file_that_does_not_exist" - IRBRC - - 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 - - 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 bd107551df..0000000000 --- a/test/irb/test_input_method.rb +++ /dev/null @@ -1,195 +0,0 @@ -# frozen_string_literal: false - -require "irb" -begin - require "rdoc" -rescue LoadError -end -require_relative "helper" - -module TestIRB - class InputMethodTest < TestCase - def setup - @conf_backup = IRB.conf.dup - IRB.init_config(nil) - 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_colorize - IRB.conf[:USE_COLORIZE] = true - IRB.conf[:VERBOSE] = false - original_colorable = IRB::Color.method(:colorable?) - IRB::Color.instance_eval { undef :colorable? } - IRB::Color.define_singleton_method(:colorable?) { true } - workspace = IRB::WorkSpace.new(binding) - input_method = IRB::RelineInputMethod.new(IRB::RegexpCompletor.new) - IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new(workspace, input_method).context - assert_equal "\e[1m$\e[0m\e[m", Reline.output_modifier_proc.call('$', complete: false) - assert_equal "\e[1m$\e[0m\e[m \e[34m\e[1m1\e[0m + \e[34m\e[1m2\e[0m", Reline.output_modifier_proc.call('$ 1 + 2', complete: false) - assert_equal "\e[32m\e[1m$a\e[0m", Reline.output_modifier_proc.call('$a', complete: false) - ensure - IRB::Color.instance_eval { undef :colorable? } - IRB::Color.define_singleton_method(:colorable?, original_colorable) - 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 - omit 'This test requires RDoc' unless defined?(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 - - 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 if defined?(RDoc) -end diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb deleted file mode 100644 index 617e9c9614..0000000000 --- a/test/irb/test_irb.rb +++ /dev/null @@ -1,936 +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_commands_dont_override_stored_last_result - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type "1 + 1" - type "ls" - 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.3." - 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 NestedBindingIrbTest < IntegrationTestCase - def test_current_context_restore - write_ruby <<~'RUBY' - binding.irb - RUBY - - output = run_ruby_file do - type '$ctx = IRB.CurrentContext' - type 'binding.irb' - type 'p context_changed: IRB.CurrentContext != $ctx' - type 'exit' - type 'p context_restored: IRB.CurrentContext == $ctx' - type 'exit' - end - - assert_include output, {context_changed: true}.inspect - assert_include output, {context_restored: true}.inspect - 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 - 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 - - class BacktraceFilteringTest < TestIRB::IntegrationTestCase - def setup - super - # These tests are sensitive to warnings, so we disable them - original_rubyopt = [ENV["RUBYOPT"], @envs["RUBYOPT"]].compact.join(" ") - @envs["RUBYOPT"] = original_rubyopt + " -W0" - end - - def test_backtrace_filtering - write_ruby <<~'RUBY' - def foo - raise "error" - end - - def bar - foo - end - - binding.irb - RUBY - - output = run_ruby_file do - type "bar" - type "exit" - end - - assert_match(/irbtest-.*\.rb:2:in (`|'Object#)foo': error \(RuntimeError\)/, output) - frame_traces = output.split("\n").select { |line| line.strip.match?(/from /) }.map(&:strip) - - expected_traces = if RUBY_VERSION >= "3.3.0" - [ - /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/, - /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/, - /from <internal:kernel>:\d+:in (`|'Kernel#)loop'/, - /from <internal:prelude>:\d+:in (`|'Binding#)irb'/, - /from .*\/irbtest-.*.rb:9:in [`']<main>'/ - ] - else - [ - /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/, - /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/, - /from <internal:prelude>:\d+:in (`|'Binding#)irb'/, - /from .*\/irbtest-.*.rb:9:in [`']<main>'/ - ] - end - - expected_traces.reverse! if RUBY_VERSION < "3.0.0" - - expected_traces.each_with_index do |expected_trace, index| - assert_match(expected_trace, frame_traces[index]) - end - end - - def test_backtrace_filtering_with_backtrace_filter - write_rc <<~'RUBY' - class TestBacktraceFilter - def self.call(backtrace) - backtrace.reject { |line| line.include?("internal") } - end - end - - IRB.conf[:BACKTRACE_FILTER] = TestBacktraceFilter - RUBY - - write_ruby <<~'RUBY' - def foo - raise "error" - end - - def bar - foo - end - - binding.irb - RUBY - - output = run_ruby_file do - type "bar" - type "exit" - end - - assert_match(/irbtest-.*\.rb:2:in (`|'Object#)foo': error \(RuntimeError\)/, output) - frame_traces = output.split("\n").select { |line| line.strip.match?(/from /) }.map(&:strip) - - expected_traces = [ - /from .*\/irbtest-.*.rb:6:in (`|'Object#)bar'/, - /from .*\/irbtest-.*.rb\(irb\):1:in [`']<main>'/, - /from .*\/irbtest-.*.rb:9:in [`']<main>'/ - ] - - expected_traces.reverse! if RUBY_VERSION < "3.0.0" - - expected_traces.each_with_index do |expected_trace, index| - assert_match(expected_trace, frame_traces[index]) - end - 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 6b4f54ee21..0000000000 --- a/test/irb/test_nesting_parser.rb +++ /dev/null @@ -1,339 +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}` - p(``); p ``; p x: ``; p 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 - 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_pager.rb b/test/irb/test_pager.rb deleted file mode 100644 index 0fad94da30..0000000000 --- a/test/irb/test_pager.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: false -require 'irb/pager' - -require_relative 'helper' - -module TestIRB - class PagerTest < TestCase - def test_take_first_page - assert_equal ['a' * 40, true], IRB::Pager.take_first_page(10, 4) {|io| io.puts 'a' * 41; raise 'should not reach here' } - assert_equal ["a\nb\na\nb\n", true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.puts "a\nb\n" } } - assert_equal ["a\n\n\na\n", true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.puts "a\n\n\n" } } - assert_equal ["11\n" * 4, true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.write 1; io.puts 1 } } - assert_equal ["\n" * 4, true], IRB::Pager.take_first_page(10, 4) {|io| 10.times { io.write nil; io.puts nil } } - assert_equal ['a' * 39, false], IRB::Pager.take_first_page(10, 4) {|io| io.write 'a' * 39 } - assert_equal ['a' * 39 + 'b', false], IRB::Pager.take_first_page(10, 4) {|io| io.write 'a' * 39 + 'b' } - assert_equal ['a' * 39 + 'b', true], IRB::Pager.take_first_page(10, 4) {|io| io.write 'a' * 39 + 'bc' } - assert_equal ["a\nb\nc\nd\n", false], IRB::Pager.take_first_page(10, 4) {|io| io.write "a\nb\nc\nd\n" } - assert_equal ["a\nb\nc\nd\n", true], IRB::Pager.take_first_page(10, 4) {|io| io.write "a\nb\nc\nd\ne" } - assert_equal ['a' * 15 + "\n" + 'b' * 20, true], IRB::Pager.take_first_page(10, 4) {|io| io.puts 'a' * 15; io.puts 'b' * 30 } - assert_equal ["\e[31mA\e[0m" * 10 + 'x' * 30, true], IRB::Pager.take_first_page(10, 4) {|io| io.puts "\e[31mA\e[0m" * 10 + 'x' * 31 } - text, overflow = IRB::Pager.take_first_page(10, 4) {|io| 41.times { io.write "\e[31mA\e[0m" } } - assert_equal ['A' * 40, true], [text.gsub(/\e\[\d+m/, ''), overflow] - text, overflow = IRB::Pager.take_first_page(10, 4) {|io| 41.times { io.write "\e[31mAAA\e[0m" } } - assert_equal ['A' * 40, true], [text.gsub(/\e\[\d+m/, ''), overflow] - end - end - - class PageOverflowIOTest < TestCase - def test_overflow - actual_events = [] - overflow_callback = ->(lines) do - actual_events << [:callback_called, lines] - end - out = IRB::Pager::PageOverflowIO.new(10, 4, overflow_callback) - out.puts 'a' * 15 - out.write 'b' * 15 - - actual_events << :before_write - out.write 'c' * 1000 - actual_events << :after_write - - out.puts 'd' * 1000 - out.write 'e' * 1000 - - expected_events = [ - :before_write, - [:callback_called, ['a' * 10, 'a' * 5 + "\n", 'b' * 10, 'b' * 5 + 'c' * 5]], - :after_write, - ] - assert_equal expected_events, actual_events - - expected_whole_content = 'a' * 15 + "\n" + 'b' * 15 + 'c' * 1000 + 'd' * 1000 + "\n" + 'e' * 1000 - assert_equal expected_whole_content, out.string - end - - def test_callback_delay - actual_events = [] - overflow_callback = ->(lines) do - actual_events << [:callback_called, lines] - end - out = IRB::Pager::PageOverflowIO.new(10, 4, overflow_callback, delay: 0.2) - out.write 'a' * 1000 - assert_equal ['a' * 10] * 4, out.first_page_lines - out.write 'b' - actual_events << :before_delay - sleep 0.2 - out.write 'c' - actual_events << :after_delay - out.write 'd' - assert_equal 'a' * 1000 + 'bcd', out.string - assert_equal [:before_delay, [:callback_called, ['a' * 10] * 4], :after_delay], actual_events - 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 3d0e25d19e..0000000000 --- a/test/irb/test_type_completor.rb +++ /dev/null @@ -1,109 +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 test_build_completor - IRB.init_config(nil) - verbose, $VERBOSE = $VERBOSE, nil - original_completor = IRB.conf[:COMPLETOR] - workspace = IRB::WorkSpace.new(Object.new) - @context = IRB::Context.new(nil, workspace, TestInputMethod.new) - IRB.conf[:COMPLETOR] = nil - expected_default_completor = RUBY_VERSION >= '3.4' ? 'IRB::TypeCompletor' : 'IRB::RegexpCompletor' - assert_equal expected_default_completor, @context.send(:build_completor).class.name - IRB.conf[:COMPLETOR] = :type - assert_equal 'IRB::TypeCompletor', @context.send(:build_completor).class.name - ensure - $VERBOSE = verbose - IRB.conf[:COMPLETOR] = original_completor - 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 - binding.eval("some_var = 1") - # completion for help command's argument should only include command names - assert_include(@completor.completion_candidates('help ', 's', '', bind: binding), 'show_source') - assert_not_include(@completor.completion_candidates('help ', 's', '', bind: binding), 'some_var') - - 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 ad515f91df..0000000000 --- a/test/irb/test_workspace.rb +++ /dev/null @@ -1,126 +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 c1bc81241c..0000000000 --- a/test/irb/yamatanooroti/test_rendering.rb +++ /dev/null @@ -1,494 +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 - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write(<<~EOC) - 'Hello, World!' - EOC - assert_screen(<<~EOC) - irb(main):001> 'Hello, World!' - => "Hello, World!" - irb(main):002> - EOC - close - 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: /irb\(main\)/) - write(<<~EOC) - 'Hello, World!' - EOC - assert_screen(<<~EOC) - irb(main):001> 'Hello, World!' - => "Hello, World!" - irb(main):002> - EOC - close - 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: /irb\(main\)/) - write(<<~EOC) - 'Hello, World!' - binding.irb - exit! - EOC - assert_screen(<<~EOC) - irb(main):001> 'Hello, World!' - => "Hello, World!" - irb(main):002> binding.irb - irb(main):003> exit! - irb(main):001> - EOC - close - end - - def test_nomultiline - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb --nomultiline}, startup_message: /irb\(main\)/) - write(<<~EOC) - if true - if false - a = "hello - world" - puts a - end - end - EOC - assert_screen(<<~EOC) - 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 - close - end - - def test_multiline_paste - start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - 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 - assert_screen(<<~EOC) - 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 - close - end - - def test_evaluate_each_toplevel_statement_by_multiline_paste - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - 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 - assert_screen(<<~EOC) - 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 - close - end - - def test_symbol_with_backtick - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write(<<~EOC) - :` - EOC - assert_screen(<<~EOC) - irb(main):001> :` - => :` - irb(main):002> - EOC - close - end - - def test_autocomplete_with_multiple_doc_namespaces - start_terminal(3, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write("{}.__id_") - write("\C-i") - assert_screen(/irb\(main\):001> {}\.__id__\n }\.__id__(?:Press )?/) - close - end - - def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right - rdoc_dir = File.join(@tmpdir, 'rdoc') - system("bundle exec rdoc lib -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 - LINES - start_terminal(4, 19, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /001>/) - write("IR") - write("\C-i") - - # 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) - 001> IRB - IRBPress Opti - IRB - EOC - else - assert_screen(<<~EOC) - 001> IRB - IRBPress Alt+ - IRB - EOC - end - close - end - - def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left - rdoc_dir = File.join(@tmpdir, 'rdoc') - system("bundle exec rdoc lib -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 - LINES - start_terminal(4, 12, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /001>/) - write("IR") - write("\C-i") - assert_screen(<<~EOC) - 001> IRB - PressIRB - IRB - EOC - close - end - - def test_assignment_expression_truncate - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - # 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") - assert_screen(<<~EOC) - irb(main):001> #{code} - => - [0, - ... - irb(main):002> - EOC - close - end - - def test_ctrl_c_is_handled - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - # Assignment expression code that turns into non-assignment expression after evaluation - write("\C-c") - assert_screen(<<~EOC) - irb(main):001> - ^C - irb(main):001> - EOC - close - end - - def test_show_cmds_with_pager_can_quit_with_ctrl_c - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - 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 - - # IRB should resume - assert_screen(/foobar/) - # IRB::Abort should be rescued - assert_screen(/\A(?!IRB::Abort)/) - close - end - - def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_total_length - write_irbrc <<~'LINES' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write("IRB::Pager.page_content('a' * (80 * 8))\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - - assert_screen(/a{80}/) - # because pager is invoked, foobar will not be evaluated - assert_screen(/\A(?!foobar)/) - close - end - - def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_screen_height - write_irbrc <<~'LINES' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write("IRB::Pager.page_content('a\n' * 8)\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - - assert_screen(/(a\n){8}/) - # because pager is invoked, foobar will not be evaluated - assert_screen(/\A(?!foobar)/) - close - end - - def test_pager_page_content_doesnt_page_output_when_it_fits_in_the_screen - write_irbrc <<~'LINES' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write("IRB::Pager.page_content('a' * (80 * 7))\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - - assert_screen(/a{80}/) - # because pager is not invoked, foobar will be evaluated - assert_screen(/foobar/) - close - end - - def test_long_evaluation_output_is_paged - write_irbrc <<~'LINES' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write("'a' * 80 * 11\n") - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - - assert_screen(/"a{79}\n(a{80}\n){7}/) - # because pager is invoked, foobar will not be evaluated - assert_screen(/\A(?!foobar)/) - close - end - - def test_pretty_print_preview_with_slow_inspect - write_irbrc <<~'LINES' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write("o1 = Object.new; def o1.inspect; 'INSPECT'; end\n") - write("o2 = Object.new; def o2.inspect; sleep 0.1; 'SLOW'; end\n") - # preview should be shown even if pretty_print is not completed. - write("[o1] * 20 + [o2] * 100\n") - assert_screen(/=>\n\[INSPECT,\n( INSPECT,\n){6}Preparing full inspection value\.\.\./) - write("\C-c") # abort pretty_print - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - assert_screen(/foobar/) - close - end - - def test_long_evaluation_output_is_preserved_after_paging - write_irbrc <<~'LINES' - require "irb/pager" - LINES - start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/) - write("'a' * 80 * 11\n") - write("q") # quit pager - write("'foo' + 'bar'\n") # eval something to make sure IRB resumes - - # confirm pager has exited - assert_screen(/foobar/) - # confirm output is preserved - assert_screen(/(a{80}\n){6}/) - close - 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 - binding.irb - RUBY - script.close - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: /irb\(main\)/) - write("debug\n") - write("pp 1\n") - write("pp 1") - - # submitted input shouldn't contain hint - assert_screen(/irb:rdbg\(main\):002> pp 1\n/) - # unsubmitted input should contain hint - assert_screen(/irb:rdbg\(main\):003> pp 1 # debug command\n/) - close - 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 - binding.irb - RUBY - script.close - start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: /irb\(main\)/) - write("debug\n") - write("foo") - assert_screen(/irb:rdbg\(main\):002> foo\n/) - close - ensure - File.unlink(script) if script - end - - def test_debug_integration_doesnt_hint_debugger_commands_in_nomultiline_mode - write_irbrc <<~'LINES' - IRB.conf[:USE_SINGLELINE] = true - 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") - # submitted input shouldn't contain hint - assert_screen(/irb:rdbg\(main\):002> pp 1\n/) - close - 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 diff --git a/test/reline/helper.rb b/test/reline/helper.rb deleted file mode 100644 index 6f470a617f..0000000000 --- a/test/reline/helper.rb +++ /dev/null @@ -1,158 +0,0 @@ -$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) - -ENV['TERM'] = 'xterm' # for some CI environments - -require 'reline' -require 'test/unit' - -begin - require 'rbconfig' -rescue LoadError -end - -begin - # This should exist and available in load path when this file is mirrored to ruby/ruby and running at there - if File.exist?(File.expand_path('../../tool/lib/envutil.rb', __dir__)) - require 'envutil' - end -rescue LoadError -end - -module Reline - class << self - def test_mode(ansi: false) - @original_iogate = IOGate - - if defined?(RELINE_TEST_ENCODING) - encoding = RELINE_TEST_ENCODING - else - encoding = Encoding::UTF_8 - end - - if ansi - new_io_gate = ANSI.new - # Setting ANSI gate's screen size through set_screen_size will also change the tester's stdin's screen size - # Let's avoid that side-effect by stubbing the get_screen_size method - new_io_gate.define_singleton_method(:get_screen_size) do - [24, 80] - end - new_io_gate.define_singleton_method(:encoding) do - encoding - end - else - new_io_gate = Dumb.new(encoding: encoding) - end - - remove_const('IOGate') - const_set('IOGate', new_io_gate) - core.config.instance_variable_set(:@test_mode, true) - core.config.reset - end - - def test_reset - remove_const('IOGate') - const_set('IOGate', @original_iogate) - Reline.instance_variable_set(:@core, nil) - end - - # Return a executable name to spawn Ruby process. In certain build configuration, - # "ruby" may not be available. - def test_rubybin - # When this test suite is running in ruby/ruby, prefer EnvUtil result over original implementation - if const_defined?(:EnvUtil) - return EnvUtil.rubybin - end - - # The following is a simplified port of EnvUtil.rubybin in ruby/ruby - if ruby = ENV["RUBY"] - return ruby - end - ruby = "ruby" - exeext = RbConfig::CONFIG["EXEEXT"] - rubyexe = (ruby + exeext if exeext and !exeext.empty?) - if File.exist? ruby and File.executable? ruby and !File.directory? ruby - return File.expand_path(ruby) - end - if rubyexe and File.exist? rubyexe and File.executable? rubyexe - return File.expand_path(rubyexe) - end - if defined?(RbConfig.ruby) - RbConfig.ruby - else - "ruby" - end - end - end -end - -class Reline::TestCase < Test::Unit::TestCase - private def convert_str(input) - input.encode(@line_editor.encoding, Encoding::UTF_8) - end - - def omit_unless_utf8 - omit "This test is for UTF-8 but the locale is #{Reline.core.encoding}" if Reline.core.encoding != Encoding::UTF_8 - end - - def input_key_by_symbol(method_symbol, char: nil, csi: false) - char ||= csi ? "\e[A" : "\C-a" - @line_editor.input_key(Reline::Key.new(char, method_symbol, false)) - end - - def input_keys(input) - input = convert_str(input) - - key_stroke = Reline::KeyStroke.new(@config, @encoding) - input_bytes = input.bytes - until input_bytes.empty? - expanded, input_bytes = key_stroke.expand(input_bytes) - expanded.each do |key| - @line_editor.input_key(key) - end - end - end - - def set_line_around_cursor(before, after) - input_keys("\C-a\C-k") - input_keys(after) - input_keys("\C-a") - input_keys(before) - end - - def assert_line_around_cursor(before, after) - before = convert_str(before) - after = convert_str(after) - line = @line_editor.current_line - byte_pointer = @line_editor.instance_variable_get(:@byte_pointer) - actual_before = line.byteslice(0, byte_pointer) - actual_after = line.byteslice(byte_pointer..) - assert_equal([before, after], [actual_before, actual_after]) - end - - def assert_byte_pointer_size(expected) - expected = convert_str(expected) - byte_pointer = @line_editor.instance_variable_get(:@byte_pointer) - chunk = @line_editor.line.byteslice(0, byte_pointer) - assert_equal( - expected.bytesize, byte_pointer, - <<~EOM) - <#{expected.inspect} (#{expected.encoding.inspect})> expected but was - <#{chunk.inspect} (#{chunk.encoding.inspect})> in <Terminal #{Reline::Dumb.new.encoding.inspect}> - EOM - end - - def assert_line_index(expected) - assert_equal(expected, @line_editor.instance_variable_get(:@line_index)) - end - - def assert_whole_lines(expected) - assert_equal(expected, @line_editor.whole_lines) - end - - def assert_key_binding(input, method_symbol, editing_modes = [:emacs, :vi_insert, :vi_command]) - editing_modes.each do |editing_mode| - @config.editing_mode = editing_mode - assert_equal(method_symbol, @config.editing_mode.get(input.bytes)) - end - end -end diff --git a/test/reline/test_ansi.rb b/test/reline/test_ansi.rb deleted file mode 100644 index 5e28e72b06..0000000000 --- a/test/reline/test_ansi.rb +++ /dev/null @@ -1,72 +0,0 @@ -require_relative 'helper' -require 'reline' - -class Reline::ANSITest < Reline::TestCase - def setup - Reline.send(:test_mode, ansi: true) - @config = Reline::Config.new - Reline.core.io_gate.set_default_key_bindings(@config) - end - - def teardown - Reline.test_reset - end - - def test_home - assert_key_binding("\e[1~", :ed_move_to_beg) # Console (80x25) - assert_key_binding("\e[H", :ed_move_to_beg) # KDE - assert_key_binding("\e[7~", :ed_move_to_beg) # urxvt / exoterm - assert_key_binding("\eOH", :ed_move_to_beg) # GNOME - end - - def test_end - assert_key_binding("\e[4~", :ed_move_to_end) # Console (80x25) - assert_key_binding("\e[F", :ed_move_to_end) # KDE - assert_key_binding("\e[8~", :ed_move_to_end) # urxvt / exoterm - assert_key_binding("\eOF", :ed_move_to_end) # GNOME - end - - def test_delete - assert_key_binding("\e[3~", :key_delete) - end - - def test_up_arrow - assert_key_binding("\e[A", :ed_prev_history) # Console (80x25) - assert_key_binding("\eOA", :ed_prev_history) - end - - def test_down_arrow - assert_key_binding("\e[B", :ed_next_history) # Console (80x25) - assert_key_binding("\eOB", :ed_next_history) - end - - def test_right_arrow - assert_key_binding("\e[C", :ed_next_char) # Console (80x25) - assert_key_binding("\eOC", :ed_next_char) - end - - def test_left_arrow - assert_key_binding("\e[D", :ed_prev_char) # Console (80x25) - assert_key_binding("\eOD", :ed_prev_char) - end - - # Ctrl+arrow and Meta+arrow - def test_extended - assert_key_binding("\e[1;5C", :em_next_word) # Ctrl+→ - assert_key_binding("\e[1;5D", :ed_prev_word) # Ctrl+← - assert_key_binding("\e[1;3C", :em_next_word) # Meta+→ - assert_key_binding("\e[1;3D", :ed_prev_word) # Meta+← - assert_key_binding("\e\e[C", :em_next_word) # Meta+→ - assert_key_binding("\e\e[D", :ed_prev_word) # Meta+← - end - - def test_shift_tab - assert_key_binding("\e[Z", :completion_journey_up, [:emacs, :vi_insert]) - end - - # A few emacs bindings that are always mapped - def test_more_emacs - assert_key_binding("\e ", :em_set_mark, [:emacs]) - assert_key_binding("\C-x\C-x", :em_exchange_mark, [:emacs]) - end -end diff --git a/test/reline/test_config.rb b/test/reline/test_config.rb deleted file mode 100644 index 3c9094eece..0000000000 --- a/test/reline/test_config.rb +++ /dev/null @@ -1,616 +0,0 @@ -require_relative 'helper' - -class Reline::Config::Test < Reline::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) - Reline.test_mode - @config = Reline::Config.new - @inputrc_backup = ENV['INPUTRC'] - end - - def teardown - Dir.chdir(@pwd) - FileUtils.rm_rf(@tmpdir) - Reline.test_reset - @config.reset - ENV['INPUTRC'] = @inputrc_backup - end - - def get_config_variable(variable) - @config.instance_variable_get(variable) - end - - def additional_key_bindings(keymap_label) - get_config_variable(:@additional_key_bindings)[keymap_label].instance_variable_get(:@key_bindings) - end - - def registered_key_bindings(keys) - key_bindings = @config.key_bindings - keys.to_h { |key| [key, key_bindings.get(key)] } - end - - def test_read_lines - @config.read_lines(<<~LINES.lines) - set show-mode-in-prompt on - LINES - - assert_equal true, get_config_variable(:@show_mode_in_prompt) - end - - def test_read_lines_with_variable - @config.read_lines(<<~LINES.lines) - set disable-completion on - LINES - - assert_equal true, get_config_variable(:@disable_completion) - end - - def test_string_value - @config.read_lines(<<~LINES.lines) - set show-mode-in-prompt on - set emacs-mode-string Emacs - LINES - - assert_equal 'Emacs', get_config_variable(:@emacs_mode_string) - end - - def test_string_value_with_brackets - @config.read_lines(<<~LINES.lines) - set show-mode-in-prompt on - set emacs-mode-string [Emacs] - LINES - - assert_equal '[Emacs]', get_config_variable(:@emacs_mode_string) - end - - def test_string_value_with_brackets_and_quotes - @config.read_lines(<<~LINES.lines) - set show-mode-in-prompt on - set emacs-mode-string "[Emacs]" - LINES - - assert_equal '[Emacs]', get_config_variable(:@emacs_mode_string) - end - - def test_string_value_with_parens - @config.read_lines(<<~LINES.lines) - set show-mode-in-prompt on - set emacs-mode-string (Emacs) - LINES - - assert_equal '(Emacs)', get_config_variable(:@emacs_mode_string) - end - - def test_string_value_with_parens_and_quotes - @config.read_lines(<<~LINES.lines) - set show-mode-in-prompt on - set emacs-mode-string "(Emacs)" - LINES - - assert_equal '(Emacs)', get_config_variable(:@emacs_mode_string) - end - - def test_encoding_is_ascii - @config.reset - Reline.core.io_gate.instance_variable_set(:@encoding, Encoding::US_ASCII) - @config = Reline::Config.new - - assert_equal true, @config.convert_meta - end - - def test_encoding_is_not_ascii - @config = Reline::Config.new - - assert_equal false, @config.convert_meta - end - - def test_invalid_keystroke - @config.read_lines(<<~LINES.lines) - #"a": comment - a: error - "b": no-error - LINES - key_bindings = additional_key_bindings(:emacs) - assert_not_include key_bindings, 'a'.bytes - assert_not_include key_bindings, nil - assert_not_include key_bindings, [] - assert_include key_bindings, 'b'.bytes - end - - def test_bind_key - assert_equal ['input'.bytes, 'abcde'.bytes], @config.parse_key_binding('"input"', '"abcde"') - end - - def test_bind_key_with_macro - - assert_equal ['input'.bytes, :abcde], @config.parse_key_binding('"input"', 'abcde') - end - - def test_bind_key_with_escaped_chars - assert_equal ['input'.bytes, "\e \\ \" ' \a \b \d \f \n \r \t \v".bytes], @config.parse_key_binding('"input"', '"\\e \\\\ \\" \\\' \\a \\b \\d \\f \\n \\r \\t \\v"') - end - - def test_bind_key_with_ctrl_chars - assert_equal ['input'.bytes, "\C-h\C-h\C-_".bytes], @config.parse_key_binding('"input"', '"\C-h\C-H\C-_"') - assert_equal ['input'.bytes, "\C-h\C-h\C-_".bytes], @config.parse_key_binding('"input"', '"\Control-h\Control-H\Control-_"') - end - - def test_bind_key_with_meta_chars - assert_equal ['input'.bytes, "\eh\eH\e_".bytes], @config.parse_key_binding('"input"', '"\M-h\M-H\M-_"') - assert_equal ['input'.bytes, "\eh\eH\e_".bytes], @config.parse_key_binding('"input"', '"\Meta-h\Meta-H\M-_"') - end - - def test_bind_key_with_ctrl_meta_chars - assert_equal ['input'.bytes, "\e\C-h\e\C-h\e\C-_".bytes], @config.parse_key_binding('"input"', '"\M-\C-h\C-\M-H\M-\C-_"') - assert_equal ['input'.bytes, "\e\C-h\e\C-_".bytes], @config.parse_key_binding('"input"', '"\Meta-\Control-h\Control-\Meta-_"') - end - - def test_bind_key_with_octal_number - input = %w{i n p u t}.map(&:ord) - assert_equal [input, "\1".bytes], @config.parse_key_binding('"input"', '"\1"') - assert_equal [input, "\12".bytes], @config.parse_key_binding('"input"', '"\12"') - assert_equal [input, "\123".bytes], @config.parse_key_binding('"input"', '"\123"') - assert_equal [input, "\123".bytes + '4'.bytes], @config.parse_key_binding('"input"', '"\1234"') - end - - def test_bind_key_with_hexadecimal_number - input = %w{i n p u t}.map(&:ord) - assert_equal [input, "\x4".bytes], @config.parse_key_binding('"input"', '"\x4"') - assert_equal [input, "\x45".bytes], @config.parse_key_binding('"input"', '"\x45"') - assert_equal [input, "\x45".bytes + '6'.bytes], @config.parse_key_binding('"input"', '"\x456"') - end - - def test_include - File.open('included_partial', 'wt') do |f| - f.write(<<~PARTIAL_LINES) - set show-mode-in-prompt on - PARTIAL_LINES - end - @config.read_lines(<<~LINES.lines) - $include included_partial - LINES - - assert_equal true, get_config_variable(:@show_mode_in_prompt) - end - - def test_include_expand_path - home_backup = ENV['HOME'] - File.open('included_partial', 'wt') do |f| - f.write(<<~PARTIAL_LINES) - set show-mode-in-prompt on - PARTIAL_LINES - end - ENV['HOME'] = Dir.pwd - @config.read_lines(<<~LINES.lines) - $include ~/included_partial - LINES - - assert_equal true, get_config_variable(:@show_mode_in_prompt) - ensure - ENV['HOME'] = home_backup - end - - def test_if - @config.read_lines(<<~LINES.lines) - $if Ruby - set vi-cmd-mode-string (cmd) - $else - set vi-cmd-mode-string [cmd] - $endif - LINES - - assert_equal '(cmd)', get_config_variable(:@vi_cmd_mode_string) - end - - def test_if_with_false - @config.read_lines(<<~LINES.lines) - $if Python - set vi-cmd-mode-string (cmd) - $else - set vi-cmd-mode-string [cmd] - $endif - LINES - - assert_equal '[cmd]', get_config_variable(:@vi_cmd_mode_string) - end - - def test_if_with_indent - %w[Ruby Reline].each do |cond| - @config.read_lines(<<~LINES.lines) - set vi-cmd-mode-string {cmd} - $if #{cond} - set vi-cmd-mode-string (cmd) - $else - set vi-cmd-mode-string [cmd] - $endif - LINES - - assert_equal '(cmd)', get_config_variable(:@vi_cmd_mode_string) - end - end - - def test_nested_if_else - @config.read_lines(<<~LINES.lines) - $if Ruby - "\x1": "O" - $if NotRuby - "\x2": "X" - $else - "\x3": "O" - $if Ruby - "\x4": "O" - $else - "\x5": "X" - $endif - "\x6": "O" - $endif - "\x7": "O" - $else - "\x8": "X" - $if NotRuby - "\x9": "X" - $else - "\xA": "X" - $endif - "\xB": "X" - $endif - "\xC": "O" - LINES - keys = [0x1, 0x3, 0x4, 0x6, 0x7, 0xC] - key_bindings = keys.to_h { |k| [[k], ['O'.ord]] } - assert_equal(key_bindings, additional_key_bindings(:emacs)) - end - - def test_unclosed_if - e = assert_raise(Reline::Config::InvalidInputrc) do - @config.read_lines(<<~LINES.lines, "INPUTRC") - $if Ruby - LINES - end - assert_equal "INPUTRC:1: unclosed if", e.message - end - - def test_unmatched_else - e = assert_raise(Reline::Config::InvalidInputrc) do - @config.read_lines(<<~LINES.lines, "INPUTRC") - $else - LINES - end - assert_equal "INPUTRC:1: unmatched else", e.message - end - - def test_unmatched_endif - e = assert_raise(Reline::Config::InvalidInputrc) do - @config.read_lines(<<~LINES.lines, "INPUTRC") - $endif - LINES - end - assert_equal "INPUTRC:1: unmatched endif", e.message - end - - def test_if_with_mode - @config.read_lines(<<~LINES.lines) - $if mode=emacs - "\C-e": history-search-backward # comment - $else - "\C-f": history-search-forward - $endif - LINES - - assert_equal({[5] => :history_search_backward}, additional_key_bindings(:emacs)) - assert_equal({}, additional_key_bindings(:vi_insert)) - assert_equal({}, additional_key_bindings(:vi_command)) - end - - def test_else - @config.read_lines(<<~LINES.lines) - $if mode=vi - "\C-e": history-search-backward # comment - $else - "\C-f": history-search-forward - $endif - LINES - - assert_equal({[6] => :history_search_forward}, additional_key_bindings(:emacs)) - assert_equal({}, additional_key_bindings(:vi_insert)) - assert_equal({}, additional_key_bindings(:vi_command)) - end - - def test_if_with_invalid_mode - @config.read_lines(<<~LINES.lines) - $if mode=vim - "\C-e": history-search-backward - $else - "\C-f": history-search-forward # comment - $endif - LINES - - assert_equal({[6] => :history_search_forward}, additional_key_bindings(:emacs)) - assert_equal({}, additional_key_bindings(:vi_insert)) - assert_equal({}, additional_key_bindings(:vi_command)) - end - - def test_mode_label_differs_from_keymap_label - @config.read_lines(<<~LINES.lines) - # Sets mode_label and keymap_label to vi - set editing-mode vi - # Change keymap_label to emacs. mode_label is still vi. - set keymap emacs - # condition=true because current mode_label is vi - $if mode=vi - # sets keybinding to current keymap_label=emacs - "\C-e": history-search-backward - $endif - LINES - assert_equal({[5] => :history_search_backward}, additional_key_bindings(:emacs)) - assert_equal({}, additional_key_bindings(:vi_insert)) - assert_equal({}, additional_key_bindings(:vi_command)) - end - - def test_if_without_else_condition - @config.read_lines(<<~LINES.lines) - set editing-mode vi - $if mode=vi - "\C-e": history-search-backward - $endif - LINES - - assert_equal({}, additional_key_bindings(:emacs)) - assert_equal({[5] => :history_search_backward}, additional_key_bindings(:vi_insert)) - assert_equal({}, additional_key_bindings(:vi_command)) - end - - def test_default_key_bindings - @config.add_default_key_binding('abcd'.bytes, 'EFGH'.bytes) - @config.read_lines(<<~'LINES'.lines) - "abcd": "ABCD" - "ijkl": "IJKL" - LINES - - expected = { 'abcd'.bytes => 'ABCD'.bytes, 'ijkl'.bytes => 'IJKL'.bytes } - assert_equal expected, registered_key_bindings(expected.keys) - end - - def test_additional_key_bindings - @config.read_lines(<<~'LINES'.lines) - "ef": "EF" - "gh": "GH" - LINES - - expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes } - assert_equal expected, registered_key_bindings(expected.keys) - end - - def test_unquoted_additional_key_bindings - @config.read_lines(<<~'LINES'.lines) - Meta-a: "Ma" - Control-b: "Cb" - Meta-Control-c: "MCc" - Control-Meta-d: "CMd" - M-C-e: "MCe" - C-M-f: "CMf" - LINES - - expected = { "\ea".bytes => 'Ma'.bytes, "\C-b".bytes => 'Cb'.bytes, "\e\C-c".bytes => 'MCc'.bytes, "\e\C-d".bytes => 'CMd'.bytes, "\e\C-e".bytes => 'MCe'.bytes, "\e\C-f".bytes => 'CMf'.bytes } - assert_equal expected, registered_key_bindings(expected.keys) - end - - def test_additional_key_bindings_with_nesting_and_comment_out - @config.read_lines(<<~'LINES'.lines) - #"ab": "AB" - #"cd": "cd" - "ef": "EF" - "gh": "GH" - LINES - - expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes } - assert_equal expected, registered_key_bindings(expected.keys) - end - - def test_additional_key_bindings_for_other_keymap - @config.read_lines(<<~'LINES'.lines) - set keymap vi-command - "ab": "AB" - set keymap vi-insert - "cd": "CD" - set keymap emacs - "ef": "EF" - set editing-mode vi # keymap changes to be vi-insert - LINES - - expected = { 'cd'.bytes => 'CD'.bytes } - assert_equal expected, registered_key_bindings(expected.keys) - end - - def test_additional_key_bindings_for_auxiliary_emacs_keymaps - @config.read_lines(<<~'LINES'.lines) - set keymap emacs - "ab": "AB" - set keymap emacs-standard - "cd": "CD" - set keymap emacs-ctlx - "ef": "EF" - set keymap emacs-meta - "gh": "GH" - set editing-mode emacs # keymap changes to be emacs - LINES - - expected = { - 'ab'.bytes => 'AB'.bytes, - 'cd'.bytes => 'CD'.bytes, - "\C-xef".bytes => 'EF'.bytes, - "\egh".bytes => 'GH'.bytes, - } - assert_equal expected, registered_key_bindings(expected.keys) - end - - def test_key_bindings_with_reset - # @config.reset is called after each readline. - # inputrc file is read once, so key binding shouldn't be cleared by @config.reset - @config.add_default_key_binding('default'.bytes, 'DEFAULT'.bytes) - @config.read_lines(<<~'LINES'.lines) - "additional": "ADDITIONAL" - LINES - @config.reset - expected = { 'default'.bytes => 'DEFAULT'.bytes, 'additional'.bytes => 'ADDITIONAL'.bytes } - assert_equal expected, registered_key_bindings(expected.keys) - end - - def test_history_size - @config.read_lines(<<~LINES.lines) - set history-size 5000 - LINES - - assert_equal 5000, get_config_variable(:@history_size) - history = Reline::History.new(@config) - history << "a\n" - assert_equal 1, history.size - end - - def test_empty_inputrc_env - inputrc_backup = ENV['INPUTRC'] - ENV['INPUTRC'] = '' - assert_nothing_raised do - @config.read - end - ensure - ENV['INPUTRC'] = inputrc_backup - end - - def test_inputrc - inputrc_backup = ENV['INPUTRC'] - expected = "#{@tmpdir}/abcde" - ENV['INPUTRC'] = expected - assert_equal expected, @config.inputrc_path - ensure - ENV['INPUTRC'] = inputrc_backup - end - - def test_inputrc_raw_value - @config.read_lines(<<~'LINES'.lines) - set editing-mode vi ignored-string - set vi-ins-mode-string aaa aaa - set vi-cmd-mode-string bbb ccc # comment - LINES - assert_equal :vi_insert, get_config_variable(:@editing_mode_label) - assert_equal 'aaa aaa', @config.vi_ins_mode_string - assert_equal 'bbb ccc # comment', @config.vi_cmd_mode_string - end - - def test_inputrc_with_utf8 - # This file is encoded by UTF-8 so this heredoc string is also UTF-8. - @config.read_lines(<<~'LINES'.lines) - set editing-mode vi - set vi-cmd-mode-string 🍸 - set vi-ins-mode-string 🍶 - LINES - assert_equal '🍸', @config.vi_cmd_mode_string - assert_equal '🍶', @config.vi_ins_mode_string - rescue Reline::ConfigEncodingConversionError - # do nothing - end - - def test_inputrc_with_eucjp - @config.read_lines(<<~"LINES".encode(Encoding::EUC_JP).lines) - set editing-mode vi - set vi-cmd-mode-string ォャッ - set vi-ins-mode-string 能 - LINES - assert_equal 'ォャッ'.encode(Reline.encoding_system_needs), @config.vi_cmd_mode_string - assert_equal '能'.encode(Reline.encoding_system_needs), @config.vi_ins_mode_string - rescue Reline::ConfigEncodingConversionError - # do nothing - end - - def test_empty_inputrc - assert_nothing_raised do - @config.read_lines([]) - end - end - - def test_xdg_config_home - home_backup = ENV['HOME'] - xdg_config_home_backup = ENV['XDG_CONFIG_HOME'] - inputrc_backup = ENV['INPUTRC'] - xdg_config_home = File.expand_path("#{@tmpdir}/.config/example_dir") - expected = File.expand_path("#{xdg_config_home}/readline/inputrc") - FileUtils.mkdir_p(File.dirname(expected)) - FileUtils.touch(expected) - ENV['HOME'] = @tmpdir - ENV['XDG_CONFIG_HOME'] = xdg_config_home - ENV['INPUTRC'] = '' - assert_equal expected, @config.inputrc_path - ensure - FileUtils.rm(expected) - ENV['XDG_CONFIG_HOME'] = xdg_config_home_backup - ENV['HOME'] = home_backup - ENV['INPUTRC'] = inputrc_backup - end - - def test_empty_xdg_config_home - home_backup = ENV['HOME'] - xdg_config_home_backup = ENV['XDG_CONFIG_HOME'] - inputrc_backup = ENV['INPUTRC'] - ENV['HOME'] = @tmpdir - ENV['XDG_CONFIG_HOME'] = '' - ENV['INPUTRC'] = '' - expected = File.expand_path('~/.config/readline/inputrc') - FileUtils.mkdir_p(File.dirname(expected)) - FileUtils.touch(expected) - assert_equal expected, @config.inputrc_path - ensure - FileUtils.rm(expected) - ENV['XDG_CONFIG_HOME'] = xdg_config_home_backup - ENV['HOME'] = home_backup - ENV['INPUTRC'] = inputrc_backup - end - - def test_relative_xdg_config_home - home_backup = ENV['HOME'] - xdg_config_home_backup = ENV['XDG_CONFIG_HOME'] - inputrc_backup = ENV['INPUTRC'] - ENV['HOME'] = @tmpdir - ENV['INPUTRC'] = '' - expected = File.expand_path('~/.config/readline/inputrc') - FileUtils.mkdir_p(File.dirname(expected)) - FileUtils.touch(expected) - result = Dir.chdir(@tmpdir) do - xdg_config_home = ".config/example_dir" - ENV['XDG_CONFIG_HOME'] = xdg_config_home - inputrc = "#{xdg_config_home}/readline/inputrc" - FileUtils.mkdir_p(File.dirname(inputrc)) - FileUtils.touch(inputrc) - @config.inputrc_path - end - assert_equal expected, result - FileUtils.rm(expected) - ENV['XDG_CONFIG_HOME'] = xdg_config_home_backup - ENV['HOME'] = home_backup - ENV['INPUTRC'] = inputrc_backup - end - - def test_reload - inputrc = "#{@tmpdir}/inputrc" - ENV['INPUTRC'] = inputrc - - File.write(inputrc, "set emacs-mode-string !") - @config.read - assert_equal '!', @config.emacs_mode_string - - File.write(inputrc, "set emacs-mode-string ?") - @config.reload - assert_equal '?', @config.emacs_mode_string - - File.write(inputrc, "") - @config.reload - assert_equal '@', @config.emacs_mode_string - end -end diff --git a/test/reline/test_face.rb b/test/reline/test_face.rb deleted file mode 100644 index 8fa2be8fa4..0000000000 --- a/test/reline/test_face.rb +++ /dev/null @@ -1,257 +0,0 @@ -# frozen_string_literal: true - -require_relative 'helper' - -class Reline::Face::Test < Reline::TestCase - RESET_SGR = "\e[0m" - - def setup - @colorterm_backup = ENV['COLORTERM'] - ENV['COLORTERM'] = 'truecolor' - end - - def teardown - Reline::Face.reset_to_initial_configs - ENV['COLORTERM'] = @colorterm_backup - end - - class WithInsufficientSetupTest < self - def setup - super - Reline::Face.config(:my_insufficient_config) do |face| - end - @face = Reline::Face[:my_insufficient_config] - end - - def test_my_insufficient_config_line - assert_equal RESET_SGR, @face[:default] - assert_equal RESET_SGR, @face[:enhanced] - assert_equal RESET_SGR, @face[:scrollbar] - end - - def test_my_insufficient_configs - my_configs = Reline::Face.configs[:my_insufficient_config] - assert_equal( - { - default: { style: :reset, escape_sequence: RESET_SGR }, - enhanced: { style: :reset, escape_sequence: RESET_SGR }, - scrollbar: { style: :reset, escape_sequence: RESET_SGR } - }, - my_configs - ) - end - end - - class WithSetupTest < self - def setup - super - Reline::Face.config(:my_config) do |face| - face.define :default, foreground: :blue - face.define :enhanced, foreground: "#FF1020", background: :black, style: [:bold, :underlined] - end - Reline::Face.config(:another_config) do |face| - face.define :another_label, foreground: :red - end - @face = Reline::Face[:my_config] - end - - def test_now_there_are_four_configs - assert_equal %i(default completion_dialog my_config another_config), Reline::Face.configs.keys - end - - def test_resetting_config_discards_user_defined_configs - Reline::Face.reset_to_initial_configs - assert_equal %i(default completion_dialog), Reline::Face.configs.keys - end - - def test_my_configs - my_configs = Reline::Face.configs[:my_config] - assert_equal( - { - default: { - escape_sequence: "#{RESET_SGR}\e[34m", foreground: :blue - }, - enhanced: { - background: :black, - foreground: "#FF1020", - style: [:bold, :underlined], - escape_sequence: "\e[0m\e[38;2;255;16;32;40;1;4m" - }, - scrollbar: { - style: :reset, - escape_sequence: "\e[0m" - } - }, - my_configs - ) - end - - def test_my_config_line - assert_equal "#{RESET_SGR}\e[34m", @face[:default] - end - - def test_my_config_enhanced - assert_equal "#{RESET_SGR}\e[38;2;255;16;32;40;1;4m", @face[:enhanced] - end - - def test_not_respond_to_another_label - assert_equal false, @face.respond_to?(:another_label) - end - end - - class WithoutSetupTest < self - def test_my_config_default - Reline::Face.config(:my_config) do |face| - # do nothing - end - face = Reline::Face[:my_config] - assert_equal RESET_SGR, face[:default] - end - - def test_style_does_not_exist - face = Reline::Face[:default] - assert_raise ArgumentError do - face[:style_does_not_exist] - end - end - - def test_invalid_keyword - assert_raise ArgumentError do - Reline::Face.config(:invalid_config) do |face| - face.define :default, invalid_keyword: :red - end - end - end - - def test_invalid_foreground_name - assert_raise ArgumentError do - Reline::Face.config(:invalid_config) do |face| - face.define :default, foreground: :invalid_name - end - end - end - - def test_invalid_background_name - assert_raise ArgumentError do - Reline::Face.config(:invalid_config) do |face| - face.define :default, background: :invalid_name - end - end - end - - def test_invalid_style_name - assert_raise ArgumentError do - Reline::Face.config(:invalid_config) do |face| - face.define :default, style: :invalid_name - end - end - end - - def test_private_constants - [:SGR_PARAMETER, :Config, :CONFIGS].each do |name| - assert_equal false, Reline::Face.constants.include?(name) - end - end - end - - class ConfigTest < self - def setup - super - @config = Reline::Face.const_get(:Config).new(:my_config) { } - end - - def teardown - super - Reline::Face.instance_variable_set(:@force_truecolor, nil) - end - - def test_rgb? - assert_equal true, @config.send(:rgb_expression?, "#FFFFFF") - end - - def test_invalid_rgb? - assert_equal false, @config.send(:rgb_expression?, "FFFFFF") - assert_equal false, @config.send(:rgb_expression?, "#FFFFF") - end - - def test_format_to_sgr_preserves_order - assert_equal( - "#{RESET_SGR}\e[37;41;1;3m", - @config.send(:format_to_sgr, foreground: :white, background: :red, style: [:bold, :italicized]) - ) - - assert_equal( - "#{RESET_SGR}\e[37;1;3;41m", - @config.send(:format_to_sgr, foreground: :white, style: [:bold, :italicized], background: :red) - ) - end - - def test_format_to_sgr_with_reset - assert_equal( - RESET_SGR, - @config.send(:format_to_sgr, style: :reset) - ) - assert_equal( - "#{RESET_SGR}\e[37;0;41m", - @config.send(:format_to_sgr, foreground: :white, style: :reset, background: :red) - ) - end - - def test_format_to_sgr_with_single_style - assert_equal( - "#{RESET_SGR}\e[37;41;1m", - @config.send(:format_to_sgr, foreground: :white, background: :red, style: :bold) - ) - end - - def test_truecolor - ENV['COLORTERM'] = 'truecolor' - assert_equal true, Reline::Face.truecolor? - ENV['COLORTERM'] = '24bit' - assert_equal true, Reline::Face.truecolor? - ENV['COLORTERM'] = nil - assert_equal false, Reline::Face.truecolor? - Reline::Face.force_truecolor - assert_equal true, Reline::Face.truecolor? - end - - def test_sgr_rgb_truecolor - ENV['COLORTERM'] = 'truecolor' - assert_equal "38;2;255;255;255", @config.send(:sgr_rgb, :foreground, "#ffffff") - assert_equal "48;2;18;52;86", @config.send(:sgr_rgb, :background, "#123456") - end - - def test_sgr_rgb_256color - ENV['COLORTERM'] = nil - assert_equal '38;5;231', @config.send(:sgr_rgb, :foreground, '#ffffff') - assert_equal '48;5;16', @config.send(:sgr_rgb, :background, '#000000') - # Color steps are [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] - assert_equal '38;5;24', @config.send(:sgr_rgb, :foreground, '#005f87') - assert_equal '38;5;67', @config.send(:sgr_rgb, :foreground, '#5f87af') - assert_equal '48;5;110', @config.send(:sgr_rgb, :background, '#87afd7') - assert_equal '48;5;153', @config.send(:sgr_rgb, :background, '#afd7ff') - # Boundary values are [0x30, 0x73, 0x9b, 0xc3, 0xeb] - assert_equal '38;5;24', @config.send(:sgr_rgb, :foreground, '#2f729a') - assert_equal '38;5;67', @config.send(:sgr_rgb, :foreground, '#30739b') - assert_equal '48;5;110', @config.send(:sgr_rgb, :background, '#9ac2ea') - assert_equal '48;5;153', @config.send(:sgr_rgb, :background, '#9bc3eb') - end - - def test_force_truecolor_reconfigure - ENV['COLORTERM'] = nil - - Reline::Face.config(:my_config) do |face| - face.define :default, foreground: '#005f87' - face.define :enhanced, background: '#afd7ff' - end - - assert_equal "\e[0m\e[38;5;24m", Reline::Face[:my_config][:default] - assert_equal "\e[0m\e[48;5;153m", Reline::Face[:my_config][:enhanced] - - Reline::Face.force_truecolor - - assert_equal "\e[0m\e[38;2;0;95;135m", Reline::Face[:my_config][:default] - assert_equal "\e[0m\e[48;2;175;215;255m", Reline::Face[:my_config][:enhanced] - end - end -end diff --git a/test/reline/test_history.rb b/test/reline/test_history.rb deleted file mode 100644 index ea902b0653..0000000000 --- a/test/reline/test_history.rb +++ /dev/null @@ -1,317 +0,0 @@ -require_relative 'helper' -require "reline/history" - -class Reline::History::Test < Reline::TestCase - def setup - Reline.send(:test_mode) - end - - def teardown - Reline.test_reset - end - - def test_ancestors - assert_equal(Reline::History.ancestors.include?(Array), true) - end - - def test_to_s - history = history_new - expected = "HISTORY" - assert_equal(expected, history.to_s) - end - - def test_get - history, lines = lines = history_new_and_push_history(5) - lines.each_with_index do |s, i| - assert_external_string_equal(s, history[i]) - end - end - - def test_get__negative - history, lines = lines = history_new_and_push_history(5) - (1..5).each do |i| - assert_equal(lines[-i], history[-i]) - end - end - - def test_get__out_of_range - history, _ = history_new_and_push_history(5) - invalid_indexes = [5, 6, 100, -6, -7, -100] - invalid_indexes.each do |i| - assert_raise(IndexError, "i=<#{i}>") do - history[i] - end - end - - invalid_indexes = [100_000_000_000_000_000_000, - -100_000_000_000_000_000_000] - invalid_indexes.each do |i| - assert_raise(RangeError, "i=<#{i}>") do - history[i] - end - end - end - - def test_set - begin - history, _ = history_new_and_push_history(5) - 5.times do |i| - expected = "set: #{i}" - history[i] = expected - assert_external_string_equal(expected, history[i]) - end - rescue NotImplementedError - end - end - - def test_set__out_of_range - history = history_new - assert_raise(IndexError, NotImplementedError, "index=<0>") do - history[0] = "set: 0" - end - - history, _ = history_new_and_push_history(5) - invalid_indexes = [5, 6, 100, -6, -7, -100] - invalid_indexes.each do |i| - assert_raise(IndexError, NotImplementedError, "index=<#{i}>") do - history[i] = "set: #{i}" - end - end - - invalid_indexes = [100_000_000_000_000_000_000, - -100_000_000_000_000_000_000] - invalid_indexes.each do |i| - assert_raise(RangeError, NotImplementedError, "index=<#{i}>") do - history[i] = "set: #{i}" - end - end - end - - def test_push - history = history_new - 5.times do |i| - s = i.to_s - assert_equal(history, history.push(s)) - assert_external_string_equal(s, history[i]) - end - assert_equal(5, history.length) - end - - def test_push__operator - history = history_new - 5.times do |i| - s = i.to_s - assert_equal(history, history << s) - assert_external_string_equal(s, history[i]) - end - assert_equal(5, history.length) - end - - def test_push__plural - history = history_new - assert_equal(history, history.push("0", "1", "2", "3", "4")) - (0..4).each do |i| - assert_external_string_equal(i.to_s, history[i]) - end - assert_equal(5, history.length) - - assert_equal(history, history.push("5", "6", "7", "8", "9")) - (5..9).each do |i| - assert_external_string_equal(i.to_s, history[i]) - end - assert_equal(10, history.length) - end - - def test_pop - history = history_new - begin - assert_equal(nil, history.pop) - - history, lines = lines = history_new_and_push_history(5) - (1..5).each do |i| - assert_external_string_equal(lines[-i], history.pop) - assert_equal(lines.length - i, history.length) - end - - assert_equal(nil, history.pop) - rescue NotImplementedError - end - end - - def test_shift - history = history_new - begin - assert_equal(nil, history.shift) - - history, lines = lines = history_new_and_push_history(5) - (0..4).each do |i| - assert_external_string_equal(lines[i], history.shift) - assert_equal(lines.length - (i + 1), history.length) - end - - assert_equal(nil, history.shift) - rescue NotImplementedError - end - end - - def test_each - history = history_new - e = history.each do |s| - assert(false) # not reachable - end - assert_equal(history, e) - history, lines = lines = history_new_and_push_history(5) - i = 0 - e = history.each do |s| - assert_external_string_equal(history[i], s) - assert_external_string_equal(lines[i], s) - i += 1 - end - assert_equal(history, e) - end - - def test_each__enumerator - history = history_new - e = history.each - assert_instance_of(Enumerator, e) - end - - def test_length - history = history_new - assert_equal(0, history.length) - push_history(history, 1) - assert_equal(1, history.length) - push_history(history, 4) - assert_equal(5, history.length) - history.clear - assert_equal(0, history.length) - end - - def test_empty_p - history = history_new - 2.times do - assert(history.empty?) - history.push("s") - assert_equal(false, history.empty?) - history.clear - assert(history.empty?) - end - end - - def test_delete_at - begin - history, lines = lines = history_new_and_push_history(5) - (0..4).each do |i| - assert_external_string_equal(lines[i], history.delete_at(0)) - end - assert(history.empty?) - - history, lines = lines = history_new_and_push_history(5) - (1..5).each do |i| - assert_external_string_equal(lines[lines.length - i], history.delete_at(-1)) - end - assert(history.empty?) - - history, lines = lines = history_new_and_push_history(5) - assert_external_string_equal(lines[0], history.delete_at(0)) - assert_external_string_equal(lines[4], history.delete_at(3)) - assert_external_string_equal(lines[1], history.delete_at(0)) - assert_external_string_equal(lines[3], history.delete_at(1)) - assert_external_string_equal(lines[2], history.delete_at(0)) - assert(history.empty?) - rescue NotImplementedError - end - end - - def test_delete_at__out_of_range - history = history_new - assert_raise(IndexError, NotImplementedError, "index=<0>") do - history.delete_at(0) - end - - history, _ = history_new_and_push_history(5) - invalid_indexes = [5, 6, 100, -6, -7, -100] - invalid_indexes.each do |i| - assert_raise(IndexError, NotImplementedError, "index=<#{i}>") do - history.delete_at(i) - end - end - - invalid_indexes = [100_000_000_000_000_000_000, - -100_000_000_000_000_000_000] - invalid_indexes.each do |i| - assert_raise(RangeError, NotImplementedError, "index=<#{i}>") do - history.delete_at(i) - end - end - end - - def test_history_size_zero - history = history_new(history_size: 0) - assert_equal 0, history.size - history << 'aa' - history << 'bb' - assert_equal 0, history.size - history.push(*%w{aa bb cc}) - assert_equal 0, history.size - end - - def test_history_size_negative_unlimited - history = history_new(history_size: -1) - assert_equal 0, history.size - history << 'aa' - history << 'bb' - assert_equal 2, history.size - history.push(*%w{aa bb cc}) - assert_equal 5, history.size - end - - def test_history_encoding_conversion - history = history_new - text1 = String.new("a\u{65535}b\xFFc", encoding: Encoding::UTF_8) - text2 = String.new("d\xFFe", encoding: Encoding::Shift_JIS) - history.push(text1.dup, text2.dup) - expected = [text1, text2].map { |s| s.encode(Reline.encoding_system_needs, invalid: :replace, undef: :replace) } - assert_equal(expected, history.to_a) - end - - private - - def history_new(history_size: 10) - Reline::History.new(Struct.new(:history_size).new(history_size)) - end - - def push_history(history, num) - lines = [] - num.times do |i| - s = "a" - i.times do - s = s.succ - end - lines.push("#{i + 1}:#{s}") - end - history.push(*lines) - return history, lines - end - - def history_new_and_push_history(num) - history = history_new(history_size: 100) - return push_history(history, num) - end - - def assert_external_string_equal(expected, actual) - assert_equal(expected, actual) - mes = "Encoding of #{actual.inspect} is expected #{get_default_internal_encoding.inspect} but #{actual.encoding}" - assert_equal(get_default_internal_encoding, actual.encoding, mes) - end - - def get_default_internal_encoding - if encoding = Reline.core.encoding - encoding - elsif RUBY_PLATFORM =~ /mswin|mingw/ - Encoding.default_internal || Encoding::UTF_8 - else - Encoding.default_internal || Encoding.find("locale") - end - end -end diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb deleted file mode 100644 index 78b4c936b9..0000000000 --- a/test/reline/test_key_actor_emacs.rb +++ /dev/null @@ -1,1743 +0,0 @@ -require_relative 'helper' - -class Reline::KeyActor::EmacsTest < Reline::TestCase - def setup - Reline.send(:test_mode) - @prompt = '> ' - @config = Reline::Config.new # Emacs mode is default - @config.autocompletion = false - Reline::HISTORY.instance_variable_set(:@config, @config) - Reline::HISTORY.clear - @encoding = Reline.core.encoding - @line_editor = Reline::LineEditor.new(@config) - @line_editor.reset(@prompt) - end - - def teardown - Reline.test_reset - end - - def test_ed_insert_one - input_keys('a') - assert_line_around_cursor('a', '') - end - - def test_ed_insert_two - input_keys('ab') - assert_line_around_cursor('ab', '') - end - - def test_ed_insert_mbchar_one - input_keys('か') - assert_line_around_cursor('か', '') - end - - def test_ed_insert_mbchar_two - input_keys('かき') - assert_line_around_cursor('かき', '') - end - - def test_ed_insert_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099") - assert_line_around_cursor("か\u3099", '') - end - - def test_ed_insert_for_plural_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099") - assert_line_around_cursor("か\u3099き\u3099", '') - end - - def test_move_next_and_prev - input_keys('abd') - assert_line_around_cursor('abd', '') - input_keys("\C-b") - assert_line_around_cursor('ab', 'd') - input_keys("\C-b") - assert_line_around_cursor('a', 'bd') - input_keys("\C-f") - assert_line_around_cursor('ab', 'd') - input_keys('c') - assert_line_around_cursor('abc', 'd') - end - - def test_move_next_and_prev_for_mbchar - input_keys('かきけ') - assert_line_around_cursor('かきけ', '') - input_keys("\C-b") - assert_line_around_cursor('かき', 'け') - input_keys("\C-b") - assert_line_around_cursor('か', 'きけ') - input_keys("\C-f") - assert_line_around_cursor('かき', 'け') - input_keys('く') - assert_line_around_cursor('かきく', 'け') - end - - def test_move_next_and_prev_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099け\u3099") - assert_line_around_cursor("か\u3099き\u3099け\u3099", '') - input_keys("\C-b") - assert_line_around_cursor("か\u3099き\u3099", "け\u3099") - input_keys("\C-b") - assert_line_around_cursor("か\u3099", "き\u3099け\u3099") - input_keys("\C-f") - assert_line_around_cursor("か\u3099き\u3099", "け\u3099") - input_keys("く\u3099") - assert_line_around_cursor("か\u3099き\u3099く\u3099", "け\u3099") - end - - def test_move_to_beg_end - input_keys('bcd') - assert_line_around_cursor('bcd', '') - input_keys("\C-a") - assert_line_around_cursor('', 'bcd') - input_keys('a') - assert_line_around_cursor('a', 'bcd') - input_keys("\C-e") - assert_line_around_cursor('abcd', '') - input_keys('e') - assert_line_around_cursor('abcde', '') - end - - def test_ed_newline_with_cr - input_keys('ab') - assert_line_around_cursor('ab', '') - refute(@line_editor.finished?) - input_keys("\C-m") - assert_line_around_cursor('ab', '') - assert(@line_editor.finished?) - end - - def test_ed_newline_with_lf - input_keys('ab') - assert_line_around_cursor('ab', '') - refute(@line_editor.finished?) - input_keys("\C-j") - assert_line_around_cursor('ab', '') - assert(@line_editor.finished?) - end - - def test_em_delete_prev_char - input_keys('ab') - assert_line_around_cursor('ab', '') - input_keys("\C-h") - assert_line_around_cursor('a', '') - end - - def test_em_delete_prev_char_for_mbchar - input_keys('かき') - assert_line_around_cursor('かき', '') - input_keys("\C-h") - assert_line_around_cursor('か', '') - end - - def test_em_delete_prev_char_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099") - assert_line_around_cursor("か\u3099き\u3099", '') - input_keys("\C-h") - assert_line_around_cursor("か\u3099", '') - end - - def test_bracketed_paste_insert - set_line_around_cursor('A', 'Z') - input_key_by_symbol(:insert_multiline_text, char: "abc\n\C-abc") - assert_whole_lines(['Aabc', "\C-abcZ"]) - assert_line_around_cursor("\C-abc", 'Z') - end - - def test_ed_quoted_insert - set_line_around_cursor('A', 'Z') - input_key_by_symbol(:insert_raw_char, char: "\C-a") - assert_line_around_cursor("A\C-a", 'Z') - end - - def test_ed_quoted_insert_with_vi_arg - input_keys("a\C-[3") - input_key_by_symbol(:insert_raw_char, char: "\C-a") - input_keys("b\C-[4") - input_key_by_symbol(:insert_raw_char, char: '1') - assert_line_around_cursor("a\C-a\C-a\C-ab1111", '') - end - - def test_ed_kill_line - input_keys("\C-k") - assert_line_around_cursor('', '') - input_keys('abc') - assert_line_around_cursor('abc', '') - input_keys("\C-k") - assert_line_around_cursor('abc', '') - input_keys("\C-b\C-k") - assert_line_around_cursor('ab', '') - end - - def test_em_kill_line - input_key_by_symbol(:em_kill_line) - assert_line_around_cursor('', '') - input_keys('abc') - input_key_by_symbol(:em_kill_line) - assert_line_around_cursor('', '') - input_keys('abc') - input_keys("\C-b") - input_key_by_symbol(:em_kill_line) - assert_line_around_cursor('', '') - input_keys('abc') - input_keys("\C-a") - input_key_by_symbol(:em_kill_line) - assert_line_around_cursor('', '') - end - - def test_ed_move_to_beg - input_keys('abd') - assert_line_around_cursor('abd', '') - input_keys("\C-b") - assert_line_around_cursor('ab', 'd') - input_keys('c') - assert_line_around_cursor('abc', 'd') - input_keys("\C-a") - assert_line_around_cursor('', 'abcd') - input_keys('012') - assert_line_around_cursor('012', 'abcd') - input_keys("\C-a") - assert_line_around_cursor('', '012abcd') - input_keys('ABC') - assert_line_around_cursor('ABC', '012abcd') - input_keys("\C-f" * 10 + "\C-a") - assert_line_around_cursor('', 'ABC012abcd') - input_keys('a') - assert_line_around_cursor('a', 'ABC012abcd') - end - - def test_ed_move_to_beg_with_blank - input_keys(' abc') - assert_line_around_cursor(' abc', '') - input_keys("\C-a") - assert_line_around_cursor('', ' abc') - end - - def test_ed_move_to_end - input_keys('abd') - assert_line_around_cursor('abd', '') - input_keys("\C-b") - assert_line_around_cursor('ab', 'd') - input_keys('c') - assert_line_around_cursor('abc', 'd') - input_keys("\C-e") - assert_line_around_cursor('abcd', '') - input_keys('012') - assert_line_around_cursor('abcd012', '') - input_keys("\C-e") - assert_line_around_cursor('abcd012', '') - input_keys('ABC') - assert_line_around_cursor('abcd012ABC', '') - input_keys("\C-b" * 10 + "\C-e") - assert_line_around_cursor('abcd012ABC', '') - input_keys('a') - assert_line_around_cursor('abcd012ABCa', '') - end - - def test_em_delete - input_keys('ab') - assert_line_around_cursor('ab', '') - input_keys("\C-a") - assert_line_around_cursor('', 'ab') - input_keys("\C-d") - assert_line_around_cursor('', 'b') - end - - def test_em_delete_for_mbchar - input_keys('かき') - assert_line_around_cursor('かき', '') - input_keys("\C-a") - assert_line_around_cursor('', 'かき') - input_keys("\C-d") - assert_line_around_cursor('', 'き') - end - - def test_em_delete_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099") - assert_line_around_cursor("か\u3099き\u3099", '') - input_keys("\C-a") - assert_line_around_cursor('', "か\u3099き\u3099") - input_keys("\C-d") - assert_line_around_cursor('', "き\u3099") - end - - def test_em_delete_ends_editing - input_keys("\C-d") # quit from inputing - assert_nil(@line_editor.line) - assert(@line_editor.finished?) - end - - def test_ed_clear_screen - @line_editor.instance_variable_get(:@rendered_screen).lines = [[]] - input_keys("\C-l") - assert_empty(@line_editor.instance_variable_get(:@rendered_screen).lines) - end - - def test_ed_clear_screen_with_inputted - input_keys('abc') - input_keys("\C-b") - @line_editor.instance_variable_get(:@rendered_screen).lines = [[]] - assert_line_around_cursor('ab', 'c') - input_keys("\C-l") - assert_empty(@line_editor.instance_variable_get(:@rendered_screen).lines) - assert_line_around_cursor('ab', 'c') - end - - def test_key_delete - input_keys('abc') - assert_line_around_cursor('abc', '') - input_key_by_symbol(:key_delete) - assert_line_around_cursor('abc', '') - end - - def test_key_delete_does_not_end_editing - input_key_by_symbol(:key_delete) - assert_line_around_cursor('', '') - refute(@line_editor.finished?) - end - - def test_key_delete_preserves_cursor - input_keys('abc') - input_keys("\C-b") - assert_line_around_cursor('ab', 'c') - input_key_by_symbol(:key_delete) - assert_line_around_cursor('ab', '') - end - - def test_em_next_word - assert_line_around_cursor('', '') - input_keys('abc def{bbb}ccc') - input_keys("\C-a\eF") - assert_line_around_cursor('abc', ' def{bbb}ccc') - input_keys("\eF") - assert_line_around_cursor('abc def', '{bbb}ccc') - input_keys("\eF") - assert_line_around_cursor('abc def{bbb', '}ccc') - input_keys("\eF") - assert_line_around_cursor('abc def{bbb}ccc', '') - input_keys("\eF") - assert_line_around_cursor('abc def{bbb}ccc', '') - end - - def test_em_next_word_for_mbchar - assert_line_around_cursor('', '') - input_keys('あいう かきく{さしす}たちつ') - input_keys("\C-a\eF") - assert_line_around_cursor('あいう', ' かきく{さしす}たちつ') - input_keys("\eF") - assert_line_around_cursor('あいう かきく', '{さしす}たちつ') - input_keys("\eF") - assert_line_around_cursor('あいう かきく{さしす', '}たちつ') - input_keys("\eF") - assert_line_around_cursor('あいう かきく{さしす}たちつ', '') - input_keys("\eF") - assert_line_around_cursor('あいう かきく{さしす}たちつ', '') - end - - def test_em_next_word_for_mbchar_by_plural_code_points - omit_unless_utf8 - assert_line_around_cursor("", "") - input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - input_keys("\C-a\eF") - assert_line_around_cursor("あいう", " か\u3099き\u3099く\u3099{さしす}たちつ") - input_keys("\eF") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099", "{さしす}たちつ") - input_keys("\eF") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす", "}たちつ") - input_keys("\eF") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") - input_keys("\eF") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") - end - - def test_em_prev_word - input_keys('abc def{bbb}ccc') - assert_line_around_cursor('abc def{bbb}ccc', '') - input_keys("\eB") - assert_line_around_cursor('abc def{bbb}', 'ccc') - input_keys("\eB") - assert_line_around_cursor('abc def{', 'bbb}ccc') - input_keys("\eB") - assert_line_around_cursor('abc ', 'def{bbb}ccc') - input_keys("\eB") - assert_line_around_cursor('', 'abc def{bbb}ccc') - input_keys("\eB") - assert_line_around_cursor('', 'abc def{bbb}ccc') - end - - def test_em_prev_word_for_mbchar - input_keys('あいう かきく{さしす}たちつ') - assert_line_around_cursor('あいう かきく{さしす}たちつ', '') - input_keys("\eB") - assert_line_around_cursor('あいう かきく{さしす}', 'たちつ') - input_keys("\eB") - assert_line_around_cursor('あいう かきく{', 'さしす}たちつ') - input_keys("\eB") - assert_line_around_cursor('あいう ', 'かきく{さしす}たちつ') - input_keys("\eB") - assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') - input_keys("\eB") - assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') - end - - def test_em_prev_word_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") - input_keys("\eB") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", "たちつ") - input_keys("\eB") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", "さしす}たちつ") - input_keys("\eB") - assert_line_around_cursor("あいう ", "か\u3099き\u3099く\u3099{さしす}たちつ") - input_keys("\eB") - assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ") - input_keys("\eB") - assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ") - end - - def test_em_delete_next_word - input_keys('abc def{bbb}ccc') - input_keys("\C-a") - assert_line_around_cursor('', 'abc def{bbb}ccc') - input_keys("\ed") - assert_line_around_cursor('', ' def{bbb}ccc') - input_keys("\ed") - assert_line_around_cursor('', '{bbb}ccc') - input_keys("\ed") - assert_line_around_cursor('', '}ccc') - input_keys("\ed") - assert_line_around_cursor('', '') - end - - def test_em_delete_next_word_for_mbchar - input_keys('あいう かきく{さしす}たちつ') - input_keys("\C-a") - assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') - input_keys("\ed") - assert_line_around_cursor('', ' かきく{さしす}たちつ') - input_keys("\ed") - assert_line_around_cursor('', '{さしす}たちつ') - input_keys("\ed") - assert_line_around_cursor('', '}たちつ') - input_keys("\ed") - assert_line_around_cursor('', '') - end - - def test_em_delete_next_word_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - input_keys("\C-a") - assert_line_around_cursor('', "あいう か\u3099き\u3099く\u3099{さしす}たちつ") - input_keys("\ed") - assert_line_around_cursor('', " か\u3099き\u3099く\u3099{さしす}たちつ") - input_keys("\ed") - assert_line_around_cursor('', '{さしす}たちつ') - input_keys("\ed") - assert_line_around_cursor('', '}たちつ') - input_keys("\ed") - assert_line_around_cursor('', '') - end - - def test_ed_delete_prev_word - input_keys('abc def{bbb}ccc') - assert_line_around_cursor('abc def{bbb}ccc', '') - input_keys("\e\C-H") - assert_line_around_cursor('abc def{bbb}', '') - input_keys("\e\C-H") - assert_line_around_cursor('abc def{', '') - input_keys("\e\C-H") - assert_line_around_cursor('abc ', '') - input_keys("\e\C-H") - assert_line_around_cursor('', '') - end - - def test_ed_delete_prev_word_for_mbchar - input_keys('あいう かきく{さしす}たちつ') - assert_line_around_cursor('あいう かきく{さしす}たちつ', '') - input_keys("\e\C-H") - assert_line_around_cursor('あいう かきく{さしす}', '') - input_keys("\e\C-H") - assert_line_around_cursor('あいう かきく{', '') - input_keys("\e\C-H") - assert_line_around_cursor('あいう ', '') - input_keys("\e\C-H") - assert_line_around_cursor('', '') - end - - def test_ed_delete_prev_word_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '') - input_keys("\e\C-H") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '') - input_keys("\e\C-H") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '') - input_keys("\e\C-H") - assert_line_around_cursor('あいう ', '') - input_keys("\e\C-H") - assert_line_around_cursor('', '') - end - - def test_ed_transpose_chars - input_keys('abc') - input_keys("\C-a") - assert_line_around_cursor('', 'abc') - input_keys("\C-t") - assert_line_around_cursor('', 'abc') - input_keys("\C-f\C-t") - assert_line_around_cursor('ba', 'c') - input_keys("\C-t") - assert_line_around_cursor('bca', '') - input_keys("\C-t") - assert_line_around_cursor('bac', '') - end - - def test_ed_transpose_chars_for_mbchar - input_keys('あかさ') - input_keys("\C-a") - assert_line_around_cursor('', 'あかさ') - input_keys("\C-t") - assert_line_around_cursor('', 'あかさ') - input_keys("\C-f\C-t") - assert_line_around_cursor('かあ', 'さ') - input_keys("\C-t") - assert_line_around_cursor('かさあ', '') - input_keys("\C-t") - assert_line_around_cursor('かあさ', '') - end - - def test_ed_transpose_chars_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("あか\u3099さ") - input_keys("\C-a") - assert_line_around_cursor('', "あか\u3099さ") - input_keys("\C-t") - assert_line_around_cursor('', "あか\u3099さ") - input_keys("\C-f\C-t") - assert_line_around_cursor("か\u3099あ", 'さ') - input_keys("\C-t") - assert_line_around_cursor("か\u3099さあ", '') - input_keys("\C-t") - assert_line_around_cursor("か\u3099あさ", '') - end - - def test_ed_transpose_words - input_keys('abc def') - assert_line_around_cursor('abc def', '') - input_keys("\et") - assert_line_around_cursor('def abc', '') - input_keys("\C-a\C-k") - input_keys(' abc def ') - input_keys("\C-b" * 4) - assert_line_around_cursor(' abc de', 'f ') - input_keys("\et") - assert_line_around_cursor(' def abc', ' ') - input_keys("\C-a\C-k") - input_keys(' abc def ') - input_keys("\C-b" * 6) - assert_line_around_cursor(' abc ', 'def ') - input_keys("\et") - assert_line_around_cursor(' def abc', ' ') - input_keys("\et") - assert_line_around_cursor(' abc def', '') - end - - def test_ed_transpose_words_for_mbchar - input_keys('あいう かきく') - assert_line_around_cursor('あいう かきく', '') - input_keys("\et") - assert_line_around_cursor('かきく あいう', '') - input_keys("\C-a\C-k") - input_keys(' あいう かきく ') - input_keys("\C-b" * 4) - assert_line_around_cursor(' あいう かき', 'く ') - input_keys("\et") - assert_line_around_cursor(' かきく あいう', ' ') - input_keys("\C-a\C-k") - input_keys(' あいう かきく ') - input_keys("\C-b" * 6) - assert_line_around_cursor(' あいう ', 'かきく ') - input_keys("\et") - assert_line_around_cursor(' かきく あいう', ' ') - input_keys("\et") - assert_line_around_cursor(' あいう かきく', '') - end - - def test_ed_transpose_words_with_one_word - input_keys('abc ') - assert_line_around_cursor('abc ', '') - input_keys("\et") - assert_line_around_cursor('abc ', '') - input_keys("\C-b") - assert_line_around_cursor('abc ', ' ') - input_keys("\et") - assert_line_around_cursor('abc ', ' ') - input_keys("\C-b" * 2) - assert_line_around_cursor('ab', 'c ') - input_keys("\et") - assert_line_around_cursor('ab', 'c ') - input_keys("\et") - assert_line_around_cursor('ab', 'c ') - end - - def test_ed_transpose_words_with_one_word_for_mbchar - input_keys('あいう ') - assert_line_around_cursor('あいう ', '') - input_keys("\et") - assert_line_around_cursor('あいう ', '') - input_keys("\C-b") - assert_line_around_cursor('あいう ', ' ') - input_keys("\et") - assert_line_around_cursor('あいう ', ' ') - input_keys("\C-b" * 2) - assert_line_around_cursor('あい', 'う ') - input_keys("\et") - assert_line_around_cursor('あい', 'う ') - input_keys("\et") - assert_line_around_cursor('あい', 'う ') - end - - def test_ed_digit - input_keys('0123') - assert_line_around_cursor('0123', '') - end - - def test_ed_next_and_prev_char - input_keys('abc') - assert_line_around_cursor('abc', '') - input_keys("\C-b") - assert_line_around_cursor('ab', 'c') - input_keys("\C-b") - assert_line_around_cursor('a', 'bc') - input_keys("\C-b") - assert_line_around_cursor('', 'abc') - input_keys("\C-b") - assert_line_around_cursor('', 'abc') - input_keys("\C-f") - assert_line_around_cursor('a', 'bc') - input_keys("\C-f") - assert_line_around_cursor('ab', 'c') - input_keys("\C-f") - assert_line_around_cursor('abc', '') - input_keys("\C-f") - assert_line_around_cursor('abc', '') - end - - def test_ed_next_and_prev_char_for_mbchar - input_keys('あいう') - assert_line_around_cursor('あいう', '') - input_keys("\C-b") - assert_line_around_cursor('あい', 'う') - input_keys("\C-b") - assert_line_around_cursor('あ', 'いう') - input_keys("\C-b") - assert_line_around_cursor('', 'あいう') - input_keys("\C-b") - assert_line_around_cursor('', 'あいう') - input_keys("\C-f") - assert_line_around_cursor('あ', 'いう') - input_keys("\C-f") - assert_line_around_cursor('あい', 'う') - input_keys("\C-f") - assert_line_around_cursor('あいう', '') - input_keys("\C-f") - assert_line_around_cursor('あいう', '') - end - - def test_ed_next_and_prev_char_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099く\u3099") - assert_line_around_cursor("か\u3099き\u3099く\u3099", '') - input_keys("\C-b") - assert_line_around_cursor("か\u3099き\u3099", "く\u3099") - input_keys("\C-b") - assert_line_around_cursor("か\u3099", "き\u3099く\u3099") - input_keys("\C-b") - assert_line_around_cursor('', "か\u3099き\u3099く\u3099") - input_keys("\C-b") - assert_line_around_cursor('', "か\u3099き\u3099く\u3099") - input_keys("\C-f") - assert_line_around_cursor("か\u3099", "き\u3099く\u3099") - input_keys("\C-f") - assert_line_around_cursor("か\u3099き\u3099", "く\u3099") - input_keys("\C-f") - assert_line_around_cursor("か\u3099き\u3099く\u3099", '') - input_keys("\C-f") - assert_line_around_cursor("か\u3099き\u3099く\u3099", '') - end - - def test_em_capitol_case - input_keys('abc def{bbb}ccc') - input_keys("\C-a\ec") - assert_line_around_cursor('Abc', ' def{bbb}ccc') - input_keys("\ec") - assert_line_around_cursor('Abc Def', '{bbb}ccc') - input_keys("\ec") - assert_line_around_cursor('Abc Def{Bbb', '}ccc') - input_keys("\ec") - assert_line_around_cursor('Abc Def{Bbb}Ccc', '') - end - - def test_em_capitol_case_with_complex_example - input_keys('{}#* AaA!!!cCc ') - input_keys("\C-a\ec") - assert_line_around_cursor('{}#* Aaa', '!!!cCc ') - input_keys("\ec") - assert_line_around_cursor('{}#* Aaa!!!Ccc', ' ') - input_keys("\ec") - assert_line_around_cursor('{}#* Aaa!!!Ccc ', '') - end - - def test_em_lower_case - input_keys('AbC def{bBb}CCC') - input_keys("\C-a\el") - assert_line_around_cursor('abc', ' def{bBb}CCC') - input_keys("\el") - assert_line_around_cursor('abc def', '{bBb}CCC') - input_keys("\el") - assert_line_around_cursor('abc def{bbb', '}CCC') - input_keys("\el") - assert_line_around_cursor('abc def{bbb}ccc', '') - end - - def test_em_lower_case_with_complex_example - input_keys('{}#* AaA!!!cCc ') - input_keys("\C-a\el") - assert_line_around_cursor('{}#* aaa', '!!!cCc ') - input_keys("\el") - assert_line_around_cursor('{}#* aaa!!!ccc', ' ') - input_keys("\el") - assert_line_around_cursor('{}#* aaa!!!ccc ', '') - end - - def test_em_upper_case - input_keys('AbC def{bBb}CCC') - input_keys("\C-a\eu") - assert_line_around_cursor('ABC', ' def{bBb}CCC') - input_keys("\eu") - assert_line_around_cursor('ABC DEF', '{bBb}CCC') - input_keys("\eu") - assert_line_around_cursor('ABC DEF{BBB', '}CCC') - input_keys("\eu") - assert_line_around_cursor('ABC DEF{BBB}CCC', '') - end - - def test_em_upper_case_with_complex_example - input_keys('{}#* AaA!!!cCc ') - input_keys("\C-a\eu") - assert_line_around_cursor('{}#* AAA', '!!!cCc ') - input_keys("\eu") - assert_line_around_cursor('{}#* AAA!!!CCC', ' ') - input_keys("\eu") - assert_line_around_cursor('{}#* AAA!!!CCC ', '') - end - - def test_em_delete_or_list - @line_editor.completion_proc = proc { |word| - %w{ - foo_foo - foo_bar - foo_baz - qux - }.map { |i| - i.encode(@encoding) - } - } - input_keys('fooo') - assert_line_around_cursor('fooo', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-b") - assert_line_around_cursor('foo', 'o') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_key_by_symbol(:em_delete_or_list) - assert_line_around_cursor('foo', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_key_by_symbol(:em_delete_or_list) - assert_line_around_cursor('foo', '') - assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) - end - - def test_completion_duplicated_list - @line_editor.completion_proc = proc { |word| - %w{ - foo_foo - foo_foo - foo_bar - }.map { |i| - i.encode(@encoding) - } - } - input_keys('foo_') - assert_line_around_cursor('foo_', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list) - end - - def test_completion - @line_editor.completion_proc = proc { |word| - %w{ - foo_foo - foo_bar - foo_baz - qux - }.map { |i| - i.encode(@encoding) - } - } - input_keys('fo') - assert_line_around_cursor('fo', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) - input_keys('a') - input_keys("\C-i") - assert_line_around_cursor('foo_a', '') - input_keys("\C-h") - input_keys('b') - input_keys("\C-i") - assert_line_around_cursor('foo_ba', '') - input_keys("\C-h") - input_key_by_symbol(:complete) - assert_line_around_cursor('foo_ba', '') - input_keys("\C-h") - input_key_by_symbol(:menu_complete) - assert_line_around_cursor('foo_bar', '') - input_key_by_symbol(:menu_complete) - assert_line_around_cursor('foo_baz', '') - input_keys("\C-h") - input_key_by_symbol(:menu_complete_backward) - assert_line_around_cursor('foo_baz', '') - input_key_by_symbol(:menu_complete_backward) - assert_line_around_cursor('foo_bar', '') - end - - def test_autocompletion - @config.autocompletion = true - @line_editor.completion_proc = proc { |word| - %w{ - Readline - Regexp - RegexpError - }.map { |i| - i.encode(@encoding) - } - } - input_keys('Re') - assert_line_around_cursor('Re', '') - input_keys("\C-i") - assert_line_around_cursor('Readline', '') - input_keys("\C-i") - assert_line_around_cursor('Regexp', '') - input_key_by_symbol(:completion_journey_up) - assert_line_around_cursor('Readline', '') - input_key_by_symbol(:complete) - assert_line_around_cursor('Regexp', '') - input_key_by_symbol(:menu_complete_backward) - assert_line_around_cursor('Readline', '') - input_key_by_symbol(:menu_complete) - assert_line_around_cursor('Regexp', '') - ensure - @config.autocompletion = false - end - - def test_completion_with_indent - @line_editor.completion_proc = proc { |word| - %w{ - foo_foo - foo_bar - foo_baz - qux - }.map { |i| - i.encode(@encoding) - } - } - input_keys(' fo') - assert_line_around_cursor(' fo', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor(' foo_', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor(' foo_', '') - assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) - end - - def test_completion_with_perfect_match - @line_editor.completion_proc = proc { |word| - %w{ - foo - foo_bar - }.map { |i| - i.encode(@encoding) - } - } - matched = nil - @line_editor.dig_perfect_match_proc = proc { |m| - matched = m - } - input_keys('fo') - assert_line_around_cursor('fo', '') - assert_equal(Reline::LineEditor::CompletionState::NORMAL, @line_editor.instance_variable_get(:@completion_state)) - assert_equal(nil, matched) - input_keys("\C-i") - assert_line_around_cursor('foo', '') - assert_equal(Reline::LineEditor::CompletionState::MENU_WITH_PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) - assert_equal(nil, matched) - input_keys("\C-i") - assert_line_around_cursor('foo', '') - assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) - assert_equal(nil, matched) - input_keys("\C-i") - assert_line_around_cursor('foo', '') - assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) - assert_equal('foo', matched) - matched = nil - input_keys('_') - input_keys("\C-i") - assert_line_around_cursor('foo_bar', '') - assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) - assert_equal(nil, matched) - input_keys("\C-i") - assert_line_around_cursor('foo_bar', '') - assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) - assert_equal('foo_bar', matched) - end - - def test_continuous_completion_with_perfect_match - @line_editor.completion_proc = proc { |word| - word == 'f' ? ['foo'] : %w[foobar foobaz] - } - input_keys('f') - input_keys("\C-i") - assert_line_around_cursor('foo', '') - input_keys("\C-i") - assert_line_around_cursor('fooba', '') - end - - def test_continuous_completion_disabled_with_perfect_match - @line_editor.completion_proc = proc { |word| - word == 'f' ? ['foo'] : %w[foobar foobaz] - } - @line_editor.dig_perfect_match_proc = proc {} - input_keys('f') - input_keys("\C-i") - assert_line_around_cursor('foo', '') - input_keys("\C-i") - assert_line_around_cursor('foo', '') - end - - def test_completion_append_character - @line_editor.completion_proc = proc { |word| - %w[foo_ foo_foo foo_bar].select { |s| s.start_with? word } - } - @line_editor.completion_append_character = 'X' - input_keys('f') - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - input_keys('f') - input_keys("\C-i") - assert_line_around_cursor('foo_fooX', '') - input_keys(' foo_bar') - input_keys("\C-i") - assert_line_around_cursor('foo_fooX foo_barX', '') - end - - def test_completion_with_quote_append - @line_editor.completion_proc = proc { |word| - %w[foo bar baz].select { |s| s.start_with? word } - } - set_line_around_cursor('x = "b', '') - input_keys("\C-i") - assert_line_around_cursor('x = "ba', '') - set_line_around_cursor('x = "f', ' ') - input_keys("\C-i") - assert_line_around_cursor('x = "foo', ' ') - set_line_around_cursor("x = 'f", '') - input_keys("\C-i") - assert_line_around_cursor("x = 'foo'", '') - set_line_around_cursor('"a "f', '') - input_keys("\C-i") - assert_line_around_cursor('"a "foo', '') - set_line_around_cursor('"a\\" "f', '') - input_keys("\C-i") - assert_line_around_cursor('"a\\" "foo', '') - set_line_around_cursor('"a" "f', '') - input_keys("\C-i") - assert_line_around_cursor('"a" "foo"', '') - end - - def test_completion_with_completion_ignore_case - @line_editor.completion_proc = proc { |word| - %w{ - foo_foo - foo_bar - Foo_baz - qux - }.map { |i| - i.encode(@encoding) - } - } - input_keys('fo') - assert_line_around_cursor('fo', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list) - @config.completion_ignore_case = true - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) - input_keys('a') - input_keys("\C-i") - assert_line_around_cursor('foo_a', '') - input_keys("\C-h") - input_keys('b') - input_keys("\C-i") - assert_line_around_cursor('foo_ba', '') - input_keys('Z') - input_keys("\C-i") - assert_line_around_cursor('Foo_baz', '') - end - - def test_completion_in_middle_of_line - @line_editor.completion_proc = proc { |word| - %w{ - foo_foo - foo_bar - foo_baz - qux - }.map { |i| - i.encode(@encoding) - } - } - input_keys('abcde fo ABCDE') - assert_line_around_cursor('abcde fo ABCDE', '') - input_keys("\C-b" * 6 + "\C-i") - assert_line_around_cursor('abcde foo_', ' ABCDE') - input_keys("\C-b" * 2 + "\C-i") - assert_line_around_cursor('abcde foo_', 'o_ ABCDE') - end - - def test_completion_with_nil_value - @line_editor.completion_proc = proc { |word| - %w{ - foo_foo - foo_bar - Foo_baz - qux - }.map { |i| - i.encode(@encoding) - }.prepend(nil) - } - @config.completion_ignore_case = true - input_keys('fo') - assert_line_around_cursor('fo', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) - input_keys("\C-i") - assert_line_around_cursor('foo_', '') - assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) - input_keys('a') - input_keys("\C-i") - assert_line_around_cursor('foo_a', '') - input_keys("\C-h") - input_keys('b') - input_keys("\C-i") - assert_line_around_cursor('foo_ba', '') - end - - def test_em_kill_region - input_keys('abc def{bbb}ccc ddd ') - assert_line_around_cursor('abc def{bbb}ccc ddd ', '') - input_keys("\C-w") - assert_line_around_cursor('abc def{bbb}ccc ', '') - input_keys("\C-w") - assert_line_around_cursor('abc ', '') - input_keys("\C-w") - assert_line_around_cursor('', '') - input_keys("\C-w") - assert_line_around_cursor('', '') - end - - def test_em_kill_region_mbchar - input_keys('あ い う{う}う ') - assert_line_around_cursor('あ い う{う}う ', '') - input_keys("\C-w") - assert_line_around_cursor('あ い ', '') - input_keys("\C-w") - assert_line_around_cursor('あ ', '') - input_keys("\C-w") - assert_line_around_cursor('', '') - end - - def test_vi_search_prev - Reline::HISTORY.concat(%w{abc 123 AAA}) - assert_line_around_cursor('', '') - input_keys("\C-ra\C-j") - assert_line_around_cursor('', 'abc') - end - - def test_larger_histories_than_history_size - history_size = @config.history_size - @config.history_size = 2 - Reline::HISTORY.concat(%w{abc 123 AAA}) - assert_line_around_cursor('', '') - input_keys("\C-p") - assert_line_around_cursor('AAA', '') - input_keys("\C-p") - assert_line_around_cursor('123', '') - input_keys("\C-p") - assert_line_around_cursor('123', '') - ensure - @config.history_size = history_size - end - - def test_search_history_to_back - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-r123") - assert_line_around_cursor('1234', '') - input_keys("\C-ha") - assert_line_around_cursor('12aa', '') - input_keys("\C-h3") - assert_line_around_cursor('1235', '') - end - - def test_search_history_to_front - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-s123") - assert_line_around_cursor('1235', '') - input_keys("\C-ha") - assert_line_around_cursor('12aa', '') - input_keys("\C-h3") - assert_line_around_cursor('1234', '') - end - - def test_search_history_front_and_back - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-s12") - assert_line_around_cursor('1235', '') - input_keys("\C-s") - assert_line_around_cursor('12aa', '') - input_keys("\C-r") - assert_line_around_cursor('12aa', '') - input_keys("\C-r") - assert_line_around_cursor('1235', '') - end - - def test_search_history_back_and_front - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-r12") - assert_line_around_cursor('1234', '') - input_keys("\C-r") - assert_line_around_cursor('12aa', '') - input_keys("\C-s") - assert_line_around_cursor('12aa', '') - input_keys("\C-s") - assert_line_around_cursor('1234', '') - end - - def test_search_history_to_back_in_the_middle_of_histories - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-p\C-p") - assert_line_around_cursor('12aa', '') - input_keys("\C-r123") - assert_line_around_cursor('1235', '') - end - - def test_search_history_twice - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-r123") - assert_line_around_cursor('1234', '') - input_keys("\C-r") - assert_line_around_cursor('1235', '') - end - - def test_search_history_by_last_determined - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-r123") - assert_line_around_cursor('1234', '') - input_keys("\C-j") - assert_line_around_cursor('', '1234') - input_keys("\C-k") # delete - assert_line_around_cursor('', '') - input_keys("\C-r") - assert_line_around_cursor('', '') - input_keys("\C-r") - assert_line_around_cursor('1235', '') - end - - def test_search_history_with_isearch_terminator - @config.read_lines(<<~LINES.split(/(?<=\n)/)) - set isearch-terminators "XYZ" - LINES - Reline::HISTORY.concat([ - '1235', # old - '12aa', - '1234' # new - ]) - assert_line_around_cursor('', '') - input_keys("\C-r12a") - assert_line_around_cursor('12aa', '') - input_keys('Y') - assert_line_around_cursor('', '12aa') - input_keys('x') - assert_line_around_cursor('x', '12aa') - end - - def test_em_set_mark_and_em_exchange_mark - input_keys('aaa bbb ccc ddd') - assert_line_around_cursor('aaa bbb ccc ddd', '') - input_keys("\C-a\eF\eF") - assert_line_around_cursor('aaa bbb', ' ccc ddd') - assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) - input_keys("\x00") # C-Space - assert_line_around_cursor('aaa bbb', ' ccc ddd') - assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) - input_keys("\C-a") - assert_line_around_cursor('', 'aaa bbb ccc ddd') - assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) - input_key_by_symbol(:em_exchange_mark) - assert_line_around_cursor('aaa bbb', ' ccc ddd') - assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer)) - end - - def test_em_exchange_mark_without_mark - input_keys('aaa bbb ccc ddd') - assert_line_around_cursor('aaa bbb ccc ddd', '') - input_keys("\C-a\ef") - assert_line_around_cursor('aaa', ' bbb ccc ddd') - assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) - input_key_by_symbol(:em_exchange_mark) - assert_line_around_cursor('aaa', ' bbb ccc ddd') - assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) - end - - def test_modify_lines_with_wrong_rs - verbose, $VERBOSE = $VERBOSE, nil - original_global_slash = $/ - $/ = 'b' - $VERBOSE = verbose - @line_editor.output_modifier_proc = proc { |output| Reline::Unicode.escape_for_print(output) } - input_keys("abcdef\n") - result = @line_editor.__send__(:modify_lines, @line_editor.whole_lines, @line_editor.finished?) - $/ = nil - assert_equal(['abcdef'], result) - ensure - $VERBOSE = nil - $/ = original_global_slash - $VERBOSE = verbose - end - - def test_ed_search_prev_history - Reline::HISTORY.concat([ - '12356', # old - '12aaa', - '12345' # new - ]) - input_keys('123') - # The ed_search_prev_history doesn't have default binding - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_around_cursor('123', '45') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_around_cursor('123', '56') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_around_cursor('123', '56') - end - - def test_ed_search_prev_history_with_empty - Reline::HISTORY.concat([ - '12356', # old - '12aaa', - '12345' # new - ]) - # The ed_search_prev_history doesn't have default binding - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12345', '') - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12aaa', '') - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12356', '') - input_key_by_symbol(:ed_search_next_history) - assert_line_around_cursor('12aaa', '') - input_key_by_symbol(:ed_prev_char) - input_key_by_symbol(:ed_next_char) - assert_line_around_cursor('12aaa', '') - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12aaa', '') - 3.times { input_key_by_symbol(:ed_prev_char) } - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12', '356') - end - - def test_ed_search_prev_history_without_match - Reline::HISTORY.concat([ - '12356', # old - '12aaa', - '12345' # new - ]) - input_keys('ABC') - # The ed_search_prev_history doesn't have default binding - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_around_cursor('ABC', '') - end - - def test_ed_search_next_history - Reline::HISTORY.concat([ - '12356', # old - '12aaa', - '12345' # new - ]) - input_keys('123') - # The ed_search_prev_history and ed_search_next_history doesn't have default binding - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_around_cursor('123', '45') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_around_cursor('123', '56') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_around_cursor('123', '56') - @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_line_around_cursor('123', '45') - @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_line_around_cursor('123', '45') - end - - def test_ed_search_next_history_with_empty - Reline::HISTORY.concat([ - '12356', # old - '12aaa', - '12345' # new - ]) - # The ed_search_prev_history and ed_search_next_history doesn't have default binding - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12345', '') - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12aaa', '') - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12356', '') - input_key_by_symbol(:ed_search_next_history) - assert_line_around_cursor('12aaa', '') - input_key_by_symbol(:ed_search_next_history) - assert_line_around_cursor('12345', '') - input_key_by_symbol(:ed_search_prev_history) - assert_line_around_cursor('12aaa', '') - input_key_by_symbol(:ed_prev_char) - input_key_by_symbol(:ed_next_char) - input_key_by_symbol(:ed_search_next_history) - assert_line_around_cursor('12aaa', '') - 3.times { input_key_by_symbol(:ed_prev_char) } - input_key_by_symbol(:ed_search_next_history) - assert_line_around_cursor('12', '345') - end - - def test_incremental_search_history_cancel_by_symbol_key - # ed_prev_char should move cursor left and cancel incremental search - input_keys("abc\C-r") - input_key_by_symbol(:ed_prev_char, csi: true) - input_keys('d') - assert_line_around_cursor('abd', 'c') - end - - def test_incremental_search_history_saves_and_restores_last_input - Reline::HISTORY.concat(['abc', '123']) - input_keys("abcd") - # \C-j: terminate incremental search - input_keys("\C-r12\C-j") - assert_line_around_cursor('', '123') - input_key_by_symbol(:ed_next_history) - assert_line_around_cursor('abcd', '') - # Most non-printable keys also terminates incremental search - input_keys("\C-r12\C-i") - assert_line_around_cursor('', '123') - input_key_by_symbol(:ed_next_history) - assert_line_around_cursor('abcd', '') - # \C-g: cancel incremental search and restore input, cursor position and history index - input_key_by_symbol(:ed_prev_history) - input_keys("\C-b\C-b") - assert_line_around_cursor('1', '23') - input_keys("\C-rab\C-g") - assert_line_around_cursor('1', '23') - input_key_by_symbol(:ed_next_history) - assert_line_around_cursor('abcd', '') - end - - # Unicode emoji test - def test_ed_insert_for_include_zwj_emoji - omit_unless_utf8 - # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨👩👧👦" - input_keys("\u{1F468}") # U+1F468 is man "👨" - assert_line_around_cursor('👨', '') - input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line_around_cursor('👨', '') - input_keys("\u{1F469}") # U+1F469 is woman "👩" - assert_line_around_cursor('👨👩', '') - input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line_around_cursor('👨👩', '') - input_keys("\u{1F467}") # U+1F467 is girl "👧" - assert_line_around_cursor('👨👩👧', '') - input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line_around_cursor('👨👩👧', '') - input_keys("\u{1F466}") # U+1F466 is boy "👦" - assert_line_around_cursor('👨👩👧👦', '') - # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨👩👧👦" - input_keys("\u{1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_line_around_cursor('👨👩👧👦👨👩👧👦', '') - end - - def test_ed_insert_for_include_valiation_selector - omit_unless_utf8 - # U+0030 U+FE00 is DIGIT ZERO + VARIATION SELECTOR-1 "0︀" - input_keys("\u0030") # U+0030 is DIGIT ZERO - assert_line_around_cursor('0', '') - input_keys("\uFE00") # U+FE00 is VARIATION SELECTOR-1 - assert_line_around_cursor('0︀', '') - end - - def test_em_yank_pop - input_keys("def hoge\C-w\C-b\C-f\C-w") - assert_line_around_cursor('', '') - input_keys("\C-y") - assert_line_around_cursor('def ', '') - input_keys("\e\C-y") - assert_line_around_cursor('hoge', '') - end - - def test_em_kill_region_with_kill_ring - input_keys("def hoge\C-b\C-b\C-b\C-b") - assert_line_around_cursor('def ', 'hoge') - input_keys("\C-k\C-w") - assert_line_around_cursor('', '') - input_keys("\C-y") - assert_line_around_cursor('def hoge', '') - end - - def test_ed_search_prev_next_history_in_multibyte - Reline::HISTORY.concat([ - "def hoge\n 67890\n 12345\nend", # old - "def aiu\n 0xDEADBEEF\nend", - "def foo\n 12345\nend" # new - ]) - @line_editor.multiline_on - input_keys(' 123') - # The ed_search_prev_history doesn't have default binding - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_whole_lines(['def foo', ' 12345', 'end']) - assert_line_index(1) - assert_whole_lines(['def foo', ' 12345', 'end']) - assert_line_around_cursor(' 123', '45') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_index(2) - assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end']) - assert_line_around_cursor(' 123', '45') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_line_index(2) - assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end']) - assert_line_around_cursor(' 123', '45') - @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_line_index(1) - assert_whole_lines(['def foo', ' 12345', 'end']) - assert_line_around_cursor(' 123', '45') - @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_line_index(1) - assert_whole_lines(['def foo', ' 12345', 'end']) - assert_line_around_cursor(' 123', '45') - end - - def test_ignore_NUL_by_ed_quoted_insert - input_keys('"') - input_key_by_symbol(:insert_raw_char, char: 0.chr) - input_keys('"') - assert_line_around_cursor('""', '') - end - - def test_ed_argument_digit_by_meta_num - input_keys('abcdef') - assert_line_around_cursor('abcdef', '') - input_keys("\e2") - input_keys("\C-h") - assert_line_around_cursor('abcd', '') - end - - def test_ed_digit_with_ed_argument_digit - input_keys('1' * 30) - assert_line_around_cursor('1' * 30, '') - input_keys("\e2") - input_keys('3') - input_keys("\C-h") - input_keys('4') - assert_line_around_cursor('1' * 7 + '4', '') - end - - def test_halfwidth_kana_width_dakuten - omit_unless_utf8 - input_keys('ガギゲゴ') - assert_line_around_cursor('ガギゲゴ', '') - input_keys("\C-b\C-b") - assert_line_around_cursor('ガギ', 'ゲゴ') - input_keys('グ') - assert_line_around_cursor('ガギグ', 'ゲゴ') - end - - def test_input_unknown_char - omit_unless_utf8 - input_keys('') # U+0378 (unassigned) - assert_line_around_cursor('', '') - end - - def test_unix_line_discard - input_keys("\C-u") - assert_line_around_cursor('', '') - input_keys('abc') - assert_line_around_cursor('abc', '') - input_keys("\C-b\C-u") - assert_line_around_cursor('', 'c') - input_keys("\C-f\C-u") - assert_line_around_cursor('', '') - end - - def test_vi_editing_mode - @line_editor.__send__(:vi_editing_mode, nil) - assert(@config.editing_mode_is?(:vi_insert)) - end - - def test_undo - input_keys("\C-_") - assert_line_around_cursor('', '') - input_keys("aあb\C-h\C-h\C-h") - assert_line_around_cursor('', '') - input_keys("\C-_") - assert_line_around_cursor('a', '') - input_keys("\C-_") - assert_line_around_cursor('aあ', '') - input_keys("\C-_") - assert_line_around_cursor('aあb', '') - input_keys("\C-_") - assert_line_around_cursor('aあ', '') - input_keys("\C-_") - assert_line_around_cursor('a', '') - input_keys("\C-_") - assert_line_around_cursor('', '') - end - - def test_undo_with_cursor_position - input_keys("abc\C-b\C-h") - assert_line_around_cursor('a', 'c') - input_keys("\C-_") - assert_line_around_cursor('ab', 'c') - input_keys("あいう\C-b\C-h") - assert_line_around_cursor('abあ', 'うc') - input_keys("\C-_") - assert_line_around_cursor('abあい', 'うc') - end - - def test_undo_with_multiline - @line_editor.multiline_on - @line_editor.confirm_multiline_termination_proc = proc {} - input_keys("1\n2\n3") - assert_whole_lines(["1", "2", "3"]) - assert_line_index(2) - assert_line_around_cursor('3', '') - input_keys("\C-p\C-h\C-h") - assert_whole_lines(["1", "3"]) - assert_line_index(0) - assert_line_around_cursor('1', '') - input_keys("\C-_") - assert_whole_lines(["1", "", "3"]) - assert_line_index(1) - assert_line_around_cursor('', '') - input_keys("\C-_") - assert_whole_lines(["1", "2", "3"]) - assert_line_index(1) - assert_line_around_cursor('2', '') - input_keys("\C-_") - assert_whole_lines(["1", "2", ""]) - assert_line_index(2) - assert_line_around_cursor('', '') - input_keys("\C-_") - assert_whole_lines(["1", "2"]) - assert_line_index(1) - assert_line_around_cursor('2', '') - end - - def test_undo_with_many_times - str = "a" + "b" * 99 - input_keys(str) - 100.times { input_keys("\C-_") } - assert_line_around_cursor('a', '') - input_keys("\C-_") - assert_line_around_cursor('a', '') - end - - def test_redo - input_keys("aあb") - assert_line_around_cursor('aあb', '') - input_keys("\e\C-_") - assert_line_around_cursor('aあb', '') - input_keys("\C-_") - assert_line_around_cursor('aあ', '') - input_keys("\C-_") - assert_line_around_cursor('a', '') - input_keys("\e\C-_") - assert_line_around_cursor('aあ', '') - input_keys("\e\C-_") - assert_line_around_cursor('aあb', '') - input_keys("\C-_") - assert_line_around_cursor('aあ', '') - input_keys("c") - assert_line_around_cursor('aあc', '') - input_keys("\e\C-_") - assert_line_around_cursor('aあc', '') - end - - def test_redo_with_cursor_position - input_keys("abc\C-b\C-h") - assert_line_around_cursor('a', 'c') - input_keys("\e\C-_") - assert_line_around_cursor('a', 'c') - input_keys("\C-_") - assert_line_around_cursor('ab', 'c') - input_keys("\e\C-_") - assert_line_around_cursor('a', 'c') - end - - def test_redo_with_multiline - @line_editor.multiline_on - @line_editor.confirm_multiline_termination_proc = proc {} - input_keys("1\n2\n3") - assert_whole_lines(["1", "2", "3"]) - assert_line_index(2) - assert_line_around_cursor('3', '') - - input_keys("\C-_") - assert_whole_lines(["1", "2", ""]) - assert_line_index(2) - assert_line_around_cursor('', '') - - input_keys("\C-_") - assert_whole_lines(["1", "2"]) - assert_line_index(1) - assert_line_around_cursor('2', '') - - input_keys("\e\C-_") - assert_whole_lines(["1", "2", ""]) - assert_line_index(2) - assert_line_around_cursor('', '') - - input_keys("\e\C-_") - assert_whole_lines(["1", "2", "3"]) - assert_line_index(2) - assert_line_around_cursor('3', '') - - input_keys("\C-p\C-h\C-h") - assert_whole_lines(["1", "3"]) - assert_line_index(0) - assert_line_around_cursor('1', '') - - input_keys("\C-n") - assert_whole_lines(["1", "3"]) - assert_line_index(1) - assert_line_around_cursor('3', '') - - input_keys("\C-_") - assert_whole_lines(["1", "", "3"]) - assert_line_index(1) - assert_line_around_cursor('', '') - - input_keys("\C-_") - assert_whole_lines(["1", "2", "3"]) - assert_line_index(1) - assert_line_around_cursor('2', '') - - input_keys("\e\C-_") - assert_whole_lines(["1", "", "3"]) - assert_line_index(1) - assert_line_around_cursor('', '') - - input_keys("\e\C-_") - assert_whole_lines(["1", "3"]) - assert_line_index(1) - assert_line_around_cursor('3', '') - end - - def test_undo_redo_restores_indentation - @line_editor.multiline_on - @line_editor.confirm_multiline_termination_proc = proc {} - input_keys(" 1") - assert_whole_lines([' 1']) - input_keys("2") - assert_whole_lines([' 12']) - @line_editor.auto_indent_proc = proc { 2 } - input_keys("\C-_") - assert_whole_lines([' 1']) - input_keys("\e\C-_") - assert_whole_lines([' 12']) - end - - def test_redo_with_many_times - str = "a" + "b" * 98 + "c" - input_keys(str) - 100.times { input_keys("\C-_") } - assert_line_around_cursor('a', '') - input_keys("\C-_") - assert_line_around_cursor('a', '') - 100.times { input_keys("\e\C-_") } - assert_line_around_cursor(str, '') - input_keys("\e\C-_") - assert_line_around_cursor(str, '') - end -end diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb deleted file mode 100644 index 083433f9a8..0000000000 --- a/test/reline/test_key_actor_vi.rb +++ /dev/null @@ -1,967 +0,0 @@ -require_relative 'helper' - -class Reline::ViInsertTest < Reline::TestCase - def setup - Reline.send(:test_mode) - @prompt = '> ' - @config = Reline::Config.new - @config.read_lines(<<~LINES.split(/(?<=\n)/)) - set editing-mode vi - LINES - @encoding = Reline.core.encoding - @line_editor = Reline::LineEditor.new(@config) - @line_editor.reset(@prompt) - end - - def editing_mode_label - @config.instance_variable_get(:@editing_mode_label) - end - - def teardown - Reline.test_reset - end - - def test_vi_command_mode - input_keys("\C-[") - assert_equal(:vi_command, editing_mode_label) - end - - def test_vi_command_mode_with_input - input_keys("abc\C-[") - assert_equal(:vi_command, editing_mode_label) - assert_line_around_cursor('ab', 'c') - end - - def test_vi_insert - assert_equal(:vi_insert, editing_mode_label) - input_keys('i') - assert_line_around_cursor('i', '') - assert_equal(:vi_insert, editing_mode_label) - input_keys("\C-[") - assert_line_around_cursor('', 'i') - assert_equal(:vi_command, editing_mode_label) - input_keys('i') - assert_line_around_cursor('', 'i') - assert_equal(:vi_insert, editing_mode_label) - end - - def test_vi_add - assert_equal(:vi_insert, editing_mode_label) - input_keys('a') - assert_line_around_cursor('a', '') - assert_equal(:vi_insert, editing_mode_label) - input_keys("\C-[") - assert_line_around_cursor('', 'a') - assert_equal(:vi_command, editing_mode_label) - input_keys('a') - assert_line_around_cursor('a', '') - assert_equal(:vi_insert, editing_mode_label) - end - - def test_vi_insert_at_bol - input_keys('I') - assert_line_around_cursor('I', '') - assert_equal(:vi_insert, editing_mode_label) - input_keys("12345\C-[hh") - assert_line_around_cursor('I12', '345') - assert_equal(:vi_command, editing_mode_label) - input_keys('I') - assert_line_around_cursor('', 'I12345') - assert_equal(:vi_insert, editing_mode_label) - end - - def test_vi_add_at_eol - input_keys('A') - assert_line_around_cursor('A', '') - assert_equal(:vi_insert, editing_mode_label) - input_keys("12345\C-[hh") - assert_line_around_cursor('A12', '345') - assert_equal(:vi_command, editing_mode_label) - input_keys('A') - assert_line_around_cursor('A12345', '') - assert_equal(:vi_insert, editing_mode_label) - end - - def test_ed_insert_one - input_keys('a') - assert_line_around_cursor('a', '') - end - - def test_ed_insert_two - input_keys('ab') - assert_line_around_cursor('ab', '') - end - - def test_ed_insert_mbchar_one - input_keys('か') - assert_line_around_cursor('か', '') - end - - def test_ed_insert_mbchar_two - input_keys('かき') - assert_line_around_cursor('かき', '') - end - - def test_ed_insert_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099") - assert_line_around_cursor("か\u3099", '') - end - - def test_ed_insert_for_plural_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099") - assert_line_around_cursor("か\u3099き\u3099", '') - end - - def test_ed_insert_ignore_in_vi_command - input_keys("\C-[") - chars_to_be_ignored = "\C-Oあ=".chars - input_keys(chars_to_be_ignored.join) - assert_line_around_cursor('', '') - input_keys(chars_to_be_ignored.map {|c| "5#{c}" }.join) - assert_line_around_cursor('', '') - input_keys('iい') - assert_line_around_cursor("い", '') - end - - def test_ed_next_char - input_keys("abcdef\C-[0") - assert_line_around_cursor('', 'abcdef') - input_keys('l') - assert_line_around_cursor('a', 'bcdef') - input_keys('2l') - assert_line_around_cursor('abc', 'def') - end - - def test_ed_prev_char - input_keys("abcdef\C-[") - assert_line_around_cursor('abcde', 'f') - input_keys('h') - assert_line_around_cursor('abcd', 'ef') - input_keys('2h') - assert_line_around_cursor('ab', 'cdef') - end - - def test_history - Reline::HISTORY.concat(%w{abc 123 AAA}) - input_keys("\C-[") - assert_line_around_cursor('', '') - input_keys('k') - assert_line_around_cursor('', 'AAA') - input_keys('2k') - assert_line_around_cursor('', 'abc') - input_keys('j') - assert_line_around_cursor('', '123') - input_keys('2j') - assert_line_around_cursor('', '') - end - - def test_vi_paste_prev - input_keys("abcde\C-[3h") - assert_line_around_cursor('a', 'bcde') - input_keys('P') - assert_line_around_cursor('a', 'bcde') - input_keys('d$') - assert_line_around_cursor('', 'a') - input_keys('P') - assert_line_around_cursor('bcd', 'ea') - input_keys('2P') - assert_line_around_cursor('bcdbcdbcd', 'eeea') - end - - def test_vi_paste_next - input_keys("abcde\C-[3h") - assert_line_around_cursor('a', 'bcde') - input_keys('p') - assert_line_around_cursor('a', 'bcde') - input_keys('d$') - assert_line_around_cursor('', 'a') - input_keys('p') - assert_line_around_cursor('abcd', 'e') - input_keys('2p') - assert_line_around_cursor('abcdebcdebcd', 'e') - end - - def test_vi_paste_prev_for_mbchar - input_keys("あいうえお\C-[3h") - assert_line_around_cursor('あ', 'いうえお') - input_keys('P') - assert_line_around_cursor('あ', 'いうえお') - input_keys('d$') - assert_line_around_cursor('', 'あ') - input_keys('P') - assert_line_around_cursor('いうえ', 'おあ') - input_keys('2P') - assert_line_around_cursor('いうえいうえいうえ', 'おおおあ') - end - - def test_vi_paste_next_for_mbchar - input_keys("あいうえお\C-[3h") - assert_line_around_cursor('あ', 'いうえお') - input_keys('p') - assert_line_around_cursor('あ', 'いうえお') - input_keys('d$') - assert_line_around_cursor('', 'あ') - input_keys('p') - assert_line_around_cursor('あいうえ', 'お') - input_keys('2p') - assert_line_around_cursor('あいうえおいうえおいうえ', 'お') - end - - def test_vi_paste_prev_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h") - assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") - input_keys('P') - assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") - input_keys('d$') - assert_line_around_cursor('', "か\u3099") - input_keys('P') - assert_line_around_cursor("き\u3099く\u3099け\u3099", "こ\u3099か\u3099") - input_keys('2P') - assert_line_around_cursor("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099", "こ\u3099こ\u3099こ\u3099か\u3099") - end - - def test_vi_paste_next_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h") - assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") - input_keys('p') - assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") - input_keys('d$') - assert_line_around_cursor('', "か\u3099") - input_keys('p') - assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099", "こ\u3099") - input_keys('2p') - assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099", "こ\u3099") - end - - def test_vi_prev_next_word - input_keys("aaa b{b}b ccc\C-[0") - assert_line_around_cursor('', 'aaa b{b}b ccc') - input_keys('w') - assert_line_around_cursor('aaa ', 'b{b}b ccc') - input_keys('w') - assert_line_around_cursor('aaa b', '{b}b ccc') - input_keys('w') - assert_line_around_cursor('aaa b{', 'b}b ccc') - input_keys('w') - assert_line_around_cursor('aaa b{b', '}b ccc') - input_keys('w') - assert_line_around_cursor('aaa b{b}', 'b ccc') - input_keys('w') - assert_line_around_cursor('aaa b{b}b ', 'ccc') - input_keys('w') - assert_line_around_cursor('aaa b{b}b cc', 'c') - input_keys('b') - assert_line_around_cursor('aaa b{b}b ', 'ccc') - input_keys('b') - assert_line_around_cursor('aaa b{b}', 'b ccc') - input_keys('b') - assert_line_around_cursor('aaa b{b', '}b ccc') - input_keys('b') - assert_line_around_cursor('aaa b{', 'b}b ccc') - input_keys('b') - assert_line_around_cursor('aaa b', '{b}b ccc') - input_keys('b') - assert_line_around_cursor('aaa ', 'b{b}b ccc') - input_keys('b') - assert_line_around_cursor('', 'aaa b{b}b ccc') - input_keys('3w') - assert_line_around_cursor('aaa b{', 'b}b ccc') - input_keys('3w') - assert_line_around_cursor('aaa b{b}b ', 'ccc') - input_keys('3w') - assert_line_around_cursor('aaa b{b}b cc', 'c') - input_keys('3b') - assert_line_around_cursor('aaa b{b', '}b ccc') - input_keys('3b') - assert_line_around_cursor('aaa ', 'b{b}b ccc') - input_keys('3b') - assert_line_around_cursor('', 'aaa b{b}b ccc') - end - - def test_vi_end_word - input_keys("aaa b{b}}}b ccc\C-[0") - assert_line_around_cursor('', 'aaa b{b}}}b ccc') - input_keys('e') - assert_line_around_cursor('aa', 'a b{b}}}b ccc') - input_keys('e') - assert_line_around_cursor('aaa ', 'b{b}}}b ccc') - input_keys('e') - assert_line_around_cursor('aaa b', '{b}}}b ccc') - input_keys('e') - assert_line_around_cursor('aaa b{', 'b}}}b ccc') - input_keys('e') - assert_line_around_cursor('aaa b{b}}', '}b ccc') - input_keys('e') - assert_line_around_cursor('aaa b{b}}}', 'b ccc') - input_keys('e') - assert_line_around_cursor('aaa b{b}}}b cc', 'c') - input_keys('e') - assert_line_around_cursor('aaa b{b}}}b cc', 'c') - input_keys('03e') - assert_line_around_cursor('aaa b', '{b}}}b ccc') - input_keys('3e') - assert_line_around_cursor('aaa b{b}}}', 'b ccc') - input_keys('3e') - assert_line_around_cursor('aaa b{b}}}b cc', 'c') - end - - def test_vi_prev_next_big_word - input_keys("aaa b{b}b ccc\C-[0") - assert_line_around_cursor('', 'aaa b{b}b ccc') - input_keys('W') - assert_line_around_cursor('aaa ', 'b{b}b ccc') - input_keys('W') - assert_line_around_cursor('aaa b{b}b ', 'ccc') - input_keys('W') - assert_line_around_cursor('aaa b{b}b cc', 'c') - input_keys('B') - assert_line_around_cursor('aaa b{b}b ', 'ccc') - input_keys('B') - assert_line_around_cursor('aaa ', 'b{b}b ccc') - input_keys('B') - assert_line_around_cursor('', 'aaa b{b}b ccc') - input_keys('2W') - assert_line_around_cursor('aaa b{b}b ', 'ccc') - input_keys('2W') - assert_line_around_cursor('aaa b{b}b cc', 'c') - input_keys('2B') - assert_line_around_cursor('aaa ', 'b{b}b ccc') - input_keys('2B') - assert_line_around_cursor('', 'aaa b{b}b ccc') - end - - def test_vi_end_big_word - input_keys("aaa b{b}}}b ccc\C-[0") - assert_line_around_cursor('', 'aaa b{b}}}b ccc') - input_keys('E') - assert_line_around_cursor('aa', 'a b{b}}}b ccc') - input_keys('E') - assert_line_around_cursor('aaa b{b}}}', 'b ccc') - input_keys('E') - assert_line_around_cursor('aaa b{b}}}b cc', 'c') - input_keys('E') - assert_line_around_cursor('aaa b{b}}}b cc', 'c') - end - - def test_ed_quoted_insert - input_keys('ab') - input_key_by_symbol(:insert_raw_char, char: "\C-a") - assert_line_around_cursor("ab\C-a", '') - end - - def test_ed_quoted_insert_with_vi_arg - input_keys("ab\C-[3") - input_key_by_symbol(:insert_raw_char, char: "\C-a") - input_keys('4') - input_key_by_symbol(:insert_raw_char, char: '1') - assert_line_around_cursor("a\C-a\C-a\C-a1111", 'b') - end - - def test_vi_replace_char - input_keys("abcdef\C-[03l") - assert_line_around_cursor('abc', 'def') - input_keys('rz') - assert_line_around_cursor('abc', 'zef') - input_keys('2rx') - assert_line_around_cursor('abcxx', 'f') - end - - def test_vi_replace_char_with_mbchar - input_keys("あいうえお\C-[0l") - assert_line_around_cursor('あ', 'いうえお') - input_keys('rx') - assert_line_around_cursor('あ', 'xうえお') - input_keys('l2ry') - assert_line_around_cursor('あxyy', 'お') - end - - def test_vi_next_char - input_keys("abcdef\C-[0") - assert_line_around_cursor('', 'abcdef') - input_keys('fz') - assert_line_around_cursor('', 'abcdef') - input_keys('fe') - assert_line_around_cursor('abcd', 'ef') - end - - def test_vi_to_next_char - input_keys("abcdef\C-[0") - assert_line_around_cursor('', 'abcdef') - input_keys('tz') - assert_line_around_cursor('', 'abcdef') - input_keys('te') - assert_line_around_cursor('abc', 'def') - end - - def test_vi_prev_char - input_keys("abcdef\C-[") - assert_line_around_cursor('abcde', 'f') - input_keys('Fz') - assert_line_around_cursor('abcde', 'f') - input_keys('Fa') - assert_line_around_cursor('', 'abcdef') - end - - def test_vi_to_prev_char - input_keys("abcdef\C-[") - assert_line_around_cursor('abcde', 'f') - input_keys('Tz') - assert_line_around_cursor('abcde', 'f') - input_keys('Ta') - assert_line_around_cursor('a', 'bcdef') - end - - def test_vi_delete_next_char - input_keys("abc\C-[h") - assert_line_around_cursor('a', 'bc') - input_keys('x') - assert_line_around_cursor('a', 'c') - input_keys('x') - assert_line_around_cursor('', 'a') - input_keys('x') - assert_line_around_cursor('', '') - input_keys('x') - assert_line_around_cursor('', '') - end - - def test_vi_delete_next_char_for_mbchar - input_keys("あいう\C-[h") - assert_line_around_cursor('あ', 'いう') - input_keys('x') - assert_line_around_cursor('あ', 'う') - input_keys('x') - assert_line_around_cursor('', 'あ') - input_keys('x') - assert_line_around_cursor('', '') - input_keys('x') - assert_line_around_cursor('', '') - end - - def test_vi_delete_next_char_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099く\u3099\C-[h") - assert_line_around_cursor("か\u3099", "き\u3099く\u3099") - input_keys('x') - assert_line_around_cursor("か\u3099", "く\u3099") - input_keys('x') - assert_line_around_cursor('', "か\u3099") - input_keys('x') - assert_line_around_cursor('', '') - input_keys('x') - assert_line_around_cursor('', '') - end - - def test_vi_delete_prev_char - input_keys('ab') - assert_line_around_cursor('ab', '') - input_keys("\C-h") - assert_line_around_cursor('a', '') - end - - def test_vi_delete_prev_char_for_mbchar - input_keys('かき') - assert_line_around_cursor('かき', '') - input_keys("\C-h") - assert_line_around_cursor('か', '') - end - - def test_vi_delete_prev_char_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("か\u3099き\u3099") - assert_line_around_cursor("か\u3099き\u3099", '') - input_keys("\C-h") - assert_line_around_cursor("か\u3099", '') - end - - def test_ed_delete_prev_char - input_keys("abcdefg\C-[h") - assert_line_around_cursor('abcde', 'fg') - input_keys('X') - assert_line_around_cursor('abcd', 'fg') - input_keys('3X') - assert_line_around_cursor('a', 'fg') - input_keys('p') - assert_line_around_cursor('afbc', 'dg') - end - - def test_ed_delete_prev_word - input_keys('abc def{bbb}ccc') - assert_line_around_cursor('abc def{bbb}ccc', '') - input_keys("\C-w") - assert_line_around_cursor('abc def{bbb}', '') - input_keys("\C-w") - assert_line_around_cursor('abc def{', '') - input_keys("\C-w") - assert_line_around_cursor('abc ', '') - input_keys("\C-w") - assert_line_around_cursor('', '') - end - - def test_ed_delete_prev_word_for_mbchar - input_keys('あいう かきく{さしす}たちつ') - assert_line_around_cursor('あいう かきく{さしす}たちつ', '') - input_keys("\C-w") - assert_line_around_cursor('あいう かきく{さしす}', '') - input_keys("\C-w") - assert_line_around_cursor('あいう かきく{', '') - input_keys("\C-w") - assert_line_around_cursor('あいう ', '') - input_keys("\C-w") - assert_line_around_cursor('', '') - end - - def test_ed_delete_prev_word_for_mbchar_by_plural_code_points - omit_unless_utf8 - input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '') - input_keys("\C-w") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '') - input_keys("\C-w") - assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '') - input_keys("\C-w") - assert_line_around_cursor('あいう ', '') - input_keys("\C-w") - assert_line_around_cursor('', '') - end - - def test_ed_newline_with_cr - input_keys('ab') - assert_line_around_cursor('ab', '') - refute(@line_editor.finished?) - input_keys("\C-m") - assert_line_around_cursor('ab', '') - assert(@line_editor.finished?) - end - - def test_ed_newline_with_lf - input_keys('ab') - assert_line_around_cursor('ab', '') - refute(@line_editor.finished?) - input_keys("\C-j") - assert_line_around_cursor('ab', '') - assert(@line_editor.finished?) - end - - def test_vi_list_or_eof - input_keys("\C-d") # quit from inputing - assert_nil(@line_editor.line) - assert(@line_editor.finished?) - end - - def test_vi_list_or_eof_with_non_empty_line - input_keys('ab') - assert_line_around_cursor('ab', '') - refute(@line_editor.finished?) - input_keys("\C-d") - assert_line_around_cursor('ab', '') - assert(@line_editor.finished?) - end - - def test_completion_journey - @line_editor.completion_proc = proc { |word| - %w{ - foo_bar - foo_bar_baz - }.map { |i| - i.encode(@encoding) - } - } - input_keys('foo') - assert_line_around_cursor('foo', '') - input_keys("\C-n") - assert_line_around_cursor('foo_bar', '') - input_keys("\C-n") - assert_line_around_cursor('foo_bar_baz', '') - input_keys("\C-n") - assert_line_around_cursor('foo', '') - input_keys("\C-n") - assert_line_around_cursor('foo_bar', '') - input_keys("_\C-n") - assert_line_around_cursor('foo_bar_baz', '') - input_keys("\C-n") - assert_line_around_cursor('foo_bar_', '') - end - - def test_completion_journey_reverse - @line_editor.completion_proc = proc { |word| - %w{ - foo_bar - foo_bar_baz - }.map { |i| - i.encode(@encoding) - } - } - input_keys('foo') - assert_line_around_cursor('foo', '') - input_keys("\C-p") - assert_line_around_cursor('foo_bar_baz', '') - input_keys("\C-p") - assert_line_around_cursor('foo_bar', '') - input_keys("\C-p") - assert_line_around_cursor('foo', '') - input_keys("\C-p") - assert_line_around_cursor('foo_bar_baz', '') - input_keys("\C-h\C-p") - assert_line_around_cursor('foo_bar_baz', '') - input_keys("\C-p") - assert_line_around_cursor('foo_bar_ba', '') - end - - def test_completion_journey_in_middle_of_line - @line_editor.completion_proc = proc { |word| - %w{ - foo_bar - foo_bar_baz - }.map { |i| - i.encode(@encoding) - } - } - input_keys('abcde fo ABCDE') - assert_line_around_cursor('abcde fo ABCDE', '') - input_keys("\C-[" + 'h' * 5 + "i\C-n") - assert_line_around_cursor('abcde foo_bar', ' ABCDE') - input_keys("\C-n") - assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') - input_keys("\C-n") - assert_line_around_cursor('abcde fo', ' ABCDE') - input_keys("\C-n") - assert_line_around_cursor('abcde foo_bar', ' ABCDE') - input_keys("_\C-n") - assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') - input_keys("\C-n") - assert_line_around_cursor('abcde foo_bar_', ' ABCDE') - input_keys("\C-n") - assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') - end - - def test_completion - @line_editor.completion_proc = proc { |word| - %w{ - foo_bar - foo_bar_baz - }.map { |i| - i.encode(@encoding) - } - } - input_keys('foo') - assert_line_around_cursor('foo', '') - input_keys("\C-i") - assert_line_around_cursor('foo_bar', '') - end - - def test_autocompletion_with_upward_navigation - @config.autocompletion = true - @line_editor.completion_proc = proc { |word| - %w{ - Readline - Regexp - RegexpError - }.map { |i| - i.encode(@encoding) - } - } - input_keys('Re') - assert_line_around_cursor('Re', '') - input_keys("\C-i") - assert_line_around_cursor('Readline', '') - input_keys("\C-i") - assert_line_around_cursor('Regexp', '') - input_key_by_symbol(:completion_journey_up) - assert_line_around_cursor('Readline', '') - ensure - @config.autocompletion = false - end - - def test_autocompletion_with_upward_navigation_and_menu_complete_backward - @config.autocompletion = true - @line_editor.completion_proc = proc { |word| - %w{ - Readline - Regexp - RegexpError - }.map { |i| - i.encode(@encoding) - } - } - input_keys('Re') - assert_line_around_cursor('Re', '') - input_keys("\C-i") - assert_line_around_cursor('Readline', '') - input_keys("\C-i") - assert_line_around_cursor('Regexp', '') - input_key_by_symbol(:menu_complete_backward) - assert_line_around_cursor('Readline', '') - ensure - @config.autocompletion = false - end - - def test_completion_with_disable_completion - @config.disable_completion = true - @line_editor.completion_proc = proc { |word| - %w{ - foo_bar - foo_bar_baz - }.map { |i| - i.encode(@encoding) - } - } - input_keys('foo') - assert_line_around_cursor('foo', '') - input_keys("\C-i") - assert_line_around_cursor('foo', '') - end - - def test_vi_first_print - input_keys("abcde\C-[^") - assert_line_around_cursor('', 'abcde') - input_keys("0\C-ki") - input_keys(" abcde\C-[^") - assert_line_around_cursor(' ', 'abcde') - input_keys("0\C-ki") - input_keys(" abcde ABCDE \C-[^") - assert_line_around_cursor(' ', 'abcde ABCDE ') - end - - def test_ed_move_to_beg - input_keys("abcde\C-[0") - assert_line_around_cursor('', 'abcde') - input_keys("0\C-ki") - input_keys(" abcde\C-[0") - assert_line_around_cursor('', ' abcde') - input_keys("0\C-ki") - input_keys(" abcde ABCDE \C-[0") - assert_line_around_cursor('', ' abcde ABCDE ') - end - - def test_vi_to_column - input_keys("a一二三\C-[0") - input_keys('1|') - assert_line_around_cursor('', 'a一二三') - input_keys('2|') - assert_line_around_cursor('a', '一二三') - input_keys('3|') - assert_line_around_cursor('a', '一二三') - input_keys('4|') - assert_line_around_cursor('a一', '二三') - input_keys('9|') - assert_line_around_cursor('a一二', '三') - end - - def test_vi_delete_meta - input_keys("aaa bbb ccc ddd eee\C-[02w") - assert_line_around_cursor('aaa bbb ', 'ccc ddd eee') - input_keys('dw') - assert_line_around_cursor('aaa bbb ', 'ddd eee') - input_keys('db') - assert_line_around_cursor('aaa ', 'ddd eee') - end - - def test_vi_delete_meta_nothing - input_keys("foo\C-[0") - assert_line_around_cursor('', 'foo') - input_keys('dhp') - assert_line_around_cursor('', 'foo') - end - - def test_vi_delete_meta_with_vi_next_word_at_eol - input_keys("foo bar\C-[0w") - assert_line_around_cursor('foo ', 'bar') - input_keys('w') - assert_line_around_cursor('foo ba', 'r') - input_keys('0dw') - assert_line_around_cursor('', 'bar') - input_keys('dw') - assert_line_around_cursor('', '') - end - - def test_vi_delete_meta_with_vi_next_char - input_keys("aaa bbb ccc ___ ddd\C-[02w") - assert_line_around_cursor('aaa bbb ', 'ccc ___ ddd') - input_keys('df_') - assert_line_around_cursor('aaa bbb ', '__ ddd') - end - - def test_vi_delete_meta_with_arg - input_keys("aaa bbb ccc ddd\C-[03w") - assert_line_around_cursor('aaa bbb ccc ', 'ddd') - input_keys('2dl') - assert_line_around_cursor('aaa bbb ccc ', 'd') - input_keys('d2h') - assert_line_around_cursor('aaa bbb cc', 'd') - input_keys('2d3h') - assert_line_around_cursor('aaa ', 'd') - input_keys('dd') - assert_line_around_cursor('', '') - end - - def test_vi_change_meta - input_keys("aaa bbb ccc ddd eee\C-[02w") - assert_line_around_cursor('aaa bbb ', 'ccc ddd eee') - input_keys('cwaiueo') - assert_line_around_cursor('aaa bbb aiueo', ' ddd eee') - input_keys("\C-[") - assert_line_around_cursor('aaa bbb aiue', 'o ddd eee') - input_keys('cb') - assert_line_around_cursor('aaa bbb ', 'o ddd eee') - end - - def test_vi_change_meta_with_vi_next_word - input_keys("foo bar baz\C-[0w") - assert_line_around_cursor('foo ', 'bar baz') - input_keys('cwhoge') - assert_line_around_cursor('foo hoge', ' baz') - input_keys("\C-[") - assert_line_around_cursor('foo hog', 'e baz') - end - - def test_vi_waiting_operator_with_waiting_proc - input_keys("foo foo foo foo foo\C-[0") - input_keys('2d3fo') - assert_line_around_cursor('', ' foo foo') - input_keys('fo') - assert_line_around_cursor(' f', 'oo foo') - end - - def test_waiting_operator_arg_including_zero - input_keys("a111111111111222222222222\C-[0") - input_keys('10df1') - assert_line_around_cursor('', '11222222222222') - input_keys('d10f2') - assert_line_around_cursor('', '22') - end - - def test_vi_waiting_operator_cancel - input_keys("aaa bbb ccc\C-[02w") - assert_line_around_cursor('aaa bbb ', 'ccc') - # dc dy should cancel delete_meta - input_keys('dch') - input_keys('dyh') - # cd cy should cancel change_meta - input_keys('cdh') - input_keys('cyh') - # yd yc should cancel yank_meta - # P should not paste yanked text because yank_meta is canceled - input_keys('ydhP') - input_keys('ychP') - assert_line_around_cursor('aa', 'a bbb ccc') - end - - def test_cancel_waiting_with_symbol_key - input_keys("aaa bbb lll\C-[0") - assert_line_around_cursor('', 'aaa bbb lll') - # ed_next_char should move cursor right and cancel vi_next_char - input_keys('f') - input_key_by_symbol(:ed_next_char, csi: true) - input_keys('l') - assert_line_around_cursor('aa', 'a bbb lll') - # vi_delete_meta + ed_next_char should delete character - input_keys('d') - input_key_by_symbol(:ed_next_char, csi: true) - input_keys('l') - assert_line_around_cursor('aa ', 'bbb lll') - end - - def test_unimplemented_vi_command_should_be_no_op - input_keys("abc\C-[h") - assert_line_around_cursor('a', 'bc') - input_keys('@') - assert_line_around_cursor('a', 'bc') - end - - def test_vi_yank - input_keys("foo bar\C-[2h") - assert_line_around_cursor('foo ', 'bar') - input_keys('y3l') - assert_line_around_cursor('foo ', 'bar') - input_keys('P') - assert_line_around_cursor('foo ba', 'rbar') - input_keys('3h3yhP') - assert_line_around_cursor('foofo', 'o barbar') - input_keys('yyP') - assert_line_around_cursor('foofofoofoo barba', 'ro barbar') - end - - def test_vi_yank_nothing - input_keys("foo\C-[0") - assert_line_around_cursor('', 'foo') - input_keys('yhp') - assert_line_around_cursor('', 'foo') - end - - def test_vi_end_word_with_operator - input_keys("foo bar\C-[0") - assert_line_around_cursor('', 'foo bar') - input_keys('de') - assert_line_around_cursor('', ' bar') - input_keys('de') - assert_line_around_cursor('', '') - input_keys('de') - assert_line_around_cursor('', '') - end - - def test_vi_end_big_word_with_operator - input_keys("aaa b{b}}}b\C-[0") - assert_line_around_cursor('', 'aaa b{b}}}b') - input_keys('dE') - assert_line_around_cursor('', ' b{b}}}b') - input_keys('dE') - assert_line_around_cursor('', '') - input_keys('dE') - assert_line_around_cursor('', '') - end - - def test_vi_next_char_with_operator - input_keys("foo bar\C-[0") - assert_line_around_cursor('', 'foo bar') - input_keys('df ') - assert_line_around_cursor('', 'bar') - end - - def test_ed_delete_next_char_at_eol - input_keys('"あ"') - assert_line_around_cursor('"あ"', '') - input_keys("\C-[") - assert_line_around_cursor('"あ', '"') - input_keys('xa"') - assert_line_around_cursor('"あ"', '') - end - - def test_vi_kill_line_prev - input_keys("\C-u") - assert_line_around_cursor('', '') - input_keys('abc') - assert_line_around_cursor('abc', '') - input_keys("\C-u") - assert_line_around_cursor('', '') - input_keys('abc') - input_keys("\C-[\C-u") - assert_line_around_cursor('', 'c') - input_keys("\C-u") - assert_line_around_cursor('', 'c') - end - - def test_vi_change_to_eol - input_keys("abcdef\C-[2hC") - assert_line_around_cursor('abc', '') - input_keys("\C-[0C") - assert_line_around_cursor('', '') - assert_equal(:vi_insert, editing_mode_label) - end - - def test_vi_motion_operators - assert_equal(:vi_insert, editing_mode_label) - - assert_nothing_raised do - input_keys("test = { foo: bar }\C-[BBBldt}b") - end - end - - def test_emacs_editing_mode - @line_editor.__send__(:emacs_editing_mode, nil) - assert(@config.editing_mode_is?(:emacs)) - end -end diff --git a/test/reline/test_key_stroke.rb b/test/reline/test_key_stroke.rb deleted file mode 100644 index fb2cb1c8b8..0000000000 --- a/test/reline/test_key_stroke.rb +++ /dev/null @@ -1,111 +0,0 @@ -require_relative 'helper' - -class Reline::KeyStroke::Test < Reline::TestCase - def encoding - Reline.core.encoding - end - - def test_match_status - config = Reline::Config.new - { - 'a' => 'xx', - 'ab' => 'y', - 'abc' => 'z', - 'x' => 'rr' - }.each_pair do |key, func| - config.add_default_key_binding(key.bytes, func.bytes) - end - stroke = Reline::KeyStroke.new(config, encoding) - assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status("a".bytes)) - assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status("ab".bytes)) - assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("abc".bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("abz".bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("abcx".bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("aa".bytes)) - assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("x".bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("xa".bytes)) - end - - def test_match_unknown - config = Reline::Config.new - config.add_default_key_binding("\e[9abc".bytes, 'x') - stroke = Reline::KeyStroke.new(config, encoding) - sequences = [ - "\e[9abc", - "\e[9d", - "\e[A", # Up - "\e[1;1R", # Cursor position report - "\e[15~", # F5 - "\eOP", # F1 - "\e\e[A", # Option+Up - "\eX", - "\e\eX" - ] - sequences.each do |seq| - assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status(seq.bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status(seq.bytes + [32])) - (2...seq.size).each do |i| - assert_equal(Reline::KeyStroke::MATCHING, stroke.match_status(seq.bytes.take(i))) - end - end - end - - def test_expand - config = Reline::Config.new - { - 'abc' => 'AB', - 'ab' => "1\C-a" - }.each_pair do |key, func| - config.add_default_key_binding(key.bytes, func.bytes) - end - stroke = Reline::KeyStroke.new(config, encoding) - assert_equal([[Reline::Key.new('A', :ed_insert, false), Reline::Key.new('B', :ed_insert, false)], 'de'.bytes], stroke.expand('abcde'.bytes)) - assert_equal([[Reline::Key.new('1', :ed_digit, false), Reline::Key.new("\C-a", :ed_move_to_beg, false)], 'de'.bytes], stroke.expand('abde'.bytes)) - # CSI sequence - assert_equal([[], 'bc'.bytes], stroke.expand("\e[1;2;3;4;5abc".bytes)) - assert_equal([[], 'BC'.bytes], stroke.expand("\e\e[ABC".bytes)) - # SS3 sequence - assert_equal([[], 'QR'.bytes], stroke.expand("\eOPQR".bytes)) - end - - def test_oneshot_key_bindings - config = Reline::Config.new - { - 'abc'.bytes => '123', - # IRB version <= 1.13.1 wrongly uses Reline::Key with wrong argument. It should be ignored without error. - [Reline::Key.new(nil, 0xE4, true)] => '012', - "\eda".bytes => 'abc', # Alt+d a - [195, 164] => 'def' - }.each_pair do |key, func| - config.add_oneshot_key_binding(key, func.bytes) - end - stroke = Reline::KeyStroke.new(config, encoding) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status('zzz'.bytes)) - assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status('abc'.bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status('da'.bytes)) - assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("\eda".bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status(" \eda".bytes)) - assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status([195, 164])) - end - - def test_multibyte_matching - begin - char = 'あ'.encode(encoding) - rescue Encoding::UndefinedConversionError - omit - end - config = Reline::Config.new - stroke = Reline::KeyStroke.new(config, encoding) - key = Reline::Key.new(char, :ed_insert, false) - bytes = char.bytes - assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status(bytes)) - assert_equal([[key], []], stroke.expand(bytes)) - assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status(bytes * 2)) - assert_equal([[key], bytes], stroke.expand(bytes * 2)) - (1...bytes.size).each do |i| - partial_bytes = bytes.take(i) - assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status(partial_bytes)) - assert_equal([[], []], stroke.expand(partial_bytes)) - end - end -end diff --git a/test/reline/test_kill_ring.rb b/test/reline/test_kill_ring.rb deleted file mode 100644 index 9f6e0c3e74..0000000000 --- a/test/reline/test_kill_ring.rb +++ /dev/null @@ -1,268 +0,0 @@ -require_relative 'helper' - -class Reline::KillRing::Test < Reline::TestCase - def setup - @prompt = '> ' - @kill_ring = Reline::KillRing.new - end - - def test_append_one - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('a', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('a', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['a', 'a'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['a', 'a'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_two - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('b', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('b', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['a', 'b'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['b', 'a'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_three - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('c') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('c', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('c', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['b', 'c'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['a', 'b'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['c', 'a'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_three_with_max_two - @kill_ring = Reline::KillRing.new(2) - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('c') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('c', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('c', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['b', 'c'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['c', 'b'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['b', 'c'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_four_with_max_two - @kill_ring = Reline::KillRing.new(2) - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('c') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('d') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('d', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('d', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['c', 'd'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['d', 'c'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['c', 'd'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_after - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('ab', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('ab', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['ab', 'ab'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['ab', 'ab'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_before - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b', true) - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('ba', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('ba', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['ba', 'ba'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['ba', 'ba'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_chain_two - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('c') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('d') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('cd', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('cd', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['ab', 'cd'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['cd', 'ab'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_append_complex_chain - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('c') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('d') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('b', true) - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('e') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('a', true) - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::FRESH, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('A') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.append('B') - assert_equal(Reline::KillRing::State::CONTINUED, @kill_ring.instance_variable_get(:@state)) - @kill_ring.process - assert_equal(Reline::KillRing::State::PROCESSED, @kill_ring.instance_variable_get(:@state)) - assert_equal('AB', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal('AB', @kill_ring.yank) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['abcde', 'AB'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - assert_equal(['AB', 'abcde'], @kill_ring.yank_pop) - assert_equal(Reline::KillRing::State::YANK, @kill_ring.instance_variable_get(:@state)) - end - - def test_enumerable - @kill_ring.append('a') - @kill_ring.process - @kill_ring.process - @kill_ring.append('b') - @kill_ring.process - @kill_ring.process - @kill_ring.append('c') - @kill_ring.process - assert_equal(%w{c b a}, @kill_ring.to_a) - end -end diff --git a/test/reline/test_line_editor.rb b/test/reline/test_line_editor.rb deleted file mode 100644 index 28fcbfa6df..0000000000 --- a/test/reline/test_line_editor.rb +++ /dev/null @@ -1,271 +0,0 @@ -require_relative 'helper' -require 'reline/line_editor' -require 'stringio' - -class Reline::LineEditor - - class CompletionBlockTest < Reline::TestCase - def setup - @original_quote_characters = Reline.completer_quote_characters - @original_word_break_characters = Reline.completer_word_break_characters - @line_editor = Reline::LineEditor.new(nil) - end - - def retrieve_completion_block(lines, line_index, byte_pointer) - @line_editor.instance_variable_set(:@buffer_of_lines, lines) - @line_editor.instance_variable_set(:@line_index, line_index) - @line_editor.instance_variable_set(:@byte_pointer, byte_pointer) - @line_editor.retrieve_completion_block - end - - def retrieve_completion_quote(line) - _, _, _, quote = retrieve_completion_block([line], 0, line.bytesize) - quote - end - - def teardown - Reline.completer_quote_characters = @original_quote_characters - Reline.completer_word_break_characters = @original_word_break_characters - end - - def test_retrieve_completion_block - Reline.completer_word_break_characters = ' ([{' - Reline.completer_quote_characters = '' - assert_equal(['', '', 'foo', nil], retrieve_completion_block(['foo'], 0, 0)) - assert_equal(['', 'f', 'oo', nil], retrieve_completion_block(['foo'], 0, 1)) - assert_equal(['foo ', 'ba', 'r baz', nil], retrieve_completion_block(['foo bar baz'], 0, 6)) - assert_equal(['foo([', 'b', 'ar])baz', nil], retrieve_completion_block(['foo([bar])baz'], 0, 6)) - assert_equal(['foo([{', '', '}])baz', nil], retrieve_completion_block(['foo([{}])baz'], 0, 6)) - assert_equal(["abc\nfoo ", 'ba', "r baz\ndef", nil], retrieve_completion_block(['abc', 'foo bar baz', 'def'], 1, 6)) - end - - def test_retrieve_completion_block_with_quote_characters - Reline.completer_word_break_characters = ' ([{' - Reline.completer_quote_characters = '' - assert_equal(['"" ', '"wo', 'rd', nil], retrieve_completion_block(['"" "word'], 0, 6)) - Reline.completer_quote_characters = '"' - assert_equal(['"" "', 'wo', 'rd', nil], retrieve_completion_block(['"" "word'], 0, 6)) - end - - def test_retrieve_completion_quote - Reline.completer_quote_characters = '"\'' - assert_equal('"', retrieve_completion_quote('"\'')) - assert_equal(nil, retrieve_completion_quote('""')) - assert_equal("'", retrieve_completion_quote('""\'"')) - assert_equal(nil, retrieve_completion_quote('""\'\'')) - assert_equal('"', retrieve_completion_quote('"\\"')) - assert_equal(nil, retrieve_completion_quote('"\\""')) - assert_equal(nil, retrieve_completion_quote('"\\\\"')) - end - end - - class CursorPositionTest < Reline::TestCase - def setup - @line_editor = Reline::LineEditor.new(nil) - @line_editor.instance_variable_set(:@config, Reline::Config.new) - end - - def test_cursor_position_with_escaped_input - @line_editor.instance_variable_set(:@screen_size, [4, 16]) - @line_editor.instance_variable_set(:@prompt, "\e[1mprompt\e[0m> ") - @line_editor.instance_variable_set(:@buffer_of_lines, ["\e[1m\0\1\2\3\4\5\6\7abcd"]) - @line_editor.instance_variable_set(:@line_index, 0) - # prompt> ^[[1m^@^ - # A^B^C^D^E^F^Gabc - # d - @line_editor.instance_variable_set(:@byte_pointer, 0) - assert_equal [8, 0], @line_editor.wrapped_cursor_position - @line_editor.instance_variable_set(:@byte_pointer, 5) - assert_equal [15, 0], @line_editor.wrapped_cursor_position - @line_editor.instance_variable_set(:@byte_pointer, 6) - assert_equal [1, 1], @line_editor.wrapped_cursor_position - @line_editor.instance_variable_set(:@byte_pointer, 14) - assert_equal [15, 1], @line_editor.wrapped_cursor_position - @line_editor.instance_variable_set(:@byte_pointer, 15) - assert_equal [0, 2], @line_editor.wrapped_cursor_position - @line_editor.instance_variable_set(:@byte_pointer, 16) - assert_equal [1, 2], @line_editor.wrapped_cursor_position - end - end - - class RenderLineDifferentialTest < Reline::TestCase - class TestIO < Reline::IO - def write(string) - @output << string - end - - def move_cursor_column(col) - @output << "[COL_#{col}]" - end - - def erase_after_cursor - @output << '[ERASE]' - end - end - - def setup - verbose, $VERBOSE = $VERBOSE, nil - @line_editor = Reline::LineEditor.new(nil) - @original_iogate = Reline::IOGate - @output = StringIO.new - @line_editor.instance_variable_set(:@screen_size, [24, 80]) - Reline.send(:remove_const, :IOGate) - Reline.const_set(:IOGate, TestIO.new) - Reline::IOGate.instance_variable_set(:@output, @output) - ensure - $VERBOSE = verbose - end - - def assert_output(expected) - @output.reopen(+'') - yield - actual = @output.string - assert_equal(expected, actual.gsub("\e[0m", '')) - end - - def teardown - Reline.send(:remove_const, :IOGate) - Reline.const_set(:IOGate, @original_iogate) - end - - def test_line_increase_decrease - assert_output '[COL_0]bb' do - @line_editor.render_line_differential([[0, 1, 'a']], [[0, 2, 'bb']]) - end - - assert_output '[COL_0]b[COL_1][ERASE]' do - @line_editor.render_line_differential([[0, 2, 'aa']], [[0, 1, 'b']]) - end - end - - def test_dialog_appear_disappear - assert_output '[COL_3]dialog' do - @line_editor.render_line_differential([[0, 1, 'a']], [[0, 1, 'a'], [3, 6, 'dialog']]) - end - - assert_output '[COL_3]dialog' do - @line_editor.render_line_differential([[0, 10, 'a' * 10]], [[0, 10, 'a' * 10], [3, 6, 'dialog']]) - end - - assert_output '[COL_1][ERASE]' do - @line_editor.render_line_differential([[0, 1, 'a'], [3, 6, 'dialog']], [[0, 1, 'a']]) - end - - assert_output '[COL_3]aaaaaa' do - @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10]]) - end - end - - def test_dialog_change - assert_output '[COL_3]DIALOG' do - @line_editor.render_line_differential([[0, 2, 'a'], [3, 6, 'dialog']], [[0, 2, 'a'], [3, 6, 'DIALOG']]) - end - - assert_output '[COL_3]DIALOG' do - @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10], [3, 6, 'DIALOG']]) - end - end - - def test_update_under_dialog - assert_output '[COL_0]b[COL_1] ' do - @line_editor.render_line_differential([[0, 2, 'aa'], [4, 6, 'dialog']], [[0, 1, 'b'], [4, 6, 'dialog']]) - end - - assert_output '[COL_0]bbb[COL_9]b' do - @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'b' * 10], [3, 6, 'dialog']]) - end - - assert_output '[COL_0]b[COL_1] [COL_9][ERASE]' do - @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 1, 'b'], [3, 6, 'dialog']]) - end - end - - def test_dialog_move - assert_output '[COL_3]dialog[COL_9][ERASE]' do - @line_editor.render_line_differential([[0, 1, 'a'], [4, 6, 'dialog']], [[0, 1, 'a'], [3, 6, 'dialog']]) - end - - assert_output '[COL_4] [COL_5]dialog' do - @line_editor.render_line_differential([[0, 1, 'a'], [4, 6, 'dialog']], [[0, 1, 'a'], [5, 6, 'dialog']]) - end - - assert_output '[COL_2]dialog[COL_8]a' do - @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10], [2, 6, 'dialog']]) - end - - assert_output '[COL_2]a[COL_3]dialog' do - @line_editor.render_line_differential([[0, 10, 'a' * 10], [2, 6, 'dialog']], [[0, 10, 'a' * 10], [3, 6, 'dialog']]) - end - end - - def test_multibyte - base = [0, 12, '一二三一二三'] - left = [0, 3, 'LLL'] - right = [9, 3, 'RRR'] - front = [3, 6, 'FFFFFF'] - # 一 FFFFFF 三 - # 一二三一二三 - assert_output '[COL_2]二三一二' do - @line_editor.render_line_differential([base, front], [base, nil]) - end - - # LLLFFFFFF 三 - # LLL 三一二三 - assert_output '[COL_3] 三一二' do - @line_editor.render_line_differential([base, left, front], [base, left, nil]) - end - - # 一 FFFFFFRRR - # 一二三一 RRR - assert_output '[COL_2]二三一 ' do - @line_editor.render_line_differential([base, right, front], [base, right, nil]) - end - - # LLLFFFFFFRRR - # LLL 三一 RRR - assert_output '[COL_3] 三一 ' do - @line_editor.render_line_differential([base, left, right, front], [base, left, right, nil]) - end - end - - def test_complicated - state_a = [nil, [19, 7, 'bbbbbbb'], [15, 8, 'cccccccc'], [10, 5, 'ddddd'], [18, 4, 'eeee'], [1, 3, 'fff'], [17, 2, 'gg'], [7, 1, 'h']] - state_b = [[5, 9, 'aaaaaaaaa'], nil, [15, 8, 'cccccccc'], nil, [18, 4, 'EEEE'], [25, 4, 'ffff'], [17, 2, 'gg'], [2, 2, 'hh']] - # state_a: " fff h dddddccggeeecbbb" - # state_b: " hh aaaaaaaaa ccggEEEc ffff" - - assert_output '[COL_1] [COL_2]hh[COL_5]aaaaaaaaa[COL_14] [COL_19]EEE[COL_23] [COL_25]ffff' do - @line_editor.render_line_differential(state_a, state_b) - end - - assert_output '[COL_1]fff[COL_5] [COL_7]h[COL_8] [COL_10]ddddd[COL_19]eee[COL_23]bbb[COL_26][ERASE]' do - @line_editor.render_line_differential(state_b, state_a) - end - end - end - - def test_menu_info_format - list = %w[aa b c d e f g hhh i j k] - col3 = [ - 'aa e i', - 'b f j', - 'c g k', - 'd hhh' - ] - col2 = [ - 'aa g', - 'b hhh', - 'c i', - 'd j', - 'e k', - 'f' - ] - assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(19)) - assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(15)) - assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(14)) - assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(10)) - assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(9)) - assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(0)) - assert_equal([], Reline::LineEditor::MenuInfo.new([]).lines(10)) - end -end diff --git a/test/reline/test_macro.rb b/test/reline/test_macro.rb deleted file mode 100644 index cacdb76c60..0000000000 --- a/test/reline/test_macro.rb +++ /dev/null @@ -1,40 +0,0 @@ -require_relative 'helper' - -class Reline::MacroTest < Reline::TestCase - def setup - Reline.send(:test_mode) - @config = Reline::Config.new - @encoding = Reline.core.encoding - @line_editor = Reline::LineEditor.new(@config) - @output = Reline::IOGate.output = File.open(IO::NULL, "w") - end - - def teardown - @output.close - Reline.test_reset - end - - def input_key(char, method_symbol = :ed_insert) - @line_editor.input_key(Reline::Key.new(char, method_symbol, false)) - end - - def input(str) - str.each_char {|c| input_key(c)} - end - - def test_simple_input - input('abc') - assert_equal 'abc', @line_editor.line - end - - def test_alias - class << @line_editor - alias delete_char ed_delete_prev_char - end - input('abc') - assert_nothing_raised(ArgumentError) { - input_key('x', :delete_char) - } - assert_equal 'ab', @line_editor.line - end -end diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb deleted file mode 100644 index 691ed9ffda..0000000000 --- a/test/reline/test_reline.rb +++ /dev/null @@ -1,487 +0,0 @@ -require_relative 'helper' -require 'reline' -require 'stringio' -begin - require "pty" -rescue LoadError # some platforms don't support PTY -end - -class Reline::Test < Reline::TestCase - class DummyCallbackObject - def call; end - end - - def setup - Reline.send(:test_mode) - Reline.output_modifier_proc = nil - Reline.completion_proc = nil - Reline.prompt_proc = nil - Reline.auto_indent_proc = nil - Reline.pre_input_hook = nil - Reline.dig_perfect_match_proc = nil - end - - def teardown - Reline.test_reset - end - - def test_completion_append_character - completion_append_character = Reline.completion_append_character - - assert_equal(nil, Reline.completion_append_character) - - Reline.completion_append_character = "" - assert_equal(nil, Reline.completion_append_character) - - Reline.completion_append_character = "a".encode(Encoding::ASCII) - assert_equal("a", Reline.completion_append_character) - assert_equal(get_reline_encoding, Reline.completion_append_character.encoding) - - Reline.completion_append_character = "ba".encode(Encoding::ASCII) - assert_equal("b", Reline.completion_append_character) - assert_equal(get_reline_encoding, Reline.completion_append_character.encoding) - - Reline.completion_append_character = "cba".encode(Encoding::ASCII) - assert_equal("c", Reline.completion_append_character) - assert_equal(get_reline_encoding, Reline.completion_append_character.encoding) - - Reline.completion_append_character = nil - assert_equal(nil, Reline.completion_append_character) - ensure - Reline.completion_append_character = completion_append_character - end - - def test_basic_word_break_characters - basic_word_break_characters = Reline.basic_word_break_characters - - assert_equal(" \t\n`><=;|&{(", Reline.basic_word_break_characters) - - Reline.basic_word_break_characters = "[".encode(Encoding::ASCII) - assert_equal("[", Reline.basic_word_break_characters) - assert_equal(get_reline_encoding, Reline.basic_word_break_characters.encoding) - ensure - Reline.basic_word_break_characters = basic_word_break_characters - end - - def test_completer_word_break_characters - completer_word_break_characters = Reline.completer_word_break_characters - - assert_equal(" \t\n`><=;|&{(", Reline.completer_word_break_characters) - - Reline.completer_word_break_characters = "[".encode(Encoding::ASCII) - assert_equal("[", Reline.completer_word_break_characters) - assert_equal(get_reline_encoding, Reline.completer_word_break_characters.encoding) - - assert_nothing_raised { Reline.completer_word_break_characters = '' } - ensure - Reline.completer_word_break_characters = completer_word_break_characters - end - - def test_basic_quote_characters - basic_quote_characters = Reline.basic_quote_characters - - assert_equal('"\'', Reline.basic_quote_characters) - - Reline.basic_quote_characters = "`".encode(Encoding::ASCII) - assert_equal("`", Reline.basic_quote_characters) - assert_equal(get_reline_encoding, Reline.basic_quote_characters.encoding) - ensure - Reline.basic_quote_characters = basic_quote_characters - end - - def test_completer_quote_characters - completer_quote_characters = Reline.completer_quote_characters - - assert_equal('"\'', Reline.completer_quote_characters) - - Reline.completer_quote_characters = "`".encode(Encoding::ASCII) - assert_equal("`", Reline.completer_quote_characters) - assert_equal(get_reline_encoding, Reline.completer_quote_characters.encoding) - - assert_nothing_raised { Reline.completer_quote_characters = '' } - ensure - Reline.completer_quote_characters = completer_quote_characters - end - - def test_filename_quote_characters - filename_quote_characters = Reline.filename_quote_characters - - assert_equal('', Reline.filename_quote_characters) - - Reline.filename_quote_characters = "\'".encode(Encoding::ASCII) - assert_equal("\'", Reline.filename_quote_characters) - assert_equal(get_reline_encoding, Reline.filename_quote_characters.encoding) - ensure - Reline.filename_quote_characters = filename_quote_characters - end - - def test_special_prefixes - special_prefixes = Reline.special_prefixes - - assert_equal('', Reline.special_prefixes) - - Reline.special_prefixes = "\'".encode(Encoding::ASCII) - assert_equal("\'", Reline.special_prefixes) - assert_equal(get_reline_encoding, Reline.special_prefixes.encoding) - ensure - Reline.special_prefixes = special_prefixes - end - - def test_completion_case_fold - completion_case_fold = Reline.completion_case_fold - - assert_equal(nil, Reline.completion_case_fold) - - Reline.completion_case_fold = true - assert_equal(true, Reline.completion_case_fold) - - Reline.completion_case_fold = "hoge".encode(Encoding::ASCII) - assert_equal("hoge", Reline.completion_case_fold) - ensure - Reline.completion_case_fold = completion_case_fold - end - - def test_completion_proc - omit unless Reline.completion_proc == nil - # Another test can set Reline.completion_proc - - # assert_equal(nil, Reline.completion_proc) - - dummy_proc = proc {} - Reline.completion_proc = dummy_proc - assert_equal(dummy_proc, Reline.completion_proc) - - l = lambda {} - Reline.completion_proc = l - assert_equal(l, Reline.completion_proc) - - assert_raise(ArgumentError) { Reline.completion_proc = 42 } - assert_raise(ArgumentError) { Reline.completion_proc = "hoge" } - - dummy = DummyCallbackObject.new - Reline.completion_proc = dummy - assert_equal(dummy, Reline.completion_proc) - end - - def test_output_modifier_proc - assert_equal(nil, Reline.output_modifier_proc) - - dummy_proc = proc {} - Reline.output_modifier_proc = dummy_proc - assert_equal(dummy_proc, Reline.output_modifier_proc) - - l = lambda {} - Reline.output_modifier_proc = l - assert_equal(l, Reline.output_modifier_proc) - - assert_raise(ArgumentError) { Reline.output_modifier_proc = 42 } - assert_raise(ArgumentError) { Reline.output_modifier_proc = "hoge" } - - dummy = DummyCallbackObject.new - Reline.output_modifier_proc = dummy - assert_equal(dummy, Reline.output_modifier_proc) - end - - def test_prompt_proc - assert_equal(nil, Reline.prompt_proc) - - dummy_proc = proc {} - Reline.prompt_proc = dummy_proc - assert_equal(dummy_proc, Reline.prompt_proc) - - l = lambda {} - Reline.prompt_proc = l - assert_equal(l, Reline.prompt_proc) - - assert_raise(ArgumentError) { Reline.prompt_proc = 42 } - assert_raise(ArgumentError) { Reline.prompt_proc = "hoge" } - - dummy = DummyCallbackObject.new - Reline.prompt_proc = dummy - assert_equal(dummy, Reline.prompt_proc) - end - - def test_auto_indent_proc - assert_equal(nil, Reline.auto_indent_proc) - - dummy_proc = proc {} - Reline.auto_indent_proc = dummy_proc - assert_equal(dummy_proc, Reline.auto_indent_proc) - - l = lambda {} - Reline.auto_indent_proc = l - assert_equal(l, Reline.auto_indent_proc) - - assert_raise(ArgumentError) { Reline.auto_indent_proc = 42 } - assert_raise(ArgumentError) { Reline.auto_indent_proc = "hoge" } - - dummy = DummyCallbackObject.new - Reline.auto_indent_proc = dummy - assert_equal(dummy, Reline.auto_indent_proc) - end - - def test_pre_input_hook - assert_equal(nil, Reline.pre_input_hook) - - dummy_proc = proc {} - Reline.pre_input_hook = dummy_proc - assert_equal(dummy_proc, Reline.pre_input_hook) - - l = lambda {} - Reline.pre_input_hook = l - assert_equal(l, Reline.pre_input_hook) - end - - def test_dig_perfect_match_proc - assert_equal(nil, Reline.dig_perfect_match_proc) - - dummy_proc = proc {} - Reline.dig_perfect_match_proc = dummy_proc - assert_equal(dummy_proc, Reline.dig_perfect_match_proc) - - l = lambda {} - Reline.dig_perfect_match_proc = l - assert_equal(l, Reline.dig_perfect_match_proc) - - assert_raise(ArgumentError) { Reline.dig_perfect_match_proc = 42 } - assert_raise(ArgumentError) { Reline.dig_perfect_match_proc = "hoge" } - - dummy = DummyCallbackObject.new - Reline.dig_perfect_match_proc = dummy - assert_equal(dummy, Reline.dig_perfect_match_proc) - end - - def test_insert_text - assert_equal('', Reline.line_buffer) - assert_equal(0, Reline.point) - Reline.insert_text('abc') - assert_equal('abc', Reline.line_buffer) - assert_equal(3, Reline.point) - end - - def test_delete_text - assert_equal('', Reline.line_buffer) - assert_equal(0, Reline.point) - Reline.insert_text('abc') - assert_equal('abc', Reline.line_buffer) - assert_equal(3, Reline.point) - Reline.delete_text() - assert_equal('', Reline.line_buffer) - assert_equal(0, Reline.point) - Reline.insert_text('abc') - Reline.delete_text(1) - assert_equal('a', Reline.line_buffer) - assert_equal(1, Reline.point) - Reline.insert_text('defghi') - Reline.delete_text(2, 2) - assert_equal('adghi', Reline.line_buffer) - assert_equal(5, Reline.point) - end - - def test_set_input_and_output - assert_raise(TypeError) do - Reline.input = "This is not a file." - end - assert_raise(TypeError) do - Reline.output = "This is not a file." - end - - input, to_write = IO.pipe - to_read, output = IO.pipe - unless Reline.__send__(:input=, input) - omit "Setting to input is not effective on #{Reline.core.io_gate}" - end - Reline.output = output - - to_write.write "a\n" - result = Reline.readline - to_write.close - read_text = to_read.read_nonblock(100) - assert_equal('a', result) - refute(read_text.empty?) - ensure - input&.close - output&.close - to_read&.close - end - - def test_vi_editing_mode - Reline.vi_editing_mode - assert_equal(:vi_insert, Reline.core.config.instance_variable_get(:@editing_mode_label)) - end - - def test_emacs_editing_mode - Reline.emacs_editing_mode - assert_equal(:emacs, Reline.core.config.instance_variable_get(:@editing_mode_label)) - end - - def test_add_dialog_proc - dummy_proc = proc {} - Reline.add_dialog_proc(:test_proc, dummy_proc) - d = Reline.dialog_proc(:test_proc) - assert_equal(dummy_proc, d.dialog_proc) - - dummy_proc_2 = proc {} - Reline.add_dialog_proc(:test_proc, dummy_proc_2) - d = Reline.dialog_proc(:test_proc) - assert_equal(dummy_proc_2, d.dialog_proc) - - Reline.add_dialog_proc(:test_proc, nil) - assert_nil(Reline.dialog_proc(:test_proc)) - - l = lambda {} - Reline.add_dialog_proc(:test_lambda, l) - d = Reline.dialog_proc(:test_lambda) - assert_equal(l, d.dialog_proc) - - assert_equal(nil, Reline.dialog_proc(:test_nothing)) - - assert_raise(ArgumentError) { Reline.add_dialog_proc(:error, 42) } - assert_raise(ArgumentError) { Reline.add_dialog_proc(:error, 'hoge') } - assert_raise(ArgumentError) { Reline.add_dialog_proc('error', proc {} ) } - - dummy = DummyCallbackObject.new - Reline.add_dialog_proc(:dummy, dummy) - d = Reline.dialog_proc(:dummy) - assert_equal(dummy, d.dialog_proc) - end - - def test_add_dialog_proc_with_context - dummy_proc = proc {} - array = Array.new - Reline.add_dialog_proc(:test_proc, dummy_proc, array) - d = Reline.dialog_proc(:test_proc) - assert_equal(dummy_proc, d.dialog_proc) - assert_equal(array, d.context) - - Reline.add_dialog_proc(:test_proc, dummy_proc, nil) - d = Reline.dialog_proc(:test_proc) - assert_equal(dummy_proc, d.dialog_proc) - assert_equal(nil, d.context) - end - - def test_readmultiline - # readmultiline is module function - assert_include(Reline.methods, :readmultiline) - assert_include(Reline.private_instance_methods, :readmultiline) - end - - def test_readline - # readline is module function - assert_include(Reline.methods, :readline) - assert_include(Reline.private_instance_methods, :readline) - end - - def test_read_io - # TODO in Reline::Core - end - - def test_dumb_terminal - lib = File.expand_path("../../lib", __dir__) - out = IO.popen([{"TERM"=>"dumb"}, Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", "p Reline.core.io_gate"], &:read) - assert_match(/#<Reline::Dumb/, out.chomp) - end - - def test_print_prompt_before_everything_else - pend if win? - lib = File.expand_path("../../lib", __dir__) - code = "p Reline::IOGate.class; p Reline.readline 'prompt> '" - out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io| - io.write "abc\n" - io.close_write - io.read - end - assert_match(/\AReline::ANSI\nprompt> /, out) - end - - def test_read_eof_returns_input - pend if win? - lib = File.expand_path("../../lib", __dir__) - code = "p result: Reline.readline" - out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io| - io.write "a\C-a" - io.close_write - io.read - end - assert_include(out, { result: 'a' }.inspect) - end - - def test_read_eof_returns_nil_if_empty - pend if win? - lib = File.expand_path("../../lib", __dir__) - code = "p result: Reline.readline" - out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io| - io.write "a\C-h" - io.close_write - io.read - end - assert_include(out, { result: nil }.inspect) - end - - def test_require_reline_should_not_trigger_winsize - pend if win? - lib = File.expand_path("../../lib", __dir__) - code = <<~RUBY - require "io/console" - def STDIN.tty?; true; end - def STDOUT.tty?; true; end - def STDIN.winsize; raise; end - require("reline") && p(Reline.core.io_gate) - RUBY - out = IO.popen([{}, Reline.test_rubybin, "-I#{lib}", "-e", code], &:read) - assert_include(out.chomp, "Reline::ANSI") - end - - def win? - /mswin|mingw/.match?(RUBY_PLATFORM) - end - - def test_tty_amibuous_width - omit unless defined?(PTY) - ruby_file = Tempfile.create('rubyfile') - ruby_file.write(<<~RUBY) - require 'reline' - Thread.new { sleep 2; puts 'timeout'; exit } - p [Reline.ambiguous_width, gets.chomp] - RUBY - ruby_file.close - lib = File.expand_path('../../lib', __dir__) - cmd = [{ 'TERM' => 'xterm' }, Reline.test_rubybin, '-I', lib, ruby_file.to_path] - - # Calculate ambiguous width from cursor position - [1, 2].each do |ambiguous_width| - PTY.spawn(*cmd) do |r, w, pid| - loop { break if r.readpartial(1024).include?("\e[6n") } - w.puts "hello\e[10;#{ambiguous_width + 1}Rworld" - assert_include(r.gets, [ambiguous_width, 'helloworld'].inspect) - ensure - r.close - w.close - Process.waitpid pid - end - end - - # Ambiguous width = 1 when cursor pos timed out - PTY.spawn(*cmd) do |r, w, pid| - loop { break if r.readpartial(1024).include?("\e[6n") } - w.puts "hello\e[10;2Sworld" - assert_include(r.gets, [1, "hello\e[10;2Sworld"].inspect) - ensure - r.close - w.close - Process.waitpid pid - end - ensure - File.delete(ruby_file.path) if ruby_file - end - - def get_reline_encoding - if encoding = Reline.core.encoding - encoding - elsif win? - Encoding::UTF_8 - else - Encoding::default_external - end - end -end diff --git a/test/reline/test_reline_key.rb b/test/reline/test_reline_key.rb deleted file mode 100644 index b6260d57d6..0000000000 --- a/test/reline/test_reline_key.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative 'helper' -require "reline" - -class Reline::TestKey < Reline::TestCase - def test_match_symbol - assert(Reline::Key.new('a', :key1, false).match?(:key1)) - refute(Reline::Key.new('a', :key1, false).match?(:key2)) - refute(Reline::Key.new('a', :key1, false).match?(nil)) - end -end diff --git a/test/reline/test_string_processing.rb b/test/reline/test_string_processing.rb deleted file mode 100644 index a105be9aba..0000000000 --- a/test/reline/test_string_processing.rb +++ /dev/null @@ -1,46 +0,0 @@ -require_relative 'helper' - -class Reline::LineEditor::StringProcessingTest < Reline::TestCase - def setup - Reline.send(:test_mode) - @prompt = '> ' - @config = Reline::Config.new - Reline::HISTORY.instance_variable_set(:@config, @config) - @line_editor = Reline::LineEditor.new(@config) - @line_editor.reset(@prompt) - end - - def teardown - Reline.test_reset - end - - def test_calculate_width - width = @line_editor.send(:calculate_width, 'Ruby string') - assert_equal('Ruby string'.size, width) - end - - def test_calculate_width_with_escape_sequence - width = @line_editor.send(:calculate_width, "\1\e[31m\2RubyColor\1\e[34m\2 default string \1\e[m\2>", true) - assert_equal('RubyColor default string >'.size, width) - end - - def test_completion_proc_with_preposing_and_postposing - buf = ['def hoge', ' puts :aaa', 'end'] - - @line_editor.instance_variable_set(:@is_multiline, true) - @line_editor.instance_variable_set(:@buffer_of_lines, buf) - @line_editor.instance_variable_set(:@byte_pointer, 6) - @line_editor.instance_variable_set(:@line_index, 1) - completion_proc_called = false - @line_editor.instance_variable_set(:@completion_proc, proc { |target, pre, post| - assert_equal('puts', target) - assert_equal("def hoge\n ", pre) - assert_equal(" :aaa\nend", post) - completion_proc_called = true - }) - - assert_equal(["def hoge\n ", 'puts', " :aaa\nend", nil], @line_editor.retrieve_completion_block) - @line_editor.__send__(:call_completion_proc, "def hoge\n ", 'puts', " :aaa\nend", nil) - assert(completion_proc_called) - end -end diff --git a/test/reline/test_unicode.rb b/test/reline/test_unicode.rb deleted file mode 100644 index 0778306c32..0000000000 --- a/test/reline/test_unicode.rb +++ /dev/null @@ -1,286 +0,0 @@ -require_relative 'helper' -require "reline/unicode" - -class Reline::Unicode::Test < Reline::TestCase - def setup - Reline.send(:test_mode) - end - - def teardown - Reline.test_reset - end - - def test_get_mbchar_width - assert_equal Reline.ambiguous_width, Reline::Unicode.get_mbchar_width('é') - end - - def test_ambiguous_width - assert_equal 1, Reline::Unicode.calculate_width('√', true) - end - - def test_csi_regexp - csi_sequences = ["\e[m", "\e[1m", "\e[12;34m", "\e[12;34H"] - assert_equal(csi_sequences, "text#{csi_sequences.join('text')}text".scan(Reline::Unicode::CSI_REGEXP)) - end - - def test_osc_regexp - osc_sequences = ["\e]1\a", "\e]0;OSC\a", "\e]1\e\\", "\e]0;OSC\e\\"] - separator = "text\atext" - assert_equal(osc_sequences, "#{separator}#{osc_sequences.join(separator)}#{separator}".scan(Reline::Unicode::OSC_REGEXP)) - end - - def test_split_by_width - # IRB uses this method. - assert_equal [['abc', 'de'], 2], Reline::Unicode.split_by_width('abcde', 3) - end - - def test_split_line_by_width - assert_equal ['abc', 'de'], Reline::Unicode.split_line_by_width('abcde', 3) - assert_equal ['abc', 'def', ''], Reline::Unicode.split_line_by_width('abcdef', 3) - assert_equal ['ab', 'あd', 'ef'], Reline::Unicode.split_line_by_width('abあdef', 3) - assert_equal ['ab[zero]c', 'def', ''], Reline::Unicode.split_line_by_width("ab\1[zero]\2cdef", 3) - assert_equal ["\e[31mabc", "\e[31md\e[42mef", "\e[31m\e[42mg"], Reline::Unicode.split_line_by_width("\e[31mabcd\e[42mefg", 3) - assert_equal ["ab\e]0;1\ac", "\e]0;1\ad"], Reline::Unicode.split_line_by_width("ab\e]0;1\acd", 3) - end - - def test_split_line_by_width_csi_reset_sgr_optimization - assert_equal ["\e[1ma\e[mb\e[2mc", "\e[2md\e[0me\e[3mf", "\e[3mg"], Reline::Unicode.split_line_by_width("\e[1ma\e[mb\e[2mcd\e[0me\e[3mfg", 3) - assert_equal ["\e[1ma\e[mzero\e[0m\e[2mb", "\e[1m\e[2mc"], Reline::Unicode.split_line_by_width("\e[1ma\1\e[mzero\e[0m\2\e[2mbc", 2) - end - - def test_take_range - assert_equal 'cdef', Reline::Unicode.take_range('abcdefghi', 2, 4) - assert_equal 'あde', Reline::Unicode.take_range('abあdef', 2, 4) - assert_equal '[zero]cdef', Reline::Unicode.take_range("ab\1[zero]\2cdef", 2, 4) - assert_equal 'b[zero]cde', Reline::Unicode.take_range("ab\1[zero]\2cdef", 1, 4) - assert_equal "\e[31mcd\e[42mef", Reline::Unicode.take_range("\e[31mabcd\e[42mefg", 2, 4) - assert_equal "\e]0;1\acd", Reline::Unicode.take_range("ab\e]0;1\acd", 2, 3) - assert_equal 'いう', Reline::Unicode.take_range('あいうえお', 2, 4) - end - - def test_nonprinting_start_end - # \1 and \2 should be removed - assert_equal 'ab[zero]cd', Reline::Unicode.take_range("ab\1[zero]\2cdef", 0, 4) - assert_equal ['ab[zero]cd', 'ef'], Reline::Unicode.split_line_by_width("ab\1[zero]\2cdef", 4) - # CSI between \1 and \2 does not need to be applied to the sebsequent line - assert_equal ["\e[31mab\e[32mcd", "\e[31mef"], Reline::Unicode.split_line_by_width("\e[31mab\1\e[32m\2cdef", 4) - end - - def test_strip_non_printing_start_end - assert_equal "ab[zero]cd[ze\1ro]ef[zero]", Reline::Unicode.strip_non_printing_start_end("ab\1[zero]\2cd\1[ze\1ro]\2ef\1[zero]") - end - - def test_calculate_width - assert_equal 9, Reline::Unicode.calculate_width('abcdefghi') - assert_equal 9, Reline::Unicode.calculate_width('abcdefghi', true) - assert_equal 7, Reline::Unicode.calculate_width('abあdef') - assert_equal 7, Reline::Unicode.calculate_width('abあdef', true) - assert_equal 16, Reline::Unicode.calculate_width("ab\1[zero]\2cdef") - assert_equal 6, Reline::Unicode.calculate_width("ab\1[zero]\2cdef", true) - assert_equal 19, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg") - assert_equal 7, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg", true) - assert_equal 12, Reline::Unicode.calculate_width("ab\e]0;1\acd") - assert_equal 4, Reline::Unicode.calculate_width("ab\e]0;1\acd", true) - assert_equal 10, Reline::Unicode.calculate_width('あいうえお') - assert_equal 10, Reline::Unicode.calculate_width('あいうえお', true) - end - - def test_take_mbchar_range - assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4) - assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, padding: true) - assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_begin: true) - assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_end: true) - assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4) - assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, padding: true) - assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_begin: true) - assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_end: true) - assert_equal ['う', 4, 2], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4) - assert_equal [' う ', 3, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, padding: true) - assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true) - assert_equal ['うえ', 4, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true) - assert_equal ['いう ', 2, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true, padding: true) - assert_equal [' うえ', 3, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true, padding: true) - assert_equal [' うえお ', 3, 10], Reline::Unicode.take_mbchar_range('あいうえお', 3, 10, padding: true) - assert_equal [" \e[41mうえお\e[0m ", 3, 10], Reline::Unicode.take_mbchar_range("あい\e[41mうえお", 3, 10, padding: true) - assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true) - assert_equal ["\e[31mc[ABC]d\e[0mef", 2, 4], Reline::Unicode.take_mbchar_range("\e[31mabc\1[ABC]\2d\e[0mefghi", 2, 4) - assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true) - end - - def test_common_prefix - assert_equal('', Reline::Unicode.common_prefix([])) - assert_equal('abc', Reline::Unicode.common_prefix(['abc'])) - assert_equal('12', Reline::Unicode.common_prefix(['123', '123️⃣'])) - assert_equal('', Reline::Unicode.common_prefix(['abc', 'xyz'])) - assert_equal('ab', Reline::Unicode.common_prefix(['abcd', 'abc', 'abx', 'abcd'])) - assert_equal('A', Reline::Unicode.common_prefix(['AbcD', 'ABC', 'AbX', 'AbCD'])) - assert_equal('Ab', Reline::Unicode.common_prefix(['AbcD', 'ABC', 'AbX', 'AbCD'], ignore_case: true)) - end - - def test_encoding_conversion - texts = [ - String.new("invalid\xFFutf8", encoding: 'utf-8'), - String.new("invalid\xFFsjis", encoding: 'sjis'), - "utf8#{33111.chr('sjis')}convertible", - "utf8#{33222.chr('sjis')}inconvertible", - "sjis->utf8->sjis#{60777.chr('sjis')}irreversible" - ] - utf8_texts = [ - 'invalid�utf8', - 'invalid�sjis', - 'utf8仝convertible', - 'utf8�inconvertible', - 'sjis->utf8->sjis劦irreversible' - ] - sjis_texts = [ - 'invalid?utf8', - 'invalid?sjis', - "utf8#{33111.chr('sjis')}convertible", - 'utf8?inconvertible', - "sjis->utf8->sjis#{60777.chr('sjis')}irreversible" - ] - assert_equal(utf8_texts, texts.map { |s| Reline::Unicode.safe_encode(s, 'utf-8') }) - assert_equal(utf8_texts, texts.map { |s| Reline::Unicode.safe_encode(s, Encoding::UTF_8) }) - assert_equal(sjis_texts, texts.map { |s| Reline::Unicode.safe_encode(s, 'sjis') }) - assert_equal(sjis_texts, texts.map { |s| Reline::Unicode.safe_encode(s, Encoding::Windows_31J) }) - end - - def test_em_forward_word - assert_equal(12, Reline::Unicode.em_forward_word('abc---fooあbar-baz', 3)) - assert_equal(11, Reline::Unicode.em_forward_word('abc---fooあbar-baz'.encode('sjis'), 3)) - assert_equal(3, Reline::Unicode.em_forward_word('abcfoo', 3)) - assert_equal(3, Reline::Unicode.em_forward_word('abc---', 3)) - assert_equal(0, Reline::Unicode.em_forward_word('abc', 3)) - end - - def test_em_forward_word_with_capitalization - assert_equal([12, '---Fooあbar'], Reline::Unicode.em_forward_word_with_capitalization('abc---foOあBar-baz', 3)) - assert_equal([11, '---Fooあbar'.encode('sjis')], Reline::Unicode.em_forward_word_with_capitalization('abc---foOあBar-baz'.encode('sjis'), 3)) - assert_equal([3, 'Foo'], Reline::Unicode.em_forward_word_with_capitalization('abcfOo', 3)) - assert_equal([3, '---'], Reline::Unicode.em_forward_word_with_capitalization('abc---', 3)) - assert_equal([0, ''], Reline::Unicode.em_forward_word_with_capitalization('abc', 3)) - assert_equal([6, 'Ii̇i̇'], Reline::Unicode.em_forward_word_with_capitalization('ıİİ', 0)) - end - - def test_em_backward_word - assert_equal(12, Reline::Unicode.em_backward_word('abc foo-barあbaz--- xyz', 20)) - assert_equal(11, Reline::Unicode.em_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 19)) - assert_equal(2, Reline::Unicode.em_backward_word(' ', 2)) - assert_equal(2, Reline::Unicode.em_backward_word('ab', 2)) - assert_equal(0, Reline::Unicode.em_backward_word('ab', 0)) - end - - def test_em_big_backward_word - assert_equal(16, Reline::Unicode.em_big_backward_word('abc foo-barあbaz--- xyz', 20)) - assert_equal(15, Reline::Unicode.em_big_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 19)) - assert_equal(2, Reline::Unicode.em_big_backward_word(' ', 2)) - assert_equal(2, Reline::Unicode.em_big_backward_word('ab', 2)) - assert_equal(0, Reline::Unicode.em_big_backward_word('ab', 0)) - end - - def test_ed_transpose_words - # any value that does not trigger transpose - assert_equal([0, 0, 0, 2], Reline::Unicode.ed_transpose_words('aa bb cc ', 1)) - - assert_equal([0, 2, 3, 5], Reline::Unicode.ed_transpose_words('aa bb cc ', 2)) - assert_equal([0, 2, 3, 5], Reline::Unicode.ed_transpose_words('aa bb cc ', 4)) - assert_equal([3, 5, 6, 8], Reline::Unicode.ed_transpose_words('aa bb cc ', 5)) - assert_equal([3, 5, 6, 8], Reline::Unicode.ed_transpose_words('aa bb cc ', 7)) - assert_equal([3, 5, 6, 10], Reline::Unicode.ed_transpose_words('aa bb cc ', 8)) - assert_equal([3, 5, 6, 10], Reline::Unicode.ed_transpose_words('aa bb cc ', 9)) - ['sjis', 'utf-8'].each do |encoding| - texts = ['fooあ', 'barあbaz', 'aaa -', '- -', '- bbb'] - word1, word2, left, middle, right = texts.map { |text| text.encode(encoding) } - expected = [left.bytesize, (left + word1).bytesize, (left + word1 + middle).bytesize, (left + word1 + middle + word2).bytesize] - assert_equal(expected, Reline::Unicode.ed_transpose_words(left + word1 + middle + word2 + right, left.bytesize + word1.bytesize)) - assert_equal(expected, Reline::Unicode.ed_transpose_words(left + word1 + middle + word2 + right, left.bytesize + word1.bytesize + middle.bytesize)) - assert_equal(expected, Reline::Unicode.ed_transpose_words(left + word1 + middle + word2 + right, left.bytesize + word1.bytesize + middle.bytesize + word2.bytesize - 1)) - end - end - - def test_vi_big_forward_word - assert_equal(18, Reline::Unicode.vi_big_forward_word('abc---fooあbar-baz xyz', 3)) - assert_equal(8, Reline::Unicode.vi_big_forward_word('abcfooあ --', 3)) - assert_equal(7, Reline::Unicode.vi_big_forward_word('abcfooあ --'.encode('sjis'), 3)) - assert_equal(6, Reline::Unicode.vi_big_forward_word('abcfooあ', 3)) - assert_equal(3, Reline::Unicode.vi_big_forward_word('abc- ', 3)) - assert_equal(0, Reline::Unicode.vi_big_forward_word('abc', 3)) - end - - def test_vi_big_forward_end_word - assert_equal(4, Reline::Unicode.vi_big_forward_end_word('a bb c', 0)) - assert_equal(4, Reline::Unicode.vi_big_forward_end_word('- bb c', 0)) - assert_equal(1, Reline::Unicode.vi_big_forward_end_word('-a b', 0)) - assert_equal(1, Reline::Unicode.vi_big_forward_end_word('a- b', 0)) - assert_equal(1, Reline::Unicode.vi_big_forward_end_word('aa b', 0)) - assert_equal(3, Reline::Unicode.vi_big_forward_end_word(' aa b', 0)) - assert_equal(15, Reline::Unicode.vi_big_forward_end_word('abc---fooあbar-baz xyz', 3)) - assert_equal(14, Reline::Unicode.vi_big_forward_end_word('abc---fooあbar-baz xyz'.encode('sjis'), 3)) - assert_equal(3, Reline::Unicode.vi_big_forward_end_word('abcfooあ --', 3)) - assert_equal(3, Reline::Unicode.vi_big_forward_end_word('abcfooあ', 3)) - assert_equal(2, Reline::Unicode.vi_big_forward_end_word('abc- ', 3)) - assert_equal(0, Reline::Unicode.vi_big_forward_end_word('abc', 3)) - end - - def test_vi_big_backward_word - assert_equal(16, Reline::Unicode.vi_big_backward_word('abc foo-barあbaz--- xyz', 20)) - assert_equal(15, Reline::Unicode.vi_big_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 19)) - assert_equal(2, Reline::Unicode.vi_big_backward_word(' ', 2)) - assert_equal(2, Reline::Unicode.vi_big_backward_word('ab', 2)) - assert_equal(0, Reline::Unicode.vi_big_backward_word('ab', 0)) - end - - def test_vi_forward_word - assert_equal(3, Reline::Unicode.vi_forward_word('abc---fooあbar-baz', 3)) - assert_equal(9, Reline::Unicode.vi_forward_word('abc---fooあbar-baz', 6)) - assert_equal(8, Reline::Unicode.vi_forward_word('abc---fooあbar-baz'.encode('sjis'), 6)) - assert_equal(6, Reline::Unicode.vi_forward_word('abcfooあ', 3)) - assert_equal(3, Reline::Unicode.vi_forward_word('abc---', 3)) - assert_equal(0, Reline::Unicode.vi_forward_word('abc', 3)) - assert_equal(2, Reline::Unicode.vi_forward_word('abc def', 1, true)) - assert_equal(5, Reline::Unicode.vi_forward_word('abc def', 1, false)) - end - - def test_vi_forward_end_word - assert_equal(2, Reline::Unicode.vi_forward_end_word('abc---fooあbar-baz', 3)) - assert_equal(8, Reline::Unicode.vi_forward_end_word('abc---fooあbar-baz', 6)) - assert_equal(7, Reline::Unicode.vi_forward_end_word('abc---fooあbar-baz'.encode('sjis'), 6)) - assert_equal(3, Reline::Unicode.vi_forward_end_word('abcfooあ', 3)) - assert_equal(2, Reline::Unicode.vi_forward_end_word('abc---', 3)) - assert_equal(0, Reline::Unicode.vi_forward_end_word('abc', 3)) - end - - def test_vi_backward_word - assert_equal(3, Reline::Unicode.vi_backward_word('abc foo-barあbaz--- xyz', 20)) - assert_equal(9, Reline::Unicode.vi_backward_word('abc foo-barあbaz--- xyz', 17)) - assert_equal(8, Reline::Unicode.vi_backward_word('abc foo-barあbaz--- xyz'.encode('sjis'), 16)) - assert_equal(2, Reline::Unicode.vi_backward_word(' ', 2)) - assert_equal(2, Reline::Unicode.vi_backward_word('ab', 2)) - assert_equal(0, Reline::Unicode.vi_backward_word('ab', 0)) - end - - def test_vi_first_print - assert_equal(3, Reline::Unicode.vi_first_print(' abcdefg')) - assert_equal(3, Reline::Unicode.vi_first_print(' ')) - assert_equal(0, Reline::Unicode.vi_first_print('abc')) - assert_equal(0, Reline::Unicode.vi_first_print('あ')) - assert_equal(0, Reline::Unicode.vi_first_print('あ'.encode('sjis'))) - assert_equal(0, Reline::Unicode.vi_first_print('')) - end - - def test_character_type - assert(Reline::Unicode.word_character?('a')) - assert(Reline::Unicode.word_character?('あ')) - assert(Reline::Unicode.word_character?('あ'.encode('sjis'))) - refute(Reline::Unicode.word_character?(33345.chr('sjis'))) - refute(Reline::Unicode.word_character?('-')) - refute(Reline::Unicode.word_character?(nil)) - - assert(Reline::Unicode.space_character?(' ')) - refute(Reline::Unicode.space_character?('あ')) - refute(Reline::Unicode.space_character?('あ'.encode('sjis'))) - refute(Reline::Unicode.space_character?(33345.chr('sjis'))) - refute(Reline::Unicode.space_character?('-')) - refute(Reline::Unicode.space_character?(nil)) - end -end diff --git a/test/reline/test_within_pipe.rb b/test/reline/test_within_pipe.rb deleted file mode 100644 index e5d0c12b9c..0000000000 --- a/test/reline/test_within_pipe.rb +++ /dev/null @@ -1,77 +0,0 @@ -require_relative 'helper' - -class Reline::WithinPipeTest < Reline::TestCase - def setup - Reline.send(:test_mode) - @encoding = Reline.core.encoding - @input_reader, @writer = IO.pipe(@encoding) - Reline.input = @input_reader - @reader, @output_writer = IO.pipe(@encoding) - @output = Reline.output = @output_writer - @config = Reline.core.config - @config.keyseq_timeout *= 600 if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # for --jit-wait CI - @line_editor = Reline.core.line_editor - end - - def teardown - Reline.input = STDIN - Reline.output = STDOUT - Reline.point = 0 - Reline.delete_text - @input_reader.close - @writer.close - @reader.close - @output_writer.close - @config.reset - Reline.test_reset - end - - def test_simple_input - @writer.write("abc\n") - assert_equal 'abc', Reline.readmultiline(&proc{ true }) - end - - def test_unknown_macro - @config.add_default_key_binding('abc'.bytes, :unknown_macro) - @writer.write("abcd\n") - assert_equal 'd', Reline.readmultiline(&proc{ true }) - end - - def test_macro_commands_for_moving - @config.add_default_key_binding("\C-x\C-a".bytes, :beginning_of_line) - @config.add_default_key_binding("\C-x\C-e".bytes, :end_of_line) - @config.add_default_key_binding("\C-x\C-f".bytes, :forward_char) - @config.add_default_key_binding("\C-x\C-b".bytes, :backward_char) - @config.add_default_key_binding("\C-x\ef".bytes, :forward_word) - @config.add_default_key_binding("\C-x\eb".bytes, :backward_word) - @writer.write(" def\C-x\C-aabc\C-x\C-e ghi\C-x\C-a\C-x\C-f\C-x\C-f_\C-x\C-b\C-x\C-b_\C-x\C-f\C-x\C-f\C-x\C-f\C-x\ef_\C-x\eb\n") - assert_equal 'a_b_c def_ ghi', Reline.readmultiline(&proc{ true }) - end - - def test_macro_commands_for_editing - @config.add_default_key_binding("\C-x\C-d".bytes, :delete_char) - @config.add_default_key_binding("\C-x\C-h".bytes, :backward_delete_char) - @config.add_default_key_binding("\C-x\C-v".bytes, :quoted_insert) - #@config.add_default_key_binding("\C-xa".bytes, :self_insert) - @config.add_default_key_binding("\C-x\C-t".bytes, :transpose_chars) - @config.add_default_key_binding("\C-x\et".bytes, :transpose_words) - @config.add_default_key_binding("\C-x\eu".bytes, :upcase_word) - @config.add_default_key_binding("\C-x\el".bytes, :downcase_word) - @config.add_default_key_binding("\C-x\ec".bytes, :capitalize_word) - @writer.write("abcde\C-b\C-b\C-b\C-x\C-d\C-x\C-h\C-x\C-v\C-a\C-f\C-f EF\C-x\C-t gh\C-x\et\C-b\C-b\C-b\C-b\C-b\C-b\C-b\C-b\C-x\eu\C-x\el\C-x\ec\n") - assert_equal "a\C-aDE gh Fe", Reline.readmultiline(&proc{ true }) - end - - def test_delete_text_in_multiline - @writer.write("abc\ndef\nxyz\n") - result = Reline.readmultiline(&proc{ |str| - if str.include?('xyz') - Reline.delete_text - true - else - false - end - }) - assert_equal "abc\ndef", result - end -end diff --git a/test/reline/windows/test_key_event_record.rb b/test/reline/windows/test_key_event_record.rb deleted file mode 100644 index 25c860606a..0000000000 --- a/test/reline/windows/test_key_event_record.rb +++ /dev/null @@ -1,41 +0,0 @@ -require_relative '../helper' -return unless Reline.const_defined?(:Windows) - -class Reline::Windows - class KeyEventRecord::Test < Reline::TestCase - - def setup - # Ctrl+A - @key = Reline::Windows::KeyEventRecord.new(0x41, 1, Reline::Windows::LEFT_CTRL_PRESSED) - end - - def test_matches__with_no_arguments_raises_error - assert_raise(ArgumentError) { @key.match? } - end - - def test_matches_char_code - assert @key.match?(char_code: 0x1) - end - - def test_matches_virtual_key_code - assert @key.match?(virtual_key_code: 0x41) - end - - def test_matches_control_keys - assert @key.match?(control_keys: :CTRL) - end - - def test_doesnt_match_alt - refute @key.match?(control_keys: :ALT) - end - - def test_doesnt_match_empty_control_key - refute @key.match?(control_keys: []) - end - - def test_matches_control_keys_and_virtual_key_code - assert @key.match?(control_keys: :CTRL, virtual_key_code: 0x41) - end - - end -end diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl deleted file mode 100755 index 8b82be60f4..0000000000 --- a/test/reline/yamatanooroti/multiline_repl +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/env ruby - - -require 'bundler' -Bundler.require - -require 'reline' -require 'optparse' -require_relative 'termination_checker' - -opt = OptionParser.new -opt.on('--dynamic-prompt') { - Reline.prompt_proc = proc { |lines| - lines.each_with_index.map { |l, i| - "\e[1m[%04d]>\e[m " % i - } - } -} -opt.on('--broken-dynamic-prompt') { - Reline.prompt_proc = proc { |lines| - range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0) - lines[range].each_with_index.map { |l, i| - '[%04d]> ' % i - } - } -} -opt.on('--dynamic-prompt-returns-empty') { - Reline.prompt_proc = proc { |l| [] } -} -opt.on('--dynamic-prompt-with-newline') { - Reline.prompt_proc = proc { |lines| - range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0) - lines[range].each_with_index.map { |l, i| - '[%04d\n]> ' % i - } - } -} -opt.on('--broken-dynamic-prompt-assert-no-escape-sequence') { - Reline.prompt_proc = proc { |lines| - has_escape_sequence = lines.join.include?("\e") - (lines.size + 1).times.map { |i| - has_escape_sequence ? 'error>' : '[%04d]> ' % i - } - } -} -opt.on('--color-bold') { - Reline.output_modifier_proc = ->(output, complete:){ - output.gsub(/./) { |c| "\e[1m#{c}\e[0m" } - } -} -opt.on('--dynamic-prompt-show-line') { - Reline.prompt_proc = proc { |lines| - lines.map { |l| - '[%4.4s]> ' % l - } - } -} - -def assert_auto_indent_params(lines, line_index, byte_pointer, is_newline) - raise 'Wrong lines type' unless lines.all?(String) - - line = lines[line_index] - raise 'Wrong line_index value' unless line - - # The condition `byte_pointer <= line.bytesize` is not satisfied. Maybe bug. - # Instead, loose constraint `byte_pointer <= line.bytesize + 1` seems to be satisfied when is_newline is false. - return if is_newline - - raise 'byte_pointer out of bounds' unless byte_pointer <= line.bytesize + 1 - raise 'Invalid byte_pointer' unless line.byteslice(0, byte_pointer).valid_encoding? -end - -opt.on('--auto-indent') { - Reline.auto_indent_proc = lambda do |lines, line_index, byte_pointer, is_newline| - assert_auto_indent_params(lines, line_index, byte_pointer, is_newline) - AutoIndent.calculate_indent(lines, line_index, byte_pointer, is_newline) - end -} -opt.on('--dialog VAL') { |v| - Reline.add_dialog_proc(:simple_dialog, lambda { - return nil if v.include?('nil') - if v.include?('simple') - contents = <<~RUBY.split("\n") - Ruby is... - A dynamic, open source programming - language with a focus on simplicity - and productivity. It has an elegant - syntax that is natural to read and - easy to write. - RUBY - elsif v.include?('long') - contents = <<~RUBY.split("\n") - Ruby is... - A dynamic, open - source programming - language with a - focus on simplicity - and productivity. - It has an elegant - syntax that is - natural to read - and easy to write. - RUBY - elsif v.include?('fullwidth') - contents = <<~RUBY.split("\n") - Rubyとは... - - オープンソースの動的なプログラミン - グ言語で、シンプルさと高い生産性を - 備えています。エレガントな文法を持 - ち、自然に読み書きができます。 - RUBY - end - if v.include?('scrollkey') - dialog.trap_key = nil - if key and key.match?(dialog.name) - if dialog.pointer.nil? - dialog.pointer = 0 - elsif dialog.pointer >= (contents.size - 1) - dialog.pointer = 0 - else - dialog.pointer += 1 - end - end - dialog.trap_key = [?j.ord] - height = 4 - end - scrollbar = false - if v.include?('scrollbar') - scrollbar = true - end - if v.include?('alt-scrollbar') - scrollbar = true - end - Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar, face: :completion_dialog) - }) - if v.include?('alt-scrollbar') - ENV['RELINE_ALT_SCROLLBAR'] = '1' - end -} -opt.on('--complete') { - Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - %w{String ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) } - } -} -opt.on('--complete-menu-with-perfect-match') { - Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - %w{abs abs2}.select{ |c| c.start_with?(target) } - } -} -opt.on('--autocomplete') { - Reline.autocompletion = true - Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - %w{String Struct Symbol ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) } - } -} -opt.on('--autocomplete-empty') { - Reline.autocompletion = true - Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| [] } -} -opt.on('--autocomplete-long') { - Reline.autocompletion = true - Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - %w{ - String - Struct - Symbol - StopIteration - SystemCallError - SystemExit - SystemStackError - ScriptError - SyntaxError - Signal - SizedQueue - Set - SecureRandom - Socket - StringIO - StringScanner - Shellwords - Syslog - Singleton - SDBM - }.select{ |c| c.start_with?(target) } - } -} -opt.on('--autocomplete-super-long') { - Reline.autocompletion = true - Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - c = +'A' - 2000.times.map{ s = "Str_#{c}"; c.succ!; s }.select{ |c| c.start_with?(target) } - } -} - -opt.on('--autocomplete-width-long') { - Reline.autocompletion = true - Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - %w{ - remove_instance_variable - respond_to? - ruby2_keywords - rand - readline - readlines - require - require_relative - raise - respond_to_missing? - redo - rescue - retry - return - }.select{ |c| c.start_with?(target) } - } -} -opt.parse!(ARGV) - -begin - stty_save = `stty -g`.chomp -rescue -end - -begin - prompt = ENV['RELINE_TEST_PROMPT'] || "\e[1mprompt>\e[m " - puts 'Multiline REPL.' - while code = Reline.readmultiline(prompt, true) { |code| TerminationChecker.terminated?(code) } - case code.chomp - when 'exit', 'quit', 'q' - exit 0 - when '' - # NOOP - else - begin - result = eval(code) - puts "=> #{result.inspect}" - rescue ScriptError, StandardError => e - puts "Traceback (most recent call last):" - e.backtrace.reverse_each do |f| - puts " #{f}" - end - puts e.message - end - end - end -rescue Interrupt - puts '^C' - `stty #{stty_save}` if stty_save - exit 0 -ensure - `stty #{stty_save}` if stty_save -end -begin - puts -rescue Errno::EIO - # Maybe the I/O has been closed. -end diff --git a/test/reline/yamatanooroti/termination_checker.rb b/test/reline/yamatanooroti/termination_checker.rb deleted file mode 100644 index b97c798c59..0000000000 --- a/test/reline/yamatanooroti/termination_checker.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'ripper' - -module TerminationChecker - def self.terminated?(code) - Ripper.sexp(code) ? true : false - end -end - -module AutoIndent - def self.calculate_indent(lines, line_index, byte_pointer, is_newline) - if is_newline - 2 * nesting_level(lines[0..line_index - 1]) - else - lines = lines.dup - lines[line_index] = lines[line_index]&.byteslice(0, byte_pointer) - prev_level = nesting_level(lines[0..line_index - 1]) - level = nesting_level(lines[0..line_index]) - 2 * level if level < prev_level - end - end - - def self.nesting_level(lines) - code = lines.join("\n") - code.scan(/if|def|\(|\[|\{/).size - code.scan(/end|\)|\]|\}/).size - end -end diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb deleted file mode 100644 index aff5c0462b..0000000000 --- a/test/reline/yamatanooroti/test_rendering.rb +++ /dev/null @@ -1,1915 +0,0 @@ -require 'reline' - -begin - require 'yamatanooroti' - - class Reline::RenderingTest < Yamatanooroti::TestCase - - FACE_CONFIGS = { no_config: "", valid_config: <<~VALID_CONFIG, incomplete_config: <<~INCOMPLETE_CONFIG } - require "reline" - Reline::Face.config(:completion_dialog) do |face| - face.define :default, foreground: :white, background: :blue - face.define :enhanced, foreground: :white, background: :magenta - face.define :scrollbar, foreground: :white, background: :blue - end - VALID_CONFIG - require "reline" - Reline::Face.config(:completion_dialog) do |face| - face.define :default, foreground: :white, background: :black - face.define :scrollbar, foreground: :white, background: :cyan - end - INCOMPLETE_CONFIG - - def iterate_over_face_configs(&block) - FACE_CONFIGS.each do |config_name, face_config| - config_file = Tempfile.create(%w{face_config- .rb}) - config_file.write face_config - block.call(config_name, config_file) - ensure - config_file.close - File.delete(config_file) - end - end - - def setup - @pwd = Dir.pwd - suffix = '%010d' % Random.rand(0..65535) - @tmpdir = File.join(File.expand_path(Dir.tmpdir), "test_reline_config_#{$$}_#{suffix}") - begin - Dir.mkdir(@tmpdir) - rescue Errno::EEXIST - FileUtils.rm_rf(@tmpdir) - Dir.mkdir(@tmpdir) - end - @inputrc_backup = ENV['INPUTRC'] - @inputrc_file = ENV['INPUTRC'] = File.join(@tmpdir, 'temporaty_inputrc') - File.unlink(@inputrc_file) if File.exist?(@inputrc_file) - end - - def teardown - FileUtils.rm_rf(@tmpdir) - ENV['INPUTRC'] = @inputrc_backup - ENV.delete('RELINE_TEST_PROMPT') if ENV['RELINE_TEST_PROMPT'] - end - - def test_history_back - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":a\n") - write("\C-p") - assert_screen(<<~EOC) - Multiline REPL. - prompt> :a - => :a - prompt> :a - EOC - close - end - - def test_backspace - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":abc\C-h\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> :ab - => :ab - prompt> - EOC - close - end - - def test_autowrap - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write('01234567890123456789012') - assert_screen(<<~EOC) - Multiline REPL. - prompt> 0123456789012345678901 - 2 - EOC - close - end - - def test_fullwidth - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":あ\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> :あ - => :あ - prompt> - EOC - close - end - - def test_two_fullwidth - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":あい\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> :あい - => :あい - prompt> - EOC - close - end - - def test_finish_autowrapped_line - start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("[{'user'=>{'email'=>'a@a', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}]\n") - expected = [{'user'=>{'email'=>'a@a', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}].inspect - assert_screen(<<~EOC) - Multiline REPL. - prompt> [{'user'=>{'email'=>'a@a', 'id'= - >'ABC'}, 'version'=>4, 'status'=>'succee - ded'}] - #{fold_multiline("=> " + expected, 40)} - prompt> - EOC - close - end - - def test_finish_autowrapped_line_in_the_middle_of_lines - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("[{'user'=>{'email'=>'abcdef@abcdef', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}]#{"\C-b"*7}") - write("\n") - expected = [{'user'=>{'email'=>'abcdef@abcdef', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}].inspect - assert_screen(<<~EOC) - Multiline REPL. - prompt> [{'user'=>{'email'=>'a - bcdef@abcdef', 'id'=>'ABC'}, ' - version'=>4, 'status'=>'succee - ded'}] - #{fold_multiline("=> " + expected, 30)} - prompt> - EOC - close - end - - def test_finish_autowrapped_line_in_the_middle_of_multilines - omit if RUBY_VERSION < '2.7' - start_terminal(30, 16, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("<<~EOM\n ABCDEFG\nEOM\n") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> <<~EOM - prompt> ABCDEF - G - prompt> EOM - => "ABCDEFG\n" - prompt> - EOC - close - end - - def test_prompt - write_inputrc <<~'LINES' - "abc": "123" - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("abc\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> 123 - => 123 - prompt> - EOC - close - end - - def test_mode_string_emacs - write_inputrc <<~LINES - set show-mode-in-prompt on - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - assert_screen(<<~EOC) - Multiline REPL. - @prompt> - EOC - close - end - - def test_mode_string_vi - write_inputrc <<~LINES - set editing-mode vi - set show-mode-in-prompt on - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":a\n\C-[k") - write("i\n:a") - write("\C-[h") - assert_screen(<<~EOC) - (ins)prompt> :a - => :a - (ins)prompt> :a - => :a - (cmd)prompt> :a - EOC - close - end - - def test_original_mode_string_emacs - write_inputrc <<~LINES - set show-mode-in-prompt on - set emacs-mode-string [emacs] - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - assert_screen(<<~EOC) - Multiline REPL. - [emacs]prompt> - EOC - close - end - - def test_original_mode_string_with_quote - write_inputrc <<~LINES - set show-mode-in-prompt on - set emacs-mode-string "[emacs]" - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - assert_screen(<<~EOC) - Multiline REPL. - [emacs]prompt> - EOC - close - end - - def test_original_mode_string_vi - write_inputrc <<~LINES - set editing-mode vi - set show-mode-in-prompt on - set vi-ins-mode-string "{InS}" - set vi-cmd-mode-string "{CmD}" - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":a\n\C-[k") - assert_screen(<<~EOC) - Multiline REPL. - {InS}prompt> :a - => :a - {CmD}prompt> :a - EOC - close - end - - def test_mode_string_vi_changing - write_inputrc <<~LINES - set editing-mode vi - set show-mode-in-prompt on - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":a\C-[ab\C-[ac\C-h\C-h\C-h\C-h:a") - assert_screen(<<~EOC) - Multiline REPL. - (ins)prompt> :a - EOC - close - end - - def test_esc_input - omit if Reline::IOGate.win? - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def\C-aabc") - write("\e") # single ESC - sleep 1 - write("A") - write("B\eAC") # ESC + A (M-A, no key specified in Reline::KeyActor::Emacs) - assert_screen(<<~EOC) - Multiline REPL. - prompt> abcABCdef - EOC - close - end - - def test_prompt_with_escape_sequence - ENV['RELINE_TEST_PROMPT'] = "\1\e[30m\2prompt> \1\e[m\2" - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("123\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> 123 - => 123 - prompt> - EOC - close - end - - def test_prompt_with_escape_sequence_and_autowrap - ENV['RELINE_TEST_PROMPT'] = "\1\e[30m\2prompt> \1\e[m\2" - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("1234567890123\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> 123456789012 - 3 - => 1234567890123 - prompt> - EOC - close - end - - def test_readline_with_multiline_input - start_terminal(5, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt}, startup_message: 'Multiline REPL.') - write("def foo\n bar\nend\n") - write("Reline.readline('prompt> ')\n") - write("\C-p\C-p") - assert_screen(<<~EOC) - => :foo - [0000]> Reline.readline('prompt> ') - prompt> def foo - bar - end - EOC - close - end - - def test_multiline_and_autowrap - start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def aaaaaaaaaa\n 33333333\n end\C-a\C-pputs\C-e\e\C-m888888888888888") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def aaaaaaaa - aa - prompt> puts 333333 - 33 - prompt> 888888888888 - 888 - prompt> e - nd - EOC - close - end - - def test_multiline_add_new_line_and_autowrap - start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def aaaaaaaaaa") - write("\n") - write(" bbbbbbbbbbbb") - write("\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def aaaaaaaa - aa - prompt> bbbbbbbbbb - bb - prompt> - EOC - close - end - - def test_clear - start_terminal(10, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("3\C-l") - assert_screen(<<~EOC) - prompt> 3 - EOC - close - end - - def test_clear_multiline_and_autowrap - start_terminal(10, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def aaaaaa\n 3\n\C-lend") - assert_screen(<<~EOC) - prompt> def aaa - aaa - prompt> 3 - prompt> end - EOC - close - end - - def test_nearest_cursor - start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def ああ\n :いい\nend\C-pbb\C-pcc") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def ccああ - prompt> :bbいい - prompt> end - EOC - close - end - - def test_delete_line - start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def a\n\nend\C-p\C-h") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def a - prompt> end - EOC - close - end - - def test_last_line_of_screen - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("\n\n\n\n\ndef a\nend") - assert_screen(<<~EOC) - prompt> - prompt> - prompt> - prompt> def a - prompt> end - EOC - close - end - - # c17a09b7454352e2aff5a7d8722e80afb73e454b - def test_autowrap_at_last_line_of_screen - start_terminal(5, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def a\nend\n\C-p") - assert_screen(<<~EOC) - prompt> def a - prompt> end - => :a - prompt> def a - prompt> end - EOC - close - end - - # f002483b27cdb325c5edf9e0fe4fa4e1c71c4b0e - def test_insert_line_in_the_middle_of_line - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("333\C-b\C-b\e\C-m8") - assert_screen(<<~EOC) - Multiline REPL. - prompt> 3 - prompt> 833 - EOC - close - end - - # 9d8978961c5de5064f949d56d7e0286df9e18f43 - def test_insert_line_in_the_middle_of_line_at_last_line_of_screen - start_terminal(3, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("333333333333333\C-a\C-f\e\C-m") - assert_screen(<<~EOC) - prompt> 3 - prompt> 333333333333 - 33 - EOC - close - end - - def test_insert_after_clear - start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def a\n 01234\nend\C-l\C-p5678") - assert_screen(<<~EOC) - prompt> def a - prompt> 056781234 - prompt> end - EOC - close - end - - def test_foced_newline_insertion - start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - #write("def a\nend\C-p\C-e\e\C-m 3") - write("def a\nend\C-p\C-e\e\x0D") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def a - prompt> - prompt> end - EOC - close - end - - def test_multiline_incremental_search - start_terminal(6, 25, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def a\n 8\nend\ndef b\n 3\nend\C-s8") - assert_screen(<<~EOC) - prompt> 8 - prompt> end - => :a - (i-search)`8'def a - (i-search)`8' 8 - (i-search)`8'end - EOC - close - end - - def test_multiline_incremental_search_finish - start_terminal(6, 25, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def a\n 8\nend\ndef b\n 3\nend\C-r8\C-j") - assert_screen(<<~EOC) - prompt> 8 - prompt> end - => :a - prompt> def a - prompt> 8 - prompt> end - EOC - close - end - - def test_binding_for_vi_movement_mode - write_inputrc <<~LINES - set editing-mode vi - "\\C-a": vi-movement-mode - LINES - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(":1234\C-ahhhi0") - assert_screen(<<~EOC) - Multiline REPL. - prompt> :01234 - EOC - close - end - - def test_broken_prompt_list - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --broken-dynamic-prompt}, startup_message: 'Multiline REPL.') - write("def hoge\n 3\nend") - assert_screen(<<~EOC) - Multiline REPL. - [0000]> def hoge - [0001]> 3 - [0001]> end - EOC - close - end - - def test_no_escape_sequence_passed_to_dynamic_prompt - start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --color-bold --broken-dynamic-prompt-assert-no-escape-sequence}, startup_message: 'Multiline REPL.') - write("%[ S") - write("\n") - assert_screen(<<~EOC) - Multiline REPL. - [0000]> %[ S - [0001]> - EOC - close - end - - def test_bracketed_paste - omit if Reline.core.io_gate.win? - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("\e[200~def hoge\r\t3\rend\e[201~") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - prompt> 3 - prompt> end - EOC - write("\e[200~.tap do\r\t4\r\t5\rend\e[201~") - assert_screen(<<~EOC) - prompt> 3 - prompt> end.tap do - prompt> 4 - prompt> 5 - prompt> end - EOC - close - end - - def test_bracketed_paste_with_undo_redo - omit if Reline.core.io_gate.win? - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("abc") - write("\e[200~def hoge\r\t3\rend\e[201~") - write("\C-_") - assert_screen(<<~EOC) - Multiline REPL. - prompt> abc - EOC - write("\e\C-_") - assert_screen(<<~EOC) - Multiline REPL. - prompt> abcdef hoge - prompt> 3 - prompt> end - EOC - close - end - - def test_backspace_until_returns_to_initial - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("ABC") - write("\C-h\C-h\C-h") - assert_screen(<<~EOC) - Multiline REPL. - prompt> - EOC - close - end - - def test_longer_than_screen_height - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(<<~EOC.chomp) - def each_top_level_statement - initialize_input - catch(:TERM_INPUT) do - loop do - begin - prompt - unless l = lex - throw :TERM_INPUT if @line == '' - else - @line_no += l.count("\n") - next if l == "\n" - @line.concat l - if @code_block_open or @ltype or @continue or @indent > 0 - next - end - end - if @line != "\n" - @line.force_encoding(@io.encoding) - yield @line, @exp_line_no - end - break if @io.eof? - @line = '' - @exp_line_no = @line_no - # - @indent = 0 - rescue TerminateLineInput - initialize_input - prompt - end - end - end - end - EOC - assert_screen(<<~EOC) - prompt> prompt - prompt> end - prompt> end - prompt> end - prompt> end - EOC - write("\C-p" * 6) - assert_screen(<<~EOC) - prompt> rescue Terminate - LineInput - prompt> initialize_inp - ut - prompt> prompt - EOC - write("\C-n" * 4) - assert_screen(<<~EOC) - prompt> initialize_inp - ut - prompt> prompt - prompt> end - prompt> end - EOC - close - end - - def test_longer_than_screen_height_nearest_cursor_with_scroll_back - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write(<<~EOC.chomp) - if 1 - if 2 - if 3 - if 4 - puts - end - end - end - end - EOC - write("\C-p" * 4 + "\C-e" + "\C-p" * 4) - write("2") - assert_screen(<<~EOC) - prompt> if 12 - prompt> if 2 - prompt> if 3 - prompt> if 4 - prompt> puts - EOC - close - end - - def test_update_cursor_correctly_when_just_cursor_moving - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def hoge\n 01234678") - write("\C-p") - write("\C-b") - write("\C-n") - write('5') - write("\C-e") - write('9') - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - prompt> 0123456789 - EOC - close - end - - def test_auto_indent - start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - "def hoge\nputs(\n1,\n2\n)\nend".lines do |line| - write line - end - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - prompt> puts( - prompt> 1, - prompt> 2 - prompt> ) - prompt> end - EOC - close - end - - def test_auto_indent_when_inserting_line - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write 'aa(bb(cc(dd(ee(' - write "\C-b" * 5 + "\n" - assert_screen(<<~EOC) - Multiline REPL. - prompt> aa(bb(cc(d - prompt> d(ee( - EOC - close - end - - def test_auto_indent_multibyte_insert_line - start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write "if true\n" - write "あいうえお\n" - 4.times { write "\C-b\C-b\C-b\C-b\e\r" } - assert_screen(<<~EOC) - Multiline REPL. - prompt> if true - prompt> あ - prompt> い - prompt> う - prompt> え - prompt> お - prompt> - EOC - close - end - - def test_newline_after_wrong_indent - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write "if 1\n aa" - write "\n" - assert_screen(<<~EOC) - Multiline REPL. - prompt> if 1 - prompt> aa - prompt> - EOC - close - end - - def test_suppress_auto_indent_just_after_pasted - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write("def hoge\n [[\n 3]]\ned") - write("\C-bn") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - prompt> [[ - prompt> 3]] - prompt> end - EOC - close - end - - def test_suppress_auto_indent_for_adding_newlines_in_pasting - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write("<<~Q\n") - write("{\n #\n}") - write("#") - assert_screen(<<~EOC) - Multiline REPL. - prompt> <<~Q - prompt> { - prompt> # - prompt> }# - EOC - close - end - - def test_auto_indent_with_various_spaces - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write "(\n\C-v" - write "\C-k\n\C-v" - write "\C-k)" - assert_screen(<<~EOC) - Multiline REPL. - prompt> ( - prompt> ^K - prompt> ) - EOC - close - end - - def test_autowrap_in_the_middle_of_a_line - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def abcdefg; end\C-b\C-b\C-b\C-b\C-b") - %w{h i}.each do |c| - write(c) - end - assert_screen(<<~EOC) - Multiline REPL. - prompt> def abcdefgh - i; end - EOC - close - end - - def test_newline_in_the_middle_of_lines - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def hoge\n 1\n 2\n 3\n 4\nend\n") - write("\C-p\C-p\C-p\C-e\n") - assert_screen(<<~EOC) - prompt> def hoge - prompt> 1 - prompt> 2 - prompt> 3 - prompt> - EOC - close - end - - def test_ed_force_submit_in_the_middle_of_lines - write_inputrc <<~LINES - "\\C-a": ed_force_submit - LINES - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def hoge\nend") - write("\C-p\C-a") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - prompt> end - => :hoge - prompt> - EOC - close - end - - def test_dynamic_prompt_returns_empty - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-returns-empty}, startup_message: 'Multiline REPL.') - write("def hoge\nend\n") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - prompt> end - => :hoge - prompt> - EOC - close - end - - def test_reset_rest_height_when_clear_screen - start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("\n\n\n\C-l3\n") - assert_screen(<<~EOC) - prompt> 3 - => 3 - prompt> - EOC - close - end - - def test_meta_key - start_terminal(30, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def ge\ebho") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - EOC - close - end - - def test_not_meta_key - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("おだんご") # "だ" in UTF-8 contains "\xA0" - assert_screen(<<~EOC) - Multiline REPL. - prompt> おだんご - EOC - close - end - - def test_force_enter - start_terminal(30, 120, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def hoge\nend\C-p\C-e") - write("\e\x0D") - assert_screen(<<~EOC) - Multiline REPL. - prompt> def hoge - prompt> - prompt> end - EOC - close - end - - def test_nontty - omit if Reline.core.io_gate.win? - cmd = %Q{ruby -e 'puts(%Q{ello\C-ah\C-e})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })' | ruby -e 'print STDIN.read'} - start_terminal(40, 50, ['bash', '-c', cmd]) - assert_screen(<<~'EOC') - > hello - "hello" - EOC - close - end - - def test_eof_with_newline - omit if Reline.core.io_gate.win? - cmd = %Q{ruby -e 'print(%Q{abc def \\e\\r})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'} - start_terminal(40, 50, ['bash', '-c', cmd]) - assert_screen(<<~'EOC') - > abc def - "abc def " - EOC - close - end - - def test_eof_without_newline - omit if Reline.core.io_gate.win? - cmd = %Q{ruby -e 'print(%{hello})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'} - start_terminal(40, 50, ['bash', '-c', cmd]) - assert_screen(<<~'EOC') - > hello - "hello" - EOC - close - end - - def test_em_set_mark_and_em_exchange_mark - start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("aaa bbb ccc ddd\eb\eb\e\x20\eb\C-x\C-xX\C-x\C-xY") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> aaa Ybbb Xccc ddd - EOC - close - end - - def test_multiline_completion - start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') - write("def hoge\n St\n St\C-p\t") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> def hoge - prompt> String - prompt> St - EOC - close - end - - def test_completion_journey_2nd_line - write_inputrc <<~LINES - set editing-mode vi - LINES - start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') - write("def hoge\n S\C-n") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> def hoge - prompt> String - EOC - close - end - - def test_completion_journey_with_empty_line - write_inputrc <<~LINES - set editing-mode vi - LINES - start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') - write("\C-n\C-p") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> - EOC - close - end - - def test_completion_menu_is_displayed_horizontally - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') - write("S\t\t") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> S - ScriptError String - Signal SyntaxError - EOC - close - end - - def test_show_all_if_ambiguous_on - write_inputrc <<~LINES - set show-all-if-ambiguous on - LINES - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') - write("S\t") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> S - ScriptError String - Signal SyntaxError - EOC - close - end - - def test_show_all_if_ambiguous_on_and_menu_with_perfect_match - write_inputrc <<~LINES - set show-all-if-ambiguous on - LINES - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete-menu-with-perfect-match}, startup_message: 'Multiline REPL.') - write("a\t") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> abs - abs abs2 - EOC - close - end - - def test_simple_dialog - iterate_over_face_configs do |config_name, config_file| - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') - write('a') - write('b') - write('c') - write("\C-h") - close - assert_screen(<<~'EOC', "Failed with `#{config_name}` in Face") - Multiline REPL. - prompt> ab - Ruby is... - A dynamic, open source programming - language with a focus on simplicity - and productivity. It has an elegant - syntax that is natural to read and - easy to write. - EOC - end - end - - def test_simple_dialog_at_right_edge - iterate_over_face_configs do |config_name, config_file| - start_terminal(20, 40, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') - write('a') - write('b') - write('c') - write("\C-h") - close - assert_screen(<<~'EOC') - Multiline REPL. - prompt> ab - Ruby is... - A dynamic, open source programming - language with a focus on simplicity - and productivity. It has an elegant - syntax that is natural to read and - easy to write. - EOC - end - end - - def test_dialog_scroll_pushup_condition - iterate_over_face_configs do |config_name, config_file| - start_terminal(10, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("\n" * 10) - write("if 1\n sSts\nend") - write("\C-p\C-h\C-e\C-h") - assert_screen(<<~'EOC') - prompt> - prompt> - prompt> - prompt> - prompt> - prompt> - prompt> if 1 - prompt> St - prompt> enString - Struct - EOC - close - end - end - - def test_simple_dialog_with_scroll_screen - iterate_over_face_configs do |config_name, config_file| - start_terminal(5, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: /prompt>/) - write("if 1\n 2\n 3\n 4\n 5\n 6") - write("\C-p\C-n\C-p\C-p\C-p#") - close - assert_screen(<<~'EOC') - prompt> 2 - prompt> 3# - prompt> 4 - prompt> 5 Ruby is... - prompt> 6 A dynamic, open source programming - EOC - end - end - - def test_autocomplete_at_bottom - start_terminal(15, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write('def hoge' + "\C-m" * 10 + "end\C-p ") - write('S') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> def hoge - prompt> - prompt> - prompt> String - prompt> Struct - prompt> Symbol - prompt> ScriptError - prompt> SyntaxError - prompt> Signal - prompt> S - prompt> end - EOC - close - end - - def test_autocomplete_return_to_original - start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write('S') - write('t') - write('r') - 3.times{ write("\C-i") } - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Str - String - Struct - EOC - close - end - - def test_autocomplete_target_is_wrapped - start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write(' ') - write('S') - write('t') - write('r') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> St - r - String - Struct - EOC - close - end - - def test_autocomplete_target_at_end_of_line - start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write(' ') - write('Str') - write("\C-i") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Str - ing String - Struct - EOC - close - end - - def test_autocomplete_completed_input_is_wrapped - start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write(' ') - write('Str') - write("\C-i") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Stri - ng String - Struct - EOC - close - end - - def test_force_insert_before_autocomplete - start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write('Sy') - write(";St\t\t") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Sy;Struct - String - Struct - EOC - close - end - - def test_simple_dialog_with_scroll_key - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog long,scrollkey}, startup_message: 'Multiline REPL.') - write('a') - 5.times{ write('j') } - assert_screen(<<~'EOC') - Multiline REPL. - prompt> a - A dynamic, open - source programming - language with a - focus on simplicity - EOC - close - end - - def test_simple_dialog_scrollbar_with_moving_to_right - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog long,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') - 6.times{ write('j') } - write('a') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> a - source programming ▄ - language with a █ - focus on simplicity - and productivity. - EOC - close - end - - def test_simple_dialog_scrollbar_with_moving_to_left - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog long,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') - write('a') - 6.times{ write('j') } - write("\C-h") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> - source programming ▄ - language with a █ - focus on simplicity - and productivity. - EOC - close - end - - def test_dialog_with_fullwidth_chars - ENV['RELINE_TEST_PROMPT'] = '> ' - start_terminal(20, 5, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') - 6.times{ write('j') } - assert_screen(<<~'EOC') - Multi - line - REPL. - > - オー - グ言▄ - 備え█ - ち、█ - EOC - close - end - - def test_dialog_with_fullwidth_chars_split - ENV['RELINE_TEST_PROMPT'] = '> ' - start_terminal(20, 6, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') - 6.times{ write('j') } - assert_screen(<<~'EOC') - Multil - ine RE - PL. - > - オー - グ言 ▄ - 備え █ - ち、 █ - EOC - close - end - - def test_autocomplete_empty - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write('Street') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Street - EOC - close - end - - def test_autocomplete - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write('Str') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Str - String - Struct - EOC - close - end - - def test_autocomplete_empty_string - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("\C-i") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> String - String █ - Struct ▀ - Symbol - EOC - close - end - - def test_paste_code_with_tab_indent_does_not_fail - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-empty}, startup_message: 'Multiline REPL.') - write("2.times do\n\tputs\n\tputs\nend") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> 2.times do - prompt> puts - prompt> puts - prompt> end - EOC - close - end - - def test_autocomplete_after_2nd_line - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("def hoge\n Str") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> def hoge - prompt> Str - String - Struct - EOC - close - end - - def test_autocomplete_rerender_under_dialog - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("def hoge\n\n 123456\n 456789\nend\C-p\C-p\C-p a = Str") - write('i') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> def hoge - prompt> a = Stri - prompt> 1234String - prompt> 456789 - prompt> end - EOC - close - end - - def test_rerender_multiple_dialog - start_terminal(20, 60, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --dialog simple}, startup_message: 'Multiline REPL.') - write("if\n abcdef\n 123456\n 456789\nend\C-p\C-p\C-p\C-p Str") - write("\t") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> if String - prompt> aStringRuby is... - prompt> 1StructA dynamic, open source programming - prompt> 456789 language with a focus on simplicity - prompt> end and productivity. It has an elegant - syntax that is natural to read and - easy to write. - EOC - close - end - - def test_autocomplete_long_with_scrollbar - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-long}, startup_message: 'Multiline REPL.') - write('S') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> S - String █ - Struct █ - Symbol █ - StopIteration █ - SystemCallError █ - SystemExit █ - SystemStackError█ - ScriptError █ - SyntaxError █ - Signal █ - SizedQueue █ - Set - SecureRandom - Socket - StringIO - EOC - write("\C-i" * 16) - assert_screen(<<~'EOC') - Multiline REPL. - prompt> StringScanner - Struct ▄ - Symbol █ - StopIteration █ - SystemCallError █ - SystemExit █ - SystemStackError█ - ScriptError █ - SyntaxError █ - Signal █ - SizedQueue █ - Set █ - SecureRandom ▀ - Socket - StringIO - StringScanner - EOC - close - end - - def test_autocomplete_super_long_scroll_to_bottom - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.') - shift_tab = [27, 91, 90] - write('S' + shift_tab.map(&:chr).join) - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Str_BXX - Str_BXJ - Str_BXK - Str_BXL - Str_BXM - Str_BXN - Str_BXO - Str_BXP - Str_BXQ - Str_BXR - Str_BXS - Str_BXT - Str_BXU - Str_BXV - Str_BXW - Str_BXX▄ - EOC - close - end - - def test_autocomplete_super_long_and_backspace - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.') - shift_tab = [27, 91, 90] - write('S' + shift_tab.map(&:chr).join) - write("\C-h") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> Str_BX - Str_BX █ - Str_BXA█ - Str_BXB█ - Str_BXC█ - Str_BXD█ - Str_BXE█ - Str_BXF█ - Str_BXG█ - Str_BXH█ - Str_BXI - Str_BXJ - Str_BXK - Str_BXL - Str_BXM - Str_BXN - EOC - close - end - - def test_dialog_callback_returns_nil - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog nil}, startup_message: 'Multiline REPL.') - write('a') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> a - EOC - close - end - - def test_dialog_narrower_than_screen - start_terminal(20, 11, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') - assert_screen(<<~'EOC') - Multiline R - EPL. - prompt> - Ruby is... - A dynamic, - language wi - and product - syntax that - easy to wri - EOC - close - end - - def test_dialog_narrower_than_screen_with_scrollbar - start_terminal(20, 11, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-long}, startup_message: 'Multiline REPL.') - write('S' + "\C-i" * 3) - assert_screen(<<~'EOC') - Multiline R - EPL. - prompt> Sym - String █ - Struct █ - Symbol █ - StopIterat█ - SystemCall█ - SystemExit█ - SystemStac█ - ScriptErro█ - SyntaxErro█ - Signal █ - SizedQueue█ - Set - SecureRand - Socket - StringIO - EOC - close - end - - def test_dialog_with_fullwidth_scrollbar - start_terminal(20, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple,scrollkey,alt-scrollbar}, startup_message: 'Multiline REPL.') - assert_screen(<<~'EOC') - Multiline REPL. - prompt> - Ruby is... :: - A dynamic, open source programming :: - language with a focus on simplicity'' - and productivity. It has an elegant - EOC - close - end - - def test_rerender_argument_prompt_after_pasting - start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write('abcdef') - write("\e3\C-h") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> abc - EOC - close - end - - def test_autocomplete_old_dialog_width_greater_than_dialog_width - start_terminal(40, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-width-long}, startup_message: 'Multiline REPL.') - write("0+ \n12345678901234") - write("\C-p") - write("r") - write("a") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> 0+ ra - prompt> 123rand 901234 - raise - EOC - close - end - - def test_scroll_at_bottom_for_dialog - start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("\n\n\n\n\n\n\n\n\n\n\n") - write("def hoge\n\nend\C-p\C-e") - write(" S") - assert_screen(<<~'EOC') - prompt> - prompt> - prompt> - prompt> - prompt> - prompt> def hoge - prompt> S - prompt> enString █ - Struct ▀ - Symbol - EOC - close - end - - def test_clear_dialog_in_pasting - start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("S") - write("tring ") - assert_screen(<<~'EOC') - Multiline REPL. - prompt> String - EOC - close - end - - def test_prompt_with_newline - ENV['RELINE_TEST_PROMPT'] = "::\n> " - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("def hoge\n 3\nend") - assert_screen(<<~'EOC') - Multiline REPL. - ::\n> def hoge - ::\n> 3 - ::\n> end - EOC - close - end - - def test_dynamic_prompt_with_newline - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-with-newline}, startup_message: 'Multiline REPL.') - write("def hoge\n 3\nend") - assert_screen(<<~'EOC') - Multiline REPL. - [0000\n]> def hoge - [0001\n]> 3 - [0001\n]> end - EOC - close - end - - def test_lines_passed_to_dynamic_prompt - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-show-line}, startup_message: 'Multiline REPL.') - write("if true") - write("\n") - assert_screen(<<~EOC) - Multiline REPL. - [if t]> if true - [ ]> - EOC - close - end - - def test_clear_dialog_when_just_move_cursor_at_last_line - start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("class A\n 3\nend\n\n\n") - write("\C-p\C-p\C-e; S") - assert_screen(/String/) - write("\C-n") - write(";") - assert_screen(<<~'EOC') - prompt> 3 - prompt> end - => 3 - prompt> - prompt> - prompt> class A - prompt> 3; S - prompt> end; - EOC - close - end - - def test_clear_dialog_when_adding_new_line_to_end_of_buffer - start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("class A\n def a\n 3\n 3\n end\nend") - write("\n") - write("class S") - write("\n") - write(" 3") - assert_screen(<<~'EOC') - prompt> def a - prompt> 3 - prompt> 3 - prompt> end - prompt> end - => :a - prompt> class S - prompt> 3 - EOC - close - end - - def test_insert_newline_in_the_middle_of_buffer_just_after_dialog - start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("class A\n def a\n 3\n end\nend") - write("\n") - write("\C-p\C-p\C-p\C-p\C-p\C-e\C-hS") - write("\e\x0D") - write(" 3") - assert_screen(<<~'EOC') - prompt> 3 - prompt> end - prompt> end - => :a - prompt> class S - prompt> 3 - prompt> def a - prompt> 3 - prompt> end - prompt> end - EOC - close - end - - def test_incremental_search_on_not_last_line - start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("def abc\nend\n") - write("def def\nend\n") - write("\C-p\C-p\C-e") - write("\C-r") - write("a") - write("\n\n") - assert_screen(<<~'EOC') - prompt> def abc - prompt> end - => :abc - prompt> def def - prompt> end - => :def - prompt> def abc - prompt> end - => :abc - prompt> - EOC - close - end - - def test_bracket_newline_indent - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write("[\n") - write("1") - assert_screen(<<~EOC) - Multiline REPL. - prompt> [ - prompt> 1 - EOC - close - end - - def test_repeated_input_delete - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("a\C-h" * 4000) - assert_screen(<<~'EOC') - Multiline REPL. - prompt> - EOC - close - end - - def test_exit_with_ctrl_d - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - begin - write("\C-d") - close - rescue EOFError - # EOFError is raised when process terminated. - end - assert_screen(<<~EOC) - Multiline REPL. - prompt> - EOC - close - end - - def test_quoted_insert_intr_keys - omit if Reline.core.io_gate.win? - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write '"' - write "\C-v" - write "\C-c" - write "\C-v" - write "\C-z" - write "\C-v" - write "\C-\\" - write "\".bytes\n" - assert_screen(<<~EOC) - Multiline REPL. - prompt> "^C^Z^\\\".bytes - => [3, 26, 28] - prompt> - EOC - close - end - - def test_print_before_readline - code = <<~RUBY - puts 'Multiline REPL.' - 2.times do - print 'a' * 10 - Reline.readline '>' - end - RUBY - start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.') - write "x\n" - assert_screen(<<~EOC) - Multiline REPL. - >x - > - EOC - close - end - - def test_pre_input_hook_with_redisplay - code = <<~'RUBY' - puts 'Multiline REPL.' - Reline.pre_input_hook = -> do - Reline.insert_text 'abc' - Reline.redisplay # Reline doesn't need this but Readline requires calling redisplay - end - Reline.readline('prompt> ') - RUBY - start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.') - assert_screen(<<~EOC) - Multiline REPL. - prompt> abc - EOC - close - end - - def test_pre_input_hook_with_multiline_text_insert - # Frequently used pattern of pre_input_hook - code = <<~'RUBY' - puts 'Multiline REPL.' - Reline.pre_input_hook = -> do - Reline.insert_text "abc\nef" - end - Reline.readline('>') - RUBY - start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.') - write("\C-ad") - assert_screen(<<~EOC) - Multiline REPL. - >abc - def - EOC - close - end - - def test_thread_safe - start_terminal(6, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') - write("[Thread.new{Reline.readline'>'},Thread.new{Reline.readmultiline('>'){true}}].map(&:join).size\n") - write("exit\n") - write("exit\n") - write("42\n") - assert_screen(<<~EOC) - >exit - >exit - => 2 - prompt> 42 - => 42 - prompt> - EOC - close - end - - def test_user_defined_winch - omit if Reline.core.io_gate.win? - pidfile = Tempfile.create('pidfile') - rubyfile = Tempfile.create('rubyfile') - rubyfile.write <<~RUBY - File.write(#{pidfile.path.inspect}, Process.pid) - winch_called = false - Signal.trap(:WINCH, ->(_arg){ winch_called = true }) - p Reline.readline('>') - puts "winch: \#{winch_called}" - RUBY - rubyfile.close - - start_terminal(10, 50, %W{ruby -I#{@pwd}/lib -rreline #{rubyfile.path}}) - assert_screen(/^>/) - write 'a' - assert_screen(/^>a/) - pid = pidfile.tap(&:rewind).read.to_i - Process.kill(:WINCH, pid) unless pid.zero? - write "b\n" - assert_screen(/"ab"\nwinch: true/) - close - ensure - File.delete(rubyfile.path) if rubyfile - pidfile.close if pidfile - File.delete(pidfile.path) if pidfile - end - - def test_stop_continue - omit if Reline.core.io_gate.win? - pidfile = Tempfile.create('pidfile') - rubyfile = Tempfile.create('rubyfile') - rubyfile.write <<~RUBY - File.write(#{pidfile.path.inspect}, Process.pid) - cont_called = false - Signal.trap(:CONT, ->(_arg){ cont_called = true }) - Reline.readmultiline('>'){|input| input.match?(/ghi/) } - puts "cont: \#{cont_called}" - RUBY - rubyfile.close - start_terminal(10, 50, ['bash']) - write "ruby -I#{@pwd}/lib -rreline #{rubyfile.path}\n" - assert_screen(/^>/) - write "abc\ndef\nhi" - pid = pidfile.tap(&:rewind).read.to_i - Process.kill(:STOP, pid) unless pid.zero? - write "fg\n" - assert_screen(/fg\n.*>/m) - write "\ebg" - assert_screen(/>abc\n>def\n>ghi\n/) - write "\n" - assert_screen(/cont: true/) - close - ensure - File.delete(rubyfile.path) if rubyfile - pidfile.close if pidfile - File.delete(pidfile.path) if pidfile - end - - def write_inputrc(content) - File.open(@inputrc_file, 'w') do |f| - f.write content - end - end - - def fold_multiline(str, width) - str.scan(/.{1,#{width}}/).each(&:rstrip!).join("\n") - end - end -rescue LoadError, NameError - # On Ruby repository, this test suit doesn't run because Ruby repo doesn't - # have the yamatanooroti gem. -end |