From 35ffb0313e9a87d52465a199a4a5ab9daf6069d6 Mon Sep 17 00:00:00 2001 From: r7kamura Date: Wed, 7 Feb 2024 08:45:50 +0900 Subject: [PATCH] Fix `RSpec/ExampleWording` autocorrection to correctly escape quotes on str node case --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/example_wording.rb | 23 +++-- .../rubocop/cop/rspec/example_wording_spec.rb | 90 +++++++++++++++++++ 3 files changed, 107 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e88b3368..e1dab9d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Support correcting `assert_not_equal` and `assert_not_nil` in `RSpec/Rails/MinitestAssertions`. ([@G-Rath]) - Fix a false positive for `RSpec/ExpectActual` when used with rspec-rails routing matchers. ([@naveg]) - Add new `RSpec/RepeatedSubjectCall` cop. ([@drcapulet]) +- Fix `RSpec/ExampleWording` in escaping and `%` string literals. ([@r7kamura]) ## 2.26.1 (2024-01-05) diff --git a/lib/rubocop/cop/rspec/example_wording.rb b/lib/rubocop/cop/rspec/example_wording.rb index a650183f2..b31cb5c31 100644 --- a/lib/rubocop/cop/rspec/example_wording.rb +++ b/lib/rubocop/cop/rspec/example_wording.rb @@ -92,18 +92,27 @@ def add_wording_offense(node, message) add_offense(docstring, message: message) do |corrector| next if node.heredoc? - corrector.replace(docstring, replacement_text(node)) + if node.str_type? && needs_escape?(node) + corrector.replace(node, replacement_text(node).inspect) + else + corrector.replace(docstring, replacement_text(node)) + end end end def docstring(node) - expr = node.source_range + if node.str_type? && !node.heredoc? + node.source_range.with( + begin_pos: node.loc.begin.end_pos, + end_pos: node.loc.end.begin_pos + ) + else + node.source_range.adjust(begin_pos: 1, end_pos: -1) + end + end - Parser::Source::Range.new( - expr.source_buffer, - expr.begin_pos + 1, - expr.end_pos - 1 - ) + def needs_escape?(node) + node.value.include?(node.loc.end.source) end def replacement_text(node) diff --git a/spec/rubocop/cop/rspec/example_wording_spec.rb b/spec/rubocop/cop/rspec/example_wording_spec.rb index 100ae719d..5955055dc 100644 --- a/spec/rubocop/cop/rspec/example_wording_spec.rb +++ b/spec/rubocop/cop/rspec/example_wording_spec.rb @@ -351,5 +351,95 @@ end RUBY end + + context "when message includes `'` in `'...'`" do + it 'corrects message with `String#inspect`' do + expect_offense(<<~'RUBY') + it 'should return foo\'s bar' do + ^^^^^^^^^^^^^^^^^^^^^^^^ Do not use should when describing your tests. + end + RUBY + + expect_correction(<<~RUBY) + it "returns foo's bar" do + end + RUBY + end + end + + context 'when message includes `"` in `"..."`' do + it 'corrects message with `String#inspect`' do + expect_offense(<<~'RUBY') + it "should return \"foo\"" do + ^^^^^^^^^^^^^^^^^^^^^ Do not use should when describing your tests. + end + RUBY + + expect_correction(<<~'RUBY') + it "returns \"foo\"" do + end + RUBY + end + end + + context 'when message includes `!` in `%!...!`' do + it 'corrects message with `String#inspect`' do + expect_offense(<<~'RUBY') + it %!should return foo\!! do + ^^^^^^^^^^^^^^^^^^^ Do not use should when describing your tests. + end + RUBY + + expect_correction(<<~RUBY) + it "returns foo!" do + end + RUBY + end + end + + context 'when message includes `)` in `%q(...)`' do + it 'corrects message with `String#inspect`' do + expect_offense(<<~RUBY) + it %q(should return foo (bar)) do + ^^^^^^^^^^^^^^^^^^^^^^^ Do not use should when describing your tests. + end + RUBY + + expect_correction(<<~RUBY) + it "returns foo (bar)" do + end + RUBY + end + end + + context 'when message includes `"` in `%q(...)`' do + it 'corrects message with direct substring replacement' do + expect_offense(<<~RUBY) + it %q(should return "foo") do + ^^^^^^^^^^^^^^^^^^^ Do not use should when describing your tests. + end + RUBY + + expect_correction(<<~RUBY) + it %q(returns "foo") do + end + RUBY + end + end + + context 'when message includes `"` and `)` in `%q(...)`' do + it 'corrects message with `String#inspect`' do + expect_offense(<<~RUBY) + it %q(should return "foo (bar)") do + ^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use should when describing your tests. + end + RUBY + + expect_correction(<<~'RUBY') + it "returns \"foo (bar)\"" do + end + RUBY + end + end end end