rubocop-rspec 1.7.0 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +955 -79
- data/CODE_OF_CONDUCT.md +17 -0
- data/MIT-LICENSE.md +1 -2
- data/README.md +35 -35
- data/config/default.yml +940 -52
- data/config/obsoletion.yml +30 -0
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/any_instance.rb +10 -13
- data/lib/rubocop/cop/rspec/around_block.rb +97 -0
- data/lib/rubocop/cop/rspec/base.rb +26 -0
- data/lib/rubocop/cop/rspec/be.rb +39 -0
- data/lib/rubocop/cop/rspec/be_empty.rb +45 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +47 -0
- data/lib/rubocop/cop/rspec/be_eql.rb +18 -15
- data/lib/rubocop/cop/rspec/be_nil.rb +74 -0
- data/lib/rubocop/cop/rspec/before_after_all.rb +45 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +184 -0
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/contain_exactly.rb +56 -0
- data/lib/rubocop/cop/rspec/context_method.rb +57 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +117 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +52 -21
- data/lib/rubocop/cop/rspec/describe_method.rb +26 -11
- data/lib/rubocop/cop/rspec/describe_symbol.rb +37 -0
- data/lib/rubocop/cop/rspec/described_class.rb +181 -34
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +38 -0
- data/lib/rubocop/cop/rspec/dialect.rb +84 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +58 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +134 -47
- data/lib/rubocop/cop/rspec/empty_hook.rb +49 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +42 -0
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +40 -0
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +36 -0
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +38 -20
- data/lib/rubocop/cop/rspec/example_without_description.rb +98 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +117 -27
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +110 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +46 -20
- data/lib/rubocop/cop/rspec/expect_change.rb +86 -0
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +50 -0
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/expect_output.rb +50 -0
- data/lib/rubocop/cop/rspec/focus.rb +79 -25
- data/lib/rubocop/cop/rspec/hook_argument.rb +48 -36
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +81 -0
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +37 -0
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +68 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +100 -0
- data/lib/rubocop/cop/rspec/implicit_subject.rb +167 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +112 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +74 -0
- data/lib/rubocop/cop/rspec/instance_variable.rb +28 -14
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +49 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +74 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +57 -29
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +127 -0
- data/lib/rubocop/cop/rspec/let_before_examples.rb +101 -0
- data/lib/rubocop/cop/rspec/let_setup.rb +32 -16
- data/lib/rubocop/cop/rspec/match_array.rb +59 -0
- data/lib/rubocop/cop/rspec/message_chain.rb +10 -15
- data/lib/rubocop/cop/rspec/message_expectation.rb +12 -9
- data/lib/rubocop/cop/rspec/message_spies.rb +88 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +59 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
- data/lib/rubocop/cop/rspec/mixin/inside_example_group.rb +29 -0
- data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +63 -0
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +39 -0
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +14 -12
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +86 -26
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +146 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +97 -0
- data/lib/rubocop/cop/rspec/named_subject.rb +107 -27
- data/lib/rubocop/cop/rspec/nested_groups.rb +84 -47
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +102 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +30 -27
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +74 -0
- data/lib/rubocop/cop/rspec/pending.rb +80 -0
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +159 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +341 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +89 -0
- data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
- data/lib/rubocop/cop/rspec/receive_never.rb +41 -0
- data/lib/rubocop/cop/rspec/redundant_around.rb +65 -0
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_description.rb +98 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +53 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +100 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +96 -0
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +105 -0
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +169 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +59 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +92 -0
- data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
- data/lib/rubocop/cop/rspec/shared_examples.rb +125 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +93 -0
- data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +71 -0
- data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
- data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +176 -0
- data/lib/rubocop/cop/rspec/subject_declaration.rb +46 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +93 -74
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +67 -0
- data/lib/rubocop/cop/rspec/variable_definition.rb +77 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +68 -0
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +111 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +28 -14
- data/lib/rubocop/cop/rspec/void_expect.rb +60 -0
- data/lib/rubocop/cop/rspec/yield.rb +82 -0
- data/lib/rubocop/cop/rspec_cops.rb +112 -0
- data/lib/rubocop/rspec/align_let_brace.rb +63 -0
- data/lib/rubocop/rspec/concept.rb +33 -0
- data/lib/rubocop/rspec/config_formatter.rb +27 -4
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/corrector/move_node.rb +51 -0
- data/lib/rubocop/rspec/description_extractor.rb +60 -18
- data/lib/rubocop/rspec/example.rb +37 -0
- data/lib/rubocop/rspec/example_group.rb +67 -0
- data/lib/rubocop/rspec/hook.rb +79 -0
- data/lib/rubocop/rspec/inject.rb +3 -1
- data/lib/rubocop/rspec/language.rb +184 -41
- data/lib/rubocop/rspec/node.rb +19 -0
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +29 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +61 -19
- data/lib/rubocop/rspec.rb +6 -2
- data/lib/rubocop-rspec.rb +45 -34
- metadata +130 -195
- data/Gemfile +0 -13
- data/Rakefile +0 -48
- data/lib/rubocop/cop/rspec/file_path.rb +0 -83
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -16
- data/lib/rubocop/rspec/spec_only.rb +0 -61
- data/lib/rubocop/rspec/top_level_describe.rb +0 -61
- data/lib/rubocop/rspec/util.rb +0 -19
- data/rubocop-rspec.gemspec +0 -42
- data/spec/expect_violation/expectation_spec.rb +0 -85
- data/spec/project/changelog_spec.rb +0 -81
- data/spec/project/default_config_spec.rb +0 -52
- data/spec/project/project_requires_spec.rb +0 -8
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -30
- data/spec/rubocop/cop/rspec/be_eql_spec.rb +0 -59
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +0 -113
- data/spec/rubocop/cop/rspec/describe_method_spec.rb +0 -32
- data/spec/rubocop/cop/rspec/described_class_spec.rb +0 -219
- data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +0 -79
- data/spec/rubocop/cop/rspec/example_length_spec.rb +0 -117
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +0 -82
- data/spec/rubocop/cop/rspec/expect_actual_spec.rb +0 -136
- data/spec/rubocop/cop/rspec/file_path_spec.rb +0 -236
- data/spec/rubocop/cop/rspec/focus_spec.rb +0 -130
- data/spec/rubocop/cop/rspec/hook_argument_spec.rb +0 -189
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +0 -75
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +0 -54
- data/spec/rubocop/cop/rspec/let_setup_spec.rb +0 -66
- data/spec/rubocop/cop/rspec/message_chain_spec.rb +0 -21
- data/spec/rubocop/cop/rspec/message_expectation_spec.rb +0 -63
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -28
- data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +0 -84
- data/spec/rubocop/cop/rspec/named_subject_spec.rb +0 -62
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +0 -55
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -57
- data/spec/rubocop/cop/rspec/subject_stub_spec.rb +0 -183
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +0 -71
- data/spec/rubocop/rspec/config_formatter_spec.rb +0 -48
- data/spec/rubocop/rspec/description_extractor_spec.rb +0 -35
- data/spec/rubocop/rspec/language/selector_set_spec.rb +0 -29
- data/spec/rubocop/rspec/spec_only_spec.rb +0 -97
- data/spec/rubocop/rspec/util/one_spec.rb +0 -21
- data/spec/rubocop/rspec/wording_spec.rb +0 -44
- data/spec/shared/rspec_only_cop_behavior.rb +0 -68
- data/spec/spec_helper.rb +0 -41
- data/spec/support/expect_violation.rb +0 -166
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Description should be descriptive.
|
7
|
+
#
|
8
|
+
# If example group or example contains only `execute string`, numbers
|
9
|
+
# and regular expressions, the description is not clear.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# describe `time` do
|
14
|
+
# # ...
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# context /when foo/ do
|
19
|
+
# # ...
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# it 10000 do
|
24
|
+
# # ...
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# describe Foo do
|
29
|
+
# # ...
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# describe '#foo' do
|
34
|
+
# # ...
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# # good
|
38
|
+
# context "when #{foo} is bar" do
|
39
|
+
# # ...
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# # good
|
43
|
+
# it 'does something' do
|
44
|
+
# # ...
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
class UndescriptiveLiteralsDescription < Base
|
48
|
+
MSG = 'Description should be descriptive.'
|
49
|
+
|
50
|
+
# @!method example_groups_or_example?(node)
|
51
|
+
def_node_matcher :example_groups_or_example?, <<~PATTERN
|
52
|
+
(block (send #rspec? {#ExampleGroups.all #Examples.all} $_) ...)
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
56
|
+
example_groups_or_example?(node) do |arg|
|
57
|
+
add_offense(arg) if offense?(arg)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def offense?(node)
|
64
|
+
%i[xstr int regexp].include?(node.type)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for a specified error in checking raised errors.
|
7
|
+
#
|
8
|
+
# Enforces one of an Exception type, a string, or a regular
|
9
|
+
# expression to match against the exception message as a parameter
|
10
|
+
# to `raise_error`
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# expect {
|
15
|
+
# raise StandardError.new('error')
|
16
|
+
# }.to raise_error
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# expect {
|
20
|
+
# raise StandardError.new('error')
|
21
|
+
# }.to raise_error(StandardError)
|
22
|
+
#
|
23
|
+
# expect {
|
24
|
+
# raise StandardError.new('error')
|
25
|
+
# }.to raise_error('error')
|
26
|
+
#
|
27
|
+
# expect {
|
28
|
+
# raise StandardError.new('error')
|
29
|
+
# }.to raise_error(/err/)
|
30
|
+
#
|
31
|
+
# expect { do_something }.not_to raise_error
|
32
|
+
#
|
33
|
+
class UnspecifiedException < Base
|
34
|
+
MSG = 'Specify the exception being captured'
|
35
|
+
RESTRICT_ON_SEND = %i[to].freeze
|
36
|
+
|
37
|
+
# @!method empty_raise_error_or_exception(node)
|
38
|
+
def_node_matcher :empty_raise_error_or_exception, <<~PATTERN
|
39
|
+
(send
|
40
|
+
(block
|
41
|
+
(send nil? :expect) ...)
|
42
|
+
:to
|
43
|
+
(send nil? {:raise_error :raise_exception})
|
44
|
+
)
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
def on_send(node)
|
48
|
+
return unless empty_exception_matcher?(node)
|
49
|
+
|
50
|
+
add_offense(node.children.last)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def empty_exception_matcher?(node)
|
56
|
+
empty_raise_error_or_exception(node) && !block_with_args?(node.parent)
|
57
|
+
end
|
58
|
+
|
59
|
+
def block_with_args?(node)
|
60
|
+
return false unless node&.block_type?
|
61
|
+
|
62
|
+
node.arguments?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks that memoized helpers names are symbols or strings.
|
7
|
+
#
|
8
|
+
# @example EnforcedStyle: symbols (default)
|
9
|
+
# # bad
|
10
|
+
# subject('user') { create_user }
|
11
|
+
# let('user_name') { 'Adam' }
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# subject(:user) { create_user }
|
15
|
+
# let(:user_name) { 'Adam' }
|
16
|
+
#
|
17
|
+
# @example EnforcedStyle: strings
|
18
|
+
# # bad
|
19
|
+
# subject(:user) { create_user }
|
20
|
+
# let(:user_name) { 'Adam' }
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# subject('user') { create_user }
|
24
|
+
# let('user_name') { 'Adam' }
|
25
|
+
#
|
26
|
+
class VariableDefinition < Base
|
27
|
+
extend AutoCorrector
|
28
|
+
include ConfigurableEnforcedStyle
|
29
|
+
include Variable
|
30
|
+
include InsideExampleGroup
|
31
|
+
|
32
|
+
MSG = 'Use %<style>s for variable names.'
|
33
|
+
|
34
|
+
def on_send(node)
|
35
|
+
return unless inside_example_group?(node)
|
36
|
+
|
37
|
+
variable_definition?(node) do |variable|
|
38
|
+
next unless style_offense?(variable)
|
39
|
+
|
40
|
+
add_offense(
|
41
|
+
variable,
|
42
|
+
message: format(MSG, style: style)
|
43
|
+
) do |corrector|
|
44
|
+
corrector.replace(variable, correct_variable(variable))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def correct_variable(variable)
|
52
|
+
case variable.type
|
53
|
+
when :dsym
|
54
|
+
variable.source[1..]
|
55
|
+
when :sym
|
56
|
+
variable.value.to_s.inspect
|
57
|
+
else
|
58
|
+
variable.value.to_sym.inspect
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def style_offense?(variable)
|
63
|
+
(style == :symbols && string?(variable)) ||
|
64
|
+
(style == :strings && symbol?(variable))
|
65
|
+
end
|
66
|
+
|
67
|
+
def string?(node)
|
68
|
+
node.str_type?
|
69
|
+
end
|
70
|
+
|
71
|
+
def symbol?(node)
|
72
|
+
node.sym_type? || node.dsym_type?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks that memoized helper names use the configured style.
|
7
|
+
#
|
8
|
+
# Variables can be excluded from checking using the `AllowedPatterns`
|
9
|
+
# option.
|
10
|
+
#
|
11
|
+
# @example EnforcedStyle: snake_case (default)
|
12
|
+
# # bad
|
13
|
+
# subject(:userName1) { 'Adam' }
|
14
|
+
# let(:userName2) { 'Adam' }
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# subject(:user_name_1) { 'Adam' }
|
18
|
+
# let(:user_name_2) { 'Adam' }
|
19
|
+
#
|
20
|
+
# @example EnforcedStyle: camelCase
|
21
|
+
# # bad
|
22
|
+
# subject(:user_name_1) { 'Adam' }
|
23
|
+
# let(:user_name_2) { 'Adam' }
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# subject(:userName1) { 'Adam' }
|
27
|
+
# let(:userName2) { 'Adam' }
|
28
|
+
#
|
29
|
+
# @example AllowedPatterns configuration
|
30
|
+
# # rubocop.yml
|
31
|
+
# # RSpec/VariableName:
|
32
|
+
# # EnforcedStyle: snake_case
|
33
|
+
# # AllowedPatterns:
|
34
|
+
# # - ^userFood
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# # okay because it matches the `^userFood` regex in `AllowedPatterns`
|
38
|
+
# subject(:userFood_1) { 'spaghetti' }
|
39
|
+
# let(:userFood_2) { 'fettuccine' }
|
40
|
+
#
|
41
|
+
class VariableName < Base
|
42
|
+
include ConfigurableNaming
|
43
|
+
include AllowedPattern
|
44
|
+
include Variable
|
45
|
+
include InsideExampleGroup
|
46
|
+
|
47
|
+
MSG = 'Use %<style>s for variable names.'
|
48
|
+
|
49
|
+
def on_send(node)
|
50
|
+
return unless inside_example_group?(node)
|
51
|
+
|
52
|
+
variable_definition?(node) do |variable|
|
53
|
+
return if variable.dstr_type? || variable.dsym_type?
|
54
|
+
return if matches_allowed_pattern?(variable.value)
|
55
|
+
|
56
|
+
check_name(node, variable.value, variable.source_range)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def message(style)
|
63
|
+
format(MSG, style: style)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for consistent verified double reference style.
|
7
|
+
#
|
8
|
+
# Only investigates references that are one of the supported styles.
|
9
|
+
#
|
10
|
+
# @see https://rspec.info/features/3-12/rspec-mocks/verifying-doubles
|
11
|
+
#
|
12
|
+
# This cop can be configured in your configuration using the
|
13
|
+
# `EnforcedStyle` option and supports `--auto-gen-config`.
|
14
|
+
#
|
15
|
+
# @example `EnforcedStyle: constant` (default)
|
16
|
+
# # bad
|
17
|
+
# let(:foo) do
|
18
|
+
# instance_double('ClassName', method_name: 'returned_value')
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# let(:foo) do
|
23
|
+
# instance_double(ClassName, method_name: 'returned_value')
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @example `EnforcedStyle: string`
|
27
|
+
# # bad
|
28
|
+
# let(:foo) do
|
29
|
+
# instance_double(ClassName, method_name: 'returned_value')
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# let(:foo) do
|
34
|
+
# instance_double('ClassName', method_name: 'returned_value')
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# @example Reference is not in the supported style list. No enforcement
|
38
|
+
#
|
39
|
+
# # good
|
40
|
+
# let(:foo) do
|
41
|
+
# instance_double(@klass, method_name: 'returned_value')
|
42
|
+
# end
|
43
|
+
class VerifiedDoubleReference < Base
|
44
|
+
extend AutoCorrector
|
45
|
+
include ConfigurableEnforcedStyle
|
46
|
+
|
47
|
+
MSG = 'Use a %<style>s class reference for verified doubles.'
|
48
|
+
|
49
|
+
RESTRICT_ON_SEND = Set[
|
50
|
+
:class_double,
|
51
|
+
:class_spy,
|
52
|
+
:instance_double,
|
53
|
+
:instance_spy,
|
54
|
+
:mock_model,
|
55
|
+
:object_double,
|
56
|
+
:object_spy,
|
57
|
+
:stub_model
|
58
|
+
].freeze
|
59
|
+
|
60
|
+
REFERENCE_TYPE_STYLES = {
|
61
|
+
str: :string,
|
62
|
+
const: :constant
|
63
|
+
}.freeze
|
64
|
+
|
65
|
+
# @!method verified_double(node)
|
66
|
+
def_node_matcher :verified_double, <<~PATTERN
|
67
|
+
(send
|
68
|
+
nil?
|
69
|
+
RESTRICT_ON_SEND
|
70
|
+
$_class_reference
|
71
|
+
...)
|
72
|
+
PATTERN
|
73
|
+
|
74
|
+
def on_send(node)
|
75
|
+
verified_double(node) do |class_reference|
|
76
|
+
break correct_style_detected unless opposing_style?(class_reference)
|
77
|
+
|
78
|
+
message = format(MSG, style: style)
|
79
|
+
expression = class_reference.source_range
|
80
|
+
|
81
|
+
add_offense(expression, message: message) do |corrector|
|
82
|
+
offense = class_reference.source
|
83
|
+
corrector.replace(expression, correct_style(offense))
|
84
|
+
|
85
|
+
opposite_style_detected
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def opposing_style?(class_reference)
|
93
|
+
class_reference_style = REFERENCE_TYPE_STYLES[class_reference.type]
|
94
|
+
|
95
|
+
# Only enforce supported styles
|
96
|
+
return false unless class_reference_style
|
97
|
+
|
98
|
+
class_reference_style != style
|
99
|
+
end
|
100
|
+
|
101
|
+
def correct_style(offense)
|
102
|
+
if style == :string
|
103
|
+
"'#{offense}'"
|
104
|
+
else
|
105
|
+
offense.gsub(/^['"]|['"]$/, '')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -5,32 +5,46 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Prefer using verifying doubles over normal doubles.
|
7
7
|
#
|
8
|
-
# @see https://
|
8
|
+
# @see https://rspec.info/features/3-12/rspec-mocks/verifying-doubles
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# let(:foo) do
|
13
|
+
# double(method_name: 'returned value')
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# let(:foo) do
|
18
|
+
# double("ClassName", method_name: 'returned value')
|
14
19
|
# end
|
15
20
|
#
|
16
21
|
# # good
|
17
|
-
#
|
18
|
-
#
|
22
|
+
# let(:foo) do
|
23
|
+
# instance_double("ClassName", method_name: 'returned value')
|
19
24
|
# end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
#
|
26
|
+
class VerifiedDoubles < Base
|
27
|
+
MSG = 'Prefer using verifying doubles over normal doubles.'
|
28
|
+
RESTRICT_ON_SEND = %i[double spy].freeze
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
# @!method unverified_double(node)
|
31
|
+
def_node_matcher :unverified_double, <<~PATTERN
|
32
|
+
{(send nil? {:double :spy} $...)}
|
27
33
|
PATTERN
|
28
34
|
|
29
35
|
def on_send(node)
|
30
|
-
|
31
|
-
|
36
|
+
unverified_double(node) do |name, *_args|
|
37
|
+
return if name.nil? && cop_config['IgnoreNameless']
|
38
|
+
return if symbol?(name) && cop_config['IgnoreSymbolicNames']
|
39
|
+
|
40
|
+
add_offense(node)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
32
45
|
|
33
|
-
|
46
|
+
def symbol?(name)
|
47
|
+
name&.sym_type?
|
34
48
|
end
|
35
49
|
end
|
36
50
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks void `expect()`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# expect(something)
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# expect(something).to be(1)
|
14
|
+
#
|
15
|
+
class VoidExpect < Base
|
16
|
+
MSG = 'Do not use `expect()` without `.to` or `.not_to`. ' \
|
17
|
+
'Chain the methods or remove it.'
|
18
|
+
RESTRICT_ON_SEND = %i[expect].freeze
|
19
|
+
|
20
|
+
# @!method expect?(node)
|
21
|
+
def_node_matcher :expect?, <<~PATTERN
|
22
|
+
(send nil? :expect ...)
|
23
|
+
PATTERN
|
24
|
+
|
25
|
+
# @!method expect_block?(node)
|
26
|
+
def_node_matcher :expect_block?, <<~PATTERN
|
27
|
+
(block #expect? (args) _body)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def on_send(node)
|
31
|
+
return unless expect?(node)
|
32
|
+
|
33
|
+
check_expect(node)
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
37
|
+
return unless expect_block?(node)
|
38
|
+
|
39
|
+
check_expect(node)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def check_expect(node)
|
45
|
+
return unless void?(node)
|
46
|
+
|
47
|
+
add_offense(node)
|
48
|
+
end
|
49
|
+
|
50
|
+
def void?(expect)
|
51
|
+
parent = expect.parent
|
52
|
+
return true unless parent
|
53
|
+
return true if parent.begin_type?
|
54
|
+
|
55
|
+
parent.block_type? && parent.body == expect
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for calling a block within a stub.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# allow(foo).to receive(:bar) { |&block| block.call(1) }
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# expect(foo).to receive(:bar).and_yield(1)
|
14
|
+
#
|
15
|
+
class Yield < Base
|
16
|
+
extend AutoCorrector
|
17
|
+
include RangeHelp
|
18
|
+
|
19
|
+
MSG = 'Use `.and_yield`.'
|
20
|
+
|
21
|
+
# @!method method_on_stub?(node)
|
22
|
+
def_node_search :method_on_stub?, '(send nil? :receive ...)'
|
23
|
+
|
24
|
+
# @!method block_arg(node)
|
25
|
+
def_node_matcher :block_arg, '(args (blockarg $_))'
|
26
|
+
|
27
|
+
# @!method block_call?(node)
|
28
|
+
def_node_matcher :block_call?, '(send (lvar %) :call ...)'
|
29
|
+
|
30
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
31
|
+
return unless method_on_stub?(node.send_node)
|
32
|
+
|
33
|
+
block_arg(node.arguments) do |block|
|
34
|
+
if calling_block?(node.body, block)
|
35
|
+
range = block_range(node)
|
36
|
+
|
37
|
+
add_offense(range) do |corrector|
|
38
|
+
autocorrect(corrector, node, range)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def autocorrect(corrector, node, range)
|
47
|
+
corrector.replace(
|
48
|
+
range_with_surrounding_space(range, side: :left),
|
49
|
+
generate_replacement(node.body)
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def calling_block?(node, block)
|
54
|
+
if node.begin_type?
|
55
|
+
node.each_child_node.all? { |child| block_call?(child, block) }
|
56
|
+
else
|
57
|
+
block_call?(node, block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def block_range(node)
|
62
|
+
node.loc.begin.with(end_pos: node.loc.end.end_pos)
|
63
|
+
end
|
64
|
+
|
65
|
+
def generate_replacement(node)
|
66
|
+
if node.begin_type?
|
67
|
+
node.children.map { |child| convert_block_to_yield(child) }.join
|
68
|
+
else
|
69
|
+
convert_block_to_yield(node)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_block_to_yield(node)
|
74
|
+
args = node.arguments
|
75
|
+
replacement = '.and_yield'
|
76
|
+
replacement += "(#{args.map(&:source).join(', ')})" if args.any?
|
77
|
+
replacement
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|