From dbd87bb1c86531b63b324622ba1c0fc48fa9bcdf Mon Sep 17 00:00:00 2001
From: Christophe Bliard <christophe.bliard@trux.info>
Date: Thu, 8 Aug 2024 18:02:00 +0200
Subject: [PATCH] Fix false-negative and error for `RSpec/MetadataStyle`

When RSpec/MetadataStyle cop is used with `EnforcedStyle: hash`,
offenses must be registered only for metadata arguments being symbols.

It was previously producing an exception if a variable was used in the
metadata arguments (except if it was the last one).
---
 CHANGELOG.md                                  |  3 ++
 lib/rubocop/cop/rspec/metadata_style.rb       |  7 +---
 spec/rubocop/cop/rspec/metadata_style_spec.rb | 33 +++++++++++++++++++
 3 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53afa0ad8..3266b77bb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
 
 ## Master (Unreleased)
 
+- Fix false-negative and error for `RSpec/MetadataStyle` when non-literal args are used in metadata in `EnforceStyle: hash`. ([@cbliard])
+
 ## 3.0.4 (2024-08-05)
 
 - Fix false-negative for `UnspecifiedException` when matcher is chained. ([@r7kamura])
@@ -911,6 +913,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
 [@bquorning]: https://github.com/bquorning
 [@brentwheeldon]: https://github.com/BrentWheeldon
 [@brianhawley]: https://github.com/BrianHawley
+[@cbliard]: https://github.com/cbliard
 [@cfabianski]: https://github.com/cfabianski
 [@clupprich]: https://github.com/clupprich
 [@composerinteralia]: https://github.com/composerinteralia
diff --git a/lib/rubocop/cop/rspec/metadata_style.rb b/lib/rubocop/cop/rspec/metadata_style.rb
index bb9d4c628..23b2b91dd 100644
--- a/lib/rubocop/cop/rspec/metadata_style.rb
+++ b/lib/rubocop/cop/rspec/metadata_style.rb
@@ -45,13 +45,8 @@ class MetadataStyle < Base # rubocop:disable Metrics/ClassLength
         PATTERN
 
         def on_metadata(symbols, hash)
-          # RSpec example groups accept two string arguments. In such a case,
-          # the rspec_metadata matcher will interpret the second string
-          # argument as a metadata symbol.
-          symbols.shift if symbols.first&.str_type?
-
           symbols.each do |symbol|
-            on_metadata_symbol(symbol)
+            on_metadata_symbol(symbol) if symbol.sym_type?
           end
 
           return unless hash
diff --git a/spec/rubocop/cop/rspec/metadata_style_spec.rb b/spec/rubocop/cop/rspec/metadata_style_spec.rb
index 58e4a852a..810e3816a 100644
--- a/spec/rubocop/cop/rspec/metadata_style_spec.rb
+++ b/spec/rubocop/cop/rspec/metadata_style_spec.rb
@@ -94,6 +94,15 @@
       end
     end
 
+    context 'with non-literal metadata and symbol metadata' do
+      it 'registers no offense' do
+        expect_no_offenses(<<~RUBY)
+          describe 'Something', a, :b do
+          end
+        RUBY
+      end
+    end
+
     context 'with boolean keyword arguments metadata and symbol metadata' do
       it 'registers offense' do
         expect_offense(<<~RUBY)
@@ -243,6 +252,15 @@
       end
     end
 
+    context 'with 2 non-literal metadata' do
+      it 'registers no offense' do
+        expect_no_offenses(<<~RUBY)
+          describe 'Something', a, b do
+          end
+        RUBY
+      end
+    end
+
     context 'with symbol metadata after 2 string arguments' do
       it 'registers offense' do
         expect_offense(<<~RUBY)
@@ -258,6 +276,21 @@
       end
     end
 
+    context 'with symbol metadata after non-literal metadata' do
+      it 'registers offense' do
+        expect_offense(<<~RUBY)
+          describe 'Something', a, :b do
+                                   ^^ Use hash style for metadata.
+          end
+        RUBY
+
+        expect_correction(<<~RUBY)
+          describe 'Something', a, b: true do
+          end
+        RUBY
+      end
+    end
+
     context 'with symbol metadata with parentheses' do
       it 'registers offense' do
         expect_offense(<<~RUBY)