forked from rubocop/rubocop-rspec
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nested_groups.rb
143 lines (131 loc) · 3.75 KB
/
nested_groups.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks for nested example groups.
#
# This cop is configurable using the `Max` option
# and supports `--auto-gen-config
#
# @example
# # bad
# context 'when using some feature' do
# let(:some) { :various }
# let(:feature) { :setup }
#
# context 'when user is signed in' do # flagged by rubocop
# let(:user) do
# UserCreate.call(user_attributes)
# end
#
# let(:user_attributes) do
# {
# name: 'John',
# age: 22,
# role: role
# }
# end
#
# context 'when user is an admin' do # flagged by rubocop
# let(:role) { 'admin' }
#
# it 'blah blah'
# it 'yada yada'
# end
# end
# end
#
# # better
# context 'using some feature as an admin' do
# let(:some) { :various }
# let(:feature) { :setup }
#
# let(:user) do
# UserCreate.call(
# name: 'John',
# age: 22,
# role: 'admin'
# )
# end
#
# it 'blah blah'
# it 'yada yada'
# end
#
# @example configuration
#
# # .rubocop.yml
# # RSpec/NestedGroups:
# # Max: 2
#
# context 'when using some feature' do
# let(:some) { :various }
# let(:feature) { :setup }
#
# context 'when user is signed in' do
# let(:user) do
# UserCreate.call(user_attributes)
# end
#
# let(:user_attributes) do
# {
# name: 'John',
# age: 22,
# role: role
# }
# end
#
# context 'when user is an admin' do # flagged by rubocop
# let(:role) { 'admin' }
#
# it 'blah blah'
# it 'yada yada'
# end
# end
# end
#
class NestedGroups < Cop
include ConfigurableMax
include RuboCop::RSpec::TopLevelDescribe
MSG = 'Maximum example group nesting exceeded [%<total>d/%<max>d].'
DEPRECATED_MAX_KEY = 'MaxNesting'
DEPRECATION_WARNING =
"Configuration key `#{DEPRECATED_MAX_KEY}` for #{cop_name} is " \
'deprecated in favor of `Max`. Please use that instead.'
def_node_search :find_contexts, ExampleGroups::ALL.block_pattern
def on_top_level_describe(node, _args)
find_nested_contexts(node.parent) do |context, nesting|
self.max = nesting
add_offense(
context.send_node,
message: message(nesting)
)
end
end
private
def find_nested_contexts(node, nesting: 1, &block)
find_contexts(node) do |nested_context|
yield(nested_context, nesting) if nesting > max_nesting
nested_context.each_child_node do |child|
find_nested_contexts(child, nesting: nesting + 1, &block)
end
end
end
def message(nesting)
format(MSG, total: nesting, max: max_nesting)
end
def max_nesting
@max_nesting ||= Integer(max_nesting_config)
end
def max_nesting_config
if cop_config.key?(DEPRECATED_MAX_KEY)
warn DEPRECATION_WARNING
cop_config.fetch(DEPRECATED_MAX_KEY)
else
cop_config.fetch('Max', 3)
end
end
end
end
end
end