Skip to content

Fix error backtrace formatting on Ruby 3.4+ #1771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
ruby: ['3.0', '3.1', '3.2', '3.3']
ruby: ['3.0', '3.1', '3.2', '3.3', '3.4']
include:
- os: ubuntu-latest
ruby: jruby-9.4
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ that need to rely on procedural loading / reloading of files should use method i

### Fixed
- Fixed an issue where a change to one example in compatibility testing wasn't fully adhered to ([luke-hill](https://github.com/luke-hill))
- Fixed Ruby 3.4+ issue where error backtraces weren't being formatted. ([#1771](https://github.com/cucumber/cucumber-ruby/pull/1771) [orien](https://github.com/orien))

### Removed
- `StepDefinitionLight` associated methods. The class itself is present but deprecated
Expand Down
4 changes: 2 additions & 2 deletions features/docs/extending_cucumber/custom_formatter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Feature: Custom Formatter
def initialize(config, options)
@io = config.out_stream
config.on_event :test_run_finished do |event|
@io.print options.inspect
@io.print options.to_json
end
end
end
Expand All @@ -54,5 +54,5 @@ Feature: Custom Formatter
When I run `cucumber features/f.feature --format MyCustom::Formatter,foo=bar,one=two --publish-quiet`
Then it should pass with exactly:
"""
{"foo"=>"bar", "one"=>"two"}
{"foo":"bar","one":"two"}
"""
4 changes: 3 additions & 1 deletion lib/cucumber/formatter/backtrace_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ def exception

if ::ENV['CUCUMBER_TRUNCATE_OUTPUT']
# Strip off file locations
regexp = RUBY_VERSION >= '3.4' ? /(.*):in '/ : /(.*):in `/
filtered = filtered.map do |line|
line =~ /(.*):in `/ ? Regexp.last_match(1) : line
match = regexp.match(line)
match ? match[1] : line
end
end

Expand Down
13 changes: 11 additions & 2 deletions lib/cucumber/glue/invoke_in_world.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ def self.replace_instance_exec_invocation_line!(backtrace, instance_exec_invocat
return unless instance_exec_pos

replacement_line = instance_exec_pos + INSTANCE_EXEC_OFFSET
backtrace[replacement_line].gsub!(/`.*'/, "`#{pseudo_method}'") if pseudo_method
if pseudo_method
pattern = RUBY_VERSION >= '3.4' ? /'.*'/ : /`.*'/
backtrace[replacement_line].gsub!(pattern, "`#{pseudo_method}'")
end

depth = backtrace.count { |line| line == instance_exec_invocation_line }
end_pos = depth > 1 ? instance_exec_pos : -1
Expand Down Expand Up @@ -49,7 +52,13 @@ def self.cucumber_compatible_arity?(args, block)
def self.cucumber_run_with_backtrace_filtering(pseudo_method)
yield
rescue Exception => e
instance_exec_invocation_line = "#{__FILE__}:#{__LINE__ - 2}:in `cucumber_run_with_backtrace_filtering'"
yield_line_number = __LINE__ - 2
instance_exec_invocation_line =
if RUBY_VERSION >= '3.4'
"#{__FILE__}:#{yield_line_number}:in '#{name}.#{__method__}'"
else
"#{__FILE__}:#{yield_line_number}:in `#{__method__}'"
end
replace_instance_exec_invocation_line!((e.backtrace || []), instance_exec_invocation_line, pseudo_method)
raise e
end
Expand Down
33 changes: 18 additions & 15 deletions spec/cucumber/glue/proto_world_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,36 +68,39 @@ module Glue

define_steps do
When('an object is logged') do
log(a: 1, b: 2, c: 3)
object = Object.new
def object.to_s
'<test-object>'
end
log(object)
end
end

it 'attached the styring version on the object' do
expect(@out.string).to include '{:a=>1, :b=>2, :c=>3}'
it 'prints the stringified version of the object as a log message' do
expect(@out.string).to include('<test-object>')
end
end

describe 'when logging multiple items on one call' do
define_feature <<-FEATURE
Feature: Banana party
Feature: Logging multiple entries

Scenario: Monkey eats banana
When monkey eats banana
Scenario: Logging multiple entries
When logging multiple entries
FEATURE

define_steps do
When('{word} {word} {word}') do |subject, verb, complement|
log "subject: #{subject}", "verb: #{verb}", "complement: #{complement}", subject: subject, verb: verb, complement: complement
When('logging multiple entries') do
log 'entry one', 'entry two', 'entry three'
end
end

it 'logs each parameter independently' do
expect(@out.string).to include [
' subject: monkey',
' verb: eats',
' complement: banana',
' {:subject=>"monkey", :verb=>"eats", :complement=>"banana"}'
].join("\n")
it 'logs each entry independently' do
expect(@out.string).to include([
' entry one',
' entry two',
' entry three'
].join("\n"))
end
end

Expand Down
Loading