rubocop-rspec 2.22.0 → 2.27.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +94 -9
  3. data/README.md +1 -1
  4. data/config/default.yml +126 -21
  5. data/lib/rubocop/cop/rspec/around_block.rb +3 -3
  6. data/lib/rubocop/cop/rspec/be.rb +1 -1
  7. data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
  8. data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
  9. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  10. data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
  11. data/lib/rubocop/cop/rspec/before_after_all.rb +7 -13
  12. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +2 -2
  13. data/lib/rubocop/cop/rspec/change_by_zero.rb +30 -4
  14. data/lib/rubocop/cop/rspec/context_method.rb +2 -2
  15. data/lib/rubocop/cop/rspec/context_wording.rb +1 -1
  16. data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
  17. data/lib/rubocop/cop/rspec/described_class.rb +33 -11
  18. data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
  19. data/lib/rubocop/cop/rspec/empty_example_group.rb +4 -1
  20. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -2
  21. data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
  22. data/lib/rubocop/cop/rspec/eq.rb +47 -0
  23. data/lib/rubocop/cop/rspec/example_length.rb +11 -5
  24. data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
  25. data/lib/rubocop/cop/rspec/example_wording.rb +11 -2
  26. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +14 -5
  27. data/lib/rubocop/cop/rspec/expect_actual.rb +7 -4
  28. data/lib/rubocop/cop/rspec/expect_change.rb +2 -2
  29. data/lib/rubocop/cop/rspec/expect_output.rb +1 -4
  30. data/lib/rubocop/cop/rspec/file_path.rb +6 -0
  31. data/lib/rubocop/cop/rspec/focus.rb +17 -2
  32. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
  33. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
  34. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -2
  35. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  36. data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -2
  37. data/lib/rubocop/cop/rspec/indexed_let.rb +32 -1
  38. data/lib/rubocop/cop/rspec/instance_spy.rb +2 -2
  39. data/lib/rubocop/cop/rspec/instance_variable.rb +3 -3
  40. data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
  41. data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -3
  42. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
  43. data/lib/rubocop/cop/rspec/let_before_examples.rb +5 -1
  44. data/lib/rubocop/cop/rspec/let_setup.rb +1 -1
  45. data/lib/rubocop/cop/rspec/message_expectation.rb +1 -2
  46. data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
  47. data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
  48. data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
  49. data/lib/rubocop/cop/rspec/mixin/metadata.rb +21 -7
  50. data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +2 -2
  51. data/lib/rubocop/cop/rspec/multiple_expectations.rb +12 -7
  52. data/lib/rubocop/cop/rspec/named_subject.rb +1 -1
  53. data/lib/rubocop/cop/rspec/pending.rb +12 -2
  54. data/lib/rubocop/cop/rspec/pending_without_reason.rb +1 -1
  55. data/lib/rubocop/cop/rspec/predicate_matcher.rb +9 -9
  56. data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +1 -1
  57. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +34 -10
  58. data/lib/rubocop/cop/rspec/rails/http_status.rb +29 -18
  59. data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +314 -22
  60. data/lib/rubocop/cop/rspec/rails/negation_be_valid.rb +102 -0
  61. data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
  62. data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
  63. data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
  64. data/lib/rubocop/cop/rspec/remove_const.rb +40 -0
  65. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
  66. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +2 -2
  67. data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
  68. data/lib/rubocop/cop/rspec/repeated_subject_call.rb +124 -0
  69. data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
  70. data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
  71. data/lib/rubocop/cop/rspec/shared_examples.rb +66 -20
  72. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -3
  73. data/lib/rubocop/cop/rspec/sort_metadata.rb +2 -1
  74. data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
  75. data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
  76. data/lib/rubocop/cop/rspec/stubbed_mock.rb +1 -1
  77. data/lib/rubocop/cop/rspec/subject_stub.rb +4 -4
  78. data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -2
  79. data/lib/rubocop/cop/rspec/variable_definition.rb +4 -4
  80. data/lib/rubocop/cop/rspec/verified_double_reference.rb +6 -6
  81. data/lib/rubocop/cop/rspec/verified_doubles.rb +2 -2
  82. data/lib/rubocop/cop/rspec/void_expect.rb +4 -3
  83. data/lib/rubocop/cop/rspec_cops.rb +11 -0
  84. data/lib/rubocop/rspec/language.rb +8 -8
  85. data/lib/rubocop/rspec/version.rb +1 -1
  86. data/lib/rubocop/rspec/wording.rb +8 -0
  87. data/lib/rubocop-rspec.rb +1 -0
  88. metadata +20 -8
