1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

[ruby/irb] Use Exception#full_message to show backtrace in the correct order

[Bug #17466]

https://github.com/ruby/irb/commit/1c76845cca
This commit is contained in:
aycabta 2021-01-08 04:17:21 +09:00
parent ed3264d37a
commit 917050220a
3 changed files with 97 additions and 42 deletions

View file

@ -610,50 +610,44 @@ module IRB
irb_bug = false
end
if STDOUT.tty?
attr = ATTR_TTY
print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n"
else
attr = ATTR_PLAIN
end
messages = []
lasts = []
levels = 0
if exc.backtrace
count = 0
exc.backtrace.each do |m|
m = @context.workspace.filter_backtrace(m) or next unless irb_bug
count += 1
if attr == ATTR_TTY
m = sprintf("%9d: from %s", count, m)
order = nil
if '2.5.0' == RUBY_VERSION
# Exception#full_message doesn't have keyword arguments.
message = exc.full_message # the same of (highlight: true, order: bottom)
order = :bottom
elsif '2.5.1' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
if STDOUT.tty?
message = exc.full_message(order: :bottom)
order = :bottom
else
m = "\tfrom #{m}"
message = exc.full_message(order: :top)
order = :top
end
if messages.size < @context.back_trace_limit
messages.push(m)
elsif lasts.size < @context.back_trace_limit
lasts.push(m).shift
levels += 1
else # RUBY_VERSION < '2.5.0' || '3.0.0' <= RUBY_VERSION
message = exc.full_message(order: :top)
order = :top
end
message = convert_invalid_byte_sequence(message)
message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
case order
when :top
lines = m.split("\n")
when :bottom
lines = m.split("\n").reverse
end
end
end
if attr == ATTR_TTY
unless lasts.empty?
puts lasts.reverse
printf "... %d levels...\n", levels if levels > 0
end
puts messages.reverse
end
converted_exc_s = convert_invalid_byte_sequence(exc.to_s.dup)
m = converted_exc_s.split(/\n/)
print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n"
puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"}
if attr == ATTR_PLAIN
puts messages
unless lasts.empty?
puts lasts
printf "... %d levels...\n", levels if levels > 0
end
unless irb_bug
lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
if lines.size > @context.back_trace_limit
omit = lines.size - @context.back_trace_limit
lines[0..(@context.back_trace_limit - 1)]
lines << '... %d levels...' % omit
end
end
lines = lines.reverse if order == :bottom
lines.map{ |l| l + "\n" }.join
}
puts message
end
print "Maybe IRB bug!\n" if irb_bug
end

View file

@ -83,6 +83,7 @@ module TestIRB
end
def test_eval_input
skip if RUBY_ENGINE == 'truffleruby'
verbose, $VERBOSE = $VERBOSE, nil
input = TestInputMethod.new([
"raise 'Foo'\n",
@ -95,7 +96,7 @@ module TestIRB
irb.eval_input
end
assert_empty err
assert_pattern_list([:*, /RuntimeError \(.*Foo.*\).*\n/,
assert_pattern_list([:*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/,
:*, /#<RuntimeError: Foo>\n/,
:*, /0$/,
:*, /0$/,
@ -415,5 +416,65 @@ module TestIRB
assert_equal("=> abc\ndef\n",
out)
end
def test_eval_input_with_exception
skip 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
if '2.5.0' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
expected = [
:*, /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
expected = [
:*, /\(irb\):1:in `fuga': unhandled exception\n/,
:*, /\tfrom \(irb\):1:in `hoge'\n/,
:*, /\tfrom \(irb\):1:in `<main>'\n/,
]
end
assert_pattern_list(expected, out)
ensure
$VERBOSE = verbose
end
def test_eval_input_with_invalid_byte_sequence_exception
skip if RUBY_ENGINE == 'truffleruby'
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
if '2.5.0' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
expected = [
:*, /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
expected = [
:*, /\(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, out)
ensure
$VERBOSE = verbose
end
end
end

View file

@ -17,7 +17,7 @@ IRB
def test_raise_exception_with_invalid_byte_sequence
skip if RUBY_ENGINE == 'truffleruby'
bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<~IRB, /StandardError \(A\\xF3B\)/, [])
assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<~IRB, /A\\xF3B \(StandardError\)/, [])
raise StandardError, "A\\xf3B"
IRB
end