-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new
InternalAffairs/ExampleDescription
cop.
The cop checks for examples in rubocop's own RSpec suite where the description does not match the expectation (ie. `expects_offense` with "does not register an offense", etc.).
- Loading branch information
1 parent
e3ca0e3
commit c37b550
Showing
4 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module InternalAffairs | ||
# Checks that RSpec examples that use `expects_offense` | ||
# or `expects_no_offenses` do not have conflicting | ||
# descriptions. | ||
# | ||
# @example | ||
# # bad | ||
# it 'does not register an offense' do | ||
# expect_offense('...') | ||
# end | ||
# | ||
# it 'registers an offense' do | ||
# expect_no_offenses('...') | ||
# end | ||
# | ||
# # good | ||
# it 'registers an offense' do | ||
# expect_offense('...') | ||
# end | ||
# | ||
# it 'does not register an offense' do | ||
# expect_no_offenses('...') | ||
# end | ||
class ExampleDescription < Base | ||
class << self | ||
attr_accessor :descriptions | ||
end | ||
|
||
MSG = 'Description does not match use of `%<method_name>s`.' | ||
|
||
RESTRICT_ON_SEND = %i[ | ||
expect_offense | ||
expect_no_offenses | ||
expect_correction | ||
expect_no_corrections | ||
].to_set.freeze | ||
|
||
EXPECT_NO_OFFENSES_INCORRECT_DESCRIPTIONS = [ | ||
/^(adds|registers|reports|finds) (an? )?offense/, | ||
/^flags\b/ | ||
].freeze | ||
|
||
EXPECT_OFFENSE_INCORRECT_DESCRIPTIONS = [ | ||
/^(does not|doesn't) (register|find|flag|report)/, | ||
/^(does not|doesn't) add (a|an|any )?offense/ | ||
].freeze | ||
|
||
EXPECT_NO_CORRECTIONS_INCORRECT_DESCRIPTIONS = [ | ||
/^(auto[- ]?)?correct/ | ||
].freeze | ||
|
||
EXPECT_CORRECTION_INCORRECT_DESCRIPTIONS = [ | ||
/\b(does not|doesn't) (auto[- ]?)?correct/ | ||
].freeze | ||
|
||
def_node_matcher :offense_example?, <<~PATTERN | ||
(block | ||
(send _ {:it :specify} $_description) | ||
_args | ||
`(send nil? %RESTRICT_ON_SEND ...) | ||
) | ||
PATTERN | ||
|
||
def on_send(node) | ||
parent = node.each_ancestor(:block).first | ||
return unless parent && (description = offense_example?(parent)) | ||
|
||
method_name = node.method_name | ||
message = format(MSG, method_name: method_name) | ||
|
||
regexp_group = self.class.const_get("#{method_name}_incorrect_descriptions".upcase) | ||
check_description(description, regexp_group, message) | ||
end | ||
|
||
private | ||
|
||
def check_description(description, regexps, message) | ||
return unless regexps.any? { |regexp| regexp.match?(description.value) } | ||
|
||
add_offense(description, message: message) | ||
end | ||
end | ||
end | ||
end | ||
end |
124 changes: 124 additions & 0 deletions
124
spec/rubocop/cop/internal_affairs/example_description_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::InternalAffairs::ExampleDescription, :config do | ||
context 'with `expect_offense`' do | ||
it 'registers an offense when given an improper description' do | ||
expect_offense(<<~RUBY) | ||
it 'does not register an offense' do | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description does not match use of `expect_offense`. | ||
expect_offense('code') | ||
end | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when given a proper description' do | ||
expect_no_offenses(<<~RUBY) | ||
it 'finds an offense' do | ||
expect_offense('code') | ||
end | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when given an unexpected description' do | ||
expect_no_offenses(<<~RUBY) | ||
it 'foo bar baz' do | ||
expect_offense('code') | ||
end | ||
RUBY | ||
end | ||
end | ||
|
||
context 'with `expect_no_offenses`' do | ||
it 'registers an offense when given an improper description' do | ||
expect_offense(<<~RUBY) | ||
it 'registers an offense' do | ||
^^^^^^^^^^^^^^^^^^^^^^ Description does not match use of `expect_no_offenses`. | ||
expect_no_offenses('code') | ||
end | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when given a proper description' do | ||
expect_no_offenses(<<~RUBY) | ||
it 'does not flag' do | ||
expect_no_offense('code') | ||
end | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when given an unexpected description' do | ||
expect_no_offenses(<<~RUBY) | ||
it 'foo bar baz' do | ||
expect_offense('code') | ||
end | ||
RUBY | ||
end | ||
end | ||
|
||
context 'with `expect_correction`' do | ||
it 'registers an offense when given an improper description' do | ||
expect_offense(<<~RUBY) | ||
it 'does not auto-correct' do | ||
^^^^^^^^^^^^^^^^^^^^^^^ Description does not match use of `expect_correction`. | ||
expect_correction('code', source: 'new code') | ||
end | ||
RUBY | ||
end | ||
|
||
context 'in conjunction with expect_offense' do | ||
it 'registers an offense when given an improper description' do | ||
expect_offense(<<~RUBY) | ||
it 'registers an offense but does not auto-correct' do | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description does not match use of `expect_correction`. | ||
expect_offense('code') | ||
expect_correction('code') | ||
end | ||
RUBY | ||
end | ||
|
||
context 'when the description is invalid for both methods' do | ||
it 'registers an offense for the first method encountered' do | ||
expect_offense(<<~RUBY) | ||
it 'does not register an offense and does not auto-correct' do | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description does not match use of `expect_offense`. | ||
expect_offense('code') | ||
expect_correction('code') | ||
end | ||
RUBY | ||
end | ||
end | ||
end | ||
end | ||
|
||
context 'with `expect_no_corrections`' do | ||
it 'registers an offense when given an improper description' do | ||
expect_offense(<<~RUBY) | ||
it 'autocorrects' do | ||
^^^^^^^^^^^^^^ Description does not match use of `expect_no_corrections`. | ||
expect_no_corrections | ||
end | ||
RUBY | ||
end | ||
|
||
context 'in conjunction with expect_offense' do | ||
it 'registers an offense when given an improper description' do | ||
expect_offense(<<~RUBY) | ||
it 'auto-corrects' do | ||
^^^^^^^^^^^^^^^ Description does not match use of `expect_no_corrections`. | ||
expect_offense('code') | ||
expect_no_corrections | ||
end | ||
RUBY | ||
end | ||
end | ||
end | ||
|
||
context 'when not making an expectation on offenses' do | ||
it 'does not register an offense' do | ||
expect_no_offenses(<<~RUBY) | ||
it 'registers an offense' do | ||
end | ||
RUBY | ||
end | ||
end | ||
end |