@@ -58,12 +58,12 @@ module RuboCop
58
58
  }.freeze
59
59
 
60
60
  # @!method capybara_speak(node)
61
- def_node_matcher :capybara_speak, <<-PATTERN
61
+ def_node_matcher :capybara_speak, <<~PATTERN
62
62
  {#{MAP.keys.map(&:inspect).join(' ')}}
63
63
  PATTERN
64
64
 
65
65
  # @!method feature_method(node)
66
- def_node_matcher :feature_method, <<-PATTERN
66
+ def_node_matcher :feature_method, <<~PATTERN
67
67
  (block
68
68
  $(send #rspec? $#capybara_speak ...)
69
69
  ...)
@@ -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)`.'
@@ -66,14 +68,14 @@ module RuboCop
66
68
  RESTRICT_ON_SEND = CHANGE_METHODS.freeze
67
69
 
68
70
  # @!method expect_change_with_arguments(node)
69
- def_node_matcher :expect_change_with_arguments, <<-PATTERN
71
+ def_node_matcher :expect_change_with_arguments, <<~PATTERN
70
72
  (send
71
73
  $(send nil? CHANGE_METHODS ...) :by
72
74
  (int 0))
73
75
  PATTERN
74
76
 
75
77
  # @!method expect_change_with_block(node)
76
- def_node_matcher :expect_change_with_block, <<-PATTERN
78
+ def_node_matcher :expect_change_with_block, <<~PATTERN
77
79
  (send
78
80
  (block
79
81
  $(send nil? CHANGE_METHODS)
@@ -83,7 +85,7 @@ module RuboCop
83
85
  PATTERN
84
86
 
85
87
  # @!method change_nodes(node)
86
- def_node_search :change_nodes, <<-PATTERN
88
+ def_node_search :change_nodes, <<~PATTERN
87
89
  $(send nil? CHANGE_METHODS ...)
88
90
  PATTERN
89
91
 
@@ -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
- range = node.loc.dot.with(end_pos: node.source_range.end_pos)
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
 
@@ -30,7 +30,7 @@ module RuboCop
30
30
  MSG = 'Use `describe` for testing methods.'
31
31
 
32
32
  # @!method context_method(node)
33
- def_node_matcher :context_method, <<-PATTERN
33
+ def_node_matcher :context_method, <<~PATTERN
34
34
  (block
35
35
  (send #rspec? :context
36
36
  ${(str #method_name?) (dstr (str #method_name?) ...)}
@@ -38,7 +38,7 @@ module RuboCop
38
38
  ...)
39
39
  PATTERN
40
40
 
41
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
41
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
42
42
  context_method(node) do |context|
43
43
  add_offense(context) do |corrector|
44
44
  corrector.replace(node.send_node.loc.selector, 'describe')
@@ -61,7 +61,7 @@ module RuboCop
61
61
  MSG = 'Context description should match %<patterns>s.'
62
62
 
63
63
  # @!method context_wording(node)
64
- def_node_matcher :context_wording, <<-PATTERN
64
+ def_node_matcher :context_wording, <<~PATTERN
65
65
  (block (send #rspec? { :context :shared_context } $({str dstr xstr} ...) ...) ...)
66
66
  PATTERN
67
67
 
@@ -22,7 +22,7 @@ module RuboCop
22
22
  RESTRICT_ON_SEND = %i[describe].freeze
23
23
 
24
24
  # @!method describe_symbol?(node)
25
- def_node_matcher :describe_symbol?, <<-PATTERN
25
+ def_node_matcher :describe_symbol?, <<~PATTERN
26
26
  (send #rspec? :describe $sym ...)
27
27
  PATTERN
28
28
 
@@ -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` and `SkipBlocks`
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
@@ -63,7 +77,7 @@ module RuboCop
63
77
  MSG = 'Use `%<replacement>s` instead of `%<src>s`.'
64
78
 
65
79
  # @!method common_instance_exec_closure?(node)
66
- def_node_matcher :common_instance_exec_closure?, <<-PATTERN
80
+ def_node_matcher :common_instance_exec_closure?, <<~PATTERN
67
81
  (block (send (const nil? {:Class :Module :Struct}) :new ...) ...)
68
82
  PATTERN
69
83
 
@@ -75,7 +89,7 @@ module RuboCop
75
89
  def_node_matcher :scope_changing_syntax?, '{def class module}'
76
90
 
77
91
  # @!method described_constant(node)
78
- def_node_matcher :described_constant, <<-PATTERN
92
+ def_node_matcher :described_constant, <<~PATTERN
79
93
  (block (send _ :describe $(const ...) ...) (args) $_)
80
94
  PATTERN
81
95
 
@@ -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)
@@ -148,15 +169,15 @@ module RuboCop
148
169
  end
