Skip to content
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

Fix an error for Rails/Validation when passing no arguments #1337

Merged
merged 2 commits into from
Aug 24, 2024
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
1 change: 1 addition & 0 deletions changelog/fix_error_rails_validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#1337](https://github.com/rubocop/rubocop-rails/pull/1337): Fix an error for `Rails/Validation` when passing no arguments. ([@earlopain][])
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rails/validation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ class Validation < Base

def on_send(node)
return if node.receiver
return unless (last_argument = node.last_argument)

range = node.loc.selector

add_offense(range, message: message(node)) do |corrector|
last_argument = node.last_argument
return if !last_argument.literal? && !last_argument.splat_type? && !frozen_array_argument?(last_argument)

corrector.replace(range, 'validates')
Expand Down
329 changes: 142 additions & 187 deletions spec/rubocop/cop/rails/validation_spec.rb
Original file line number Diff line number Diff line change
@@ -1,225 +1,180 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Rails::Validation, :config do
it 'accepts new style validations' do
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this test, expect_correction would raise an InfiniteLoopError if this wouldn't pass

expect_no_offenses('validates :name')
end

described_class::RESTRICT_ON_SEND.each_with_index do |validation, number|
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed these tests, they are duplicated with the loop below.

it "registers an offense for #{validation}" do
offenses = inspect_source("#{validation} :name")
expect(offenses.first.message.include?(described_class::ALLOWLIST[number])).to be(true)
described_class::TYPES.each do |type|
it "registers an offense for with validates_#{type}_of" do
type = 'length' if type == 'size'
expect_offense(<<~RUBY, type: type)
validates_#{type}_of :full_name, :birth_date
^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`.
RUBY

expect_correction(<<~RUBY)
validates :full_name, :birth_date, #{type}: true
RUBY
end
end

describe '#autocorrect' do
shared_examples 'autocorrects' do
it 'autocorrects' do
expect(autocorrect_source(source)).to eq(autocorrected_source)
end
end
it "registers an offense for with validates_#{type}_of when method arguments are enclosed in parentheses" do
type = 'length' if type == 'size'
expect_offense(<<~RUBY, type: type)
validates_#{type}_of(:full_name, :birth_date)
^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`.
RUBY

shared_examples 'does not autocorrect' do
it 'does not autocorrect' do
expect(autocorrect_source(source)).to eq(source)
end
expect_correction(<<~RUBY)
validates(:full_name, :birth_date, #{type}: true)
RUBY
end

described_class::TYPES.each do |type|
context "with validates_#{type}_of" do
let(:autocorrected_source) do
type = 'length' if type == 'size'

"validates :full_name, :birth_date, #{type}: true"
end

let(:source) do
"validates_#{type}_of :full_name, :birth_date"
end

include_examples 'autocorrects'
end

context "with validates_#{type}_of when method arguments are enclosed in parentheses" do
let(:autocorrected_source) do
type = 'length' if type == 'size'

"validates(:full_name, :birth_date, #{type}: true)"
end

let(:source) do
"validates_#{type}_of(:full_name, :birth_date)"
end

include_examples 'autocorrects'
end

context "with validates_#{type}_of when attributes are specified with array literal" do
let(:autocorrected_source) do
type = 'length' if type == 'size'

"validates :full_name, :birth_date, #{type}: true"
end

let(:source) do
"validates_#{type}_of [:full_name, :birth_date]"
end

include_examples 'autocorrects'
end

context "with validates_#{type}_of when attributes are specified with frozen array literal" do
let(:autocorrected_source) do
type = 'length' if type == 'size'

"validates :full_name, :birth_date, #{type}: true"
end

let(:source) do
"validates_#{type}_of [:full_name, :birth_date].freeze"
end

include_examples 'autocorrects'
end

context "with validates_#{type}_of when attributes are specified with symbol array literal" do
let(:autocorrected_source) do
type = 'length' if type == 'size'

"validates :full_name, :birth_date, #{type}: true"
end

let(:source) do
"validates_#{type}_of %i[full_name birth_date]"
end

include_examples 'autocorrects'
end

context "with validates_#{type}_of when attributes are specified with frozen symbol array literal" do
let(:autocorrected_source) do
type = 'length' if type == 'size'
it "registers an offense for with validates_#{type}_of when attributes are specified with array literal" do
type = 'length' if type == 'size'
expect_offense(<<~RUBY, type: type)
validates_#{type}_of [:full_name, :birth_date]
^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`.
RUBY

"validates :full_name, :birth_date, #{type}: true"
end

let(:source) do
"validates_#{type}_of %i[full_name birth_date].freeze"
end

include_examples 'autocorrects'
end
expect_correction(<<~RUBY)
validates :full_name, :birth_date, #{type}: true
RUBY
end

context 'with single attribute name' do
let(:autocorrected_source) do
'validates :a, numericality: true'
end

let(:source) do
'validates_numericality_of :a'
end
it "registers an offense for with validates_#{type}_of when attributes are specified with frozen array literal" do
type = 'length' if type == 'size'
expect_offense(<<~RUBY, type: type)
validates_#{type}_of [:full_name, :birth_date].freeze
^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`.
RUBY

include_examples 'autocorrects'
expect_correction(<<~RUBY)
validates :full_name, :birth_date, #{type}: true
RUBY
end

context 'with multi attribute names' do
let(:autocorrected_source) do
'validates :a, :b, numericality: true'
end
it "registers an offense for with validates_#{type}_of when attributes are specified with symbol array literal" do
type = 'length' if type == 'size'
expect_offense(<<~RUBY, type: type)
validates_#{type}_of %i[full_name birth_date]
^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`.
RUBY

let(:source) do
'validates_numericality_of :a, :b'
end

include_examples 'autocorrects'
expect_correction(<<~RUBY)
validates :full_name, :birth_date, #{type}: true
RUBY
end

context 'with non-braced hash literal' do
let(:autocorrected_source) do
'validates :a, :b, numericality: { minimum: 1 }'
end

let(:source) do
'validates_numericality_of :a, :b, minimum: 1'
end

include_examples 'autocorrects'
it "registers an offense for with validates_#{type}_of when " \
'attributes are specified with frozen symbol array literal' do
type = 'length' if type == 'size'
expect_offense(<<~RUBY, type: type)
validates_#{type}_of %i[full_name birth_date].freeze
^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`.
RUBY

expect_correction(<<~RUBY)
validates :full_name, :birth_date, #{type}: true
RUBY
end
end

context 'with braced hash literal' do
let(:autocorrected_source) do
'validates :a, :b, numericality: { minimum: 1 }'
end
it 'registers an offense with single attribute name' do
expect_offense(<<~RUBY)
validates_numericality_of :a
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...]
RUBY

