Skip to content

Commit

Permalink
Accessing an unregistered cop raises useful error
Browse files Browse the repository at this point in the history
Currently, when a test class includes `AssertOffense`, `AssertOffense#setup`
attempts to dynamically identify the Cop under test. If the Cop class
cannot be found, `#setup` exits early.

In these cases, the test cases continue to execute with a nil `@cop`
since it wasn't set in `#setup` as expected. When helpers such as
`#assert_offense` are used, they access `@cop` and the tests can fail
with cryptic messages such as:

```
NoMethodError: undefined method `[]=' for nil
```
  • Loading branch information
brandoncc committed Aug 12, 2024
1 parent 4d08365 commit f006b18
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 10 deletions.
18 changes: 10 additions & 8 deletions lib/rubocop/minitest/assert_offense.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ module Minitest
module AssertOffense
private

def setup
cop_name = self.class.to_s.delete_suffix('Test')
return unless RuboCop::Cop::Minitest.const_defined?(cop_name)
def cop
@cop ||= begin
cop_name = self.class.to_s.delete_suffix('Test')
raise "Cop not defined: #{cop_name}" unless RuboCop::Cop::Minitest.const_defined?(cop_name)

@cop = RuboCop::Cop::Minitest.const_get(cop_name).new(configuration)
RuboCop::Cop::Minitest.const_get(cop_name).new(configuration)
end
end

def format_offense(source, **replacements)
Expand All @@ -95,7 +97,7 @@ def format_offense(source, **replacements)
def assert_no_offenses(source, file = nil)
setup_assertion

offenses = inspect_source(source, @cop, file)
offenses = inspect_source(source, cop, file)

expected_annotations = RuboCop::RSpec::ExpectOffense::AnnotatedSource.parse(source)
actual_annotations = expected_annotations.with_offense_annotations(offenses)
Expand All @@ -106,7 +108,7 @@ def assert_no_offenses(source, file = nil)
def assert_offense(source, file = nil, **replacements)
setup_assertion

@cop.instance_variable_get(:@options)[:autocorrect] = true
cop.instance_variable_get(:@options)[:autocorrect] = true

source = format_offense(source, **replacements)
expected_annotations = RuboCop::RSpec::ExpectOffense::AnnotatedSource.parse(source)
Expand All @@ -116,7 +118,7 @@ def assert_offense(source, file = nil, **replacements)

@processed_source = parse_source!(expected_annotations.plain_source, file)

@offenses = _investigate(@cop, @processed_source)
@offenses = _investigate(cop, @processed_source)

actual_annotations = expected_annotations.with_offense_annotations(@offenses)

Expand Down Expand Up @@ -149,7 +151,7 @@ def assert_correction(correction, loop: true)
# Prepare for next loop
@processed_source = parse_source!(corrected_source, @processed_source.path)

_investigate(@cop, @processed_source)
_investigate(cop, @processed_source)
end

assert_equal(correction, new_source)
Expand Down
22 changes: 22 additions & 0 deletions test/rubocop/cop/minitest/assert_offense_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require_relative '../../../test_helper'

class AssertOffenseTest
class CopNotDefinedTest < Minitest::Test
def test_correct_failure_is_raised_when_cop_is_not_defined
error = assert_raises RuntimeError do
assert_offense(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
assert_equal(nil, somestuff)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `assert_nil(somestuff)`.
end
end
RUBY
end

assert_includes error.message, 'Cop not defined'
end
end
end
4 changes: 2 additions & 2 deletions test/rubocop/cop/minitest/test_file_name_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class TestFileNameTest < Minitest::Test
def test_registers_offense_for_invalid_path
offenses = inspect_source(<<~RUBY, @cop, 'lib/foo.rb')
offenses = inspect_source(<<~RUBY, cop, 'lib/foo.rb')
class FooTest < Minitest::Test
end
RUBY
Expand All @@ -15,7 +15,7 @@ class FooTest < Minitest::Test
end

def test_registers_offense_for_namespaced_invalid_path
offenses = inspect_source(<<~RUBY, @cop, 'lib/foo/bar.rb')
offenses = inspect_source(<<~RUBY, cop, 'lib/foo/bar.rb')
module Foo
class BarTest < Minitest::Test
end
Expand Down

0 comments on commit f006b18

Please sign in to comment.