rubocop-airbnb 1.0.0
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 +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
|