let(:source) do
'validates_numericality_of :a, :b, { minimum: 1 }'
end
expect_correction(<<~RUBY)
validates :a, numericality: true
RUBY
end

include_examples 'autocorrects'
end
it 'registers an offense with multi attribute names' do
expect_offense(<<~RUBY)
validates_numericality_of :a, :b
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...]
RUBY

context 'with a proc' do
let(:autocorrected_source) do
'validates :a, :b, comparison: { greater_than: -> { Time.zone.today } }'
end
expect_correction(<<~RUBY)
validates :a, :b, numericality: true
RUBY
end

let(:source) do
'validates_comparison_of :a, :b, greater_than: -> { Time.zone.today }'
end
it 'registers an offense with non-braced hash literal' do
expect_offense(<<~RUBY)
validates_numericality_of :a, :b, minimum: 1
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...]
RUBY

include_examples 'autocorrects'
end
expect_correction(<<~RUBY)
validates :a, :b, numericality: { minimum: 1 }
RUBY
end

context 'with splat' do
let(:autocorrected_source) do
'validates :a, *b, numericality: true'
end
it 'registers an offense with braced hash literal' do
expect_offense(<<~RUBY)
validates_numericality_of :a, :b, { minimum: 1 }
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...]
RUBY

let(:source) do
'validates_numericality_of :a, *b'
end
expect_correction(<<~RUBY)
validates :a, :b, numericality: { minimum: 1 }
RUBY
end

include_examples 'autocorrects'
end
it 'registers an offense with a proc' do
expect_offense(<<~RUBY)
validates_comparison_of :a, :b, greater_than: -> { Time.zone.today }
^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...]
RUBY

context 'with splat and options' do
let(:autocorrected_source) do
'validates :a, *b, :c, numericality: { minimum: 1 }'
end
expect_correction(<<~RUBY)
validates :a, :b, comparison: { greater_than: -> { Time.zone.today } }
RUBY
end

let(:source) do
'validates_numericality_of :a, *b, :c, minimum: 1'
end
it 'registers an offense with a splat' do
expect_offense(<<~RUBY)
validates_numericality_of :a, *b
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...]
RUBY

include_examples 'autocorrects'
end
expect_correction(<<~RUBY)
validates :a, *b, numericality: true
RUBY
end

context 'with trailing send node' do
let(:source) do
'validates_numericality_of :a, b'
end
it 'registers an offense with a splat and options' do
expect_offense(<<~RUBY)
validates_numericality_of :a, *b, :c, minimum: 1
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...]
RUBY

include_examples 'does not autocorrect'
end
expect_correction(<<~RUBY)
validates :a, *b, :c, numericality: { minimum: 1 }
RUBY
end

context 'with trailing constant' do
let(:source) do
'validates_numericality_of :a, B'
end
it 'registers no offense with trailing send node' do
expect_no_offenses(<<~RUBY)
validates_numericality_of :a, b
RUBY
end

include_examples 'does not autocorrect'
end
it 'registers no offense with trailing constant' do
expect_no_offenses(<<~RUBY)
validates_numericality_of :a, B
RUBY
end

context 'with trailing local variable' do
let(:source) do
<<~RUBY
b = { minimum: 1 }
validates_numericality_of :a, b
RUBY
end
it 'registers no offense with trailing local variable' do
expect_no_offenses(<<~RUBY)
b = { minimum: 1 }
validates_numericality_of :a, b
RUBY
end

include_examples 'does not autocorrect'
end
it 'registers no offense when no arguments are passed' do
expect_no_offenses(<<~RUBY)
validates_numericality_of
RUBY
end
end