From 1a6077d5bec47d0a09d9b970c473e18c3e179460 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Fri, 27 Dec 2024 23:09:58 +1100 Subject: [PATCH 1/6] Fix error backtrace formatting on Ruby 3.4+ Accomodate the new Ruby 3.4+ backtrace display format --- CHANGELOG.md | 1 + lib/cucumber/formatter/backtrace_filter.rb | 4 +++- lib/cucumber/glue/invoke_in_world.rb | 13 +++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35263233d2..219c081cd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/lib/cucumber/formatter/backtrace_filter.rb b/lib/cucumber/formatter/backtrace_filter.rb index 82c0628f73..d35d2b014e 100644 --- a/lib/cucumber/formatter/backtrace_filter.rb +++ b/lib/cucumber/formatter/backtrace_filter.rb @@ -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 diff --git a/lib/cucumber/glue/invoke_in_world.rb b/lib/cucumber/glue/invoke_in_world.rb index 6e957d1b88..534ae9d4d5 100644 --- a/lib/cucumber/glue/invoke_in_world.rb +++ b/lib/cucumber/glue/invoke_in_world.rb @@ -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 @@ -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 From 50e1d83efeb38813cef2336899a643e2104e301c Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Fri, 27 Dec 2024 23:10:05 +1100 Subject: [PATCH 2/6] CI: add Ruby 3.4 to the test matrix --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 84fb8b029f..51c25fd788 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -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 From 1677f720a74fb892b774c47594b78564b5a157a1 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Fri, 27 Dec 2024 23:10:07 +1100 Subject: [PATCH 3/6] Tests: support Ruby 3.4+ Hash#inspect --- .../extending_cucumber/custom_formatter.feature | 4 ++-- spec/cucumber/glue/proto_world_spec.rb | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/features/docs/extending_cucumber/custom_formatter.feature b/features/docs/extending_cucumber/custom_formatter.feature index a5728db932..187996c9da 100644 --- a/features/docs/extending_cucumber/custom_formatter.feature +++ b/features/docs/extending_cucumber/custom_formatter.feature @@ -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 @@ -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"} """ diff --git a/spec/cucumber/glue/proto_world_spec.rb b/spec/cucumber/glue/proto_world_spec.rb index c9f37b0730..41158cd5cc 100644 --- a/spec/cucumber/glue/proto_world_spec.rb +++ b/spec/cucumber/glue/proto_world_spec.rb @@ -72,8 +72,9 @@ module Glue end end - it 'attached the styring version on the object' do - expect(@out.string).to include '{:a=>1, :b=>2, :c=>3}' + it 'attached the string version on the object' do + expected_string = RUBY_VERSION >= '3.4' ? '{a: 1, b: 2, c: 3}' : '{:a=>1, :b=>2, :c=>3}' + expect(@out.string).to include expected_string end end @@ -92,11 +93,17 @@ module Glue end it 'logs each parameter independently' do + expected_hash = + if RUBY_VERSION >= '3.4' + '{subject: "monkey", verb: "eats", complement: "banana"}' + else + '{:subject=>"monkey", :verb=>"eats", :complement=>"banana"}' + end expect(@out.string).to include [ ' subject: monkey', ' verb: eats', ' complement: banana', - ' {:subject=>"monkey", :verb=>"eats", :complement=>"banana"}' + " #{expected_hash}" ].join("\n") end end From 1258deb25f0383d82814ace5087ab8e78a57a77e Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 7 Jan 2025 07:13:08 +1100 Subject: [PATCH 4/6] Tests: use deterministic object logging --- spec/cucumber/glue/proto_world_spec.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spec/cucumber/glue/proto_world_spec.rb b/spec/cucumber/glue/proto_world_spec.rb index 41158cd5cc..03e1b349c0 100644 --- a/spec/cucumber/glue/proto_world_spec.rb +++ b/spec/cucumber/glue/proto_world_spec.rb @@ -68,13 +68,16 @@ 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 + '' + end + log(object) end end - it 'attached the string version on the object' do - expected_string = RUBY_VERSION >= '3.4' ? '{a: 1, b: 2, c: 3}' : '{:a=>1, :b=>2, :c=>3}' - expect(@out.string).to include expected_string + it 'prints the stringified version of the object as a log message' do + expect(@out.string).to include('') end end From e880301d5c5fe1aeab63f4310512558a1684d5ea Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:13:21 +1100 Subject: [PATCH 5/6] =?UTF-8?q?Tests:=20avoid=20exercising=20Ruby=E2=80=99?= =?UTF-8?q?s=20Hash#inspect=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/cucumber/glue/proto_world_spec.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/spec/cucumber/glue/proto_world_spec.rb b/spec/cucumber/glue/proto_world_spec.rb index 03e1b349c0..3c1c89536e 100644 --- a/spec/cucumber/glue/proto_world_spec.rb +++ b/spec/cucumber/glue/proto_world_spec.rb @@ -91,22 +91,15 @@ def object.to_s define_steps do When('{word} {word} {word}') do |subject, verb, complement| - log "subject: #{subject}", "verb: #{verb}", "complement: #{complement}", subject: subject, verb: verb, complement: complement + log "subject: #{subject}", "verb: #{verb}", "complement: #{complement}" end end it 'logs each parameter independently' do - expected_hash = - if RUBY_VERSION >= '3.4' - '{subject: "monkey", verb: "eats", complement: "banana"}' - else - '{:subject=>"monkey", :verb=>"eats", :complement=>"banana"}' - end expect(@out.string).to include [ ' subject: monkey', ' verb: eats', - ' complement: banana', - " #{expected_hash}" + ' complement: banana' ].join("\n") end end From 039d0061c5f8230054bb2f74f68da8107a6c207a Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:19:19 +1100 Subject: [PATCH 6/6] Tests: avoid passing params unnecessarily --- spec/cucumber/glue/proto_world_spec.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/cucumber/glue/proto_world_spec.rb b/spec/cucumber/glue/proto_world_spec.rb index 3c1c89536e..1138bb5376 100644 --- a/spec/cucumber/glue/proto_world_spec.rb +++ b/spec/cucumber/glue/proto_world_spec.rb @@ -83,24 +83,24 @@ def object.to_s 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}" + 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' - ].join("\n") + it 'logs each entry independently' do + expect(@out.string).to include([ + ' entry one', + ' entry two', + ' entry three' + ].join("\n")) end end