rubocop-rspec 1.7.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +955 -79
- data/CODE_OF_CONDUCT.md +17 -0
- data/MIT-LICENSE.md +1 -2
- data/README.md +35 -35
- data/config/default.yml +940 -52
- data/config/obsoletion.yml +30 -0
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/any_instance.rb +10 -13
- data/lib/rubocop/cop/rspec/around_block.rb +97 -0
- data/lib/rubocop/cop/rspec/base.rb +26 -0
- data/lib/rubocop/cop/rspec/be.rb +39 -0
- data/lib/rubocop/cop/rspec/be_empty.rb +45 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +47 -0
- data/lib/rubocop/cop/rspec/be_eql.rb +18 -15
- data/lib/rubocop/cop/rspec/be_nil.rb +74 -0
- data/lib/rubocop/cop/rspec/before_after_all.rb +45 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +184 -0
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/contain_exactly.rb +56 -0
- data/lib/rubocop/cop/rspec/context_method.rb +57 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +117 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +52 -21
- data/lib/rubocop/cop/rspec/describe_method.rb +26 -11
- data/lib/rubocop/cop/rspec/describe_symbol.rb +37 -0
- data/lib/rubocop/cop/rspec/described_class.rb +181 -34
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +38 -0
- data/lib/rubocop/cop/rspec/dialect.rb +84 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +58 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +134 -47
- data/lib/rubocop/cop/rspec/empty_hook.rb +49 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +42 -0
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +40 -0
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +36 -0
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +38 -20
- data/lib/rubocop/cop/rspec/example_without_description.rb +98 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +117 -27
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +110 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +46 -20
- data/lib/rubocop/cop/rspec/expect_change.rb +86 -0
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +50 -0
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/expect_output.rb +50 -0
- data/lib/rubocop/cop/rspec/focus.rb +79 -25
- data/lib/rubocop/cop/rspec/hook_argument.rb +48 -36
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +81 -0
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +37 -0
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +68 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +100 -0
- data/lib/rubocop/cop/rspec/implicit_subject.rb +167 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +112 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +74 -0
- data/lib/rubocop/cop/rspec/instance_variable.rb +28 -14
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +49 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +74 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +57 -29
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +127 -0
- data/lib/rubocop/cop/rspec/let_before_examples.rb +101 -0
- data/lib/rubocop/cop/rspec/let_setup.rb +32 -16
- data/lib/rubocop/cop/rspec/match_array.rb +59 -0
- data/lib/rubocop/cop/rspec/message_chain.rb +10 -15
- data/lib/rubocop/cop/rspec/message_expectation.rb +12 -9
- data/lib/rubocop/cop/rspec/message_spies.rb +88 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +59 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
- data/lib/rubocop/cop/rspec/mixin/inside_example_group.rb +29 -0
- data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +63 -0
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +39 -0
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +14 -12
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +86 -26
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +146 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +97 -0
- data/lib/rubocop/cop/rspec/named_subject.rb +107 -27
- data/lib/rubocop/cop/rspec/nested_groups.rb +84 -47
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +102 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +30 -27
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +74 -0
- data/lib/rubocop/cop/rspec/pending.rb +80 -0
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +159 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +341 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +89 -0
- data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
- data/lib/rubocop/cop/rspec/receive_never.rb +41 -0
- data/lib/rubocop/cop/rspec/redundant_around.rb +65 -0
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_description.rb +98 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +53 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +100 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +96 -0
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +105 -0
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +169 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +59 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +92 -0
- data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
- data/lib/rubocop/cop/rspec/shared_examples.rb +125 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +93 -0
- data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +71 -0
- data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
- data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +176 -0
- data/lib/rubocop/cop/rspec/subject_declaration.rb +46 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +93 -74
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +67 -0
- data/lib/rubocop/cop/rspec/variable_definition.rb +77 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +68 -0
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +111 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +28 -14
- data/lib/rubocop/cop/rspec/void_expect.rb +60 -0
- data/lib/rubocop/cop/rspec/yield.rb +82 -0
- data/lib/rubocop/cop/rspec_cops.rb +112 -0
- data/lib/rubocop/rspec/align_let_brace.rb +63 -0
- data/lib/rubocop/rspec/concept.rb +33 -0
- data/lib/rubocop/rspec/config_formatter.rb +27 -4
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/corrector/move_node.rb +51 -0
- data/lib/rubocop/rspec/description_extractor.rb +60 -18
- data/lib/rubocop/rspec/example.rb +37 -0
- data/lib/rubocop/rspec/example_group.rb +67 -0
- data/lib/rubocop/rspec/hook.rb +79 -0
- data/lib/rubocop/rspec/inject.rb +3 -1
- data/lib/rubocop/rspec/language.rb +184 -41
- data/lib/rubocop/rspec/node.rb +19 -0
- 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/wording.rb +61 -19
- data/lib/rubocop/rspec.rb +6 -2
- data/lib/rubocop-rspec.rb +45 -34
- metadata +130 -195
- data/Gemfile +0 -13
- data/Rakefile +0 -48
- data/lib/rubocop/cop/rspec/file_path.rb +0 -83
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -16
- data/lib/rubocop/rspec/spec_only.rb +0 -61
- data/lib/rubocop/rspec/top_level_describe.rb +0 -61
- data/lib/rubocop/rspec/util.rb +0 -19
- data/rubocop-rspec.gemspec +0 -42
- data/spec/expect_violation/expectation_spec.rb +0 -85
- data/spec/project/changelog_spec.rb +0 -81
- data/spec/project/default_config_spec.rb +0 -52
- data/spec/project/project_requires_spec.rb +0 -8
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -30
- data/spec/rubocop/cop/rspec/be_eql_spec.rb +0 -59
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +0 -113
- data/spec/rubocop/cop/rspec/describe_method_spec.rb +0 -32
- data/spec/rubocop/cop/rspec/described_class_spec.rb +0 -219
- data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +0 -79
- data/spec/rubocop/cop/rspec/example_length_spec.rb +0 -117
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +0 -82
- data/spec/rubocop/cop/rspec/expect_actual_spec.rb +0 -136
- data/spec/rubocop/cop/rspec/file_path_spec.rb +0 -236
- data/spec/rubocop/cop/rspec/focus_spec.rb +0 -130
- data/spec/rubocop/cop/rspec/hook_argument_spec.rb +0 -189
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +0 -75
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +0 -54
- data/spec/rubocop/cop/rspec/let_setup_spec.rb +0 -66
- data/spec/rubocop/cop/rspec/message_chain_spec.rb +0 -21
- data/spec/rubocop/cop/rspec/message_expectation_spec.rb +0 -63
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -28
- data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +0 -84
- data/spec/rubocop/cop/rspec/named_subject_spec.rb +0 -62
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +0 -55
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -57
- data/spec/rubocop/cop/rspec/subject_stub_spec.rb +0 -183
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +0 -71
- data/spec/rubocop/rspec/config_formatter_spec.rb +0 -48
- data/spec/rubocop/rspec/description_extractor_spec.rb +0 -35
- data/spec/rubocop/rspec/language/selector_set_spec.rb +0 -29
- data/spec/rubocop/rspec/spec_only_spec.rb +0 -97
- data/spec/rubocop/rspec/util/one_spec.rb +0 -21
- data/spec/rubocop/rspec/wording_spec.rb +0 -44
- data/spec/shared/rspec_only_cop_behavior.rb +0 -68
- data/spec/spec_helper.rb +0 -41
- data/spec/support/expect_violation.rb +0 -166
@@ -0,0 +1,202 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Use consistent metadata style.
|
7
|
+
#
|
8
|
+
# This cop does not support autocorrection in the case of
|
9
|
+
# `EnforcedStyle: hash` where the trailing metadata type is ambiguous.
|
10
|
+
# (e.g. `describe 'Something', :a, b`)
|
11
|
+
#
|
12
|
+
# @example EnforcedStyle: symbol (default)
|
13
|
+
# # bad
|
14
|
+
# describe 'Something', a: true
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# describe 'Something', :a
|
18
|
+
#
|
19
|
+
# @example EnforcedStyle: hash
|
20
|
+
# # bad
|
21
|
+
# describe 'Something', :a
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# describe 'Something', a: true
|
25
|
+
class MetadataStyle < Base # rubocop:disable Metrics/ClassLength
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
include ConfigurableEnforcedStyle
|
29
|
+
include Metadata
|
30
|
+
include RangeHelp
|
31
|
+
|
32
|
+
# @!method extract_metadata_hash(node)
|
33
|
+
def_node_matcher :extract_metadata_hash, <<~PATTERN
|
34
|
+
(send _ _ _ ... $hash)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
# @!method match_boolean_metadata_pair?(node)
|
38
|
+
def_node_matcher :match_boolean_metadata_pair?, <<~PATTERN
|
39
|
+
(pair sym true)
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
# @!method match_ambiguous_trailing_metadata?(node)
|
43
|
+
def_node_matcher :match_ambiguous_trailing_metadata?, <<~PATTERN
|
44
|
+
(send _ _ _ ... !{hash sym})
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
def on_metadata(symbols, hash)
|
48
|
+
# RSpec example groups accept two string arguments. In such a case,
|
49
|
+
# the rspec_metadata matcher will interpret the second string
|
50
|
+
# argument as a metadata symbol.
|
51
|
+
symbols.shift if symbols.first&.str_type?
|
52
|
+
|
53
|
+
symbols.each do |symbol|
|
54
|
+
on_metadata_symbol(symbol)
|
55
|
+
end
|
56
|
+
|
57
|
+
return unless hash
|
58
|
+
|
59
|
+
hash.pairs.each do |pair|
|
60
|
+
on_metadata_pair(pair)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def autocorrect_pair(corrector, node)
|
67
|
+
remove_pair(corrector, node)
|
68
|
+
insert_symbol(corrector, node)
|
69
|
+
end
|
70
|
+
|
71
|
+
def autocorrect_symbol(corrector, node)
|
72
|
+
return if match_ambiguous_trailing_metadata?(node.parent)
|
73
|
+
|
74
|
+
remove_symbol(corrector, node)
|
75
|
+
insert_pair(corrector, node)
|
76
|
+
end
|
77
|
+
|
78
|
+
def bad_metadata_pair?(node)
|
79
|
+
style == :symbol && match_boolean_metadata_pair?(node)
|
80
|
+
end
|
81
|
+
|
82
|
+
def bad_metadata_symbol?(_node)
|
83
|
+
style == :hash
|
84
|
+
end
|
85
|
+
|
86
|
+
def format_symbol_to_pair_source(node)
|
87
|
+
"#{node.value}: true"
|
88
|
+
end
|
89
|
+
|
90
|
+
def insert_pair(corrector, node)
|
91
|
+
hash_node = extract_metadata_hash(node.parent)
|
92
|
+
if hash_node.nil?
|
93
|
+
insert_pair_as_last_argument(corrector, node)
|
94
|
+
elsif hash_node.pairs.any?
|
95
|
+
insert_pair_to_non_empty_hash_metadata(corrector, node, hash_node)
|
96
|
+
else
|
97
|
+
insert_pair_to_empty_hash_metadata(corrector, node, hash_node)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def insert_pair_as_last_argument(corrector, node)
|
102
|
+
corrector.insert_before(
|
103
|
+
node.parent.location.end || node.parent.source_range.with(
|
104
|
+
begin_pos: node.parent.source_range.end_pos
|
105
|
+
),
|
106
|
+
", #{format_symbol_to_pair_source(node)}"
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def insert_pair_to_empty_hash_metadata(corrector, node, hash_node)
|
111
|
+
corrector.insert_after(
|
112
|
+
hash_node.location.begin,
|
113
|
+
" #{format_symbol_to_pair_source(node)} "
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
def insert_pair_to_non_empty_hash_metadata(corrector, node, hash_node)
|
118
|
+
corrector.insert_after(
|
119
|
+
hash_node.children.last,
|
120
|
+
", #{format_symbol_to_pair_source(node)}"
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
def insert_symbol(corrector, node)
|
125
|
+
corrector.insert_after(
|
126
|
+
node.parent.left_sibling,
|
127
|
+
", #{node.key.value.inspect}"
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
def message_for_style
|
132
|
+
format(
|
133
|
+
'Use %<style>s style for metadata.',
|
134
|
+
style: style
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
def on_metadata_pair(node)
|
139
|
+
return unless bad_metadata_pair?(node)
|
140
|
+
|
141
|
+
add_offense(node, message: message_for_style) do |corrector|
|
142
|
+
autocorrect_pair(corrector, node)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def on_metadata_symbol(node)
|
147
|
+
return unless bad_metadata_symbol?(node)
|
148
|
+
|
149
|
+
add_offense(node, message: message_for_style) do |corrector|
|
150
|
+
autocorrect_symbol(corrector, node)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def remove_pair(corrector, node)
|
155
|
+
if !node.parent.braces? || node.left_siblings.any?
|
156
|
+
remove_pair_following(corrector, node)
|
157
|
+
elsif node.right_siblings.any?
|
158
|
+
remove_pair_preceding(corrector, node)
|
159
|
+
else
|
160
|
+
corrector.remove(node)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def remove_pair_following(corrector, node)
|
165
|
+
corrector.remove(
|
166
|
+
range_with_surrounding_comma(
|
167
|
+
range_with_surrounding_space(
|
168
|
+
node.source_range,
|
169
|
+
side: :left
|
170
|
+
),
|
171
|
+
:left
|
172
|
+
)
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
def remove_pair_preceding(corrector, node)
|
177
|
+
corrector.remove(
|
178
|
+
range_with_surrounding_space(
|
179
|
+
range_with_surrounding_comma(
|
180
|
+
node.source_range,
|
181
|
+
:right
|
182
|
+
),
|
183
|
+
side: :right
|
184
|
+
)
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
def remove_symbol(corrector, node)
|
189
|
+
corrector.remove(
|
190
|
+
range_with_surrounding_comma(
|
191
|
+
range_with_surrounding_space(
|
192
|
+
node.source_range,
|
193
|
+
side: :left
|
194
|
+
),
|
195
|
+
:left
|
196
|
+
)
|
197
|
+
)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks that the first argument to an example group is not empty.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# describe do
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# RSpec.describe do
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# describe TestedClass do
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# describe "A feature example" do
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class MissingExampleGroupArgument < Base
|
24
|
+
MSG = 'The first argument to `%<method>s` should not be empty.'
|
25
|
+
|
26
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
27
|
+
return unless example_group?(node)
|
28
|
+
return if node.send_node.arguments?
|
29
|
+
|
30
|
+
add_offense(node, message: format(MSG, method: node.method_name))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks if `.to`, `not_to` or `to_not` are used.
|
7
|
+
#
|
8
|
+
# The RSpec::Expectations::ExpectationTarget must use `to`, `not_to` or
|
9
|
+
# `to_not` to run. Therefore, this cop checks if other methods are used.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# expect(something).kind_of? Foo
|
14
|
+
# is_expected == 42
|
15
|
+
# expect{something}.eq? BarError
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# expect(something).to be_a Foo
|
19
|
+
# is_expected.to eq 42
|
20
|
+
# expect{something}.to raise_error BarError
|
21
|
+
#
|
22
|
+
class MissingExpectationTargetMethod < Base
|
23
|
+
MSG = 'Use `.to`, `.not_to` or `.to_not` to set an expectation.'
|
24
|
+
RESTRICT_ON_SEND = %i[expect is_expected].freeze
|
25
|
+
|
26
|
+
# @!method expect?(node)
|
27
|
+
def_node_matcher :expect?, <<~PATTERN
|
28
|
+
{
|
29
|
+
(send nil? :expect ...)
|
30
|
+
(send nil? :is_expected)
|
31
|
+
}
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
# @!method expect_block?(node)
|
35
|
+
def_node_matcher :expect_block?, <<~PATTERN
|
36
|
+
(block #expect? (args) _body)
|
37
|
+
PATTERN
|
38
|
+
|
39
|
+
# @!method expectation_without_runner?(node)
|
40
|
+
def_node_matcher :expectation_without_runner?, <<~PATTERN
|
41
|
+
(send {#expect? #expect_block?} !#Runners.all ...)
|
42
|
+
PATTERN
|
43
|
+
|
44
|
+
def on_send(node)
|
45
|
+
node = node.parent if node.parent&.block_type?
|
46
|
+
|
47
|
+
expectation_without_runner?(node.parent) do
|
48
|
+
add_offense(node.parent.loc.selector)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Help methods for working with nodes containing comments.
|
7
|
+
module CommentsHelp
|
8
|
+
include FinalEndLocation
|
9
|
+
|
10
|
+
def source_range_with_comment(node)
|
11
|
+
begin_pos = begin_pos_with_comment(node).begin_pos
|
12
|
+
end_pos = end_line_position(node).end_pos
|
13
|
+
|
14
|
+
Parser::Source::Range.new(buffer, begin_pos, end_pos)
|
15
|
+
end
|
16
|
+
|
17
|
+
def begin_pos_with_comment(node)
|
18
|
+
first_comment = processed_source.ast_with_comments[node].first
|
19
|
+
|
20
|
+
start_line_position(first_comment || node)
|
21
|
+
end
|
22
|
+
|
23
|
+
def start_line_position(node)
|
24
|
+
buffer.line_range(node.loc.line)
|
25
|
+
end
|
26
|
+
|
27
|
+
def end_line_position(node)
|
28
|
+
end_line = buffer.line_for_position(final_end_location(node).end_pos)
|
29
|
+
buffer.line_range(end_line)
|
30
|
+
end
|
31
|
+
|
32
|
+
def buffer
|
33
|
+
processed_source.buffer
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps determine the offending location if there is not an empty line
|
7
|
+
# following the node. Allows comments to follow directly after
|
8
|
+
# in the following cases.
|
9
|
+
# - `rubocop:enable` directive
|
10
|
+
# - followed by empty line(s)
|
11
|
+
module EmptyLineSeparation
|
12
|
+
include FinalEndLocation
|
13
|
+
include RangeHelp
|
14
|
+
|
15
|
+
def missing_separating_line_offense(node)
|
16
|
+
return if last_child?(node)
|
17
|
+
|
18
|
+
missing_separating_line(node) do |location|
|
19
|
+
msg = yield(node.method_name)
|
20
|
+
add_offense(location, message: msg) do |corrector|
|
21
|
+
corrector.insert_after(location.end, "\n")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def missing_separating_line(node)
|
27
|
+
line = final_end_line = final_end_location(node).line
|
28
|
+
while processed_source.line_with_comment?(line + 1)
|
29
|
+
line += 1
|
30
|
+
comment = processed_source.comment_at_line(line)
|
31
|
+
if DirectiveComment.new(comment).enabled?
|
32
|
+
enable_directive_line = line
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
return if processed_source[line].blank?
|
37
|
+
|
38
|
+
yield offending_loc(enable_directive_line || final_end_line)
|
39
|
+
end
|
40
|
+
|
41
|
+
def offending_loc(last_line)
|
42
|
+
offending_line = processed_source[last_line - 1]
|
43
|
+
|
44
|
+
content_length = offending_line.lstrip.length
|
45
|
+
start = offending_line.length - content_length
|
46
|
+
|
47
|
+
source_range(processed_source.buffer,
|
48
|
+
last_line, start, content_length)
|
49
|
+
end
|
50
|
+
|
51
|
+
def last_child?(node)
|
52
|
+
return true unless node.parent&.begin_type?
|
53
|
+
|
54
|
+
node.equal?(node.parent.children.last)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps find the true end location of nodes which might contain heredocs.
|
7
|
+
module FinalEndLocation
|
8
|
+
def final_end_location(start_node)
|
9
|
+
heredoc_endings =
|
10
|
+
start_node.each_node(:str, :dstr, :xstr)
|
11
|
+
.select(&:heredoc?)
|
12
|
+
.map { |node| node.loc.heredoc_end }
|
13
|
+
|
14
|
+
[start_node.loc.end, *heredoc_endings].max_by(&:line)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps you identify whether a given node
|
7
|
+
# is within an example group or not.
|
8
|
+
module InsideExampleGroup
|
9
|
+
private
|
10
|
+
|
11
|
+
def inside_example_group?(node)
|
12
|
+
return spec_group?(node) if example_group_root?(node)
|
13
|
+
|
14
|
+
root = node.ancestors.find { |parent| example_group_root?(parent) }
|
15
|
+
|
16
|
+
spec_group?(root)
|
17
|
+
end
|
18
|
+
|
19
|
+
def example_group_root?(node)
|
20
|
+
node.parent.nil? || example_group_root_with_siblings?(node.parent)
|
21
|
+
end
|
22
|
+
|
23
|
+
def example_group_root_with_siblings?(node)
|
24
|
+
node.begin_type? && node.parent.nil?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helper methods to location.
|
7
|
+
module LocationHelp
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# @param node [RuboCop::AST::SendNode]
|
11
|
+
# @return [Parser::Source::Range]
|
12
|
+
# @example
|
13
|
+
# foo 1, 2
|
14
|
+
# ^^^^^
|
15
|
+
def arguments_with_whitespace(node)
|
16
|
+
node.loc.selector.end.with(
|
17
|
+
end_pos: node.source_range.end_pos
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param node [RuboCop::AST::SendNode]
|
22
|
+
# @return [Parser::Source::Range]
|
23
|
+
# @example
|
24
|
+
# foo { bar }
|
25
|
+
# ^^^^^^^^
|
26
|
+
def block_with_whitespace(node)
|
27
|
+
return unless (parent = node.parent)
|
28
|
+
return unless parent.block_type?
|
29
|
+
|
30
|
+
node.source_range.end.with(
|
31
|
+
end_pos: parent.source_range.end_pos
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,63 @@
|
|
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} _ $...)
|
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 _ $...)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def on_block(node)
|
31
|
+
rspec_configure(node) do |block_var|
|
32
|
+
metadata_in_block(node, block_var) do |metadata_arguments|
|
33
|
+
on_metadata_arguments(metadata_arguments)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
rspec_metadata(node) do |metadata_arguments|
|
38
|
+
on_metadata_arguments(metadata_arguments)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias on_numblock on_block
|
42
|
+
|
43
|
+
def on_metadata(_symbols, _hash)
|
44
|
+
raise ::NotImplementedError
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def on_metadata_arguments(metadata_arguments)
|
50
|
+
*symbols, last = metadata_arguments
|
51
|
+
hash = nil
|
52
|
+
case last&.type
|
53
|
+
when :hash
|
54
|
+
hash = last
|
55
|
+
when :sym
|
56
|
+
symbols << last
|
57
|
+
end
|
58
|
+
on_metadata(symbols, hash)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps to find namespace of the node.
|
7
|
+
module Namespace
|
8
|
+
private
|
9
|
+
|
10
|
+
# @param node [RuboCop::AST::Node]
|
11
|
+
# @return [Array<String>]
|
12
|
+
# @example
|
13
|
+
# namespace(node) # => ['A', 'B', 'C']
|
14
|
+
def namespace(node)
|
15
|
+
node
|
16
|
+
.each_ancestor(:class, :module)
|
17
|
+
.reverse_each
|
18
|
+
.flat_map { |ancestor| ancestor.defined_module_name.split('::') }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps check offenses with variable definitions
|
7
|
+
module SkipOrPending
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
# @!method skipped_in_metadata?(node)
|
11
|
+
def_node_matcher :skipped_in_metadata?, <<~PATTERN
|
12
|
+
{
|
13
|
+
(send _ _ <(sym {:skip :pending}) ...>)
|
14
|
+
(send _ _ ... (hash <(pair (sym {:skip :pending}) { true str dstr }) ...>))
|
15
|
+
}
|
16
|
+
PATTERN
|
17
|
+
|
18
|
+
# @!method skip_or_pending_inside_block?(node)
|
19
|
+
# Match skip/pending statements inside a block (e.g. `context`)
|
20
|
+
#
|
21
|
+
# @example source that matches
|
22
|
+
# context 'when color is blue' do
|
23
|
+
# skip 'not implemented yet'
|
24
|
+
# pending 'not implemented yet'
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example source that does not match
|
28
|
+
# skip 'not implemented yet'
|
29
|
+
# pending 'not implemented yet'
|
30
|
+
#
|
31
|
+
# @param node [RuboCop::AST::Node]
|
32
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
33
|
+
def_node_matcher :skip_or_pending_inside_block?, <<~PATTERN
|
34
|
+
(block <(send nil? {:skip :pending} ...) ...>)
|
35
|
+
PATTERN
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helper methods for top level example group cops
|
7
|
+
module TopLevelGroup
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
def on_new_investigation
|
11
|
+
super
|
12
|
+
|
13
|
+
top_level_groups.each do |node|
|
14
|
+
on_top_level_example_group(node) if example_group?(node)
|
15
|
+
on_top_level_group(node)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def top_level_groups
|
20
|
+
@top_level_groups ||=
|
21
|
+
top_level_nodes(root_node).select { |n| spec_group?(n) }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Dummy methods to be overridden in the consumer
|
27
|
+
def on_top_level_example_group(_node); end
|
28
|
+
|
29
|
+
def on_top_level_group(_node); end
|
30
|
+
|
31
|
+
def top_level_group?(node)
|
32
|
+
top_level_groups.include?(node)
|
33
|
+
end
|
34
|
+
|
35
|
+
def top_level_nodes(node)
|
36
|
+
return [] if node.nil?
|
37
|
+
|
38
|
+
case node.type
|
39
|
+
when :begin
|
40
|
+
node.children
|
41
|
+
when :module, :class
|
42
|
+
top_level_nodes(node.body)
|
43
|
+
else
|
44
|
+
[node]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def root_node
|
49
|
+
processed_source.ast
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps check offenses with variable definitions
|
7
|
+
module Variable
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
Subjects = RuboCop::RSpec::Language::Subjects
|
11
|
+
Helpers = RuboCop::RSpec::Language::Helpers
|
12
|
+
|
13
|
+
# @!method variable_definition?(node)
|
14
|
+
def_node_matcher :variable_definition?, <<~PATTERN
|
15
|
+
(send nil? {#Subjects.all #Helpers.all}
|
16
|
+
$({sym str dsym dstr} ...) ...)
|
17
|
+
PATTERN
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|