rubocop-rspec 2.14.2 → 2.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/config/default.yml +48 -29
- data/lib/rubocop/cop/rspec/be.rb +2 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +3 -0
- data/lib/rubocop/cop/rspec/be_eql.rb +3 -0
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +3 -3
- data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +3 -5
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +1 -1
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +58 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +2 -0
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +16 -9
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +9 -2
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +74 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +2 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/message_spies.rb +2 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +49 -0
- data/lib/rubocop/cop/rspec/named_subject.rb +81 -6
- data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +123 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +2 -0
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +5 -2
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_description.rb +25 -2
- data/lib/rubocop/cop/rspec/scattered_setup.rb +2 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +4 -35
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +2 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -0
- data/lib/rubocop/cop/rspec_cops.rb +3 -0
- data/lib/rubocop/rspec/config_formatter.rb +2 -2
- data/lib/rubocop/rspec/description_extractor.rb +5 -10
- data/lib/rubocop/rspec/language.rb +9 -3
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +29 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop-rspec.rb +18 -13
- metadata +7 -2
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helper methods to find RSpec metadata.
|
7
|
+
module Metadata
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
include RuboCop::RSpec::Language
|
11
|
+
|
12
|
+
# @!method rspec_metadata(node)
|
13
|
+
def_node_matcher :rspec_metadata, <<~PATTERN
|
14
|
+
(block
|
15
|
+
(send
|
16
|
+
#rspec? {#Examples.all #ExampleGroups.all #SharedGroups.all #Hooks.all} _ ${send str sym}* (hash $...)?)
|
17
|
+
...)
|
18
|
+
PATTERN
|
19
|
+
|
20
|
+
# @!method rspec_configure(node)
|
21
|
+
def_node_matcher :rspec_configure, <<~PATTERN
|
22
|
+
(block (send #rspec? :configure) (args (arg $_)) ...)
|
23
|
+
PATTERN
|
24
|
+
|
25
|
+
# @!method metadata_in_block(node)
|
26
|
+
def_node_search :metadata_in_block, <<~PATTERN
|
27
|
+
(send (lvar %) #Hooks.all _ ${send str sym}* (hash $...)?)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def on_block(node)
|
31
|
+
rspec_configure(node) do |block_var|
|
32
|
+
metadata_in_block(node, block_var) do |symbols, pairs|
|
33
|
+
on_metadata(symbols, pairs.flatten)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
rspec_metadata(node) do |symbols, pairs|
|
38
|
+
on_metadata(symbols, pairs.flatten)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias on_numblock on_block
|
42
|
+
|
43
|
+
def on_metadata(_symbols, _pairs)
|
44
|
+
raise ::NotImplementedError
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -12,11 +12,11 @@ module RuboCop
|
|
12
12
|
# should be the most important object in your tests so they deserve
|
13
13
|
# a descriptive name.
|
14
14
|
#
|
15
|
-
# This cop can be configured in your configuration using
|
16
|
-
# `IgnoreSharedExamples` which will not report offenses for implicit
|
15
|
+
# This cop can be configured in your configuration using `EnforcedStyle`,
|
16
|
+
# and `IgnoreSharedExamples` which will not report offenses for implicit
|
17
17
|
# subjects in shared example groups.
|
18
18
|
#
|
19
|
-
# @example
|
19
|
+
# @example `EnforcedStyle: always` (default)
|
20
20
|
# # bad
|
21
21
|
# RSpec.describe User do
|
22
22
|
# subject { described_class.new }
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
# end
|
28
28
|
#
|
29
29
|
# # good
|
30
|
-
# RSpec.describe
|
30
|
+
# RSpec.describe User do
|
31
31
|
# subject(:user) { described_class.new }
|
32
32
|
#
|
33
33
|
# it 'is valid' do
|
@@ -36,13 +36,49 @@ module RuboCop
|
|
36
36
|
# end
|
37
37
|
#
|
38
38
|
# # also good
|
39
|
-
# RSpec.describe
|
39
|
+
# RSpec.describe User do
|
40
|
+
# subject(:user) { described_class.new }
|
41
|
+
#
|
42
|
+
# it { is_expected.to be_valid }
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example `EnforcedStyle: named_only`
|
46
|
+
# # bad
|
47
|
+
# RSpec.describe User do
|
48
|
+
# subject(:user) { described_class.new }
|
49
|
+
#
|
50
|
+
# it 'is valid' do
|
51
|
+
# expect(subject.valid?).to be(true)
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# # good
|
56
|
+
# RSpec.describe User do
|
40
57
|
# subject(:user) { described_class.new }
|
41
58
|
#
|
59
|
+
# it 'is valid' do
|
60
|
+
# expect(user.valid?).to be(true)
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# # also good
|
65
|
+
# RSpec.describe User do
|
66
|
+
# subject { described_class.new }
|
67
|
+
#
|
42
68
|
# it { is_expected.to be_valid }
|
43
69
|
# end
|
44
70
|
#
|
71
|
+
# # acceptable
|
72
|
+
# RSpec.describe User do
|
73
|
+
# subject { described_class.new }
|
74
|
+
#
|
75
|
+
# it 'is valid' do
|
76
|
+
# expect(subject.valid?).to be(true)
|
77
|
+
# end
|
78
|
+
# end
|
45
79
|
class NamedSubject < Base
|
80
|
+
include ConfigurableEnforcedStyle
|
81
|
+
|
46
82
|
MSG = 'Name your test subject if you need to reference it explicitly.'
|
47
83
|
|
48
84
|
# @!method example_or_hook_block?(node)
|
@@ -62,14 +98,53 @@ module RuboCop
|
|
62
98
|
end
|
63
99
|
|
64
100
|
subject_usage(node) do |subject_node|
|
65
|
-
|
101
|
+
check_explicit_subject(subject_node)
|
66
102
|
end
|
67
103
|
end
|
68
104
|
|
105
|
+
private
|
106
|
+
|
69
107
|
def ignored_shared_example?(node)
|
70
108
|
cop_config['IgnoreSharedExamples'] &&
|
71
109
|
node.each_ancestor(:block).any?(&method(:shared_example?))
|
72
110
|
end
|
111
|
+
|
112
|
+
def check_explicit_subject(node)
|
113
|
+
return if allow_explicit_subject?(node)
|
114
|
+
|
115
|
+
add_offense(node.loc.selector)
|
116
|
+
end
|
117
|
+
|
118
|
+
def allow_explicit_subject?(node)
|
119
|
+
!always? && !named_only?(node)
|
120
|
+
end
|
121
|
+
|
122
|
+
def always?
|
123
|
+
style == :always
|
124
|
+
end
|
125
|
+
|
126
|
+
def named_only?(node)
|
127
|
+
style == :named_only &&
|
128
|
+
subject_definition_is_named?(node)
|
129
|
+
end
|
130
|
+
|
131
|
+
def subject_definition_is_named?(node)
|
132
|
+
subject = nearest_subject(node)
|
133
|
+
|
134
|
+
subject&.send_node&.arguments?
|
135
|
+
end
|
136
|
+
|
137
|
+
def nearest_subject(node)
|
138
|
+
node
|
139
|
+
.each_ancestor(:block)
|
140
|
+
.lazy
|
141
|
+
.map { |block_node| find_subject(block_node) }
|
142
|
+
.find(&:itself)
|
143
|
+
end
|
144
|
+
|
145
|
+
def find_subject(block_node)
|
146
|
+
block_node.body.child_nodes.find { |send_node| subject?(send_node) }
|
147
|
+
end
|
73
148
|
end
|
74
149
|
end
|
75
150
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for pending or skipped examples without reason.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# pending 'does something' do
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# it 'does something', :pending do
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# it 'does something' do
|
19
|
+
# pending
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# xdescribe 'something' do
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # bad
|
27
|
+
# skip 'does something' do
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # bad
|
31
|
+
# it 'does something', :skip do
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # bad
|
35
|
+
# it 'does something' do
|
36
|
+
# skip
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # bad
|
40
|
+
# it 'does something'
|
41
|
+
#
|
42
|
+
# # good
|
43
|
+
# it 'does something' do
|
44
|
+
# pending 'reason'
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # good
|
48
|
+
# it 'does something' do
|
49
|
+
# skip 'reason'
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # good
|
53
|
+
# it 'does something', pending: 'reason' do
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# it 'does something', skip: 'reason' do
|
58
|
+
# end
|
59
|
+
class PendingWithoutReason < Base
|
60
|
+
MSG = 'Give the reason for pending or skip.'
|
61
|
+
|
62
|
+
# @!method pending_by_example_method?(node)
|
63
|
+
def_node_matcher :pending_by_example_method?, block_pattern(<<~PATTERN)
|
64
|
+
#Examples.pending
|
65
|
+
PATTERN
|
66
|
+
|
67
|
+
# @!method pending_by_metadata_without_reason?(node)
|
68
|
+
def_node_matcher :pending_by_metadata_without_reason?, <<~PATTERN
|
69
|
+
(send #rspec? {#ExampleGroups.all #Examples.all} ... {<(sym :pending) ...> (hash <(pair (sym :pending) true) ...>)})
|
70
|
+
PATTERN
|
71
|
+
|
72
|
+
# @!method skipped_by_example_method?(node)
|
73
|
+
def_node_matcher :skipped_by_example_method?, block_pattern(<<~PATTERN)
|
74
|
+
#Examples.skipped
|
75
|
+
PATTERN
|
76
|
+
|
77
|
+
# @!method skipped_by_example_group_method?(node)
|
78
|
+
def_node_matcher(
|
79
|
+
:skipped_by_example_group_method?,
|
80
|
+
block_pattern(<<~PATTERN)
|
81
|
+
#ExampleGroups.skipped
|
82
|
+
PATTERN
|
83
|
+
)
|
84
|
+
|
85
|
+
# @!method skipped_by_metadata_without_reason?(node)
|
86
|
+
def_node_matcher :skipped_by_metadata_without_reason?, <<~PATTERN
|
87
|
+
(send #rspec? {#ExampleGroups.all #Examples.all} ... {<(sym :skip) ...> (hash <(pair (sym :skip) true) ...>)})
|
88
|
+
PATTERN
|
89
|
+
|
90
|
+
def on_send(node)
|
91
|
+
if pending_without_reason?(node)
|
92
|
+
add_offense(node, message: 'Give the reason for pending.')
|
93
|
+
elsif skipped_without_reason?(node)
|
94
|
+
add_offense(node, message: 'Give the reason for skip.')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def pending_by_pending_step_without_reason?(node)
|
101
|
+
node.method?(:pending) && node.first_argument.nil?
|
102
|
+
end
|
103
|
+
|
104
|
+
def pending_without_reason?(node)
|
105
|
+
pending_by_example_method?(node.block_node) ||
|
106
|
+
pending_by_metadata_without_reason?(node) ||
|
107
|
+
pending_by_pending_step_without_reason?(node)
|
108
|
+
end
|
109
|
+
|
110
|
+
def skipped_by_skip_step_without_reason?(node)
|
111
|
+
node.method?(:skip) && node.first_argument.nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
def skipped_without_reason?(node)
|
115
|
+
skipped_by_example_group_method?(node.block_node) ||
|
116
|
+
skipped_by_example_method?(node.block_node) ||
|
117
|
+
skipped_by_metadata_without_reason?(node) ||
|
118
|
+
skipped_by_skip_step_without_reason?(node)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -13,20 +13,23 @@ module RuboCop
|
|
13
13
|
# # good
|
14
14
|
# expect(response).to have_http_status(200)
|
15
15
|
#
|
16
|
-
class HaveHttpStatus < Base
|
16
|
+
class HaveHttpStatus < ::RuboCop::Cop::Base
|
17
17
|
extend AutoCorrector
|
18
18
|
|
19
19
|
MSG =
|
20
20
|
'Prefer `expect(response).%<to>s have_http_status(%<status>i)` ' \
|
21
21
|
'over `expect(response.status).%<to>s %<match>s`.'
|
22
22
|
|
23
|
+
RUNNERS = %i[to to_not not_to].to_set
|
24
|
+
RESTRICT_ON_SEND = RUNNERS
|
25
|
+
|
23
26
|
# @!method match_status(node)
|
24
27
|
def_node_matcher :match_status, <<-PATTERN
|
25
28
|
(send
|
26
29
|
(send nil? :expect
|
27
30
|
$(send (send nil? :response) :status)
|
28
31
|
)
|
29
|
-
|
32
|
+
$RUNNERS
|
30
33
|
$(send nil? {:be :eq :eql :equal} (int $_))
|
31
34
|
)
|
32
35
|
PATTERN
|
@@ -45,8 +45,12 @@ module RuboCop
|
|
45
45
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
46
46
|
return unless example_group?(node)
|
47
47
|
|
48
|
-
repeated_descriptions(node).each do |
|
49
|
-
add_offense(
|
48
|
+
repeated_descriptions(node).each do |description|
|
49
|
+
add_offense(description)
|
50
|
+
end
|
51
|
+
|
52
|
+
repeated_its(node).each do |its|
|
53
|
+
add_offense(its)
|
50
54
|
end
|
51
55
|
end
|
52
56
|
|
@@ -57,6 +61,7 @@ module RuboCop
|
|
57
61
|
grouped_examples =
|
58
62
|
RuboCop::RSpec::ExampleGroup.new(node)
|
59
63
|
.examples
|
64
|
+
.reject { |n| n.definition.method?(:its) }
|
60
65
|
.group_by { |example| example_signature(example) }
|
61
66
|
|
62
67
|
grouped_examples
|
@@ -66,9 +71,27 @@ module RuboCop
|
|
66
71
|
.map(&:definition)
|
67
72
|
end
|
68
73
|
|
74
|
+
def repeated_its(node)
|
75
|
+
grouped_its =
|
76
|
+
RuboCop::RSpec::ExampleGroup.new(node)
|
77
|
+
.examples
|
78
|
+
.select { |n| n.definition.method?(:its) }
|
79
|
+
.group_by { |example| its_signature(example) }
|
80
|
+
|
81
|
+
grouped_its
|
82
|
+
.select { |signatures, group| signatures.any? && group.size > 1 }
|
83
|
+
.values
|
84
|
+
.flatten
|
85
|
+
.map(&:to_node)
|
86
|
+
end
|
87
|
+
|
69
88
|
def example_signature(example)
|
70
89
|
[example.metadata, example.doc_string]
|
71
90
|
end
|
91
|
+
|
92
|
+
def its_signature(example)
|
93
|
+
[example.doc_string, example]
|
94
|
+
end
|
72
95
|
end
|
73
96
|
end
|
74
97
|
end
|
@@ -18,45 +18,12 @@ module RuboCop
|
|
18
18
|
#
|
19
19
|
class SortMetadata < Base
|
20
20
|
extend AutoCorrector
|
21
|
+
include Metadata
|
21
22
|
include RangeHelp
|
22
23
|
|
23
24
|
MSG = 'Sort metadata alphabetically.'
|
24
25
|
|
25
|
-
|
26
|
-
def_node_matcher :rspec_metadata, <<~PATTERN
|
27
|
-
(block
|
28
|
-
(send
|
29
|
-
#rspec? {#Examples.all #ExampleGroups.all #SharedGroups.all #Hooks.all} _ ${send str sym}* (hash $...)?)
|
30
|
-
...)
|
31
|
-
PATTERN
|
32
|
-
|
33
|
-
# @!method rspec_configure(node)
|
34
|
-
def_node_matcher :rspec_configure, <<~PATTERN
|
35
|
-
(block (send #rspec? :configure) (args (arg $_)) ...)
|
36
|
-
PATTERN
|
37
|
-
|
38
|
-
# @!method metadata_in_block(node)
|
39
|
-
def_node_search :metadata_in_block, <<~PATTERN
|
40
|
-
(send (lvar %) #Hooks.all _ ${send str sym}* (hash $...)?)
|
41
|
-
PATTERN
|
42
|
-
|
43
|
-
def on_block(node)
|
44
|
-
rspec_configure(node) do |block_var|
|
45
|
-
metadata_in_block(node, block_var) do |symbols, pairs|
|
46
|
-
investigate(symbols, pairs.flatten)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
rspec_metadata(node) do |symbols, pairs|
|
51
|
-
investigate(symbols, pairs.flatten)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
alias on_numblock on_block
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def investigate(symbols, pairs)
|
26
|
+
def on_metadata(symbols, pairs)
|
60
27
|
return if sorted?(symbols, pairs)
|
61
28
|
|
62
29
|
crime_scene = crime_scene(symbols, pairs)
|
@@ -65,6 +32,8 @@ module RuboCop
|
|
65
32
|
end
|
66
33
|
end
|
67
34
|
|
35
|
+
private
|
36
|
+
|
68
37
|
def crime_scene(symbols, pairs)
|
69
38
|
metadata = symbols + pairs
|
70
39
|
|
@@ -12,6 +12,7 @@ require_relative 'rspec/factory_bot/attribute_defined_statically'
|
|
12
12
|
require_relative 'rspec/factory_bot/consistent_parentheses_style'
|
13
13
|
require_relative 'rspec/factory_bot/create_list'
|
14
14
|
require_relative 'rspec/factory_bot/factory_class_name'
|
15
|
+
require_relative 'rspec/factory_bot/factory_name_style'
|
15
16
|
require_relative 'rspec/factory_bot/syntax_methods'
|
16
17
|
|
17
18
|
require_relative 'rspec/rails/avoid_setup_hook'
|
@@ -42,6 +43,7 @@ require_relative 'rspec/describe_symbol'
|
|
42
43
|
require_relative 'rspec/described_class'
|
43
44
|
require_relative 'rspec/described_class_module_wrapping'
|
44
45
|
require_relative 'rspec/dialect'
|
46
|
+
require_relative 'rspec/duplicated_metadata'
|
45
47
|
require_relative 'rspec/empty_example_group'
|
46
48
|
require_relative 'rspec/empty_hook'
|
47
49
|
require_relative 'rspec/empty_line_after_example'
|
@@ -87,6 +89,7 @@ require_relative 'rspec/no_expectation_example'
|
|
87
89
|
require_relative 'rspec/not_to_not'
|
88
90
|
require_relative 'rspec/overwriting_setup'
|
89
91
|
require_relative 'rspec/pending'
|
92
|
+
require_relative 'rspec/pending_without_reason'
|
90
93
|
require_relative 'rspec/predicate_matcher'
|
91
94
|
require_relative 'rspec/receive_counts'
|
92
95
|
require_relative 'rspec/receive_never'
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
EXTENSION_ROOT_DEPARTMENT = %r{^(RSpec/)}.freeze
|
10
10
|
SUBDEPARTMENTS = %(RSpec/Capybara RSpec/FactoryBot RSpec/Rails)
|
11
11
|
AMENDMENTS = %(Metrics/BlockLength)
|
12
|
-
COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/
|
12
|
+
COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/'
|
13
13
|
|
14
14
|
def initialize(config, descriptions)
|
15
15
|
@config = config
|
@@ -47,7 +47,7 @@ module RuboCop
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def reference(cop)
|
50
|
-
COP_DOC_BASE_URL + cop
|
50
|
+
COP_DOC_BASE_URL + cop
|
51
51
|
end
|
52
52
|
|
53
53
|
attr_reader :config, :descriptions
|
@@ -21,7 +21,8 @@ module RuboCop
|
|
21
21
|
|
22
22
|
# Decorator of a YARD code object for working with documented rspec cops
|
23
23
|
class CodeObject
|
24
|
-
|
24
|
+
RSPEC_COP_CLASS_NAME = 'RuboCop::Cop::RSpec::Base'
|
25
|
+
RUBOCOP_COP_CLASS_NAME = 'RuboCop::Cop::Base'
|
25
26
|
RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'
|
26
27
|
|
27
28
|
def initialize(yardoc)
|
@@ -32,10 +33,7 @@ module RuboCop
|
|
32
33
|
#
|
33
34
|
# @return [Boolean]
|
34
35
|
def rspec_cop?
|
35
|
-
|
36
|
-
rspec_cop_namespace? &&
|
37
|
-
cop_subclass? &&
|
38
|
-
!abstract?
|
36
|
+
cop_subclass? && !abstract? && rspec_cop_namespace?
|
39
37
|
end
|
40
38
|
|
41
39
|
# Configuration for the documented cop that would live in default.yml
|
@@ -55,10 +53,6 @@ module RuboCop
|
|
55
53
|
yardoc.docstring.split("\n\n").first.to_s
|
56
54
|
end
|
57
55
|
|
58
|
-
def class_documentation?
|
59
|
-
yardoc.type.equal?(:class)
|
60
|
-
end
|
61
|
-
|
62
56
|
def rspec_cop_namespace?
|
63
57
|
documented_constant.start_with?(RSPEC_NAMESPACE)
|
64
58
|
end
|
@@ -68,7 +62,8 @@ module RuboCop
|
|
68
62
|
end
|
69
63
|
|
70
64
|
def cop_subclass?
|
71
|
-
yardoc.superclass.path ==
|
65
|
+
yardoc.superclass.path == RSPEC_COP_CLASS_NAME ||
|
66
|
+
yardoc.superclass.path == RUBOCOP_COP_CLASS_NAME
|
72
67
|
end
|
73
68
|
|
74
69
|
def abstract?
|
@@ -135,8 +135,9 @@ module RuboCop
|
|
135
135
|
end
|
136
136
|
|
137
137
|
module HookScopes # :nodoc:
|
138
|
+
ALL = %i[each example context all suite].freeze
|
138
139
|
def self.all(element)
|
139
|
-
|
140
|
+
ALL.include?(element)
|
140
141
|
end
|
141
142
|
end
|
142
143
|
|
@@ -158,8 +159,13 @@ module RuboCop
|
|
158
159
|
end
|
159
160
|
|
160
161
|
module Runners # :nodoc:
|
161
|
-
|
162
|
-
|
162
|
+
ALL = %i[to to_not not_to].freeze
|
163
|
+
class << self
|
164
|
+
def all(element = nil)
|
165
|
+
return ALL if element.nil?
|
166
|
+
|
167
|
+
ALL.include?(element)
|
168
|
+
end
|
163
169
|
end
|
164
170
|
end
|
165
171
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_context 'with default RSpec/Language config' do
|
4
|
+
include_context 'config'
|
5
|
+
|
6
|
+
# Deep duplication is needed to prevent config leakage between examples
|
7
|
+
let(:other_cops) do
|
8
|
+
default_language = RuboCop::ConfigLoader
|
9
|
+
.default_configuration['RSpec']['Language']
|
10
|
+
default_include = RuboCop::ConfigLoader
|
11
|
+
.default_configuration['RSpec']['Include']
|
12
|
+
{ 'RSpec' =>
|
13
|
+
{
|
14
|
+
'Include' => default_include,
|
15
|
+
'Language' => deep_dup(default_language)
|
16
|
+
} }
|
17
|
+
end
|
18
|
+
|
19
|
+
def deep_dup(object)
|
20
|
+
case object
|
21
|
+
when Array
|
22
|
+
object.map { |item| deep_dup(item) }
|
23
|
+
when Hash
|
24
|
+
object.transform_values(&method(:deep_dup))
|
25
|
+
else
|
26
|
+
object # only collections undergo modifications and need duping
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|