rubocop-airbnb 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +7 -0
- data/LICENSE.md +9 -0
- data/README.md +68 -0
- data/config/default.yml +39 -0
- data/config/rubocop-airbnb.yml +96 -0
- data/config/rubocop-bundler.yml +8 -0
- data/config/rubocop-gemspec.yml +9 -0
- data/config/rubocop-layout.yml +514 -0
- data/config/rubocop-lint.yml +315 -0
- data/config/rubocop-metrics.yml +47 -0
- data/config/rubocop-naming.yml +68 -0
- data/config/rubocop-performance.yml +143 -0
- data/config/rubocop-rails.yml +193 -0
- data/config/rubocop-rspec.yml +281 -0
- data/config/rubocop-security.yml +13 -0
- data/config/rubocop-style.yml +953 -0
- data/lib/rubocop-airbnb.rb +11 -0
- data/lib/rubocop/airbnb.rb +16 -0
- data/lib/rubocop/airbnb/inflections.rb +14 -0
- data/lib/rubocop/airbnb/inject.rb +20 -0
- data/lib/rubocop/airbnb/rails_autoloading.rb +55 -0
- data/lib/rubocop/airbnb/version.rb +8 -0
- data/lib/rubocop/cop/airbnb/class_name.rb +47 -0
- data/lib/rubocop/cop/airbnb/class_or_module_declared_in_wrong_file.rb +138 -0
- data/lib/rubocop/cop/airbnb/const_assigned_in_wrong_file.rb +74 -0
- data/lib/rubocop/cop/airbnb/continuation_slash.rb +25 -0
- data/lib/rubocop/cop/airbnb/default_scope.rb +20 -0
- data/lib/rubocop/cop/airbnb/factory_attr_references_class.rb +74 -0
- data/lib/rubocop/cop/airbnb/factory_class_use_string.rb +39 -0
- data/lib/rubocop/cop/airbnb/mass_assignment_accessible_modifier.rb +18 -0
- data/lib/rubocop/cop/airbnb/module_method_in_wrong_file.rb +104 -0
- data/lib/rubocop/cop/airbnb/no_timeout.rb +19 -0
- data/lib/rubocop/cop/airbnb/opt_arg_parameters.rb +38 -0
- data/lib/rubocop/cop/airbnb/phrase_bundle_keys.rb +67 -0
- data/lib/rubocop/cop/airbnb/risky_activerecord_invocation.rb +63 -0
- data/lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb +114 -0
- data/lib/rubocop/cop/airbnb/rspec_environment_modification.rb +58 -0
- data/lib/rubocop/cop/airbnb/simple_modifier_conditional.rb +23 -0
- data/lib/rubocop/cop/airbnb/spec_constant_assignment.rb +55 -0
- data/lib/rubocop/cop/airbnb/unsafe_yaml_marshal.rb +47 -0
- data/rubocop-airbnb.gemspec +32 -0
- data/spec/rubocop/cop/airbnb/class_name_spec.rb +78 -0
- data/spec/rubocop/cop/airbnb/class_or_module_declared_in_wrong_file_spec.rb +174 -0
- data/spec/rubocop/cop/airbnb/const_assigned_in_wrong_file_spec.rb +178 -0
- data/spec/rubocop/cop/airbnb/continuation_slash_spec.rb +162 -0
- data/spec/rubocop/cop/airbnb/default_scope_spec.rb +38 -0
- data/spec/rubocop/cop/airbnb/factory_attr_references_class_spec.rb +160 -0
- data/spec/rubocop/cop/airbnb/factory_class_use_string_spec.rb +26 -0
- data/spec/rubocop/cop/airbnb/mass_assignment_accessible_modifier_spec.rb +28 -0
- data/spec/rubocop/cop/airbnb/module_method_in_wrong_file_spec.rb +181 -0
- data/spec/rubocop/cop/airbnb/no_timeout_spec.rb +30 -0
- data/spec/rubocop/cop/airbnb/opt_arg_parameter_spec.rb +103 -0
- data/spec/rubocop/cop/airbnb/phrase_bundle_keys_spec.rb +74 -0
- data/spec/rubocop/cop/airbnb/risky_activerecord_invocation_spec.rb +54 -0
- data/spec/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace_spec.rb +284 -0
- data/spec/rubocop/cop/airbnb/rspec_environment_modification_spec.rb +64 -0
- data/spec/rubocop/cop/airbnb/simple_modifier_conditional_spec.rb +122 -0
- data/spec/rubocop/cop/airbnb/spec_constant_assignment_spec.rb +80 -0
- data/spec/rubocop/cop/airbnb/unsafe_yaml_marshal_spec.rb +50 -0
- data/spec/spec_helper.rb +35 -0
- metadata +150 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
describe RuboCop::Cop::Airbnb::ConstAssignedInWrongFile do
|
2
|
+
subject(:cop) { described_class.new(config) }
|
3
|
+
|
4
|
+
let(:config) do
|
5
|
+
RuboCop::Config.new(
|
6
|
+
{
|
7
|
+
"Rails" => {
|
8
|
+
"Enabled" => true,
|
9
|
+
},
|
10
|
+
}
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Put source in a directory under /tmp because this cop cares about the filename
|
15
|
+
# but not the parent dir name.
|
16
|
+
let(:tmpdir) { Dir.mktmpdir }
|
17
|
+
let(:models_dir) do
|
18
|
+
gemfile = File.new("#{tmpdir}/Gemfile", "w")
|
19
|
+
gemfile.close
|
20
|
+
FileUtils.mkdir_p("#{tmpdir}/app/models").first
|
21
|
+
end
|
22
|
+
|
23
|
+
after do
|
24
|
+
FileUtils.rm_rf tmpdir
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'rejects if const assignment is in a file with non-matching name' do
|
28
|
+
source = [
|
29
|
+
'module Foo',
|
30
|
+
' module Bar',
|
31
|
+
' BAZ = 42',
|
32
|
+
' end',
|
33
|
+
'end',
|
34
|
+
].join("\n")
|
35
|
+
|
36
|
+
File.open "#{models_dir}/qux.rb", "w" do |file|
|
37
|
+
inspect_source(source, file)
|
38
|
+
end
|
39
|
+
|
40
|
+
expect(cop.offenses.map(&:line)).to include(3)
|
41
|
+
expect(cop.offenses.map(&:message)).to include(%r{Const BAZ should be defined in foo/bar\.rb.})
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'rejects if const assignment is in a file with matching name but wrong parent dir' do
|
45
|
+
source = [
|
46
|
+
'module Foo',
|
47
|
+
' module Bar',
|
48
|
+
' BAZ = 42',
|
49
|
+
' end',
|
50
|
+
'end',
|
51
|
+
].join("\n")
|
52
|
+
|
53
|
+
File.open "#{models_dir}/bar.rb", "w" do |file|
|
54
|
+
inspect_source(source, file)
|
55
|
+
end
|
56
|
+
|
57
|
+
expect(cop.offenses.map(&:line)).to include(3)
|
58
|
+
expect(cop.offenses.map(&:message)).to include(%r{Const BAZ should be defined in foo/bar\.rb.})
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'accepts if const assignment is in a file with matching name and right parent dir' do
|
62
|
+
source = [
|
63
|
+
'module Foo',
|
64
|
+
' module Bar',
|
65
|
+
' BAZ = 42',
|
66
|
+
' end',
|
67
|
+
'end',
|
68
|
+
].join("\n")
|
69
|
+
|
70
|
+
FileUtils.mkdir "#{models_dir}/foo"
|
71
|
+
File.open "#{models_dir}/foo/bar.rb", "w" do |file|
|
72
|
+
inspect_source(source, file)
|
73
|
+
end
|
74
|
+
|
75
|
+
expect(cop.offenses).to be_empty
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'accepts if const assignment is in a file with matching name and right parent dir' \
|
79
|
+
'and parent modules were defined on a single line' do
|
80
|
+
source = [
|
81
|
+
'module Foo::Bar',
|
82
|
+
' BAZ = 42',
|
83
|
+
'end',
|
84
|
+
].join("\n")
|
85
|
+
|
86
|
+
FileUtils.mkdir "#{models_dir}/foo"
|
87
|
+
File.open "#{models_dir}/foo/bar.rb", "w" do |file|
|
88
|
+
inspect_source(source, file)
|
89
|
+
end
|
90
|
+
|
91
|
+
expect(cop.offenses).to be_empty
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'accepts if const assignment is in a file whose name matches the const and right parent dir' do
|
95
|
+
source = [
|
96
|
+
'module Foo',
|
97
|
+
' module Bar',
|
98
|
+
' BAZ = 42',
|
99
|
+
' end',
|
100
|
+
'end',
|
101
|
+
].join("\n")
|
102
|
+
|
103
|
+
FileUtils.mkdir_p "#{models_dir}/foo/bar"
|
104
|
+
File.open "#{models_dir}/foo/bar/baz.rb", "w" do |file|
|
105
|
+
inspect_source(source, file)
|
106
|
+
end
|
107
|
+
|
108
|
+
expect(cop.offenses).to be_empty
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'ignores if const assignment is assigning something in another scope' do
|
112
|
+
source = [
|
113
|
+
'module Foo',
|
114
|
+
' Bar::BAZ = 42',
|
115
|
+
'end',
|
116
|
+
].join("\n")
|
117
|
+
|
118
|
+
File.open "#{models_dir}/foo.rb", "w" do |file|
|
119
|
+
inspect_source(source, file)
|
120
|
+
end
|
121
|
+
|
122
|
+
expect(cop.offenses).to be_empty
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'accepts const assignment where the containing class uses an acronym' do
|
126
|
+
source = [
|
127
|
+
'module CSVFoo',
|
128
|
+
' BAZ = 42',
|
129
|
+
'end',
|
130
|
+
].join("\n")
|
131
|
+
|
132
|
+
File.open "#{models_dir}/csv_foo.rb", "w" do |file|
|
133
|
+
inspect_source(source, file)
|
134
|
+
end
|
135
|
+
|
136
|
+
expect(cop.offenses).to be_empty
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'suggests moving a global const into a namespace' do
|
140
|
+
source = [
|
141
|
+
'FOO = 42',
|
142
|
+
].join("\n")
|
143
|
+
|
144
|
+
File.open "#{models_dir}/bar.rb", "w" do |file|
|
145
|
+
inspect_source(source, file)
|
146
|
+
end
|
147
|
+
|
148
|
+
expect(cop.offenses.map(&:line)).to eq([1])
|
149
|
+
expect(cop.offenses.first.message).
|
150
|
+
to include('Const FOO should be moved into a namespace or defined in foo.rb.')
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'ignores const assignment in global namespace in a rake task' do
|
154
|
+
source = [
|
155
|
+
'FOO = 42',
|
156
|
+
].join("\n")
|
157
|
+
|
158
|
+
File.open "#{models_dir}/foo.rake", "w" do |file|
|
159
|
+
inspect_source(source, file)
|
160
|
+
end
|
161
|
+
|
162
|
+
expect(cop.offenses).to be_empty
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'ignores const assignment in a class in a rake task' do
|
166
|
+
source = [
|
167
|
+
'class Baz',
|
168
|
+
' FOO = 42',
|
169
|
+
'end',
|
170
|
+
].join("\n")
|
171
|
+
|
172
|
+
File.open "#{models_dir}/foo.rake", "w" do |file|
|
173
|
+
inspect_source(source, file)
|
174
|
+
end
|
175
|
+
|
176
|
+
expect(cop.offenses).to be_empty
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
describe RuboCop::Cop::Airbnb::ContinuationSlash do
|
2
|
+
subject(:cop) { described_class.new }
|
3
|
+
|
4
|
+
it 'rejects continuations used to continue a method call with trailing dot' do
|
5
|
+
source = [
|
6
|
+
'User. \\',
|
7
|
+
' first_name',
|
8
|
+
].join("\n")
|
9
|
+
inspect_source(source)
|
10
|
+
|
11
|
+
expect(cop.offenses.size).to eq(1)
|
12
|
+
expect(cop.offenses.map(&:line).sort).to eq([1])
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'on assignment' do
|
16
|
+
it 'rejects on constant assignment' do
|
17
|
+
source = [
|
18
|
+
'CONSTANT = "I am a string that \\',
|
19
|
+
' spans multiple lines"',
|
20
|
+
].join("\n")
|
21
|
+
inspect_source(source)
|
22
|
+
|
23
|
+
expect(cop.offenses.size).to eq(1)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'rejects on local variable assignment' do
|
27
|
+
source = [
|
28
|
+
'variable = "I am a string that \\',
|
29
|
+
' spans multiple lines"',
|
30
|
+
].join("\n")
|
31
|
+
inspect_source(source)
|
32
|
+
|
33
|
+
expect(cop.offenses.size).to eq(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'rejects on @var assignment' do
|
37
|
+
source = [
|
38
|
+
'class SomeClass',
|
39
|
+
' @class_var = "I am a string that \\',
|
40
|
+
' spans multiple lines"',
|
41
|
+
'end',
|
42
|
+
].join("\n")
|
43
|
+
inspect_source(source)
|
44
|
+
|
45
|
+
expect(cop.offenses.size).to eq(1)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'rejects on @@var assignment' do
|
49
|
+
source = [
|
50
|
+
'class SomeClass',
|
51
|
+
' @@class_var = "I am a string that \\',
|
52
|
+
' spans multiple lines"',
|
53
|
+
'end',
|
54
|
+
].join("\n")
|
55
|
+
inspect_source(source)
|
56
|
+
|
57
|
+
expect(cop.offenses.size).to eq(1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'in conditional continuation' do
|
62
|
+
it 'rejects if with continuation \\ before operator' do
|
63
|
+
source = [
|
64
|
+
'if true \\',
|
65
|
+
' && false',
|
66
|
+
' return false',
|
67
|
+
'end',
|
68
|
+
].join("\n")
|
69
|
+
inspect_source(source)
|
70
|
+
|
71
|
+
expect(cop.offenses.size).to eq(1)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'rejects unless with continuation \\' do
|
75
|
+
source = [
|
76
|
+
'unless true \\',
|
77
|
+
' && false',
|
78
|
+
' return false',
|
79
|
+
'end',
|
80
|
+
].join("\n")
|
81
|
+
inspect_source(source)
|
82
|
+
|
83
|
+
expect(cop.offenses.size).to eq(1)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'rejects if with continuation \\ after operator' do
|
87
|
+
source = [
|
88
|
+
'if true || \\',
|
89
|
+
' false',
|
90
|
+
' return false',
|
91
|
+
'end',
|
92
|
+
].join("\n")
|
93
|
+
inspect_source(source)
|
94
|
+
|
95
|
+
expect(cop.offenses.size).to eq(1)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'open string continuation' do
|
100
|
+
it 'rejects contination with space before \\' do
|
101
|
+
source = [
|
102
|
+
'I18n.t("I am a string that \\',
|
103
|
+
' spans multiple lines")',
|
104
|
+
].join("\n")
|
105
|
+
inspect_source(source)
|
106
|
+
|
107
|
+
expect(cop.offenses.size).to eq(1)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'rejects contination with no space before \\' do
|
111
|
+
source = [
|
112
|
+
'I18n.t(\'I am a string that \\',
|
113
|
+
' spans multiple lines\')',
|
114
|
+
].join("\n")
|
115
|
+
inspect_source(source)
|
116
|
+
|
117
|
+
expect(cop.offenses.size).to eq(1)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'closed string continuation' do
|
122
|
+
it 'allows double quote string with no space before \\' do
|
123
|
+
source = [
|
124
|
+
'I18n.t("I am a string that "\\',
|
125
|
+
' "spans multiple lines")',
|
126
|
+
].join("\n")
|
127
|
+
inspect_source(source)
|
128
|
+
|
129
|
+
expect(cop.offenses).to be_empty
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'allows double quote string with space before \\' do
|
133
|
+
source = [
|
134
|
+
'I18n.t("I am a string that " \\',
|
135
|
+
' "spans multiple lines")',
|
136
|
+
].join("\n")
|
137
|
+
inspect_source(source)
|
138
|
+
|
139
|
+
expect(cop.offenses).to be_empty
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'allows single quote string with no space before \\' do
|
143
|
+
source = [
|
144
|
+
'I18n.t(\'I am a string that \'\\',
|
145
|
+
' \'spans multiple lines\')',
|
146
|
+
].join("\n")
|
147
|
+
inspect_source(source)
|
148
|
+
|
149
|
+
expect(cop.offenses).to be_empty
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'allows single quote string with space before \\' do
|
153
|
+
source = [
|
154
|
+
'I18n.t(\'I am a string that \' \\',
|
155
|
+
' \'spans multiple lines\')',
|
156
|
+
].join("\n")
|
157
|
+
inspect_source(source)
|
158
|
+
|
159
|
+
expect(cop.offenses).to be_empty
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
describe RuboCop::Cop::Airbnb::DefaultScope do
|
2
|
+
subject(:cop) { described_class.new }
|
3
|
+
|
4
|
+
it 'rejects with default_scopes' do
|
5
|
+
source = [
|
6
|
+
'# encoding: UTF-8',
|
7
|
+
'module SurveyQuestion',
|
8
|
+
' class Host < PhraseBundle',
|
9
|
+
' db_magic :connection => AIRMISC_MASTER,',
|
10
|
+
' :slaves => AIRMISC_DB_SLAVES,',
|
11
|
+
' :force_slave_reads => FORCE_SLAVE_READS',
|
12
|
+
'',
|
13
|
+
' default_scope where(active: true)',
|
14
|
+
'',
|
15
|
+
' end',
|
16
|
+
'end',
|
17
|
+
].join("\n")
|
18
|
+
inspect_source(source)
|
19
|
+
|
20
|
+
expect(cop.offenses.size).to eq(1)
|
21
|
+
expect(cop.offenses.map(&:line).sort).to eq([8])
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'passes when there is no default_scope' do
|
25
|
+
source = [
|
26
|
+
'# encoding: UTF-8',
|
27
|
+
'module SurveyQuestion',
|
28
|
+
' class Host < PhraseBundle',
|
29
|
+
' db_magic :connection => AIRMISC_MASTER,',
|
30
|
+
' :slaves => AIRMISC_DB_SLAVES,',
|
31
|
+
' :force_slave_reads => FORCE_SLAVE_READS',
|
32
|
+
' end',
|
33
|
+
'end',
|
34
|
+
].join("\n")
|
35
|
+
inspect_source(source)
|
36
|
+
expect(cop.offenses).to be_empty
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
describe RuboCop::Cop::Airbnb::FactoryAttrReferencesClass do
|
2
|
+
subject(:cop) { described_class.new }
|
3
|
+
|
4
|
+
it 'rejects with `attr_name CONST_NAME` in a factory' do
|
5
|
+
source = [
|
6
|
+
'factory :reservation2 do',
|
7
|
+
' status Reservation2::STATUS_NEW',
|
8
|
+
'end',
|
9
|
+
].join("\n")
|
10
|
+
inspect_source(source)
|
11
|
+
|
12
|
+
expect(cop.offenses.size).to eq(1)
|
13
|
+
expect(cop.offenses.map(&:line)).to eq([2])
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'passes with `attr_name { CONST_NAME }` in a factory' do
|
17
|
+
source = [
|
18
|
+
'factory :reservation2 do',
|
19
|
+
' status { Reservation2::STATUS_NEW }',
|
20
|
+
'end',
|
21
|
+
].join("\n")
|
22
|
+
inspect_source(source)
|
23
|
+
|
24
|
+
expect(cop.offenses).to be_empty
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'rejects with `attr_name [CONST_NAME]`' do
|
28
|
+
source = [
|
29
|
+
'factory :reservation2 do',
|
30
|
+
' statuses [Reservation2::STATUS_NEW]',
|
31
|
+
'end',
|
32
|
+
].join("\n")
|
33
|
+
inspect_source(source)
|
34
|
+
|
35
|
+
expect(cop.offenses.size).to eq(1)
|
36
|
+
expect(cop.offenses.map(&:line)).to eq([2])
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'passes with `attr_name { [CONST_NAME] }`' do
|
40
|
+
source = [
|
41
|
+
'factory :reservation2 do',
|
42
|
+
' statuses { [Reservation2::STATUS_NEW] }',
|
43
|
+
'end',
|
44
|
+
].join("\n")
|
45
|
+
inspect_source(source)
|
46
|
+
|
47
|
+
expect(cop.offenses).to be_empty
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'rejects with `attr_name [[CONST_NAME]]`' do
|
51
|
+
source = [
|
52
|
+
'factory :reservation2 do',
|
53
|
+
' statuses [[Reservation2::STATUS_NEW]]',
|
54
|
+
'end',
|
55
|
+
].join("\n")
|
56
|
+
inspect_source(source)
|
57
|
+
|
58
|
+
expect(cop.offenses.size).to eq(1)
|
59
|
+
expect(cop.offenses.map(&:line)).to eq([2])
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'passes with `attr_name { [[CONST_NAME]] }`' do
|
63
|
+
source = [
|
64
|
+
'factory :reservation2 do',
|
65
|
+
' statuses { [[Reservation2::STATUS_NEW]] }',
|
66
|
+
'end',
|
67
|
+
].join("\n")
|
68
|
+
inspect_source(source)
|
69
|
+
|
70
|
+
expect(cop.offenses).to be_empty
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'rejects with `attr_name({ ConstName => something })' do
|
74
|
+
source = [
|
75
|
+
'factory :reservation2 do',
|
76
|
+
' status_names({ Reservation2::STATUS_NEW => "new" })',
|
77
|
+
'end',
|
78
|
+
].join("\n")
|
79
|
+
inspect_source(source)
|
80
|
+
|
81
|
+
expect(cop.offenses.size).to eq(1)
|
82
|
+
expect(cop.offenses.map(&:line)).to eq([2])
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'passes with `attr_name { { ConstName => something } }`' do
|
86
|
+
source = [
|
87
|
+
'factory :reservation2 do',
|
88
|
+
' status_names { { Reservation2::STATUS_NEW => "new" } }',
|
89
|
+
'end',
|
90
|
+
].join("\n")
|
91
|
+
inspect_source(source)
|
92
|
+
|
93
|
+
expect(cop.offenses).to be_empty
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'rejects with `attr_name ConstName[:symbol]`' do
|
97
|
+
source = [
|
98
|
+
'factory :airlock_rule do',
|
99
|
+
' stickiness Airlock::STICKINESS[:user]',
|
100
|
+
'end',
|
101
|
+
].join("\n")
|
102
|
+
inspect_source(source)
|
103
|
+
|
104
|
+
expect(cop.offenses.size).to eq(1)
|
105
|
+
expect(cop.offenses.map(&:line)).to eq([2])
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'passes with `attr_name { ConstName[:symbol] }`' do
|
109
|
+
source = [
|
110
|
+
'factory :airlock_rule do',
|
111
|
+
' stickiness { Airlock::STICKINESS[:user] }',
|
112
|
+
'end',
|
113
|
+
].join("\n")
|
114
|
+
inspect_source(source)
|
115
|
+
|
116
|
+
expect(cop.offenses).to be_empty
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'rejects even if the const is not the first attr' do
|
120
|
+
source = [
|
121
|
+
'factory :reservation2 do',
|
122
|
+
' trait :accepted do',
|
123
|
+
' cancel_policy Hosting::CANCEL_FLEXIBLE',
|
124
|
+
' status Reservation2::STATUS_NEW',
|
125
|
+
' end',
|
126
|
+
'end',
|
127
|
+
].join("\n")
|
128
|
+
inspect_source(source)
|
129
|
+
|
130
|
+
expect(cop.offenses.size).to eq(2)
|
131
|
+
expect(cop.offenses.map(&:line)).to eq([3, 4])
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'rejects with `attr_name CONST_NAME` in a trait' do
|
135
|
+
source = [
|
136
|
+
'factory :reservation2 do',
|
137
|
+
' trait :accepted do',
|
138
|
+
' status Reservation2::STATUS_NEW',
|
139
|
+
' end',
|
140
|
+
'end',
|
141
|
+
].join("\n")
|
142
|
+
inspect_source(source)
|
143
|
+
|
144
|
+
expect(cop.offenses.size).to eq(1)
|
145
|
+
expect(cop.offenses.map(&:line)).to eq([3])
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'passes with `attr_name { CONST_NAME }` in a trait' do
|
149
|
+
source = [
|
150
|
+
'factory :reservation2 do',
|
151
|
+
' trait :accepted do',
|
152
|
+
' status { Reservation2::STATUS_NEW }',
|
153
|
+
' end',
|
154
|
+
'end',
|
155
|
+
].join("\n")
|
156
|
+
inspect_source(source)
|
157
|
+
|
158
|
+
expect(cop.offenses).to be_empty
|
159
|
+
end
|
160
|
+
end
|