Skip to content

Commit

Permalink
Merge pull request #1337 from Earlopain/validation-error
Browse files Browse the repository at this point in the history
Fix an error for `Rails/Validation` when passing no arguments
  • Loading branch information
koic authored Aug 24, 2024
2 parents aa2bf3e + 5e2237a commit 6bc9b1c
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 188 deletions.
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
expect_no_offenses('validates :name')
end

described_class::RESTRICT_ON_SEND.each_with_index do |validation, number|
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

0 comments on commit 6bc9b1c

Please sign in to comment.