rubocop-minitest 0.22.2 → 0.32.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 +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +5 -5
- data/config/default.yml +82 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/minitest/assert_instance_of.rb +18 -2
- data/lib/rubocop/cop/minitest/assert_match.rb +4 -1
- data/lib/rubocop/cop/minitest/assert_operator.rb +58 -0
- data/lib/rubocop/cop/minitest/assert_output.rb +1 -2
- data/lib/rubocop/cop/minitest/assert_path_exists.rb +9 -4
- data/lib/rubocop/cop/minitest/assert_same.rb +26 -0
- data/lib/rubocop/cop/minitest/assert_truthy.rb +10 -0
- data/lib/rubocop/cop/minitest/assert_with_expected_argument.rb +7 -1
- data/lib/rubocop/cop/minitest/empty_line_before_assertion_methods.rb +101 -0
- data/lib/rubocop/cop/minitest/global_expectations.rb +3 -1
- data/lib/rubocop/cop/minitest/lifecycle_hooks_order.rb +100 -0
- data/lib/rubocop/cop/minitest/literal_as_actual_argument.rb +16 -5
- data/lib/rubocop/cop/minitest/multiple_assertions.rb +23 -4
- data/lib/rubocop/cop/minitest/no_assertions.rb +1 -8
- data/lib/rubocop/cop/minitest/no_test_cases.rb +35 -0
- data/lib/rubocop/cop/minitest/non_public_test_method.rb +55 -0
- data/lib/rubocop/cop/minitest/refute_equal.rb +2 -3
- data/lib/rubocop/cop/minitest/refute_false.rb +11 -1
- data/lib/rubocop/cop/minitest/refute_instance_of.rb +18 -2
- data/lib/rubocop/cop/minitest/refute_match.rb +4 -1
- data/lib/rubocop/cop/minitest/refute_operator.rb +58 -0
- data/lib/rubocop/cop/minitest/refute_path_exists.rb +9 -4
- data/lib/rubocop/cop/minitest/refute_same.rb +26 -0
- data/lib/rubocop/cop/minitest/return_in_test_method.rb +44 -0
- data/lib/rubocop/cop/minitest/skip_without_reason.rb +66 -0
- data/lib/rubocop/cop/minitest/test_file_name.rb +46 -0
- data/lib/rubocop/cop/minitest/test_method_name.rb +1 -12
- data/lib/rubocop/cop/minitest/useless_assertion.rb +75 -0
- data/lib/rubocop/cop/minitest_cops.rb +16 -3
- data/lib/rubocop/cop/mixin/argument_range_helper.rb +0 -6
- data/lib/rubocop/cop/mixin/instance_of_assertion_handleable.rb +48 -0
- data/lib/rubocop/cop/mixin/minitest_cop_rule.rb +16 -5
- data/lib/rubocop/cop/mixin/minitest_exploration_helpers.rb +32 -11
- data/lib/rubocop/cop/mixin/predicate_assertion_handleable.rb +1 -1
- data/lib/rubocop/minitest/assert_offense.rb +47 -6
- data/lib/rubocop/minitest/version.rb +1 -1
- metadata +20 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce290f7a13faed25c00a17d9daf8bcaf17e187599a075323fc99f8494c29c2bb
|
4
|
+
data.tar.gz: 9def860d52f65aed4e8923bcf2fd851a5188485986c7ad5bce44a9dc0d79b2d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8db20fcf7d8e58b564da63b85f6692c4a2be189ffeacdc654f4b18ea689416688442df945606c84f55e63b9007c8df51b4f173004a7ae145603733f6bac62c61
|
7
|
+
data.tar.gz: 41232dfbabd012e4edbe1e78b49f1846004246950773a6f06c50fff358cb71a79fbdcd95ed0657690387801331093606c2dabb376788368cf51438ff84846be4
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2019-
|
3
|
+
Copyright (c) 2019-2023 Bozhidar Batsov, Jonas Arvidsson, Koichi ITO
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -3,15 +3,15 @@
|
|
3
3
|
[](https://badge.fury.io/rb/rubocop-minitest)
|
4
4
|
[](https://circleci.com/gh/rubocop/rubocop-minitest)
|
5
5
|
|
6
|
-
A [RuboCop](https://github.com/rubocop/rubocop) extension focused on enforcing Minitest best practices and coding conventions.
|
6
|
+
A [RuboCop](https://github.com/rubocop/rubocop) extension focused on enforcing [Minitest](https://github.com/minitest/minitest) best practices and coding conventions.
|
7
7
|
The library is based on the guidelines outlined in the community [Minitest Style Guide](https://minitest.rubystyle.guide).
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
11
|
Just install the `rubocop-minitest` gem
|
12
12
|
|
13
|
-
```
|
14
|
-
gem install rubocop-minitest
|
13
|
+
```sh
|
14
|
+
$ gem install rubocop-minitest
|
15
15
|
```
|
16
16
|
|
17
17
|
or if you use bundler put this in your `Gemfile`
|
@@ -46,8 +46,8 @@ cops together with the standard cops.
|
|
46
46
|
|
47
47
|
### Command line
|
48
48
|
|
49
|
-
```
|
50
|
-
rubocop --require rubocop-minitest
|
49
|
+
```sh
|
50
|
+
$ rubocop --require rubocop-minitest
|
51
51
|
```
|
52
52
|
|
53
53
|
### Rake task
|
data/config/default.yml
CHANGED
@@ -59,6 +59,12 @@ Minitest/AssertNil:
|
|
59
59
|
Enabled: true
|
60
60
|
VersionAdded: '0.1'
|
61
61
|
|
62
|
+
Minitest/AssertOperator:
|
63
|
+
Description: 'This cop enforces the use of `assert_operator(expected, :<, actual)` over `assert(expected < actual)`.'
|
64
|
+
StyleGuide: 'https://minitest.rubystyle.guide#assert-operator'
|
65
|
+
Enabled: pending
|
66
|
+
VersionAdded: '0.32'
|
67
|
+
|
62
68
|
Minitest/AssertOutput:
|
63
69
|
Description: 'This cop checks for opportunities to use `assert_output`.'
|
64
70
|
StyleGuide: 'https://minitest.rubystyle.guide/#assert-output'
|
@@ -85,7 +91,9 @@ Minitest/AssertRaisesCompoundBody:
|
|
85
91
|
Minitest/AssertRaisesWithRegexpArgument:
|
86
92
|
Description: 'This cop enforces checks for regular expression literals passed to `assert_raises`.'
|
87
93
|
Enabled: pending
|
94
|
+
Severity: warning
|
88
95
|
VersionAdded: '0.22'
|
96
|
+
VersionChanged: '0.26'
|
89
97
|
|
90
98
|
Minitest/AssertRespondTo:
|
91
99
|
Description: 'This cop enforces the test to use `assert_respond_to(object, :do_something)` over `assert(object.respond_to?(:do_something))`.'
|
@@ -93,6 +101,12 @@ Minitest/AssertRespondTo:
|
|
93
101
|
Enabled: true
|
94
102
|
VersionAdded: '0.3'
|
95
103
|
|
104
|
+
Minitest/AssertSame:
|
105
|
+
Description: 'Enforces the use of `assert_same(expected, actual)` over `assert(expected.equal?(actual))`.'
|
106
|
+
StyleGuide: 'https://minitest.rubystyle.guide#assert-same'
|
107
|
+
Enabled: pending
|
108
|
+
VersionAdded: '0.26'
|
109
|
+
|
96
110
|
Minitest/AssertSilent:
|
97
111
|
Description: "This cop enforces the test to use `assert_silent { ... }` instead of using `assert_output('', '') { ... }`."
|
98
112
|
StyleGuide: 'https://github.com/rubocop/minitest-style-guide#assert-silent'
|
@@ -103,13 +117,17 @@ Minitest/AssertTruthy:
|
|
103
117
|
Description: 'This cop enforces the test to use `assert(actual)` instead of using `assert_equal(true, actual)`.'
|
104
118
|
StyleGuide: 'https://minitest.rubystyle.guide#assert-truthy'
|
105
119
|
Enabled: true
|
120
|
+
Safe: false
|
106
121
|
VersionAdded: '0.2'
|
122
|
+
VersionChanged: '0.27'
|
107
123
|
|
108
124
|
Minitest/AssertWithExpectedArgument:
|
109
125
|
Description: 'This cop tries to detect when a user accidentally used `assert` when they meant to use `assert_equal`.'
|
110
126
|
Enabled: pending
|
127
|
+
Severity: warning
|
111
128
|
Safe: false
|
112
129
|
VersionAdded: '0.11'
|
130
|
+
VersionChanged: '0.26'
|
113
131
|
|
114
132
|
Minitest/AssertionInLifecycleHook:
|
115
133
|
Description: 'This cop checks for usage of assertions in lifecycle hooks.'
|
@@ -122,10 +140,16 @@ Minitest/DuplicateTestRun:
|
|
122
140
|
Enabled: pending
|
123
141
|
VersionAdded: '0.19'
|
124
142
|
|
143
|
+
Minitest/EmptyLineBeforeAssertionMethods:
|
144
|
+
Description: 'Add empty line before assertion methods.'
|
145
|
+
Enabled: pending
|
146
|
+
VersionAdded: '0.23'
|
147
|
+
|
125
148
|
Minitest/GlobalExpectations:
|
126
149
|
Description: 'This cop checks for deprecated global expectations.'
|
127
150
|
StyleGuide: 'https://minitest.rubystyle.guide#global-expectations'
|
128
151
|
Enabled: true
|
152
|
+
Severity: warning
|
129
153
|
EnforcedStyle: any
|
130
154
|
Include:
|
131
155
|
- '**/test/**/*'
|
@@ -138,7 +162,13 @@ Minitest/GlobalExpectations:
|
|
138
162
|
- expect
|
139
163
|
- value
|
140
164
|
VersionAdded: '0.7'
|
141
|
-
VersionChanged: '0.
|
165
|
+
VersionChanged: '0.26'
|
166
|
+
|
167
|
+
Minitest/LifecycleHooksOrder:
|
168
|
+
Description: 'Checks that lifecycle hooks are declared in the order in which they will be executed.'
|
169
|
+
StyleGuide: 'https://minitest.rubystyle.guide/#hooks-ordering'
|
170
|
+
Enabled: pending
|
171
|
+
VersionAdded: '0.28'
|
142
172
|
|
143
173
|
Minitest/LiteralAsActualArgument:
|
144
174
|
Description: 'This cop enforces correct order of `expected` and `actual` arguments for `assert_equal`.'
|
@@ -157,6 +187,17 @@ Minitest/NoAssertions:
|
|
157
187
|
Enabled: false
|
158
188
|
VersionAdded: '0.12'
|
159
189
|
|
190
|
+
Minitest/NoTestCases:
|
191
|
+
Description: 'Checks if test class contains any test cases.'
|
192
|
+
Enabled: false
|
193
|
+
VersionAdded: '0.30'
|
194
|
+
|
195
|
+
Minitest/NonPublicTestMethod:
|
196
|
+
Description: 'Detects non `public` (marked as `private` or `protected`) test methods.'
|
197
|
+
Enabled: pending
|
198
|
+
Severity: warning
|
199
|
+
VersionAdded: '0.27'
|
200
|
+
|
160
201
|
Minitest/RefuteEmpty:
|
161
202
|
Description: 'This cop enforces to use `refute_empty` instead of using `refute(object.empty?)`.'
|
162
203
|
StyleGuide: 'https://minitest.rubystyle.guide#refute-empty'
|
@@ -173,7 +214,9 @@ Minitest/RefuteFalse:
|
|
173
214
|
Description: 'Check if your test uses `refute(actual)` instead of `assert_equal(false, actual)`.'
|
174
215
|
StyleGuide: 'https://minitest.rubystyle.guide#refute-false'
|
175
216
|
Enabled: true
|
217
|
+
Safe: false
|
176
218
|
VersionAdded: '0.3'
|
219
|
+
VersionChanged: '0.27'
|
177
220
|
|
178
221
|
Minitest/RefuteInDelta:
|
179
222
|
Description: 'This cop enforces the test to use `refute_in_delta` instead of using `refute_equal` to compare floats.'
|
@@ -211,6 +254,12 @@ Minitest/RefuteNil:
|
|
211
254
|
Enabled: true
|
212
255
|
VersionAdded: '0.2'
|
213
256
|
|
257
|
+
Minitest/RefuteOperator:
|
258
|
+
Description: 'This cop enforces the use of `refute_operator(expected, :<, actual)` over `refute(expected < actual)`.'
|
259
|
+
StyleGuide: 'https://minitest.rubystyle.guide#refute-operator'
|
260
|
+
Enabled: pending
|
261
|
+
VersionAdded: '0.32'
|
262
|
+
|
214
263
|
Minitest/RefutePathExists:
|
215
264
|
Description: 'This cop enforces the test to use `refute_path_exists` instead of using `refute(File.exist?(path))`.'
|
216
265
|
StyleGuide: 'https://minitest.rubystyle.guide/#refute-path-exists'
|
@@ -229,10 +278,35 @@ Minitest/RefuteRespondTo:
|
|
229
278
|
Enabled: true
|
230
279
|
VersionAdded: '0.4'
|
231
280
|
|
281
|
+
Minitest/RefuteSame:
|
282
|
+
Description: 'Enforces the use of `refute_same(expected, actual)` over `refute(expected.equal?(actual))`.'
|
283
|
+
StyleGuide: 'https://minitest.rubystyle.guide#refute-same'
|
284
|
+
Enabled: pending
|
285
|
+
VersionAdded: '0.26'
|
286
|
+
|
287
|
+
Minitest/ReturnInTestMethod:
|
288
|
+
Description: 'Enforces the use of `skip` instead of `return` in test methods.'
|
289
|
+
StyleGuide: 'https://minitest.rubystyle.guide/#skipping-runnable-methods'
|
290
|
+
Enabled: pending
|
291
|
+
VersionAdded: '0.31'
|
292
|
+
|
232
293
|
Minitest/SkipEnsure:
|
233
294
|
Description: 'Checks that `ensure` call even if `skip`.'
|
234
295
|
Enabled: pending
|
296
|
+
Severity: warning
|
235
297
|
VersionAdded: '0.20'
|
298
|
+
VersionChanged: '0.26'
|
299
|
+
|
300
|
+
Minitest/SkipWithoutReason:
|
301
|
+
Description: 'Checks for skipped tests missing the skipping reason.'
|
302
|
+
Enabled: pending
|
303
|
+
VersionAdded: '0.24'
|
304
|
+
|
305
|
+
Minitest/TestFileName:
|
306
|
+
Description: 'Checks if test file names start with `test_` or end with `_test.rb`.'
|
307
|
+
StyleGuide: 'https://minitest.rubystyle.guide/#file-naming'
|
308
|
+
Enabled: pending
|
309
|
+
VersionAdded: '0.26'
|
236
310
|
|
237
311
|
Minitest/TestMethodName:
|
238
312
|
Description: 'This cop enforces that test method names start with `test_` prefix.'
|
@@ -242,10 +316,17 @@ Minitest/TestMethodName:
|
|
242
316
|
Minitest/UnreachableAssertion:
|
243
317
|
Description: 'This cop checks for an `assert_raises` block containing any unreachable assertions.'
|
244
318
|
Enabled: pending
|
319
|
+
Severity: warning
|
245
320
|
VersionAdded: '0.14'
|
321
|
+
VersionChanged: '0.26'
|
246
322
|
|
247
323
|
Minitest/UnspecifiedException:
|
248
324
|
Description: 'This cop checks for a specified error in `assert_raises`.'
|
249
325
|
StyleGuide: 'https://minitest.rubystyle.guide#unspecified-exception'
|
250
326
|
Enabled: 'pending'
|
251
327
|
VersionAdded: '0.10'
|
328
|
+
|
329
|
+
Minitest/UselessAssertion:
|
330
|
+
Description: 'Detects useless assertions (assertions that either always pass or always fail).'
|
331
|
+
Enabled: pending
|
332
|
+
VersionAdded: '0.26'
|
@@ -11,14 +11,30 @@ module RuboCop
|
|
11
11
|
# assert(object.instance_of?(Class))
|
12
12
|
# assert(object.instance_of?(Class), 'message')
|
13
13
|
#
|
14
|
+
# # bad
|
15
|
+
# assert_equal(Class, object.class)
|
16
|
+
# assert_equal(Class, object.class, 'message')
|
17
|
+
#
|
14
18
|
# # good
|
15
19
|
# assert_instance_of(Class, object)
|
16
20
|
# assert_instance_of(Class, object, 'message')
|
17
21
|
#
|
18
22
|
class AssertInstanceOf < Base
|
19
|
-
|
23
|
+
include InstanceOfAssertionHandleable
|
24
|
+
extend AutoCorrector
|
25
|
+
|
26
|
+
RESTRICT_ON_SEND = %i[assert assert_equal].freeze
|
27
|
+
|
28
|
+
def_node_matcher :instance_of_assertion?, <<~PATTERN
|
29
|
+
{
|
30
|
+
(send nil? :assert (send $_ :instance_of? $const) $_?)
|
31
|
+
(send nil? :assert_equal $const (send $_ :class) $_?)
|
32
|
+
}
|
33
|
+
PATTERN
|
20
34
|
|
21
|
-
|
35
|
+
def on_send(node)
|
36
|
+
investigate(node, :assert)
|
37
|
+
end
|
22
38
|
end
|
23
39
|
end
|
24
40
|
end
|
@@ -9,6 +9,8 @@ module RuboCop
|
|
9
9
|
# @example
|
10
10
|
# # bad
|
11
11
|
# assert(matcher.match(string))
|
12
|
+
# assert(matcher.match?(string))
|
13
|
+
# assert(matcher =~ string)
|
12
14
|
# assert(matcher.match(string), 'message')
|
13
15
|
#
|
14
16
|
# # good
|
@@ -18,7 +20,8 @@ module RuboCop
|
|
18
20
|
class AssertMatch < Base
|
19
21
|
extend MinitestCopRule
|
20
22
|
|
21
|
-
define_rule :assert, target_method:
|
23
|
+
define_rule :assert, target_method: %i[match match? =~],
|
24
|
+
preferred_method: :assert_match, inverse: 'regexp_type?'
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Minitest
|
6
|
+
# Enforces the use of `assert_operator(expected, :<, actual)` over `assert(expected < actual)`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# assert(expected < actual)
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# assert_operator(expected, :<, actual)
|
15
|
+
#
|
16
|
+
class AssertOperator < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
19
|
+
MSG = 'Prefer using `assert_operator(%<new_arguments>s)`.'
|
20
|
+
RESTRICT_ON_SEND = %i[assert].freeze
|
21
|
+
ALLOWED_OPERATORS = [:[]].freeze
|
22
|
+
|
23
|
+
def on_send(node)
|
24
|
+
first_argument = node.first_argument
|
25
|
+
return unless first_argument.respond_to?(:binary_operation?) && first_argument.binary_operation?
|
26
|
+
|
27
|
+
operator = first_argument.to_a[1]
|
28
|
+
return if ALLOWED_OPERATORS.include?(operator)
|
29
|
+
|
30
|
+
new_arguments = build_new_arguments(node)
|
31
|
+
|
32
|
+
add_offense(node, message: format(MSG, new_arguments: new_arguments)) do |corrector|
|
33
|
+
corrector.replace(node.loc.selector, 'assert_operator')
|
34
|
+
|
35
|
+
corrector.replace(range_of_arguments(node), new_arguments)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def build_new_arguments(node)
|
42
|
+
lhs, op, rhs = *node.first_argument
|
43
|
+
new_arguments = "#{lhs.source}, :#{op}, #{rhs.source}"
|
44
|
+
|
45
|
+
if node.arguments.count == 2
|
46
|
+
new_arguments << ", #{node.last_argument.source}"
|
47
|
+
else
|
48
|
+
new_arguments
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def range_of_arguments(node)
|
53
|
+
node.first_argument.source_range.begin.join(node.last_argument.source_range.end)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -36,8 +36,7 @@ module RuboCop
|
|
36
36
|
private
|
37
37
|
|
38
38
|
def find_test_case(node)
|
39
|
-
|
40
|
-
def_ancestor if test_case?(def_ancestor)
|
39
|
+
node.each_ancestor.find { |ancestor| test_case?(ancestor) }
|
41
40
|
end
|
42
41
|
|
43
42
|
def references_gvar?(assertion, gvar_name)
|
@@ -30,20 +30,25 @@ module RuboCop
|
|
30
30
|
def on_send(node)
|
31
31
|
assert_file_exists(node) do |path, failure_message|
|
32
32
|
failure_message = failure_message.first
|
33
|
-
good_method = build_good_method(path, failure_message)
|
33
|
+
good_method = build_good_method(node, path, failure_message)
|
34
34
|
message = format(MSG, good_method: good_method)
|
35
35
|
|
36
36
|
add_offense(node, message: message) do |corrector|
|
37
|
-
corrector.replace(node,
|
37
|
+
corrector.replace(node.loc.selector, 'assert_path_exists')
|
38
|
+
corrector.replace(node.first_argument, path.source)
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
43
|
private
|
43
44
|
|
44
|
-
def build_good_method(path, message)
|
45
|
+
def build_good_method(node, path, message)
|
45
46
|
args = [path.source, message&.source].compact.join(', ')
|
46
|
-
|
47
|
+
if node.parenthesized?
|
48
|
+
"assert_path_exists(#{args})"
|
49
|
+
else
|
50
|
+
"assert_path_exists #{args}"
|
51
|
+
end
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Minitest
|
6
|
+
# Enforces the use of `assert_same(expected, actual)`
|
7
|
+
# over `assert(expected.equal?(actual))`.
|
8
|
+
#
|
9
|
+
# NOTE: Use `assert_same` only when there is a need to compare by identity.
|
10
|
+
# Otherwise, use `assert_equal`.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# assert(expected.equal?(actual))
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# assert_same(expected, actual)
|
18
|
+
#
|
19
|
+
class AssertSame < Base
|
20
|
+
extend MinitestCopRule
|
21
|
+
|
22
|
+
define_rule :assert, target_method: :equal?, preferred_method: :assert_same
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -5,6 +5,16 @@ module RuboCop
|
|
5
5
|
module Minitest
|
6
6
|
# Enforces the test to use `assert(actual)` instead of using `assert_equal(true, actual)`.
|
7
7
|
#
|
8
|
+
# @safety
|
9
|
+
# This cop is unsafe because true might be expected instead of truthy.
|
10
|
+
# False positives cannot be prevented when this is a variable or method return value.
|
11
|
+
#
|
12
|
+
# [source,ruby]
|
13
|
+
# ----
|
14
|
+
# assert_equal(true, 'truthy') # failure
|
15
|
+
# assert('truthy') # success
|
16
|
+
# ----
|
17
|
+
#
|
8
18
|
# @example
|
9
19
|
# # bad
|
10
20
|
# assert_equal(true, actual)
|
@@ -6,6 +6,9 @@ module RuboCop
|
|
6
6
|
# Tries to detect when a user accidentally used
|
7
7
|
# `assert` when they meant to use `assert_equal`.
|
8
8
|
#
|
9
|
+
# NOTE: The second argument to the `assert` method named `message` and `msg` is allowed.
|
10
|
+
# Because their names are inferred as message arguments.
|
11
|
+
#
|
9
12
|
# @safety
|
10
13
|
# This cop is unsafe because it is not possible to determine
|
11
14
|
# whether the second argument of `assert` is a message or not.
|
@@ -19,10 +22,13 @@ module RuboCop
|
|
19
22
|
# assert_equal(3, my_list.length)
|
20
23
|
# assert_equal(expected, actual)
|
21
24
|
# assert(foo, 'message')
|
25
|
+
# assert(foo, message)
|
26
|
+
# assert(foo, msg)
|
22
27
|
#
|
23
28
|
class AssertWithExpectedArgument < Base
|
24
29
|
MSG = 'Did you mean to use `assert_equal(%<arguments>s)`?'
|
25
30
|
RESTRICT_ON_SEND = %i[assert].freeze
|
31
|
+
MESSAGE_VARIABLES = %w[message msg].freeze
|
26
32
|
|
27
33
|
def_node_matcher :assert_with_two_arguments?, <<~PATTERN
|
28
34
|
(send nil? :assert $_ $_)
|
@@ -30,7 +36,7 @@ module RuboCop
|
|
30
36
|
|
31
37
|
def on_send(node)
|
32
38
|
assert_with_two_arguments?(node) do |_expected, message|
|
33
|
-
return if message.str_type? || message.dstr_type?
|
39
|
+
return if message.str_type? || message.dstr_type? || MESSAGE_VARIABLES.include?(message.source)
|
34
40
|
|
35
41
|
arguments = node.arguments.map(&:source).join(', ')
|
36
42
|
add_offense(node, message: format(MSG, arguments: arguments))
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Minitest
|
6
|
+
# Enforces empty line before assertion methods because it separates assertion phase.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# do_something
|
12
|
+
# assert_equal(expected, actual)
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# do_something
|
16
|
+
#
|
17
|
+
# assert_equal(expected, actual)
|
18
|
+
#
|
19
|
+
class EmptyLineBeforeAssertionMethods < Base
|
20
|
+
include MinitestExplorationHelpers
|
21
|
+
include RangeHelp
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
MSG = 'Add empty line before assertion.'
|
25
|
+
|
26
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
27
|
+
def on_send(node)
|
28
|
+
return unless (assertion_method = assertion_method(node))
|
29
|
+
return unless (previous_line_node = assertion_method.left_sibling)
|
30
|
+
return if node.parent.resbody_type?
|
31
|
+
return if accept_previous_line?(previous_line_node, assertion_method)
|
32
|
+
|
33
|
+
previous_line_node = previous_line_node.arguments.last if use_heredoc_argument?(previous_line_node)
|
34
|
+
return if use_assertion_method_at_last_of_block?(previous_line_node)
|
35
|
+
return unless no_empty_line?(previous_line_node, assertion_method)
|
36
|
+
|
37
|
+
register_offense(assertion_method, previous_line_node)
|
38
|
+
end
|
39
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def assertion_method(node)
|
44
|
+
return node if assertion_method?(node)
|
45
|
+
return unless (parent = node.parent)
|
46
|
+
return unless parent.block_type?
|
47
|
+
return if parent.method?(:test)
|
48
|
+
|
49
|
+
node.parent if parent.body && assertion_method?(parent.body)
|
50
|
+
end
|
51
|
+
|
52
|
+
def accept_previous_line?(previous_line_node, node)
|
53
|
+
return true if !previous_line_node.is_a?(RuboCop::AST::Node) ||
|
54
|
+
previous_line_node.args_type? || node.parent.basic_conditional?
|
55
|
+
|
56
|
+
assertion_method?(previous_line_node)
|
57
|
+
end
|
58
|
+
|
59
|
+
def use_heredoc_argument?(node)
|
60
|
+
node.respond_to?(:arguments) && heredoc?(node.arguments.last)
|
61
|
+
end
|
62
|
+
|
63
|
+
def use_assertion_method_at_last_of_block?(node)
|
64
|
+
return false if !node.block_type? || !node.body
|
65
|
+
|
66
|
+
if node.body.begin_type?
|
67
|
+
assertion_method?(node.body.children.last)
|
68
|
+
else
|
69
|
+
assertion_method?(node.body)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def heredoc?(last_argument)
|
74
|
+
last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
|
75
|
+
end
|
76
|
+
|
77
|
+
def no_empty_line?(previous_line_node, node)
|
78
|
+
previous_line = if heredoc?(previous_line_node)
|
79
|
+
previous_line_node.loc.heredoc_end.line
|
80
|
+
else
|
81
|
+
previous_line_node.loc.last_line
|
82
|
+
end
|
83
|
+
|
84
|
+
previous_line + 1 == node.loc.line
|
85
|
+
end
|
86
|
+
|
87
|
+
def register_offense(node, previous_line_node)
|
88
|
+
add_offense(node) do |corrector|
|
89
|
+
range = if heredoc?(previous_line_node)
|
90
|
+
previous_line_node.loc.heredoc_end
|
91
|
+
else
|
92
|
+
range_by_whole_lines(previous_line_node.source_range, include_final_newline: true)
|
93
|
+
end
|
94
|
+
|
95
|
+
corrector.insert_after(range, "\n")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -96,7 +96,9 @@ module RuboCop
|
|
96
96
|
wont_be_kind_of wont_match wont_be_nil wont_be wont_respond_to wont_be_same_as
|
97
97
|
].freeze
|
98
98
|
|
99
|
-
BLOCK_MATCHERS = %i[
|
99
|
+
BLOCK_MATCHERS = %i[
|
100
|
+
must_output must_pattern_match must_raise must_be_silent must_throw wont_pattern_match
|
101
|
+
].freeze
|
100
102
|
|
101
103
|
RESTRICT_ON_SEND = VALUE_MATCHERS + BLOCK_MATCHERS
|
102
104
|
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Minitest
|
6
|
+
# Checks that lifecycle hooks are declared in the order in which they will be executed.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# class FooTest < Minitest::Test
|
11
|
+
# def teardown; end
|
12
|
+
# def setup; end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# class FooTest < Minitest::Test
|
17
|
+
# def setup; end
|
18
|
+
# def teardown; end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # bad (after test cases)
|
22
|
+
# class FooTest < Minitest::Test
|
23
|
+
# def test_something
|
24
|
+
# assert foo
|
25
|
+
# end
|
26
|
+
# def setup; end
|
27
|
+
# def teardown; end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# class FooTest < Minitest::Test
|
32
|
+
# def setup; end
|
33
|
+
# def teardown; end
|
34
|
+
# def test_something
|
35
|
+
# assert foo
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # good (after non test case methods)
|
40
|
+
# class FooTest < Minitest::Test
|
41
|
+
# def do_something; end
|
42
|
+
# def setup; end
|
43
|
+
# def teardown; end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
class LifecycleHooksOrder < Base
|
47
|
+
include MinitestExplorationHelpers
|
48
|
+
include RangeHelp
|
49
|
+
extend AutoCorrector
|
50
|
+
|
51
|
+
MSG = '`%<current>s` is supposed to appear before `%<previous>s`.'
|
52
|
+
|
53
|
+
# Regular method's position should be last.
|
54
|
+
REGULAR_METHOD_POSITION = LIFECYCLE_HOOK_METHODS_IN_ORDER.size + 1
|
55
|
+
HOOKS_ORDER_MAP = Hash.new do |hash, hook|
|
56
|
+
hash[hook] = LIFECYCLE_HOOK_METHODS_IN_ORDER.index(hook) || REGULAR_METHOD_POSITION
|
57
|
+
end
|
58
|
+
|
59
|
+
# rubocop:disable Metrics/MethodLength
|
60
|
+
def on_class(class_node)
|
61
|
+
return unless test_class?(class_node)
|
62
|
+
|
63
|
+
previous_index = -1
|
64
|
+
previous_hook_node = nil
|
65
|
+
|
66
|
+
hooks_and_test_cases(class_node).each do |node|
|
67
|
+
hook = node.method_name
|
68
|
+
index = HOOKS_ORDER_MAP[hook]
|
69
|
+
|
70
|
+
if index < previous_index
|
71
|
+
message = format(MSG, current: hook, previous: previous_hook_node.method_name)
|
72
|
+
add_offense(node, message: message) do |corrector|
|
73
|
+
autocorrect(corrector, previous_hook_node, node)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
previous_index = index
|
77
|
+
previous_hook_node = node
|
78
|
+
end
|
79
|
+
end
|
80
|
+
# rubocop:enable Metrics/MethodLength
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def hooks_and_test_cases(class_node)
|
85
|
+
class_def_nodes(class_node).select do |node|
|
86
|
+
lifecycle_hook_method?(node) || test_case?(node)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def autocorrect(corrector, previous_node, node)
|
91
|
+
previous_node_range = range_with_comments_and_lines(previous_node)
|
92
|
+
node_range = range_with_comments_and_lines(node)
|
93
|
+
|
94
|
+
corrector.insert_before(previous_node_range, node_range.source)
|
95
|
+
corrector.remove(node_range)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|