rubocop-rspec 2.26.1 → 2.27.1
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 +4 -4
- data/CHANGELOG.md +19 -0
- data/config/default.yml +20 -2
- data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +27 -1
- data/lib/rubocop/cop/rspec/described_class.rb +28 -6
- data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
- data/lib/rubocop/cop/rspec/expect_actual.rb +5 -2
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -4
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/message_expectation.rb +0 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +10 -5
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +33 -9
- data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +314 -22
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +4 -2
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +124 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +1 -2
- data/lib/rubocop/cop/rspec_cops.rb +2 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 629669f9a1d9d41dae7bc62c630f3a6cdae80623d3213c8e79ac8eb207f79e59
|
4
|
+
data.tar.gz: 5005161c3684fcd8b794284bcaeedc50253a545d649be9e0e0a82958fdd125b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8af331d4b31697228397a1122cbe331223d3f040f44d2260e5148d73177df5ba08ae2aea1d481b27f698b5d59c9522d1c5f4c5e08e14b473a548de75ccf218c6
|
7
|
+
data.tar.gz: 0f86ea257bcd14e73c57b2e431f618e0959cf9dbeca6e22c4b75bd8d4945f670d8fdb65212ff12969b351b62c35f845ca28041d4b1b30627e7d64dda5932b365
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,23 @@
|
|
2
2
|
|
3
3
|
## Master (Unreleased)
|
4
4
|
|
5
|
+
## 2.27.1 (2024-03-03)
|
6
|
+
|
7
|
+
- Fix a false positive for `RSpec/RepeatedSubjectCall` when `subject.method_call`. ([@ydah])
|
8
|
+
- Add configuration option `OnlyStaticConstants` to `RSpec/DescribedClass`. ([@ydah])
|
9
|
+
|
10
|
+
## 2.27.0 (2024-03-01)
|
11
|
+
|
12
|
+
- Add new `RSpec/IsExpectedSpecify` cop. ([@ydah])
|
13
|
+
- Add new `RSpec/RepeatedSubjectCall` cop. ([@drcapulet])
|
14
|
+
- Add support for `assert_true`, `assert_false`, `assert_not_equal`, `assert_not_nil`, `*_empty`, `*_predicate`, `*_kind_of`, `*_in_delta`, `*_match`, `*_instance_of` and `*_includes` assertions in `RSpec/Rails/MinitestAssertions`. ([@ydah], [@G-Rath])
|
15
|
+
- Support asserts with messages in `Rspec/BeEmpty`. ([@G-Rath])
|
16
|
+
- Fix a false positive for `RSpec/ExpectActual` when used with rspec-rails routing matchers. ([@naveg])
|
17
|
+
- Add configuration option `ResponseMethods` to `RSpec/Rails/HaveHttpStatus`. ([@ydah])
|
18
|
+
- Fix a false negative for `RSpec/DescribedClass` when class with constant. ([@ydah])
|
19
|
+
- Fix a false positive for `RSpec/ExampleWithoutDescription` when `specify` with multi-line block and missing description. ([@ydah])
|
20
|
+
- Fix an incorrect autocorrect for `RSpec/ChangeByZero` when compound expectations with line break before `.by(0)`. ([@ydah])
|
21
|
+
|
5
22
|
## 2.26.1 (2024-01-05)
|
6
23
|
|
7
24
|
- Fix an error for `RSpec/SharedExamples` when using examples without argument. ([@ydah])
|
@@ -845,6 +862,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
845
862
|
[@deivid-rodriguez]: https://github.com/deivid-rodriguez
|
846
863
|
[@dgollahon]: https://github.com/dgollahon
|
847
864
|
[@dmitrytsepelev]: https://github.com/dmitrytsepelev
|
865
|
+
[@drcapulet]: https://github.com/drcapulet
|
848
866
|
[@drowze]: https://github.com/Drowze
|
849
867
|
[@dswij]: https://github.com/dswij
|
850
868
|
[@dvandersluis]: https://github.com/dvandersluis
|
@@ -892,6 +910,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
892
910
|
[@mockdeep]: https://github.com/mockdeep
|
893
911
|
[@mothonmars]: https://github.com/MothOnMars
|
894
912
|
[@mvz]: https://github.com/mvz
|
913
|
+
[@naveg]: https://github.com/naveg
|
895
914
|
[@nc-holodakg]: https://github.com/nc-holodakg
|
896
915
|
[@nevir]: https://github.com/nevir
|
897
916
|
[@ngouy]: https://github.com/ngouy
|
data/config/default.yml
CHANGED
@@ -283,9 +283,10 @@ RSpec/DescribedClass:
|
|
283
283
|
SupportedStyles:
|
284
284
|
- described_class
|
285
285
|
- explicit
|
286
|
+
OnlyStaticConstants: true
|
286
287
|
SafeAutoCorrect: false
|
287
288
|
VersionAdded: '1.0'
|
288
|
-
VersionChanged: '
|
289
|
+
VersionChanged: '2.27'
|
289
290
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass
|
290
291
|
|
291
292
|
RSpec/DescribedClassModuleWrapping:
|
@@ -548,6 +549,13 @@ RSpec/InstanceVariable:
|
|
548
549
|
StyleGuide: https://rspec.rubystyle.guide/#instance-variables
|
549
550
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable
|
550
551
|
|
552
|
+
RSpec/IsExpectedSpecify:
|
553
|
+
Description: Check for `specify` with `is_expected` and one-liner expectations.
|
554
|
+
Enabled: pending
|
555
|
+
VersionAdded: '2.27'
|
556
|
+
StyleGuide: https://rspec.rubystyle.guide/#it-and-specify
|
557
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IsExpectedSpecify
|
558
|
+
|
551
559
|
RSpec/ItBehavesLike:
|
552
560
|
Description: Checks that only one `it_behaves_like` style is used.
|
553
561
|
Enabled: true
|
@@ -813,6 +821,12 @@ RSpec/RepeatedIncludeExample:
|
|
813
821
|
VersionAdded: '1.44'
|
814
822
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedIncludeExample
|
815
823
|
|
824
|
+
RSpec/RepeatedSubjectCall:
|
825
|
+
Description: Checks for repeated calls to subject missing that it is memoized.
|
826
|
+
Enabled: pending
|
827
|
+
VersionAdded: '2.27'
|
828
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedSubjectCall
|
829
|
+
|
816
830
|
RSpec/ReturnFromStub:
|
817
831
|
Description: Checks for consistent style of stub's return setting.
|
818
832
|
Enabled: true
|
@@ -1126,8 +1140,12 @@ RSpec/Rails/AvoidSetupHook:
|
|
1126
1140
|
RSpec/Rails/HaveHttpStatus:
|
1127
1141
|
Description: Checks that tests use `have_http_status` instead of equality matchers.
|
1128
1142
|
Enabled: pending
|
1143
|
+
ResponseMethods:
|
1144
|
+
- response
|
1145
|
+
- last_response
|
1129
1146
|
SafeAutoCorrect: false
|
1130
1147
|
VersionAdded: '2.12'
|
1148
|
+
VersionChanged: '2.27'
|
1131
1149
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus
|
1132
1150
|
|
1133
1151
|
RSpec/Rails/HttpStatus:
|
@@ -1166,7 +1184,7 @@ RSpec/Rails/InferredSpecType:
|
|
1166
1184
|
views: view
|
1167
1185
|
|
1168
1186
|
RSpec/Rails/MinitestAssertions:
|
1169
|
-
Description: Check if using Minitest matchers.
|
1187
|
+
Description: Check if using Minitest-like matchers.
|
1170
1188
|
Enabled: pending
|
1171
1189
|
VersionAdded: '2.17'
|
1172
1190
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/MinitestAssertions
|
@@ -59,6 +59,8 @@ module RuboCop
|
|
59
59
|
#
|
60
60
|
class ChangeByZero < Base
|
61
61
|
extend AutoCorrector
|
62
|
+
include RangeHelp
|
63
|
+
|
62
64
|
MSG = 'Prefer `not_to change` over `to %<method>s.by(0)`.'
|
63
65
|
MSG_COMPOUND = 'Prefer %<preferred>s with compound expectations ' \
|
64
66
|
'over `%<method>s.by(0)`.'
|
@@ -140,8 +142,32 @@ module RuboCop
|
|
140
142
|
|
141
143
|
change_nodes(node) do |change_node|
|
142
144
|
corrector.replace(change_node.loc.selector, negated_matcher)
|
143
|
-
|
145
|
+
insert_operator(corrector, node, change_node)
|
146
|
+
remove_by_zero(corrector, node, change_node)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def insert_operator(corrector, node, change_node)
|
151
|
+
operator = node.right_siblings.first
|
152
|
+
return unless %i[& |].include?(operator)
|
153
|
+
|
154
|
+
corrector.insert_after(
|
155
|
+
replace_node(node, change_node), " #{operator}"
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
def replace_node(node, change_node)
|
160
|
+
expect_change_with_arguments(node) ? change_node : change_node.parent
|
161
|
+
end
|
162
|
+
|
163
|
+
def remove_by_zero(corrector, node, change_node)
|
164
|
+
range = node.loc.dot.with(end_pos: node.source_range.end_pos)
|
165
|
+
if change_node.loc.line == range.line
|
144
166
|
corrector.remove(range)
|
167
|
+
else
|
168
|
+
corrector.remove(
|
169
|
+
range_by_whole_lines(range, include_final_newline: true)
|
170
|
+
)
|
145
171
|
end
|
146
172
|
end
|
147
173
|
|
@@ -8,8 +8,10 @@ module RuboCop
|
|
8
8
|
# If the first argument of describe is a class, the class is exposed to
|
9
9
|
# each example via described_class.
|
10
10
|
#
|
11
|
-
# This cop can be configured using the `EnforcedStyle
|
12
|
-
# options.
|
11
|
+
# This cop can be configured using the `EnforcedStyle`, `SkipBlocks`
|
12
|
+
# and `OnlyStaticConstants` options.
|
13
|
+
# `OnlyStaticConstants` is only relevant when `EnforcedStyle` is
|
14
|
+
# `described_class`.
|
13
15
|
#
|
14
16
|
# @example `EnforcedStyle: described_class` (default)
|
15
17
|
# # bad
|
@@ -22,6 +24,18 @@ module RuboCop
|
|
22
24
|
# subject { described_class.do_something }
|
23
25
|
# end
|
24
26
|
#
|
27
|
+
# @example `OnlyStaticConstants: true` (default)
|
28
|
+
# # good
|
29
|
+
# describe MyClass do
|
30
|
+
# subject { MyClass::CONSTANT }
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# @example `OnlyStaticConstants: false`
|
34
|
+
# # bad
|
35
|
+
# describe MyClass do
|
36
|
+
# subject { MyClass::CONSTANT }
|
37
|
+
# end
|
38
|
+
#
|
25
39
|
# @example `EnforcedStyle: explicit`
|
26
40
|
# # bad
|
27
41
|
# describe MyClass do
|
@@ -54,7 +68,7 @@ module RuboCop
|
|
54
68
|
# end
|
55
69
|
# end
|
56
70
|
#
|
57
|
-
class DescribedClass < Base
|
71
|
+
class DescribedClass < Base # rubocop:disable Metrics/ClassLength
|
58
72
|
extend AutoCorrector
|
59
73
|
include ConfigurableEnforcedStyle
|
60
74
|
include Namespace
|
@@ -112,14 +126,17 @@ module RuboCop
|
|
112
126
|
|
113
127
|
def find_usage(node, &block)
|
114
128
|
yield(node) if offensive?(node)
|
115
|
-
|
116
|
-
return if scope_change?(node) || node.const_type?
|
129
|
+
return if scope_change?(node) || allowed?(node)
|
117
130
|
|
118
131
|
node.each_child_node do |child|
|
119
132
|
find_usage(child, &block)
|
120
133
|
end
|
121
134
|
end
|
122
135
|
|
136
|
+
def allowed?(node)
|
137
|
+
node.const_type? && only_static_constants?
|
138
|
+
end
|
139
|
+
|
123
140
|
def message(offense)
|
124
141
|
if style == :described_class
|
125
142
|
format(MSG, replacement: DESCRIBED_CLASS, src: offense)
|
@@ -139,6 +156,10 @@ module RuboCop
|
|
139
156
|
node.block_type? && !rspec_block?(node) && cop_config['SkipBlocks']
|
140
157
|
end
|
141
158
|
|
159
|
+
def only_static_constants?
|
160
|
+
cop_config.fetch('OnlyStaticConstants', true)
|
161
|
+
end
|
162
|
+
|
142
163
|
def offensive?(node)
|
143
164
|
if style == :described_class
|
144
165
|
offensive_described_class?(node)
|
@@ -194,7 +215,8 @@ module RuboCop
|
|
194
215
|
# const_name(s(:const, s(:const, nil, :M), :C)) # => [:M, :C]
|
195
216
|
# const_name(s(:const, s(:cbase), :C)) # => [nil, :C]
|
196
217
|
def const_name(node)
|
197
|
-
namespace
|
218
|
+
namespace = node.namespace
|
219
|
+
name = node.short_name
|
198
220
|
if !namespace
|
199
221
|
[name]
|
200
222
|
elsif namespace.const_type?
|
@@ -7,6 +7,7 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# RSpec allows for auto-generated example descriptions when there is no
|
9
9
|
# description provided or the description is an empty one.
|
10
|
+
# It is acceptable to use `specify` without a description
|
10
11
|
#
|
11
12
|
# This cop removes empty descriptions.
|
12
13
|
# It also defines whether auto-generated description is allowed, based
|
@@ -14,17 +15,24 @@ module RuboCop
|
|
14
15
|
#
|
15
16
|
# This cop can be configured using the `EnforcedStyle` option
|
16
17
|
#
|
18
|
+
# @example
|
19
|
+
# # always good
|
20
|
+
# specify do
|
21
|
+
# result = service.call
|
22
|
+
# expect(result).to be(true)
|
23
|
+
# end
|
24
|
+
#
|
17
25
|
# @example `EnforcedStyle: always_allow` (default)
|
18
26
|
# # bad
|
19
27
|
# it('') { is_expected.to be_good }
|
20
|
-
#
|
28
|
+
# specify '' do
|
21
29
|
# result = service.call
|
22
30
|
# expect(result).to be(true)
|
23
31
|
# end
|
24
32
|
#
|
25
33
|
# # good
|
26
34
|
# it { is_expected.to be_good }
|
27
|
-
#
|
35
|
+
# specify do
|
28
36
|
# result = service.call
|
29
37
|
# expect(result).to be(true)
|
30
38
|
# end
|
@@ -75,6 +83,7 @@ module RuboCop
|
|
75
83
|
def check_example_without_description(node)
|
76
84
|
return if node.arguments?
|
77
85
|
return unless disallow_empty_description?(node)
|
86
|
+
return if node.method?(:specify) && node.parent.multiline?
|
78
87
|
|
79
88
|
add_offense(node, message: MSG_ADD_DESCRIPTION)
|
80
89
|
end
|
@@ -50,7 +50,8 @@ module RuboCop
|
|
50
50
|
regexp
|
51
51
|
].freeze
|
52
52
|
|
53
|
-
|
53
|
+
SKIPPED_MATCHERS = %i[route_to be_routable].freeze
|
54
|
+
CORRECTABLE_MATCHERS = %i[eq eql equal be].freeze
|
54
55
|
|
55
56
|
# @!method expect_literal(node)
|
56
57
|
def_node_matcher :expect_literal, <<~PATTERN
|
@@ -66,8 +67,10 @@ module RuboCop
|
|
66
67
|
|
67
68
|
def on_send(node)
|
68
69
|
expect_literal(node) do |actual, matcher, expected|
|
70
|
+
next if SKIPPED_MATCHERS.include?(matcher)
|
71
|
+
|
69
72
|
add_offense(actual.source_range) do |corrector|
|
70
|
-
next unless
|
73
|
+
next unless CORRECTABLE_MATCHERS.include?(matcher)
|
71
74
|
next if literal?(expected)
|
72
75
|
|
73
76
|
swap(corrector, actual, expected)
|
@@ -22,10 +22,7 @@ module RuboCop
|
|
22
22
|
def on_gvasgn(node)
|
23
23
|
return unless inside_example_scope?(node)
|
24
24
|
|
25
|
-
|
26
|
-
variable_name, _rhs = *node
|
27
|
-
# rubocop:enable InternalAffairs/NodeDestructuring
|
28
|
-
name = variable_name[1..]
|
25
|
+
name = node.name[1..]
|
29
26
|
return unless name.eql?('stdout') || name.eql?('stderr')
|
30
27
|
|
31
28
|
add_offense(node.loc.name, message: format(MSG, name: name))
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Check for `specify` with `is_expected` and one-liner expectations.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# specify { is_expected.to be_truthy }
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# it { is_expected.to be_truthy }
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# specify do
|
17
|
+
# # ...
|
18
|
+
# end
|
19
|
+
# specify { expect(sqrt(4)).to eq(2) }
|
20
|
+
#
|
21
|
+
class IsExpectedSpecify < Base
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
RESTRICT_ON_SEND = %i[specify].freeze
|
25
|
+
IS_EXPECTED_METHODS = ::Set[:is_expected, :are_expected].freeze
|
26
|
+
MSG = 'Use `it` instead of `specify`.'
|
27
|
+
|
28
|
+
# @!method offense?(node)
|
29
|
+
def_node_matcher :offense?, <<~PATTERN
|
30
|
+
(block (send _ :specify) _ (send (send _ IS_EXPECTED_METHODS) ...))
|
31
|
+
PATTERN
|
32
|
+
|
33
|
+
def on_send(node)
|
34
|
+
block_node = node.parent
|
35
|
+
return unless block_node&.single_line? && offense?(block_node)
|
36
|
+
|
37
|
+
selector = node.loc.selector
|
38
|
+
add_offense(selector) do |corrector|
|
39
|
+
corrector.replace(selector, 'it')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -48,12 +48,17 @@ module RuboCop
|
|
48
48
|
# end
|
49
49
|
# end
|
50
50
|
#
|
51
|
-
# @example
|
52
|
-
# #
|
53
|
-
#
|
54
|
-
#
|
51
|
+
# @example `Max: 1` (default)
|
52
|
+
# # bad
|
53
|
+
# describe UserCreator do
|
54
|
+
# it 'builds a user' do
|
55
|
+
# expect(user.name).to eq("John")
|
56
|
+
# expect(user.age).to eq(22)
|
57
|
+
# end
|
58
|
+
# end
|
55
59
|
#
|
56
|
-
#
|
60
|
+
# @example `Max: 2`
|
61
|
+
# # good
|
57
62
|
# describe UserCreator do
|
58
63
|
# it 'builds a user' do
|
59
64
|
# expect(user.name).to eq("John")
|
@@ -6,20 +6,32 @@ module RuboCop
|
|
6
6
|
module Rails
|
7
7
|
# Checks that tests use `have_http_status` instead of equality matchers.
|
8
8
|
#
|
9
|
-
# @example
|
9
|
+
# @example ResponseMethods: ['response', 'last_response'] (default)
|
10
10
|
# # bad
|
11
11
|
# expect(response.status).to be(200)
|
12
|
-
# expect(
|
12
|
+
# expect(last_response.code).to eq("200")
|
13
13
|
#
|
14
14
|
# # good
|
15
15
|
# expect(response).to have_http_status(200)
|
16
|
+
# expect(last_response).to have_http_status(200)
|
17
|
+
#
|
18
|
+
# @example ResponseMethods: ['foo_response']
|
19
|
+
# # bad
|
20
|
+
# expect(foo_response.status).to be(200)
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# expect(foo_response).to have_http_status(200)
|
24
|
+
#
|
25
|
+
# # also good
|
26
|
+
# expect(response).to have_http_status(200)
|
27
|
+
# expect(last_response).to have_http_status(200)
|
16
28
|
#
|
17
29
|
class HaveHttpStatus < ::RuboCop::Cop::Base
|
18
30
|
extend AutoCorrector
|
19
31
|
|
20
32
|
MSG =
|
21
|
-
'Prefer `expect(response).%<to>s
|
22
|
-
'over `%<bad_code>s`.'
|
33
|
+
'Prefer `expect(%<response>s).%<to>s ' \
|
34
|
+
'have_http_status(%<status>s)` over `%<bad_code>s`.'
|
23
35
|
|
24
36
|
RUNNERS = %i[to to_not not_to].to_set
|
25
37
|
RESTRICT_ON_SEND = RUNNERS
|
@@ -28,26 +40,38 @@ module RuboCop
|
|
28
40
|
def_node_matcher :match_status, <<~PATTERN
|
29
41
|
(send
|
30
42
|
(send nil? :expect
|
31
|
-
$(send (send nil?
|
43
|
+
$(send $(send nil? #response_methods?) {:status :code})
|
32
44
|
)
|
33
45
|
$RUNNERS
|
34
46
|
$(send nil? {:be :eq :eql :equal} ({int str} $_))
|
35
47
|
)
|
36
48
|
PATTERN
|
37
49
|
|
38
|
-
def on_send(node)
|
39
|
-
match_status(node) do
|
50
|
+
def on_send(node) # rubocop:disable Metrics/MethodLength
|
51
|
+
match_status(node) do
|
52
|
+
|response_status, response_method, to, match, status|
|
40
53
|
return unless status.to_s.match?(/\A\d+\z/)
|
41
54
|
|
42
|
-
message = format(MSG,
|
55
|
+
message = format(MSG, response: response_method.method_name,
|
56
|
+
to: to, status: status,
|
43
57
|
bad_code: node.source)
|
44
58
|
add_offense(node, message: message) do |corrector|
|
45
|
-
corrector.replace(response_status,
|
59
|
+
corrector.replace(response_status, response_method.method_name)
|
46
60
|
corrector.replace(match.loc.selector, 'have_http_status')
|
47
61
|
corrector.replace(match.first_argument, status.to_s)
|
48
62
|
end
|
49
63
|
end
|
50
64
|
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def response_methods?(name)
|
69
|
+
response_methods.include?(name.to_s)
|
70
|
+
end
|
71
|
+
|
72
|
+
def response_methods
|
73
|
+
cop_config.fetch('ResponseMethods', [])
|
74
|
+
end
|
51
75
|
end
|
52
76
|
end
|
53
77
|
end
|
@@ -4,54 +4,346 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
6
|
module Rails
|
7
|
-
# Check if using Minitest matchers.
|
7
|
+
# Check if using Minitest-like matchers.
|
8
|
+
#
|
9
|
+
# Check the use of minitest-like matchers
|
10
|
+
# starting with `assert_` or `refute_`.
|
8
11
|
#
|
9
12
|
# @example
|
10
13
|
# # bad
|
11
14
|
# assert_equal(a, b)
|
12
15
|
# assert_equal a, b, "must be equal"
|
16
|
+
# assert_not_includes a, b
|
13
17
|
# refute_equal(a, b)
|
18
|
+
# assert_nil a
|
19
|
+
# refute_empty(b)
|
20
|
+
# assert_true(a)
|
21
|
+
# assert_false(a)
|
14
22
|
#
|
15
23
|
# # good
|
16
24
|
# expect(b).to eq(a)
|
17
25
|
# expect(b).to(eq(a), "must be equal")
|
26
|
+
# expect(a).not_to include(b)
|
18
27
|
# expect(b).not_to eq(a)
|
28
|
+
# expect(a).to eq(nil)
|
29
|
+
# expect(a).not_to be_empty
|
30
|
+
# expect(a).to be(true)
|
31
|
+
# expect(a).to be(false)
|
19
32
|
#
|
20
33
|
class MinitestAssertions < Base
|
21
34
|
extend AutoCorrector
|
22
35
|
|
36
|
+
# :nodoc:
|
37
|
+
class BasicAssertion
|
38
|
+
extend NodePattern::Macros
|
39
|
+
|
40
|
+
attr_reader :expected, :actual, :failure_message
|
41
|
+
|
42
|
+
def self.minitest_assertion
|
43
|
+
raise NotImplementedError
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(expected, actual, failure_message)
|
47
|
+
@expected = expected&.source
|
48
|
+
@actual = actual.source
|
49
|
+
@failure_message = failure_message&.source
|
50
|
+
end
|
51
|
+
|
52
|
+
def replaced(node)
|
53
|
+
runner = negated?(node) ? 'not_to' : 'to'
|
54
|
+
if failure_message.nil?
|
55
|
+
"expect(#{actual}).#{runner} #{assertion}"
|
56
|
+
else
|
57
|
+
"expect(#{actual}).#{runner}(#{assertion}, #{failure_message})"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def negated?(node)
|
62
|
+
node.method_name.start_with?('assert_not_', 'refute_')
|
63
|
+
end
|
64
|
+
|
65
|
+
def assertion
|
66
|
+
raise NotImplementedError
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# :nodoc:
|
71
|
+
class EqualAssertion < BasicAssertion
|
72
|
+
MATCHERS = %i[
|
73
|
+
assert_equal
|
74
|
+
assert_not_equal
|
75
|
+
refute_equal
|
76
|
+
].freeze
|
77
|
+
|
78
|
+
# @!method self.minitest_assertion(node)
|
79
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
80
|
+
(send nil? {:assert_equal :assert_not_equal :refute_equal} $_ $_ $_?)
|
81
|
+
PATTERN
|
82
|
+
|
83
|
+
def self.match(expected, actual, failure_message)
|
84
|
+
new(expected, actual, failure_message.first)
|
85
|
+
end
|
86
|
+
|
87
|
+
def assertion
|
88
|
+
"eq(#{expected})"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# :nodoc:
|
93
|
+
class KindOfAssertion < BasicAssertion
|
94
|
+
MATCHERS = %i[
|
95
|
+
assert_kind_of
|
96
|
+
assert_not_kind_of
|
97
|
+
refute_kind_of
|
98
|
+
].freeze
|
99
|
+
|
100
|
+
# @!method self.minitest_assertion(node)
|
101
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
102
|
+
(send nil? {:assert_kind_of :assert_not_kind_of :refute_kind_of} $_ $_ $_?)
|
103
|
+
PATTERN
|
104
|
+
|
105
|
+
def self.match(expected, actual, failure_message)
|
106
|
+
new(expected, actual, failure_message.first)
|
107
|
+
end
|
108
|
+
|
109
|
+
def assertion
|
110
|
+
"be_a_kind_of(#{expected})"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# :nodoc:
|
115
|
+
class InstanceOfAssertion < BasicAssertion
|
116
|
+
MATCHERS = %i[
|
117
|
+
assert_instance_of
|
118
|
+
assert_not_instance_of
|
119
|
+
refute_instance_of
|
120
|
+
].freeze
|
121
|
+
|
122
|
+
# @!method self.minitest_assertion(node)
|
123
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
124
|
+
(send nil? {:assert_instance_of :assert_not_instance_of :refute_instance_of} $_ $_ $_?)
|
125
|
+
PATTERN
|
126
|
+
|
127
|
+
def self.match(expected, actual, failure_message)
|
128
|
+
new(expected, actual, failure_message.first)
|
129
|
+
end
|
130
|
+
|
131
|
+
def assertion
|
132
|
+
"be_an_instance_of(#{expected})"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# :nodoc:
|
137
|
+
class IncludesAssertion < BasicAssertion
|
138
|
+
MATCHERS = %i[
|
139
|
+
assert_includes
|
140
|
+
assert_not_includes
|
141
|
+
refute_includes
|
142
|
+
].freeze
|
143
|
+
|
144
|
+
# @!method self.minitest_assertion(node)
|
145
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
146
|
+
(send nil? {:assert_includes :assert_not_includes :refute_includes} $_ $_ $_?)
|
147
|
+
PATTERN
|
148
|
+
|
149
|
+
def self.match(collection, expected, failure_message)
|
150
|
+
new(expected, collection, failure_message.first)
|
151
|
+
end
|
152
|
+
|
153
|
+
def assertion
|
154
|
+
"include(#{expected})"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# :nodoc:
|
159
|
+
class InDeltaAssertion < BasicAssertion
|
160
|
+
MATCHERS = %i[
|
161
|
+
assert_in_delta
|
162
|
+
assert_not_in_delta
|
163
|
+
refute_in_delta
|
164
|
+
].freeze
|
165
|
+
|
166
|
+
# @!method self.minitest_assertion(node)
|
167
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
168
|
+
(send nil? {:assert_in_delta :assert_not_in_delta :refute_in_delta} $_ $_ $_? $_?)
|
169
|
+
PATTERN
|
170
|
+
|
171
|
+
def self.match(expected, actual, delta, failure_message)
|
172
|
+
new(expected, actual, delta.first, failure_message.first)
|
173
|
+
end
|
174
|
+
|
175
|
+
def initialize(expected, actual, delta, fail_message)
|
176
|
+
super(expected, actual, fail_message)
|
177
|
+
|
178
|
+
@delta = delta&.source || '0.001'
|
179
|
+
end
|
180
|
+
|
181
|
+
def assertion
|
182
|
+
"be_within(#{@delta}).of(#{expected})"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# :nodoc:
|
187
|
+
class PredicateAssertion < BasicAssertion
|
188
|
+
MATCHERS = %i[
|
189
|
+
assert_predicate
|
190
|
+
assert_not_predicate
|
191
|
+
refute_predicate
|
192
|
+
].freeze
|
193
|
+
|
194
|
+
# @!method self.minitest_assertion(node)
|
195
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
196
|
+
(send nil? {:assert_predicate :assert_not_predicate :refute_predicate} $_ ${sym} $_?)
|
197
|
+
PATTERN
|
198
|
+
|
199
|
+
def self.match(subject, predicate, failure_message)
|
200
|
+
return nil unless predicate.value.end_with?('?')
|
201
|
+
|
202
|
+
new(predicate, subject, failure_message.first)
|
203
|
+
end
|
204
|
+
|
205
|
+
def assertion
|
206
|
+
"be_#{expected.delete_prefix(':').delete_suffix('?')}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# :nodoc:
|
211
|
+
class MatchAssertion < BasicAssertion
|
212
|
+
MATCHERS = %i[
|
213
|
+
assert_match
|
214
|
+
refute_match
|
215
|
+
].freeze
|
216
|
+
|
217
|
+
# @!method self.minitest_assertion(node)
|
218
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
219
|
+
(send nil? {:assert_match :refute_match} $_ $_ $_?)
|
220
|
+
PATTERN
|
221
|
+
|
222
|
+
def self.match(matcher, actual, failure_message)
|
223
|
+
new(matcher, actual, failure_message.first)
|
224
|
+
end
|
225
|
+
|
226
|
+
def assertion
|
227
|
+
"match(#{expected})"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# :nodoc:
|
232
|
+
class NilAssertion < BasicAssertion
|
233
|
+
MATCHERS = %i[
|
234
|
+
assert_nil
|
235
|
+
assert_not_nil
|
236
|
+
refute_nil
|
237
|
+
].freeze
|
238
|
+
|
239
|
+
# @!method self.minitest_assertion(node)
|
240
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
241
|
+
(send nil? {:assert_nil :assert_not_nil :refute_nil} $_ $_?)
|
242
|
+
PATTERN
|
243
|
+
|
244
|
+
def self.match(actual, failure_message)
|
245
|
+
new(nil, actual, failure_message.first)
|
246
|
+
end
|
247
|
+
|
248
|
+
def assertion
|
249
|
+
'eq(nil)'
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# :nodoc:
|
254
|
+
class EmptyAssertion < BasicAssertion
|
255
|
+
MATCHERS = %i[
|
256
|
+
assert_empty
|
257
|
+
assert_not_empty
|
258
|
+
refute_empty
|
259
|
+
].freeze
|
260
|
+
|
261
|
+
# @!method self.minitest_assertion(node)
|
262
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
263
|
+
(send nil? {:assert_empty :assert_not_empty :refute_empty} $_ $_?)
|
264
|
+
PATTERN
|
265
|
+
|
266
|
+
def self.match(actual, failure_message)
|
267
|
+
new(nil, actual, failure_message.first)
|
268
|
+
end
|
269
|
+
|
270
|
+
def assertion
|
271
|
+
'be_empty'
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# :nodoc:
|
276
|
+
class TrueAssertion < BasicAssertion
|
277
|
+
MATCHERS = %i[
|
278
|
+
assert_true
|
279
|
+
].freeze
|
280
|
+
|
281
|
+
# @!method self.minitest_assertion(node)
|
282
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
283
|
+
(send nil? {:assert_true} $_ $_?)
|
284
|
+
PATTERN
|
285
|
+
|
286
|
+
def self.match(actual, failure_message)
|
287
|
+
new(nil, actual, failure_message.first)
|
288
|
+
end
|
289
|
+
|
290
|
+
def assertion
|
291
|
+
'be(true)'
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# :nodoc:
|
296
|
+
class FalseAssertion < BasicAssertion
|
297
|
+
MATCHERS = %i[
|
298
|
+
assert_false
|
299
|
+
].freeze
|
300
|
+
|
301
|
+
# @!method self.minitest_assertion(node)
|
302
|
+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
|
303
|
+
(send nil? {:assert_false} $_ $_?)
|
304
|
+
PATTERN
|
305
|
+
|
306
|
+
def self.match(actual, failure_message)
|
307
|
+
new(nil, actual, failure_message.first)
|
308
|
+
end
|
309
|
+
|
310
|
+
def assertion
|
311
|
+
'be(false)'
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
23
315
|
MSG = 'Use `%<prefer>s`.'
|
24
|
-
RESTRICT_ON_SEND = %i[assert_equal refute_equal].freeze
|
25
316
|
|
26
|
-
#
|
27
|
-
|
28
|
-
|
29
|
-
|
317
|
+
# TODO: replace with `BasicAssertion.subclasses` in Ruby 3.1+
|
318
|
+
ASSERTION_MATCHERS = constants(false).filter_map do |c|
|
319
|
+
const = const_get(c)
|
320
|
+
|
321
|
+
const if const.is_a?(Class) && const.superclass == BasicAssertion
|
322
|
+
end
|
323
|
+
|
324
|
+
RESTRICT_ON_SEND = ASSERTION_MATCHERS.flat_map { |m| m::MATCHERS }
|
30
325
|
|
31
326
|
def on_send(node)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
327
|
+
ASSERTION_MATCHERS.each do |m|
|
328
|
+
m.minitest_assertion(node) do |*args|
|
329
|
+
assertion = m.match(*args)
|
330
|
+
|
331
|
+
next if assertion.nil?
|
332
|
+
|
333
|
+
on_assertion(node, assertion)
|
37
334
|
end
|
38
335
|
end
|
39
336
|
end
|
40
337
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
if failure_message.nil?
|
46
|
-
"expect(#{actual.source}).#{runner} eq(#{expected.source})"
|
47
|
-
else
|
48
|
-
"expect(#{actual.source}).#{runner}(eq(#{expected.source}), " \
|
49
|
-
"#{failure_message.source})"
|
338
|
+
def on_assertion(node, assertion)
|
339
|
+
preferred = assertion.replaced(node)
|
340
|
+
add_offense(node, message: message(preferred)) do |corrector|
|
341
|
+
corrector.replace(node, preferred)
|
50
342
|
end
|
51
343
|
end
|
52
344
|
|
53
|
-
def message(
|
54
|
-
format(MSG, prefer:
|
345
|
+
def message(preferred)
|
346
|
+
format(MSG, prefer: preferred)
|
55
347
|
end
|
56
348
|
end
|
57
349
|
end
|
@@ -9,10 +9,12 @@ module RuboCop
|
|
9
9
|
# # bad
|
10
10
|
# expect(foo).to be_exist(bar)
|
11
11
|
# expect(foo).not_to be_include(bar)
|
12
|
+
# expect(foo).to be_all(bar)
|
12
13
|
#
|
13
14
|
# # good
|
14
15
|
# expect(foo).to exist(bar)
|
15
16
|
# expect(foo).not_to include(bar)
|
17
|
+
# expect(foo).to all be(bar)
|
16
18
|
#
|
17
19
|
class RedundantPredicateMatcher < Base
|
18
20
|
extend AutoCorrector
|
@@ -25,7 +27,7 @@ module RuboCop
|
|
25
27
|
|
26
28
|
def on_send(node)
|
27
29
|
return if node.parent.block_type? || node.arguments.empty?
|
28
|
-
return unless
|
30
|
+
return unless replaceable_arguments?(node)
|
29
31
|
|
30
32
|
method_name = node.method_name.to_s
|
31
33
|
replaced = replaced_method_name(method_name)
|
@@ -43,7 +45,7 @@ module RuboCop
|
|
43
45
|
format(MSG, bad: bad_method, good: good_method)
|
44
46
|
end
|
45
47
|
|
46
|
-
def
|
48
|
+
def replaceable_arguments?(node)
|
47
49
|
if node.method?(:be_all)
|
48
50
|
node.first_argument.send_type?
|
49
51
|
else
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for repeated calls to subject missing that it is memoized.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# it do
|
11
|
+
# subject
|
12
|
+
# expect { subject }.to not_change { A.count }
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# it do
|
16
|
+
# expect { subject }.to change { A.count }
|
17
|
+
# expect { subject }.to not_change { A.count }
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# it do
|
22
|
+
# expect { my_method }.to change { A.count }
|
23
|
+
# expect { my_method }.to not_change { A.count }
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # also good
|
27
|
+
# it do
|
28
|
+
# expect { subject.a }.to change { A.count }
|
29
|
+
# expect { subject.b }.to not_change { A.count }
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
class RepeatedSubjectCall < Base
|
33
|
+
include TopLevelGroup
|
34
|
+
|
35
|
+
MSG = 'Calls to subject are memoized, this block is misleading'
|
36
|
+
|
37
|
+
# @!method subject?(node)
|
38
|
+
# Find a named or unnamed subject definition
|
39
|
+
#
|
40
|
+
# @example anonymous subject
|
41
|
+
# subject?(parse('subject { foo }').ast) do |name|
|
42
|
+
# name # => :subject
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example named subject
|
46
|
+
# subject?(parse('subject(:thing) { foo }').ast) do |name|
|
47
|
+
# name # => :thing
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# @param node [RuboCop::AST::Node]
|
51
|
+
#
|
52
|
+
# @yield [Symbol] subject name
|
53
|
+
def_node_matcher :subject?, <<-PATTERN
|
54
|
+
(block
|
55
|
+
(send nil?
|
56
|
+
{ #Subjects.all (sym $_) | $#Subjects.all }
|
57
|
+
) args ...)
|
58
|
+
PATTERN
|
59
|
+
|
60
|
+
# @!method subject_calls(node, method_name)
|
61
|
+
def_node_search :subject_calls, <<~PATTERN
|
62
|
+
(send nil? %)
|
63
|
+
PATTERN
|
64
|
+
|
65
|
+
def on_top_level_group(node)
|
66
|
+
@subjects_by_node = detect_subjects_in_scope(node)
|
67
|
+
|
68
|
+
detect_offenses_in_block(node)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def detect_offense(subject_node)
|
74
|
+
return if subject_node.chained?
|
75
|
+
return unless (block_node = expect_block(subject_node))
|
76
|
+
|
77
|
+
add_offense(block_node)
|
78
|
+
end
|
79
|
+
|
80
|
+
def expect_block(node)
|
81
|
+
node.each_ancestor(:block).find { |block| block.method?(:expect) }
|
82
|
+
end
|
83
|
+
|
84
|
+
def detect_offenses_in_block(node, subject_names = [])
|
85
|
+
subject_names = [*subject_names, *@subjects_by_node[node]]
|
86
|
+
|
87
|
+
if example?(node)
|
88
|
+
return detect_offenses_in_example(node, subject_names)
|
89
|
+
end
|
90
|
+
|
91
|
+
node.each_child_node(:send, :def, :block, :begin) do |child|
|
92
|
+
detect_offenses_in_block(child, subject_names)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def detect_offenses_in_example(node, subject_names)
|
97
|
+
return unless node.body
|
98
|
+
|
99
|
+
subjects_used = Hash.new(false)
|
100
|
+
|
101
|
+
subject_calls(node.body, Set[*subject_names, :subject]).each do |call|
|
102
|
+
if subjects_used[call.method_name]
|
103
|
+
detect_offense(call)
|
104
|
+
else
|
105
|
+
subjects_used[call.method_name] = true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def detect_subjects_in_scope(node)
|
111
|
+
node.each_descendant(:block).with_object({}) do |child, h|
|
112
|
+
subject?(child) do |name|
|
113
|
+
outer_example_group = child.each_ancestor(:block).find do |a|
|
114
|
+
example_group?(a)
|
115
|
+
end
|
116
|
+
|
117
|
+
(h[outer_example_group] ||= []) << name
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -78,6 +78,7 @@ require_relative 'rspec/implicit_subject'
|
|
78
78
|
require_relative 'rspec/indexed_let'
|
79
79
|
require_relative 'rspec/instance_spy'
|
80
80
|
require_relative 'rspec/instance_variable'
|
81
|
+
require_relative 'rspec/is_expected_specify'
|
81
82
|
require_relative 'rspec/it_behaves_like'
|
82
83
|
require_relative 'rspec/iterated_expectation'
|
83
84
|
require_relative 'rspec/leading_subject'
|
@@ -113,6 +114,7 @@ require_relative 'rspec/repeated_example'
|
|
113
114
|
require_relative 'rspec/repeated_example_group_body'
|
114
115
|
require_relative 'rspec/repeated_example_group_description'
|
115
116
|
require_relative 'rspec/repeated_include_example'
|
117
|
+
require_relative 'rspec/repeated_subject_call'
|
116
118
|
require_relative 'rspec/return_from_stub'
|
117
119
|
require_relative 'rspec/scattered_let'
|
118
120
|
require_relative 'rspec/scattered_setup'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.27.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Backus
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-03-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubocop
|
@@ -139,6 +139,7 @@ files:
|
|
139
139
|
- lib/rubocop/cop/rspec/indexed_let.rb
|
140
140
|
- lib/rubocop/cop/rspec/instance_spy.rb
|
141
141
|
- lib/rubocop/cop/rspec/instance_variable.rb
|
142
|
+
- lib/rubocop/cop/rspec/is_expected_specify.rb
|
142
143
|
- lib/rubocop/cop/rspec/it_behaves_like.rb
|
143
144
|
- lib/rubocop/cop/rspec/iterated_expectation.rb
|
144
145
|
- lib/rubocop/cop/rspec/leading_subject.rb
|
@@ -192,6 +193,7 @@ files:
|
|
192
193
|
- lib/rubocop/cop/rspec/repeated_example_group_body.rb
|
193
194
|
- lib/rubocop/cop/rspec/repeated_example_group_description.rb
|
194
195
|
- lib/rubocop/cop/rspec/repeated_include_example.rb
|
196
|
+
- lib/rubocop/cop/rspec/repeated_subject_call.rb
|
195
197
|
- lib/rubocop/cop/rspec/return_from_stub.rb
|
196
198
|
- lib/rubocop/cop/rspec/scattered_let.rb
|
197
199
|
- lib/rubocop/cop/rspec/scattered_setup.rb
|