149
170
 
150
171
  def offensive_described_class?(node)
151
- return unless node.const_type?
172
+ return false unless node.const_type?
152
173
 
153
174
  # E.g. `described_class::CONSTANT`
154
- return if contains_described_class?(node)
175
+ return false if contains_described_class?(node)
155
176
 
156
177
  nearest_described_class, = node.each_ancestor(:block)
157
178
  .map { |ancestor| described_constant(ancestor) }.find(&:itself)
158
179
 
159
- return if nearest_described_class.equal?(node)
180
+ return false if nearest_described_class.equal?(node)
160
181
 
161
182
  full_const_name(nearest_described_class) == full_const_name(node)
162
183
  end
@@ -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, name = *node # rubocop:disable InternalAffairs/NodeDestructuring
218
+ namespace = node.namespace
219
+ name = node.short_name
198
220
  if !namespace
199
221
  [name]
200
222
  elsif namespace.const_type?
@@ -19,7 +19,7 @@ module RuboCop
19
19
 
20
20
  MSG = 'Avoid duplicated metadata.'
21
21
 
22
- def on_metadata(symbols, _pairs)
22
+ def on_metadata(symbols, _hash)
23
23
  symbols.each do |symbol|
24
24
  on_metadata_symbol(symbol)
25
25
  end
