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.
- 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
|