2019-04-25 08:16:21 -04:00
|
|
|
# frozen_string_literal: false
|
|
|
|
require 'test/unit'
|
|
|
|
require 'irb/color'
|
2019-05-25 11:01:51 -04:00
|
|
|
require 'rubygems'
|
2019-04-25 10:53:57 -04:00
|
|
|
require 'stringio'
|
2019-04-25 08:16:21 -04:00
|
|
|
|
|
|
|
module TestIRB
|
|
|
|
class TestColor < Test::Unit::TestCase
|
|
|
|
CLEAR = "\e[0m"
|
|
|
|
BOLD = "\e[1m"
|
|
|
|
UNDERLINE = "\e[4m"
|
2019-05-27 06:59:17 -04:00
|
|
|
REVERSE = "\e[7m"
|
2019-04-25 08:16:21 -04:00
|
|
|
RED = "\e[31m"
|
|
|
|
GREEN = "\e[32m"
|
2019-05-25 23:47:29 -04:00
|
|
|
YELLOW = "\e[33m"
|
2019-04-25 08:16:21 -04:00
|
|
|
BLUE = "\e[34m"
|
|
|
|
MAGENTA = "\e[35m"
|
|
|
|
CYAN = "\e[36m"
|
|
|
|
|
|
|
|
def test_colorize_code
|
2019-05-30 17:03:18 -04:00
|
|
|
# Common behaviors. Warn parser error, but do not warn compile error.
|
2019-06-12 11:29:45 -04:00
|
|
|
tests = {
|
2019-04-25 08:16:21 -04:00
|
|
|
"1" => "#{BLUE}#{BOLD}1#{CLEAR}",
|
|
|
|
"2.3" => "#{MAGENTA}#{BOLD}2.3#{CLEAR}",
|
2019-05-26 10:44:57 -04:00
|
|
|
"7r" => "#{BLUE}#{BOLD}7r#{CLEAR}",
|
2019-05-26 13:22:57 -04:00
|
|
|
"8i" => "#{BLUE}#{BOLD}8i#{CLEAR}",
|
2019-05-25 23:47:29 -04:00
|
|
|
"['foo', :bar]" => "[#{RED}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}'#{CLEAR}, #{YELLOW}:#{CLEAR}#{YELLOW}bar#{CLEAR}]",
|
2019-04-25 08:16:21 -04:00
|
|
|
"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}",
|
2019-05-26 13:29:20 -04:00
|
|
|
'erb = ERB.new("a#{nil}b", trim_mode: "-")' => "erb = #{BLUE}#{BOLD}#{UNDERLINE}ERB#{CLEAR}.new(#{RED}\"#{CLEAR}#{RED}a#{CLEAR}#{RED}\#{#{CLEAR}#{CYAN}#{BOLD}nil#{CLEAR}#{RED}}#{CLEAR}#{RED}b#{CLEAR}#{RED}\"#{CLEAR}, #{MAGENTA}trim_mode:#{CLEAR} #{RED}\"#{CLEAR}#{RED}-#{CLEAR}#{RED}\"#{CLEAR})",
|
2019-04-25 08:16:21 -04:00
|
|
|
"# comment" => "#{BLUE}#{BOLD}# comment#{CLEAR}",
|
2019-04-25 12:43:11 -04:00
|
|
|
"yield(hello)" => "#{GREEN}yield#{CLEAR}(hello)",
|
2019-04-28 07:18:44 -04:00
|
|
|
'"##@var]"' => "#{RED}\"#{CLEAR}#{RED}##{CLEAR}#{RED}##{CLEAR}@var#{RED}]#{CLEAR}#{RED}\"#{CLEAR}",
|
|
|
|
'"foo#{a} #{b}"' => "#{RED}\"#{CLEAR}#{RED}foo#{CLEAR}#{RED}\#{#{CLEAR}a#{RED}}#{CLEAR}#{RED} #{CLEAR}#{RED}\#{#{CLEAR}b#{RED}}#{CLEAR}#{RED}\"#{CLEAR}",
|
2019-04-28 07:33:12 -04:00
|
|
|
'/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e#{RED}}#{CLEAR}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}",
|
2019-05-25 10:48:58 -04:00
|
|
|
"'a\nb'" => "#{RED}'#{CLEAR}#{RED}a#{CLEAR}\n#{RED}b#{CLEAR}#{RED}'#{CLEAR}",
|
2019-06-03 11:29:53 -04:00
|
|
|
"[1]]]\u0013" => "[1]]]^S",
|
2019-05-25 11:01:51 -04:00
|
|
|
"%w[a b]" => "#{RED}%w[#{CLEAR}#{RED}a#{CLEAR} #{RED}b#{CLEAR}#{RED}]#{CLEAR}",
|
|
|
|
"%i[c d]" => "#{RED}%i[#{CLEAR}#{RED}c#{CLEAR} #{RED}d#{CLEAR}#{RED}]#{CLEAR}",
|
|
|
|
"{'a': 1}" => "{#{RED}'#{CLEAR}#{RED}a#{CLEAR}#{RED}':#{CLEAR} #{BLUE}#{BOLD}1#{CLEAR}}",
|
2019-05-25 23:47:29 -04:00
|
|
|
":Struct" => "#{YELLOW}:#{CLEAR}#{YELLOW}Struct#{CLEAR}",
|
2019-05-25 16:54:03 -04:00
|
|
|
'"#{}"' => "#{RED}\"#{CLEAR}#{RED}\#{#{CLEAR}#{RED}}#{CLEAR}#{RED}\"#{CLEAR}",
|
2019-05-25 23:47:29 -04:00
|
|
|
':"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}'#{CLEAR}#{RED}c#{CLEAR}#{RED}'#{CLEAR} + #{RED}\"#{CLEAR}#{RED}\#{#{CLEAR} #{YELLOW}:#{CLEAR}#{YELLOW}d#{CLEAR} #{RED}}#{CLEAR}#{RED}\"#{CLEAR} #{YELLOW}}#{CLEAR}#{YELLOW}e#{CLEAR}#{YELLOW}\"#{CLEAR}",
|
2019-05-26 01:29:16 -04:00
|
|
|
"[__FILE__, __LINE__]" => "[#{CYAN}#{BOLD}__FILE__#{CLEAR}, #{CYAN}#{BOLD}__LINE__#{CLEAR}]",
|
2019-05-26 00:39:11 -04:00
|
|
|
":self" => "#{YELLOW}:#{CLEAR}#{YELLOW}self#{CLEAR}",
|
|
|
|
":class" => "#{YELLOW}:#{CLEAR}#{YELLOW}class#{CLEAR}",
|
2019-05-26 01:32:28 -04:00
|
|
|
"[:end, 2]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}end#{CLEAR}, #{BLUE}#{BOLD}2#{CLEAR}]",
|
2019-05-26 00:39:11 -04:00
|
|
|
"[:>, 3]" => "[#{YELLOW}:#{CLEAR}#{YELLOW}>#{CLEAR}, #{BLUE}#{BOLD}3#{CLEAR}]",
|
|
|
|
":Hello ? world : nil" => "#{YELLOW}:#{CLEAR}#{YELLOW}Hello#{CLEAR} ? world : #{CYAN}#{BOLD}nil#{CLEAR}",
|
|
|
|
'raise "foo#{bar}baz"' => "raise #{RED}\"#{CLEAR}#{RED}foo#{CLEAR}#{RED}\#{#{CLEAR}bar#{RED}}#{CLEAR}#{RED}baz#{CLEAR}#{RED}\"#{CLEAR}",
|
|
|
|
'["#{obj.inspect}"]' => "[#{RED}\"#{CLEAR}#{RED}\#{#{CLEAR}obj.inspect#{RED}}#{CLEAR}#{RED}\"#{CLEAR}]",
|
|
|
|
'URI.parse "#{}"' => "#{BLUE}#{BOLD}#{UNDERLINE}URI#{CLEAR}.parse #{RED}\"#{CLEAR}#{RED}\#{#{CLEAR}#{RED}}#{CLEAR}#{RED}\"#{CLEAR}",
|
|
|
|
"begin\nrescue\nend" => "#{GREEN}begin#{CLEAR}\n#{GREEN}rescue#{CLEAR}\n#{GREEN}end#{CLEAR}",
|
|
|
|
"foo %w[bar]" => "foo #{RED}%w[#{CLEAR}#{RED}bar#{CLEAR}#{RED}]#{CLEAR}",
|
|
|
|
"foo %i[bar]" => "foo #{RED}%i[#{CLEAR}#{RED}bar#{CLEAR}#{RED}]#{CLEAR}",
|
2019-05-26 13:55:37 -04:00
|
|
|
"foo :@bar, baz, :@@qux, :$quux" => "foo #{YELLOW}:#{CLEAR}#{YELLOW}@bar#{CLEAR}, baz, #{YELLOW}:#{CLEAR}#{YELLOW}@@qux#{CLEAR}, #{YELLOW}:#{CLEAR}#{YELLOW}$quux#{CLEAR}",
|
2019-05-26 01:29:16 -04:00
|
|
|
"`echo`" => "#{RED}`#{CLEAR}#{RED}echo#{CLEAR}#{RED}`#{CLEAR}",
|
|
|
|
"\t" => "\t", # not ^I
|
|
|
|
"foo(*%W(bar))" => "foo(*#{RED}%W(#{CLEAR}#{RED}bar#{CLEAR}#{RED})#{CLEAR})",
|
2019-05-26 14:32:23 -04:00
|
|
|
"$stdout" => "#{GREEN}#{BOLD}$stdout#{CLEAR}",
|
2019-06-12 11:29:45 -04:00
|
|
|
}
|
2019-05-30 17:03:18 -04:00
|
|
|
|
2019-06-12 11:40:27 -04:00
|
|
|
# specific to Ruby 2.7+
|
2019-06-12 11:29:45 -04:00
|
|
|
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')
|
|
|
|
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}",
|
|
|
|
":@1" => "#{YELLOW}:#{CLEAR}#{RED}#{REVERSE}@1#{CLEAR}",
|
|
|
|
"@@1" => "#{RED}#{REVERSE}@@1#{CLEAR}",
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
tests.each do |code, result|
|
2019-06-12 11:40:27 -04:00
|
|
|
if colorize_code_supported?
|
2019-06-12 11:29:45 -04:00
|
|
|
actual = with_term { IRB::Color.colorize_code(code, complete: true) }
|
|
|
|
assert_equal(result, actual, "Case: colorize_code(#{code.dump}, complete: true)\nResult: #{humanized_literal(actual)}")
|
|
|
|
|
|
|
|
actual = with_term { IRB::Color.colorize_code(code, complete: false) }
|
|
|
|
assert_equal(result, actual, "Case: colorize_code(#{code.dump}, complete: false)\nResult: #{humanized_literal(actual)}")
|
2019-06-12 11:40:27 -04:00
|
|
|
else
|
|
|
|
actual = with_term { IRB::Color.colorize_code(code) }
|
|
|
|
assert_equal(code, actual)
|
2019-06-12 11:29:45 -04:00
|
|
|
end
|
2019-05-30 17:03:18 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_colorize_code_complete_true
|
2019-06-12 11:40:27 -04:00
|
|
|
unless complete_option_supported?
|
2019-06-12 11:29:45 -04:00
|
|
|
skip '`complete: true` is the same as `complete: false` in Ruby 2.6-'
|
|
|
|
end
|
2019-06-12 11:40:27 -04:00
|
|
|
|
2019-06-03 11:32:16 -04:00
|
|
|
# `complete: true` behaviors. Warn end-of-file.
|
2019-05-30 17:03:18 -04:00
|
|
|
{
|
2019-05-29 09:03:47 -04:00
|
|
|
"'foo' + 'bar" => "#{RED}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}'#{CLEAR} + #{RED}'#{CLEAR}#{RED}#{REVERSE}bar#{CLEAR}",
|
2019-06-12 02:30:07 -04:00
|
|
|
"('foo" => "(#{RED}'#{CLEAR}#{RED}#{REVERSE}foo#{CLEAR}",
|
2019-05-30 17:03:18 -04:00
|
|
|
}.each do |code, result|
|
|
|
|
actual = with_term { IRB::Color.colorize_code(code, complete: true) }
|
|
|
|
assert_equal(result, actual, "Case: colorize_code(#{code.dump}, complete: true)\nResult: #{humanized_literal(actual)}")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_colorize_code_complete_false
|
2019-06-03 11:32:16 -04:00
|
|
|
# `complete: false` behaviors. Do not warn end-of-file.
|
2019-05-30 17:03:18 -04:00
|
|
|
{
|
|
|
|
"'foo' + 'bar" => "#{RED}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}'#{CLEAR} + #{RED}'#{CLEAR}#{RED}bar#{CLEAR}",
|
2019-06-12 02:30:07 -04:00
|
|
|
"('foo" => "(#{RED}'#{CLEAR}#{RED}foo#{CLEAR}",
|
2019-04-28 07:33:12 -04:00
|
|
|
}.each do |code, result|
|
2019-06-12 11:40:27 -04:00
|
|
|
if colorize_code_supported?
|
2019-06-12 11:29:45 -04:00
|
|
|
actual = with_term { IRB::Color.colorize_code(code, complete: false) }
|
|
|
|
assert_equal(result, actual, "Case: colorize_code(#{code.dump}, complete: false)\nResult: #{humanized_literal(actual)}")
|
|
|
|
|
2019-06-12 11:40:27 -04:00
|
|
|
unless complete_option_supported?
|
2019-06-12 11:29:45 -04:00
|
|
|
actual = with_term { IRB::Color.colorize_code(code, complete: true) }
|
|
|
|
assert_equal(result, actual, "Case: colorize_code(#{code.dump}, complete: false)\nResult: #{humanized_literal(actual)}")
|
|
|
|
end
|
2019-06-12 11:40:27 -04:00
|
|
|
else
|
|
|
|
actual = with_term { IRB::Color.colorize_code(code) }
|
|
|
|
assert_equal(code, actual)
|
2019-06-12 11:29:45 -04:00
|
|
|
end
|
2019-04-25 08:16:21 -04:00
|
|
|
end
|
|
|
|
end
|
2019-04-25 08:36:48 -04:00
|
|
|
|
|
|
|
def test_inspect_colorable
|
|
|
|
{
|
|
|
|
1 => true,
|
|
|
|
2.3 => true,
|
|
|
|
['foo', :bar] => true,
|
|
|
|
{ a: 4 } => true,
|
2019-04-25 12:15:30 -04:00
|
|
|
/reg/ => true,
|
2019-04-28 08:51:35 -04:00
|
|
|
(1..3) => true,
|
2019-04-25 08:36:48 -04:00
|
|
|
Object.new => false,
|
2019-04-27 09:01:10 -04:00
|
|
|
Struct => true,
|
2019-04-27 13:02:30 -04:00
|
|
|
Test => true,
|
2019-04-25 08:36:48 -04:00
|
|
|
Struct.new(:a) => false,
|
|
|
|
Struct.new(:a).new(1) => false,
|
|
|
|
}.each do |object, result|
|
2019-04-27 09:01:10 -04:00
|
|
|
assert_equal(result, IRB::Color.inspect_colorable?(object), "Case: inspect_colorable?(#{object.inspect})")
|
2019-04-25 08:36:48 -04:00
|
|
|
end
|
|
|
|
end
|
2019-04-25 10:53:57 -04:00
|
|
|
|
|
|
|
private
|
|
|
|
|
2019-06-12 11:40:27 -04:00
|
|
|
# `#colorize_code` is supported only for Ruby 2.5+. It just returns the original code in 2.4-.
|
|
|
|
def colorize_code_supported?
|
|
|
|
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
|
|
|
|
end
|
|
|
|
|
|
|
|
# `complete: true` is the same as `complete: false` in Ruby 2.6-
|
|
|
|
def complete_option_supported?
|
2019-06-12 11:29:45 -04:00
|
|
|
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')
|
|
|
|
end
|
|
|
|
|
2019-04-25 10:53:57 -04:00
|
|
|
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
|
2019-05-25 10:48:58 -04:00
|
|
|
|
|
|
|
def humanized_literal(str)
|
|
|
|
str
|
|
|
|
.gsub(CLEAR, '@@@{CLEAR}')
|
|
|
|
.gsub(BOLD, '@@@{BOLD}')
|
|
|
|
.gsub(UNDERLINE, '@@@{UNDERLINE}')
|
2019-05-27 06:59:17 -04:00
|
|
|
.gsub(REVERSE, '@@@{REVERSE}')
|
2019-05-25 10:48:58 -04:00
|
|
|
.gsub(RED, '@@@{RED}')
|
|
|
|
.gsub(GREEN, '@@@{GREEN}')
|
2019-05-25 23:47:29 -04:00
|
|
|
.gsub(YELLOW, '@@@{YELLOW}')
|
2019-05-25 10:48:58 -04:00
|
|
|
.gsub(BLUE, '@@@{BLUE}')
|
|
|
|
.gsub(MAGENTA, '@@@{MAGENTA}')
|
|
|
|
.gsub(CYAN, '@@@{CYAN}')
|
|
|
|
.dump.gsub(/@@@/, '#')
|
|
|
|
end
|
2019-04-25 08:16:21 -04:00
|
|
|
end
|
|
|
|
end
|