rubocop / rubocop-factory_bot

Code style checking for factory_bot files.
https://docs.rubocop.org/rubocop-factory_bot
MIT License
46 stars 13 forks source link

FactoryBot/IdSequence error occurred while cop was inspecting file #80

Closed taylorrf closed 9 months ago

taylorrf commented 1 year ago

Expected behavior

FactoryBot/IdSequence does not raise an error while inspecting spec/factories/sequences.rb

Actual behavior

Output for bundle exec rubocop spec/factories/sequences.rb --debug

For /private/var/www/my_project: configuration from /private/var/www/my_project/.rubocop.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-performance-1.19.0/config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-performance-1.19.0/config/default.yml
Default configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-rails-2.21.2/config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-rails-2.21.2/config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-capybara-2.19.0/config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-capybara-2.19.0/lib/../config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-factory_bot-2.24.0/config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-factory_bot-2.24.0/lib/../config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-rspec-2.24.1/config/default.yml
configuration from /Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-rspec-2.24.1/config/default.yml
Inheriting configuration from /private/var/www/my_project/.rubocop_todo.yml
Use parallel by default.
Skipping parallel inspection: only a single file needs inspection
Inspecting 1 file
Scanning /private/var/www/my_project/spec/factories/sequences.rb
An error occurred while FactoryBot/IdSequence cop was inspecting /private/var/www/my_project/spec/factories/sequences.rb:28:4.
undefined method `value' for s(:lvar, :name):RuboCop::AST::Node
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-factory_bot-2.24.0/lib/rubocop/cop/factory_bot/id_sequence.rb:27:in `on_send'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:143:in `public_send'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:143:in `block (2 levels) in trigger_restricted_cops'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:171:in `with_cop_error_handling'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:142:in `block in trigger_restricted_cops'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:141:in `each'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:141:in `trigger_restricted_cops'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:70:in `on_send'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-ast-1.29.0/lib/rubocop/ast/traversal.rb:154:in `on_block'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:71:in `on_block'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-ast-1.29.0/lib/rubocop/ast/traversal.rb:161:in `on_defs'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:71:in `on_defs'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-ast-1.29.0/lib/rubocop/ast/traversal.rb:137:in `block in on_dstr'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-ast-1.29.0/lib/rubocop/ast/traversal.rb:137:in `each'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-ast-1.29.0/lib/rubocop/ast/traversal.rb:137:in `on_dstr'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:71:in `on_begin'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-ast-1.29.0/lib/rubocop/ast/traversal.rb:158:in `on_block'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:71:in `on_block'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-ast-1.29.0/lib/rubocop/ast/traversal.rb:20:in `walk'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/commissioner.rb:87:in `investigate'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/team.rb:156:in `investigate_partial'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cop/team.rb:98:in `investigate'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:345:in `block in inspect_file'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:344:in `each'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:344:in `flat_map'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:344:in `inspect_file'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:287:in `block in do_inspection_loop'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:321:in `block in iterate_until_no_changes'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:314:in `loop'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:314:in `iterate_until_no_changes'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:283:in `do_inspection_loop'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:164:in `block in file_offenses'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:189:in `file_offense_cache'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:163:in `file_offenses'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:154:in `process_file'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:135:in `block in each_inspected_file'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:134:in `each'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:134:in `reduce'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:134:in `each_inspected_file'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:120:in `inspect_files'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/runner.rb:73:in `run'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli/command/execute_runner.rb:26:in `block in execute_runner'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli/command/execute_runner.rb:52:in `with_redirect'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli/command/execute_runner.rb:25:in `execute_runner'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli/command/execute_runner.rb:17:in `run'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli/command.rb:11:in `run'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli/environment.rb:18:in `run'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli.rb:118:in `run_command'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli.rb:125:in `execute_runners'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli.rb:51:in `block in run'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli.rb:77:in `profile_if_needed'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/lib/rubocop/cli.rb:43:in `run'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/exe/rubocop:19:in `block in <top (required)>'
/Users/taylorrf/.rvm/rubies/ruby-3.0.5/lib/ruby/3.0.0/benchmark.rb:308:in `realtime'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/gems/rubocop-1.56.3/exe/rubocop:19:in `<top (required)>'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/bin/rubocop:25:in `load'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/bin/rubocop:25:in `<main>'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/bin/ruby_executable_hooks:22:in `eval'
/Users/taylorrf/.rvm/gems/ruby-3.0.5@my_project/bin/ruby_executable_hooks:22:in `<main>'

Steps to reproduce the problem

bundle exec rubocop spec/factories/sequences.rb

1 error occurred:
An error occurred while FactoryBot/IdSequence cop was inspecting /home/circleci/my_project/spec/factories/sequences.rb:28:4.
Errors are usually caused by RuboCop bugs.

Mention the following information in the issue report:
1.56.3 (using Parser 3.2.2.4, rubocop-ast 1.29.0, running on ruby 3.0.5) [x86_64-linux]

RuboCop version

$ [bundle exec] rubocop -V
1.56.3 (using Parser 3.2.2.4, rubocop-ast 1.29.0, running on ruby 3.0.5) [x86_64-darwin22]
  - rubocop-performance 1.19.0
  - rubocop-rails 2.21.2
  - rubocop-rspec 2.24.1
pirj commented 1 year ago

Can you please share the code surrounding spec/factories/sequences.rb:28?

taylorrf commented 1 year ago

@pirj Sure, here's the relevant parts of the code surrounding spec/factories/sequences.rb:28:

27:  def self.formatted_sequence(name, digits: 6, separator: '-')
28:    sequence(name) { |n|
29:      formatted_identifier = _format_n(n, digits: digits, separator: separator)
30:      yield formatted_identifier
31:    }
32:  end
33:
34:   def self._format_n(n, digits: 6, separator: '-')
36:    format_string = "%0#{digits}d" # see Kernel#sprintf
37:    (format_string % n) \
38:      .reverse.scan(/\d{3}/).join(separator).reverse
39:  end
pirj commented 11 months ago

It’s a matter of adding a check here that node.first_argument.sym_type? and adding a couple of tests.

I’m uncertain how widespread dstr/str type arguments are and if it’s worth supporting that.

Will you be up to submit a PR, @taylorrf ?

sarambasich commented 10 months ago

Just to add, I am also experiencing this issue in our organization's project. The lines that crashes RuboCop (twice in fact) look like this:

model.collection.select do |li|
  (li.sequence == 0 || li.sequence.blank?) && (li.retry_number == 0 || li.retry_number.blank?)
end

This is written in a trait block. Curiously, there is no call to sequence in the factory for the li's type.

This occurs when running bundle exec rubocop --auto-gen-config from the terminal.

Here is the tail of the output from that command:

2 errors occurred:
An error occurred while FactoryBot/IdSequence cop was inspecting /.../spec/factories/[the_factory_file].rb:99:11.
An error occurred while FactoryBot/IdSequence cop was inspecting /.../spec/factories/[the_factory_file]:99:31.
Errors are usually caused by RuboCop bugs.
Please, report your problems to RuboCop's issue tracker.
https://github.com/rubocop/rubocop/issues

Mention the following information in the issue report:
1.58.0 (using Parser 3.2.2.4, rubocop-ast 1.30.0, running on ruby 3.0.6) [arm64-darwin22]

Also, here's the version information:

% bundle exec rubocop -V               
1.58.0 (using Parser 3.2.2.4, rubocop-ast 1.30.0, running on ruby 3.0.6) [arm64-darwin22]
  - rubocop-performance 1.19.1
  - rubocop-rails 2.22.2
  - rubocop-rake 0.6.0
  - rubocop-rspec 2.25.0
pirj commented 10 months ago

For the initial case it would be sufficient to add a check that the first_argument.sym_type? here https://github.com/rubocop/rubocop-factory_bot/blob/5a92242927b9d90386ccb97cc1f9888e2aa30f9d/lib/rubocop/cop/factory_bot/id_sequence.rb#L27

For the second - that there’s no explicit receiver.

It makes sense to add a node pattern matcher, as it would incorporate both of those checks.

Would anyone be interested in sending a PR provided any necessary support?