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.
Files changed (193) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +955 -79
  3. data/CODE_OF_CONDUCT.md +17 -0
  4. data/MIT-LICENSE.md +1 -2
  5. data/README.md +35 -35
  6. data/config/default.yml +940 -52
  7. data/config/obsoletion.yml +30 -0
  8. data/lib/rubocop/cop/rspec/align_left_let_brace.rb +49 -0
  9. data/lib/rubocop/cop/rspec/align_right_let_brace.rb +49 -0
  10. data/lib/rubocop/cop/rspec/any_instance.rb +10 -13
  11. data/lib/rubocop/cop/rspec/around_block.rb +97 -0
  12. data/lib/rubocop/cop/rspec/base.rb +26 -0
  13. data/lib/rubocop/cop/rspec/be.rb +39 -0
  14. data/lib/rubocop/cop/rspec/be_empty.rb +45 -0
  15. data/lib/rubocop/cop/rspec/be_eq.rb +47 -0
  16. data/lib/rubocop/cop/rspec/be_eql.rb +18 -15
  17. data/lib/rubocop/cop/rspec/be_nil.rb +74 -0
  18. data/lib/rubocop/cop/rspec/before_after_all.rb +45 -0
  19. data/lib/rubocop/cop/rspec/change_by_zero.rb +184 -0
  20. data/lib/rubocop/cop/rspec/class_check.rb +101 -0
  21. data/lib/rubocop/cop/rspec/contain_exactly.rb +56 -0
  22. data/lib/rubocop/cop/rspec/context_method.rb +57 -0
  23. data/lib/rubocop/cop/rspec/context_wording.rb +117 -0
  24. data/lib/rubocop/cop/rspec/describe_class.rb +52 -21
  25. data/lib/rubocop/cop/rspec/describe_method.rb +26 -11
  26. data/lib/rubocop/cop/rspec/describe_symbol.rb +37 -0
  27. data/lib/rubocop/cop/rspec/described_class.rb +181 -34
  28. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +38 -0
  29. data/lib/rubocop/cop/rspec/dialect.rb +84 -0
  30. data/lib/rubocop/cop/rspec/duplicated_metadata.rb +58 -0
  31. data/lib/rubocop/cop/rspec/empty_example_group.rb +134 -47
  32. data/lib/rubocop/cop/rspec/empty_hook.rb +49 -0
  33. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +82 -0
  34. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +42 -0
  35. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +40 -0
  36. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +82 -0
  37. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +36 -0
  38. data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
  39. data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
  40. data/lib/rubocop/cop/rspec/eq.rb +47 -0
  41. data/lib/rubocop/cop/rspec/example_length.rb +38 -20
  42. data/lib/rubocop/cop/rspec/example_without_description.rb +98 -0
  43. data/lib/rubocop/cop/rspec/example_wording.rb +117 -27
  44. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +110 -0
  45. data/lib/rubocop/cop/rspec/expect_actual.rb +46 -20
  46. data/lib/rubocop/cop/rspec/expect_change.rb +86 -0
  47. data/lib/rubocop/cop/rspec/expect_in_hook.rb +50 -0
  48. data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
  49. data/lib/rubocop/cop/rspec/expect_output.rb +50 -0
  50. data/lib/rubocop/cop/rspec/focus.rb +79 -25
  51. data/lib/rubocop/cop/rspec/hook_argument.rb +48 -36
  52. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +81 -0
  53. data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +37 -0
  54. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +68 -0
  55. data/lib/rubocop/cop/rspec/implicit_expect.rb +100 -0
  56. data/lib/rubocop/cop/rspec/implicit_subject.rb +167 -0
  57. data/lib/rubocop/cop/rspec/indexed_let.rb +112 -0
  58. data/lib/rubocop/cop/rspec/instance_spy.rb +74 -0
  59. data/lib/rubocop/cop/rspec/instance_variable.rb +28 -14
  60. data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
  61. data/lib/rubocop/cop/rspec/it_behaves_like.rb +49 -0
  62. data/lib/rubocop/cop/rspec/iterated_expectation.rb +74 -0
  63. data/lib/rubocop/cop/rspec/leading_subject.rb +57 -29
  64. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +127 -0
  65. data/lib/rubocop/cop/rspec/let_before_examples.rb +101 -0
  66. data/lib/rubocop/cop/rspec/let_setup.rb +32 -16
  67. data/lib/rubocop/cop/rspec/match_array.rb +59 -0
  68. data/lib/rubocop/cop/rspec/message_chain.rb +10 -15
  69. data/lib/rubocop/cop/rspec/message_expectation.rb +12 -9
  70. data/lib/rubocop/cop/rspec/message_spies.rb +88 -0
  71. data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
  72. data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
  73. data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
  74. data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
  75. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +59 -0
  76. data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
  77. data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
  78. data/lib/rubocop/cop/rspec/mixin/inside_example_group.rb +29 -0
  79. data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
  80. data/lib/rubocop/cop/rspec/mixin/metadata.rb +63 -0
  81. data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
  82. data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +39 -0
  83. data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
  84. data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
  85. data/lib/rubocop/cop/rspec/multiple_describes.rb +14 -12
  86. data/lib/rubocop/cop/rspec/multiple_expectations.rb +86 -26
  87. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +146 -0
  88. data/lib/rubocop/cop/rspec/multiple_subjects.rb +97 -0
  89. data/lib/rubocop/cop/rspec/named_subject.rb +107 -27
  90. data/lib/rubocop/cop/rspec/nested_groups.rb +84 -47
  91. data/lib/rubocop/cop/rspec/no_expectation_example.rb +102 -0
  92. data/lib/rubocop/cop/rspec/not_to_not.rb +30 -27
  93. data/lib/rubocop/cop/rspec/overwriting_setup.rb +74 -0
  94. data/lib/rubocop/cop/rspec/pending.rb +80 -0
  95. data/lib/rubocop/cop/rspec/pending_without_reason.rb +159 -0
  96. data/lib/rubocop/cop/rspec/predicate_matcher.rb +341 -0
  97. data/lib/rubocop/cop/rspec/receive_counts.rb +89 -0
  98. data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
  99. data/lib/rubocop/cop/rspec/receive_never.rb +41 -0
  100. data/lib/rubocop/cop/rspec/redundant_around.rb +65 -0
  101. data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
  102. data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
  103. data/lib/rubocop/cop/rspec/repeated_description.rb +98 -0
  104. data/lib/rubocop/cop/rspec/repeated_example.rb +53 -0
  105. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +100 -0
  106. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +96 -0
  107. data/lib/rubocop/cop/rspec/repeated_include_example.rb +105 -0
  108. data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
  109. data/lib/rubocop/cop/rspec/return_from_stub.rb +169 -0
  110. data/lib/rubocop/cop/rspec/scattered_let.rb +59 -0
  111. data/lib/rubocop/cop/rspec/scattered_setup.rb +92 -0
  112. data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
  113. data/lib/rubocop/cop/rspec/shared_examples.rb +125 -0
  114. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +93 -0
  115. data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
  116. data/lib/rubocop/cop/rspec/sort_metadata.rb +71 -0
  117. data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
  118. data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
  119. data/lib/rubocop/cop/rspec/stubbed_mock.rb +176 -0
  120. data/lib/rubocop/cop/rspec/subject_declaration.rb +46 -0
  121. data/lib/rubocop/cop/rspec/subject_stub.rb +93 -74
  122. data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
  123. data/lib/rubocop/cop/rspec/unspecified_exception.rb +67 -0
  124. data/lib/rubocop/cop/rspec/variable_definition.rb +77 -0
  125. data/lib/rubocop/cop/rspec/variable_name.rb +68 -0
  126. data/lib/rubocop/cop/rspec/verified_double_reference.rb +111 -0
  127. data/lib/rubocop/cop/rspec/verified_doubles.rb +28 -14
  128. data/lib/rubocop/cop/rspec/void_expect.rb +60 -0
  129. data/lib/rubocop/cop/rspec/yield.rb +82 -0
  130. data/lib/rubocop/cop/rspec_cops.rb +112 -0
  131. data/lib/rubocop/rspec/align_let_brace.rb +63 -0
  132. data/lib/rubocop/rspec/concept.rb +33 -0
  133. data/lib/rubocop/rspec/config_formatter.rb +27 -4
  134. data/lib/rubocop/rspec/cop/generator.rb +25 -0
  135. data/lib/rubocop/rspec/corrector/move_node.rb +51 -0
  136. data/lib/rubocop/rspec/description_extractor.rb +60 -18
  137. data/lib/rubocop/rspec/example.rb +37 -0
  138. data/lib/rubocop/rspec/example_group.rb +67 -0
  139. data/lib/rubocop/rspec/hook.rb +79 -0
  140. data/lib/rubocop/rspec/inject.rb +3 -1
  141. data/lib/rubocop/rspec/language.rb +184 -41
  142. data/lib/rubocop/rspec/node.rb +19 -0
  143. data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +29 -0
  144. data/lib/rubocop/rspec/version.rb +1 -1
  145. data/lib/rubocop/rspec/wording.rb +61 -19
  146. data/lib/rubocop/rspec.rb +6 -2
  147. data/lib/rubocop-rspec.rb +45 -34
  148. metadata +130 -195
  149. data/Gemfile +0 -13
  150. data/Rakefile +0 -48
  151. data/lib/rubocop/cop/rspec/file_path.rb +0 -83
  152. data/lib/rubocop/rspec/language/node_pattern.rb +0 -16
  153. data/lib/rubocop/rspec/spec_only.rb +0 -61
  154. data/lib/rubocop/rspec/top_level_describe.rb +0 -61
  155. data/lib/rubocop/rspec/util.rb +0 -19
  156. data/rubocop-rspec.gemspec +0 -42
  157. data/spec/expect_violation/expectation_spec.rb +0 -85
  158. data/spec/project/changelog_spec.rb +0 -81
  159. data/spec/project/default_config_spec.rb +0 -52
  160. data/spec/project/project_requires_spec.rb +0 -8
  161. data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -30
  162. data/spec/rubocop/cop/rspec/be_eql_spec.rb +0 -59
  163. data/spec/rubocop/cop/rspec/describe_class_spec.rb +0 -113
  164. data/spec/rubocop/cop/rspec/describe_method_spec.rb +0 -32
  165. data/spec/rubocop/cop/rspec/described_class_spec.rb +0 -219
  166. data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +0 -79
  167. data/spec/rubocop/cop/rspec/example_length_spec.rb +0 -117
  168. data/spec/rubocop/cop/rspec/example_wording_spec.rb +0 -82
  169. data/spec/rubocop/cop/rspec/expect_actual_spec.rb +0 -136
  170. data/spec/rubocop/cop/rspec/file_path_spec.rb +0 -236
  171. data/spec/rubocop/cop/rspec/focus_spec.rb +0 -130
  172. data/spec/rubocop/cop/rspec/hook_argument_spec.rb +0 -189
  173. data/spec/rubocop/cop/rspec/instance_variable_spec.rb +0 -75
  174. data/spec/rubocop/cop/rspec/leading_subject_spec.rb +0 -54
  175. data/spec/rubocop/cop/rspec/let_setup_spec.rb +0 -66
  176. data/spec/rubocop/cop/rspec/message_chain_spec.rb +0 -21
  177. data/spec/rubocop/cop/rspec/message_expectation_spec.rb +0 -63
  178. data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -28
  179. data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +0 -84
  180. data/spec/rubocop/cop/rspec/named_subject_spec.rb +0 -62
  181. data/spec/rubocop/cop/rspec/nested_groups_spec.rb +0 -55
  182. data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -57
  183. data/spec/rubocop/cop/rspec/subject_stub_spec.rb +0 -183
  184. data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +0 -71
  185. data/spec/rubocop/rspec/config_formatter_spec.rb +0 -48
  186. data/spec/rubocop/rspec/description_extractor_spec.rb +0 -35
  187. data/spec/rubocop/rspec/language/selector_set_spec.rb +0 -29
  188. data/spec/rubocop/rspec/spec_only_spec.rb +0 -97
  189. data/spec/rubocop/rspec/util/one_spec.rb +0 -21
  190. data/spec/rubocop/rspec/wording_spec.rb +0 -44
  191. data/spec/shared/rspec_only_cop_behavior.rb +0 -68
  192. data/spec/spec_helper.rb +0 -41
  193. data/spec/support/expect_violation.rb +0 -166
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for empty before and after hooks.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # before {}
11
+ # after do; end
12
+ # before(:all) do
13
+ # end
14
+ # after(:all) { }
15
+ #
16
+ # # good
17
+ # before { create_users }
18
+ # after do
19
+ # cleanup_users
20
+ # end
21
+ # before(:all) do
22
+ # create_feed
23
+ # end
24
+ # after(:all) { cleanup_feed }
25
+ #
26
+ class EmptyHook < Base
27
+ extend AutoCorrector
28
+ include RuboCop::Cop::RangeHelp
29
+
30
+ MSG = 'Empty hook detected.'
31
+
32
+ # @!method empty_hook?(node)
33
+ def_node_matcher :empty_hook?, <<~PATTERN
34
+ (block $(send nil? #Hooks.all ...) _ nil?)
35
+ PATTERN
36
+
37
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
38
+ empty_hook?(node) do |hook|
39
+ add_offense(hook) do |corrector|
40
+ corrector.remove(
41
+ range_with_surrounding_space(node.source_range, side: :left)
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after example blocks.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # RSpec.describe Foo do
11
+ # it 'does this' do
12
+ # end
13
+ # it 'does that' do
14
+ # end
15
+ # end
16
+ #
17
+ # # good
18
+ # RSpec.describe Foo do
19
+ # it 'does this' do
20
+ # end
21
+ #
22
+ # it 'does that' do
23
+ # end
24
+ # end
25
+ #
26
+ # # fair - it's ok to have non-separated one-liners
27
+ # RSpec.describe Foo do
28
+ # it { one }
29
+ # it { two }
30
+ # end
31
+ #
32
+ # @example with AllowConsecutiveOneLiners configuration
33
+ # # rubocop.yml
34
+ # # RSpec/EmptyLineAfterExample:
35
+ # # AllowConsecutiveOneLiners: false
36
+ #
37
+ # # bad
38
+ # RSpec.describe Foo do
39
+ # it { one }
40
+ # it { two }
41
+ # end
42
+ #
43
+ class EmptyLineAfterExample < Base
44
+ extend AutoCorrector
45
+ include EmptyLineSeparation
46
+
47
+ MSG = 'Add an empty line after `%<example>s`.'
48
+
49
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
50
+ return unless example?(node)
51
+ return if allowed_one_liner?(node)
52
+
53
+ missing_separating_line_offense(node) do |method|
54
+ format(MSG, example: method)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def allowed_one_liner?(node)
61
+ consecutive_one_liner?(node) && allow_consecutive_one_liners?
62
+ end
63
+
64
+ def allow_consecutive_one_liners?
65
+ cop_config['AllowConsecutiveOneLiners']
66
+ end
67
+
68
+ def consecutive_one_liner?(node)
69
+ node.single_line? && next_one_line_example?(node)
70
+ end
71
+
72
+ def next_one_line_example?(node)
73
+ next_sibling = node.right_sibling
74
+ return false unless next_sibling
75
+ return false unless example?(next_sibling)
76
+
77
+ next_sibling.single_line?
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after example group blocks.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # RSpec.describe Foo do
11
+ # describe '#bar' do
12
+ # end
13
+ # describe '#baz' do
14
+ # end
15
+ # end
16
+ #
17
+ # # good
18
+ # RSpec.describe Foo do
19
+ # describe '#bar' do
20
+ # end
21
+ #
22
+ # describe '#baz' do
23
+ # end
24
+ # end
25
+ #
26
+ class EmptyLineAfterExampleGroup < Base
27
+ extend AutoCorrector
28
+ include EmptyLineSeparation
29
+
30
+ MSG = 'Add an empty line after `%<example_group>s`.'
31
+
32
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
33
+ return unless spec_group?(node)
34
+
35
+ missing_separating_line_offense(node) do |method|
36
+ format(MSG, example_group: method)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after the last let block.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # let(:foo) { bar }
11
+ # let(:something) { other }
12
+ # it { does_something }
13
+ #
14
+ # # good
15
+ # let(:foo) { bar }
16
+ # let(:something) { other }
17
+ #
18
+ # it { does_something }
19
+ #
20
+ class EmptyLineAfterFinalLet < Base
21
+ extend AutoCorrector
22
+ include EmptyLineSeparation
23
+
24
+ MSG = 'Add an empty line after the last `%<let>s`.'
25
+
26
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
27
+ return unless example_group_with_body?(node)
28
+
29
+ final_let = node.body.child_nodes.reverse.find { |child| let?(child) }
30
+
31
+ return if final_let.nil?
32
+
33
+ missing_separating_line_offense(final_let) do |method|
34
+ format(MSG, let: method)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after hook blocks.
7
+ #
8
+ # `AllowConsecutiveOneLiners` configures whether adjacent
9
+ # one-line definitions are considered an offense.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # before { do_something }
14
+ # it { does_something }
15
+ #
16
+ # # bad
17
+ # after { do_something }
18
+ # it { does_something }
19
+ #
20
+ # # bad
21
+ # around { |test| test.run }
22
+ # it { does_something }
23
+ #
24
+ # # good
25
+ # after { do_something }
26
+ #
27
+ # it { does_something }
28
+ #
29
+ # # fair - it's ok to have non-separated one-liners hooks
30
+ # around { |test| test.run }
31
+ # after { do_something }
32
+ #
33
+ # it { does_something }
34
+ #
35
+ # @example with AllowConsecutiveOneLiners configuration
36
+ # # rubocop.yml
37
+ # # RSpec/EmptyLineAfterHook:
38
+ # # AllowConsecutiveOneLiners: false
39
+ #
40
+ # # bad
41
+ # around { |test| test.run }
42
+ # after { do_something }
43
+ #
44
+ # it { does_something }
45
+ #
46
+ # # good
47
+ # around { |test| test.run }
48
+ #
49
+ # after { do_something }
50
+ #
51
+ # it { does_something }
52
+ #
53
+ class EmptyLineAfterHook < Base
54
+ extend AutoCorrector
55
+ include ConfigurableEnforcedStyle
56
+ include EmptyLineSeparation
57
+
58
+ MSG = 'Add an empty line after `%<hook>s`.'
59
+
60
+ def on_block(node)
61
+ return unless hook?(node)
62
+ return if cop_config['AllowConsecutiveOneLiners'] &&
63
+ chained_single_line_hooks?(node)
64
+
65
+ missing_separating_line_offense(node) do |method|
66
+ format(MSG, hook: method)
67
+ end
68
+ end
69
+
70
+ alias on_numblock on_block
71
+
72
+ private
73
+
74
+ def chained_single_line_hooks?(node)
75
+ next_node = node.right_sibling
76
+
77
+ hook?(next_node) && node.single_line? && next_node.single_line?
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after subject block.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # subject(:obj) { described_class }
11
+ # let(:foo) { bar }
12
+ #
13
+ # # good
14
+ # subject(:obj) { described_class }
15
+ #
16
+ # let(:foo) { bar }
17
+ #
18
+ class EmptyLineAfterSubject < Base
19
+ extend AutoCorrector
20
+ include EmptyLineSeparation
21
+ include InsideExampleGroup
22
+
23
+ MSG = 'Add an empty line after `%<subject>s`.'
24
+
25
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
26
+ return unless subject?(node)
27
+ return unless inside_example_group?(node)
28
+
29
+ missing_separating_line_offense(node) do |method|
30
+ format(MSG, subject: method)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ 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
+ # Check that the `output` matcher is not called with an empty string.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # expect { foo }.to output('').to_stdout
11
+ # expect { bar }.not_to output('').to_stderr
12
+ #
13
+ # # good
14
+ # expect { foo }.not_to output.to_stdout
15
+ # expect { bar }.to output.to_stderr
16
+ #
17
+ class EmptyOutput < Base
18
+ extend AutoCorrector
19
+
20
+ MSG = 'Use `%<runner>s` instead of matching on an empty output.'
21
+ RESTRICT_ON_SEND = Runners.all
22
+
23
+ # @!method matching_empty_output(node)
24
+ def_node_matcher :matching_empty_output, <<~PATTERN
25
+ (send
26
+ (block
27
+ (send nil? :expect) ...
28
+ )
29
+ #Runners.all
30
+ (send $(send nil? :output (str empty?)) ...)
31
+ )
32
+ PATTERN
33
+
34
+ def on_send(send_node)
35
+ matching_empty_output(send_node) do |node|
36
+ runner = send_node.method?(:to) ? 'not_to' : 'to'
37
+ message = format(MSG, runner: runner)
38
+ add_offense(node, message: message) do |corrector|
39
+ corrector.replace(send_node.loc.selector, runner)
40
+ corrector.replace(node, 'output')
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ 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
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks for long examples.
7
7
  #
8
8
  # A long example is usually more difficult to understand. Consider
9
- # extracting out some behaviour, e.g. with a `let` block, or a helper
9
+ # extracting out some behavior, e.g. with a `let` block, or a helper
10
10
  # method.
11
11
  #
12
12
  # @example
@@ -25,32 +25,50 @@ module RuboCop
25
25
  # result = service.call
26
26
  # expect(result).to be(true)
27
27
  # end
28
- class ExampleLength < Cop
29
- include RuboCop::RSpec::SpecOnly, CodeLength
30
-
31
- EXAMPLE_BLOCKS = RuboCop::RSpec::Language::Examples::ALL
28
+ #
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.
33
+ #
34
+ # @example CountAsOne: ['array', 'heredoc', 'method_call']
35
+ #
36
+ # it do
37
+ # array = [ # +1
38
+ # 1,
39
+ # 2
40
+ # ]
41
+ #
42
+ # hash = { # +3
43
+ # key: 'value'
44
+ # }
45
+ #
46
+ # msg = <<~HEREDOC # +1
47
+ # Heredoc
48
+ # content.
49
+ # HEREDOC
50
+ #
51
+ # foo( # +1
52
+ # 1,
53
+ # 2
54
+ # )
55
+ # end # 6 points
56
+ #
57
+ class ExampleLength < Base
58
+ include CodeLength
32
59
 
33
- def on_block(node)
34
- method, _args, _body = *node
35
- _receiver, method_name, _object = *method
36
- return unless EXAMPLE_BLOCKS.include?(method_name)
60
+ LABEL = 'Example'
37
61
 
38
- length = code_length(node)
62
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
63
+ return unless example?(node)
39
64
 
40
- return unless length > max_length
41
- add_offense(node, :expression, message(length))
65
+ check_code_length(node)
42
66
  end
43
67
 
44
68
  private
45
69
 
46
- def code_length(node)
47
- lines = node.source.lines[1..-2]
48
-
49
- lines.count { |line| !irrelevant_line(line) }
50
- end
51
-
52
- def message(length)
53
- format('Example has too many lines. [%d/%d]', length, max_length)
70
+ def cop_label
71
+ LABEL
54
72
  end
55
73
  end
56
74
  end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for examples without a description.
7
+ #
8
+ # RSpec allows for auto-generated example descriptions when there is no
9
+ # description provided or the description is an empty one.
10
+ # It is acceptable to use `specify` without a description
11
+ #
12
+ # This cop removes empty descriptions.
13
+ # It also defines whether auto-generated description is allowed, based
14
+ # on the configured style.
15
+ #
16
+ # This cop can be configured using the `EnforcedStyle` option
17
+ #
18
+ # @example
19
+ # # always good
20
+ # specify do
21
+ # result = service.call
22
+ # expect(result).to be(true)
23
+ # end
24
+ #
25
+ # @example `EnforcedStyle: always_allow` (default)
26
+ # # bad
27
+ # it('') { is_expected.to be_good }
28
+ # specify '' do
29
+ # result = service.call
30
+ # expect(result).to be(true)
31
+ # end
32
+ #
33
+ # # good
34
+ # it { is_expected.to be_good }
35
+ # specify do
36
+ # result = service.call
37
+ # expect(result).to be(true)
38
+ # end
39
+ #
40
+ # @example `EnforcedStyle: single_line_only`
41
+ # # bad
42
+ # it('') { is_expected.to be_good }
43
+ # it do
44
+ # result = service.call
45
+ # expect(result).to be(true)
46
+ # end
47
+ #
48
+ # # good
49
+ # it { is_expected.to be_good }
50
+ #
51
+ # @example `EnforcedStyle: disallow`
52
+ # # bad
53
+ # it { is_expected.to be_good }
54
+ # it do
55
+ # result = service.call
56
+ # expect(result).to be(true)
57
+ # end
58
+ #
59
+ class ExampleWithoutDescription < Base
60
+ include ConfigurableEnforcedStyle
61
+
62
+ MSG_DEFAULT_ARGUMENT = 'Omit the argument when you want to ' \
63
+ 'have auto-generated description.'
64
+ MSG_ADD_DESCRIPTION = 'Add a description.'
65
+
66
+ # @!method example_description(node)
67
+ def_node_matcher :example_description, '(send nil? _ $(str $_))'
68
+
69
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
70
+ return unless example?(node)
71
+
72
+ check_example_without_description(node.send_node)
73
+
74
+ example_description(node.send_node) do |message_node, message|
75
+ return unless message.to_s.empty?
76
+
77
+ add_offense(message_node, message: MSG_DEFAULT_ARGUMENT)
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def check_example_without_description(node)
84
+ return if node.arguments?
85
+ return unless disallow_empty_description?(node)
86
+ return if node.method?(:specify) && node.parent.multiline?
87
+
88
+ add_offense(node, message: MSG_ADD_DESCRIPTION)
89
+ end
90
+
91
+ def disallow_empty_description?(node)
92
+ style == :disallow ||
93
+ (style == :single_line_only && node.parent.multiline?)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end