@@ -131,6 +131,7 @@ module RuboCop
131
131
  {
132
132
  #examples_directly_or_in_block?
133
133
  (begin <#examples_directly_or_in_block? ...>)
134
+ (begin <#examples_in_branches? ...>)
134
135
  }
135
136
  PATTERN
136
137
 
@@ -161,7 +162,7 @@ module RuboCop
161
162
  end
162
163
 
163
164
  def conditionals_with_examples?(body)
164
- return unless body.begin_type? || body.case_type?
165
+ return false unless body.begin_type? || body.case_type?
165
166
 
166
167
  body.each_descendant(:if, :case).any? do |condition_node|
167
168
  examples_in_branches?(condition_node)
@@ -169,6 +170,8 @@ module RuboCop
169
170
  end
170
171
 
171
172
  def examples_in_branches?(condition_node)
173
+ return false if !condition_node.if_type? && !condition_node.case_type?
174
+
172
175
  condition_node.branches.any? { |branch| examples?(branch) }
173
176
  end
174
177
 
@@ -71,8 +71,8 @@ module RuboCop
71
71
 
72
72
  def next_one_line_example?(node)
73
73
  next_sibling = node.right_sibling
74
- return unless next_sibling
75
- return unless example?(next_sibling)
74
+ return false unless next_sibling
75
+ return false unless example?(next_sibling)
76
76
 
77
77
  next_sibling.single_line?
78
78
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Avoid empty metadata hash.
7
+ #
8
+ # @example EnforcedStyle: symbol (default)
9
+ # # bad
10
+ # describe 'Something', {}
11
+ #
12
+ # # good
13
+ # describe 'Something'
14
+ class EmptyMetadata < Base
15
+ extend AutoCorrector
16
+
17
+ include Metadata
18
+ include RangeHelp
19
+
20
+ MSG = 'Avoid empty metadata hash.'
21
+
22
+ def on_metadata(_symbols, hash)
23
+ return unless hash&.pairs&.empty?
24
+
25
+ add_offense(hash) do |corrector|
26
+ remove_empty_metadata(corrector, hash)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def remove_empty_metadata(corrector, node)
33
+ corrector.remove(
34
+ range_with_surrounding_comma(
35
+ range_with_surrounding_space(
36
+ node.source_range,
37
+ side: :left
38
+ ),
39
+ :left
40
+ )
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Use `eq` instead of `be ==` to compare objects.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # expect(foo).to be == 42
11
+ #
12
+ # # good
13
+ # expect(foo).to eq 42
14
+ #
15
+ class Eq < Base
16
+ extend AutoCorrector
17
+ include RangeHelp
18
+
19
+ MSG = 'Use `eq` instead of `be ==` to compare objects.'
20
+ RESTRICT_ON_SEND = Runners.all
21
+
22
+ # @!method be_equals(node)
23
+ def_node_matcher :be_equals, <<~PATTERN
24
+ (send _ #Runners.all $(send (send nil? :be) :== _))
25
+ PATTERN
26
+
27
+ def on_send(node)
28
+ be_equals(node) do |matcher|
29
+ range = offense_range(matcher)
30
+ add_offense(range) do |corrector|
31
+ corrector.replace(range, 'eq')
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def offense_range(matcher)
39
+ range_between(
40
+ matcher.source_range.begin_pos,
41
+ matcher.loc.selector.end_pos
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -26,11 +26,12 @@ module RuboCop
26
26
  # expect(result).to be(true)
27
27
  # end
28
28
  #
29
- # You can set literals you want to fold with `CountAsOne`.
30
- # Available are: 'array', 'hash', and 'heredoc'. Each literal
31
- # will be counted as one line regardless of its actual size.
29
+ # You can set constructs you want to fold with `CountAsOne`.
30
+ # Available are: 'array', 'hash', 'heredoc', and 'method_call'.
31
+ # Each construct will be counted as one line regardless of
32
+ # its actual size.
32
33
  #
33
- # @example CountAsOne: ['array', 'heredoc']
34
+ # @example CountAsOne: ['array', 'heredoc', 'method_call']
34
35
  #
35
36
  # it do
36
37
  # array = [ # +1
@@ -46,7 +47,12 @@ module RuboCop
46
47
  # Heredoc
47
48
  # content.
48
49
  # HEREDOC
49
- # end # 5 points
50
+ #
51
+ # foo( # +1
52
+ # 1,
53
+ # 2
54
+ # )
55
+ # end # 6 points
50
56
  #
51
57
  class ExampleLength < Base
52
58
  include CodeLength
@@ -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
- # it '' do
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
- # it do
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
@@ -22,6 +22,9 @@ module RuboCop
22
22
  # it 'should find nothing' do
23
23
  # end
24
24
  #
25
+ # it 'will find nothing' do
26
+ # end
27
+ #
25
28
  # # good
26
29
  # it 'finds nothing' do
27
30
  # end
@@ -47,25 +50,30 @@ module RuboCop
47
50
  extend AutoCorrector
48
51
 
49
52
  MSG_SHOULD = 'Do not use should when describing your tests.'
53
+ MSG_WILL = 'Do not use the future tense when describing your tests.'
50
54
  MSG_IT = "Do not repeat 'it' when describing your tests."
51
55
  MSG_INSUFFICIENT_DESCRIPTION = 'Your example description is ' \
52
56
  'insufficient.'
53
57
 
54
58
  SHOULD_PREFIX = /\Ashould(?:n't)?\b/i.freeze
59
+ WILL_PREFIX = /\A(?:will|won't)\b/i.freeze
55
60
  IT_PREFIX = /\Ait /i.freeze
56
61
 
57
62
  # @!method it_description(node)
58
- def_node_matcher :it_description, <<-PATTERN
63
+ def_node_matcher :it_description, <<~PATTERN
59
64
  (block (send _ :it ${
60
65
  (str $_)
61
66
  (dstr (str $_ ) ...)
62
67
  } ...) ...)
63
68
  PATTERN
64
69
 
70
+ # rubocop:disable Metrics/MethodLength
65
71
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
66
72
  it_description(node) do |description_node, message|
67
73
  if message.match?(SHOULD_PREFIX)
68
74
  add_wording_offense(description_node, MSG_SHOULD)
75
+ elsif message.match?(WILL_PREFIX)
76
+ add_wording_offense(description_node, MSG_WILL)
69
77
  elsif message.match?(IT_PREFIX)
70
78
  add_wording_offense(description_node, MSG_IT)
71
79
  elsif insufficient_docstring?(description_node)
@@ -74,6 +82,7 @@ module RuboCop
74
82
  end
75
83
  end
76
84
  end
85
+ # rubocop:enable Metrics/MethodLength
77
86
 
78
87
  private
79
88
 
@@ -100,7 +109,7 @@ module RuboCop
100
109
  def replacement_text(node)
101
110
  text = text(node)
102
111
 
103
- if text.match?(SHOULD_PREFIX)
112
+ if text.match?(SHOULD_PREFIX) || text.match?(WILL_PREFIX)
104
113
  RuboCop::RSpec::Wording.new(
105
114
  text,
106
115
  ignore: ignored_words,
@@ -29,7 +29,7 @@ module RuboCop
29
29
  MSG = 'Excessive whitespace.'
30
30
 
31
31
  # @!method example_description(node)
32
- def_node_matcher :example_description, <<-PATTERN
32
+ def_node_matcher :example_description, <<~PATTERN
33
33
  (send _ {#Examples.all #ExampleGroups.all} ${
34
34
  $str
35
35
  $(dstr ({str dstr `sym} ...) ...)
@@ -52,14 +52,23 @@ module RuboCop
52
52
 
53
53
  # @param text [String]
54
54
  def excessive_whitespace?(text)
55
- return true if text.start_with?(' ') || text.end_with?(' ')
56
-
57
- text.match?(/[^\n ] +[^ ]/)
55
+ text.match?(/
56
+ # Leading space
57
+ \A[[:blank:]]
58
+ |
59
+ # Trailing space
60
+ [[:blank:]]\z
61
+ |
62
+ # Two or more consecutive spaces, except if they are leading spaces
63
+ [^[[:space:]]][[:blank:]]{2,}[^[[:blank:]]]
64
+ /x)
58
65
  end
59
66
 
60
67
  # @param text [String]
61
68
  def strip_excessive_whitespace(text)
62
- text.strip.gsub(/ +/, ' ')
69
+ text
70
+ .gsub(/[[:blank:]]{2,}/, ' ')
71
+ .gsub(/\A[[:blank:]]|[[:blank:]]\z/, '')
63
72
  end
64
73
 
65
74
  # @param node [RuboCop::AST::Node]
@@ -24,7 +24,7 @@ module RuboCop
24
24
  class ExpectActual < Base
25
25
  extend AutoCorrector
26
26
 
27
- MSG = 'Provide the actual you are testing to `expect(...)`.'
27
+ MSG = 'Provide the actual value you are testing to `expect(...)`.'
28
28
 
29
29
  RESTRICT_ON_SEND = Runners.all
30
30
 
@@ -50,7 +50,8 @@ module RuboCop
50
50
  regexp
51
51
  ].freeze
52
52
 
53
- SUPPORTED_MATCHERS = %i[eq eql equal be].freeze
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 SUPPORTED_MATCHERS.include?(matcher)
73
+ next unless CORRECTABLE_MATCHERS.include?(matcher)
71
74
  next if literal?(expected)
72
75
 
73
76
  swap(corrector, actual, expected)
@@ -77,7 +80,7 @@ module RuboCop
77
80
 
78
81
  private
79
82
 
80
- # This is not implement using a NodePattern because it seems
83
+ # This is not implemented using a NodePattern because it seems
81
84
  # to not be able to match against an explicit (nil) sexp
82
85
  def literal?(node)
83
86
  node && (simple_literal?(node) || complex_literal?(node))
@@ -38,12 +38,12 @@ module RuboCop
38
38
  RESTRICT_ON_SEND = %i[change].freeze
39
39
 
40
40
  # @!method expect_change_with_arguments(node)
41
- def_node_matcher :expect_change_with_arguments, <<-PATTERN
41
+ def_node_matcher :expect_change_with_arguments, <<~PATTERN
42
42
  (send nil? :change $_ ({sym str} $_))
43
43
  PATTERN
44
44
 
45
45
  # @!method expect_change_with_block(node)
46
- def_node_matcher :expect_change_with_block, <<-PATTERN
46
+ def_node_matcher :expect_change_with_block, <<~PATTERN
47
47
  (block
48
48
  (send nil? :change)
49
49
  (args)
@@ -22,10 +22,7 @@ module RuboCop
22
22
  def on_gvasgn(node)
23
23
  return unless inside_example_scope?(node)
24
24
 
25
- # rubocop:disable InternalAffairs/NodeDestructuring
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))
@@ -5,6 +5,12 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks that spec file paths are consistent and well-formed.
7
7
  #
8
+ # This cop is deprecated.
9
+ # We plan to remove it in the next major version update to 3.0.
10
+ # The migration targets are `RSpec/SpecFilePathSuffix`
11
+ # and `RSpec/SpecFilePathFormat`.
12
+ # If you are using this cop, please plan for migration.
13
+ #
8
14
  # By default, this checks that spec file paths are consistent with the
9
15
  # test subject and enforces that it reflects the described
10
16
  # class/module and its optionally called out method.