Skip to content

Commit

Permalink
Merge pull request #52 from owst/add_id_sequence_cop
Browse files Browse the repository at this point in the history
Add ` FactoryBot/IdSequence` cop
  • Loading branch information
ydah authored Sep 18, 2023
2 parents 9f74ec3 + 832bb0f commit 8e74bc1
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Fix a false positive for `FactoryBot/AssociationStyle` when `association` is called in trait block and column name is keyword. ([@ydah])
- Fix a false positive for `FactoryBot/AssociationStyle` when `EnforcedStyle: Explicit` and using trait within trait. ([@ydah])
- Change `FactoryBot/AssociationStyle`, `FactoryBot/AttributeDefinedStatically`, `FactoryBot/CreateList` and `FactoryBot/FactoryClassName` to work with minitest style directory. ([@ydah])
- Add `FactoryBot/IdSequence` cop. ([@owst])

## 2.23.1 (2023-05-15)

Expand Down Expand Up @@ -79,6 +80,7 @@
[@liberatys]: https://github.com/Liberatys
[@morissetcl]: https://github.com/morissetcl
[@ngouy]: https://github.com/ngouy
[@owst]: https://github.com/owst
[@pirj]: https://github.com/pirj
[@r7kamura]: https://github.com/r7kamura
[@seanpdoyle]: https://github.com/seanpdoyle
Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ FactoryBot/FactoryNameStyle:
VersionChanged: '2.23'
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/FactoryNameStyle

FactoryBot/IdSequence:
Description: Do not create a FactoryBot sequence for an id column.
Enabled: pending
VersionAdded: "<<next>>"
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/IdSequence

FactoryBot/RedundantFactoryOption:
Description: Checks for redundant `factory` option.
Enabled: pending
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* xref:cops_factorybot.adoc#factorybotfactoryassociationwithstrategy[FactoryBot/FactoryAssociationWithStrategy]
* xref:cops_factorybot.adoc#factorybotfactoryclassname[FactoryBot/FactoryClassName]
* xref:cops_factorybot.adoc#factorybotfactorynamestyle[FactoryBot/FactoryNameStyle]
* xref:cops_factorybot.adoc#factorybotidsequence[FactoryBot/IdSequence]
* xref:cops_factorybot.adoc#factorybotredundantfactoryoption[FactoryBot/RedundantFactoryOption]
* xref:cops_factorybot.adoc#factorybotsyntaxmethods[FactoryBot/SyntaxMethods]

Expand Down
33 changes: 33 additions & 0 deletions docs/modules/ROOT/pages/cops_factorybot.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,39 @@ create(:user)

* https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/FactoryNameStyle

== FactoryBot/IdSequence

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Yes
| <<next>>
| -
|===

Do not create a FactoryBot sequence for an id column.

=== Examples

[source,ruby]
----
# bad - can lead to conflicts between FactoryBot and DB sequences
factory :foo do
sequence :id
end
# good - a non-id column
factory :foo do
sequence :some_non_id_column
end
----

=== References

* https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/IdSequence

== FactoryBot/RedundantFactoryOption

|===
Expand Down
41 changes: 41 additions & 0 deletions lib/rubocop/cop/factory_bot/id_sequence.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

module RuboCop
module Cop
module FactoryBot
# Do not create a FactoryBot sequence for an id column.
#
# @example
# # bad - can lead to conflicts between FactoryBot and DB sequences
# factory :foo do
# sequence :id
# end
#
# # good - a non-id column
# factory :foo do
# sequence :some_non_id_column
# end
#
class IdSequence < ::RuboCop::Cop::Base
extend AutoCorrector
include RangeHelp

MSG = 'Do not create a sequence for an id attribute'
RESTRICT_ON_SEND = %i[sequence].freeze

def on_send(node)
return unless node.first_argument.value == :id

add_offense(node) do |corrector|
range_to_remove = range_by_whole_lines(
node.source_range,
include_final_newline: true
)

corrector.remove(range_to_remove)
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/factory_bot_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
require_relative 'factory_bot/factory_association_with_strategy'
require_relative 'factory_bot/factory_class_name'
require_relative 'factory_bot/factory_name_style'
require_relative 'factory_bot/id_sequence'
require_relative 'factory_bot/redundant_factory_option'
require_relative 'factory_bot/syntax_methods'
106 changes: 106 additions & 0 deletions spec/rubocop/cop/factory_bot/id_sequence_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::FactoryBot::IdSequence do
it 'registers an offense with no block' do
expect_offense(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
sequence :id
^^^^^^^^^^^^ Do not create a sequence for an id attribute
title { "A title" }
end
end
RUBY

expect_correction(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
title { "A title" }
end
end
RUBY
end

it 'registers an offense with a default value' do
expect_offense(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
sequence(:id, 1000)
^^^^^^^^^^^^^^^^^^^ Do not create a sequence for an id attribute
title { "A title" }
end
end
RUBY

expect_correction(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
title { "A title" }
end
end
RUBY
end

it 'registers an offense across multiple lines' do
expect_offense(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
sequence(
^^^^^^^^^ Do not create a sequence for an id attribute
:id,
1000
)
title { "A title" }
end
end
RUBY

expect_correction(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
title { "A title" }
end
end
RUBY
end

it 'registers an offense with a Enumerable of values' do
expect_offense(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
sequence(:id, (1..10).cycle)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not create a sequence for an id attribute
title { "A title" }
end
end
RUBY

expect_correction(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
title { "A title" }
end
end
RUBY
end

it 'does not register an offense for a non-id sequence' do
expect_no_offenses(<<~RUBY)
FactoryBot.define do
factory :post do
summary { "A summary" }
sequence :something_else
title { "A title" }
end
end
RUBY
end
end

0 comments on commit 8e74bc1

Please sign in to comment.