puppet-lint 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.rspec +1 -0
- data/CHANGELOG.md +56 -0
- data/Gemfile +15 -4
- data/README.md +60 -5
- data/Rakefile +13 -0
- data/lib/puppet-lint.rb +21 -4
- data/lib/puppet-lint/configuration.rb +1 -0
- data/lib/puppet-lint/data.rb +12 -4
- data/lib/puppet-lint/lexer.rb +32 -7
- data/lib/puppet-lint/optparser.rb +4 -3
- data/lib/puppet-lint/plugins/check_classes.rb +73 -0
- data/lib/puppet-lint/plugins/check_comments.rb +4 -0
- data/lib/puppet-lint/plugins/check_conditionals.rb +4 -0
- data/lib/puppet-lint/plugins/check_documentation.rb +2 -0
- data/lib/puppet-lint/plugins/check_nodes.rb +2 -0
- data/lib/puppet-lint/plugins/check_resources.rb +80 -3
- data/lib/puppet-lint/plugins/check_strings.rb +13 -1
- data/lib/puppet-lint/plugins/check_variables.rb +6 -0
- data/lib/puppet-lint/plugins/check_whitespace.rb +12 -0
- data/lib/puppet-lint/version.rb +1 -1
- data/puppet-lint.gemspec +0 -2
- data/spec/fixtures/test/manifests/ignore_reason.pp +4 -1
- data/spec/fixtures/test/manifests/mismatched_control_comment.pp +1 -0
- data/spec/puppet-lint/bin_spec.rb +25 -12
- data/spec/puppet-lint/configuration_spec.rb +1 -0
- data/spec/puppet-lint/lexer_spec.rb +56 -2
- data/spec/puppet-lint/plugins/check_classes/code_on_top_scope_spec.rb +43 -0
- data/spec/puppet-lint/plugins/check_classes/name_contains_uppercase_spec.rb +66 -0
- data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +49 -0
- data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +140 -51
- data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +24 -0
- data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +17 -0
- data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +8 -0
- data/spec/spec_helper.rb +5 -0
- metadata +9 -17
data/lib/puppet-lint/version.rb
CHANGED
data/puppet-lint.gemspec
CHANGED
@@ -14,8 +14,6 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
15
15
|
s.require_paths = ["lib"]
|
16
16
|
|
17
|
-
s.add_development_dependency 'github_changelog_generator'
|
18
|
-
|
19
17
|
s.authors = ['Tim Sharpe']
|
20
18
|
s.email = 'tim@sharpe.id.au'
|
21
19
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# lint:endignore
|
@@ -213,17 +213,6 @@ describe PuppetLint::Bin do
|
|
213
213
|
}
|
214
214
|
end
|
215
215
|
|
216
|
-
context 'to print %{linenumber}' do
|
217
|
-
let(:args) { [
|
218
|
-
'--log-format', '%{linenumber}',
|
219
|
-
'spec/fixtures/test/manifests/fail.pp'
|
220
|
-
] }
|
221
|
-
|
222
|
-
its(:exitstatus) { is_expected.to eq(1) }
|
223
|
-
its(:stdout) { is_expected.to eq('2') }
|
224
|
-
its(:stderr) { is_expected.to eq('DEPRECATION: Please use %{line} instead of %{linenumber}') }
|
225
|
-
end
|
226
|
-
|
227
216
|
context 'to print %{line}' do
|
228
217
|
let(:args) { [
|
229
218
|
'--log-format', '%{line}',
|
@@ -275,6 +264,21 @@ describe PuppetLint::Bin do
|
|
275
264
|
end
|
276
265
|
end
|
277
266
|
|
267
|
+
context 'when displaying results as json' do
|
268
|
+
let(:args) { [
|
269
|
+
'--json',
|
270
|
+
'spec/fixtures/test/manifests/warning.pp',
|
271
|
+
] }
|
272
|
+
its(:exitstatus) { is_expected.to eq(0) }
|
273
|
+
its(:stdout) do
|
274
|
+
if respond_to?(:include_json)
|
275
|
+
is_expected.to include_json([{'KIND' => 'WARNING'}])
|
276
|
+
else
|
277
|
+
is_expected.to match(/\[\n \{/)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
278
282
|
context 'when hiding ignored problems' do
|
279
283
|
let(:args) { [
|
280
284
|
'spec/fixtures/test/manifests/ignore.pp'
|
@@ -302,7 +306,7 @@ describe PuppetLint::Bin do
|
|
302
306
|
|
303
307
|
its(:exitstatus) { is_expected.to eq(0) }
|
304
308
|
its(:stdout) { is_expected.to eq([
|
305
|
-
"IGNORED: double quoted string containing no variables on line
|
309
|
+
"IGNORED: double quoted string containing no variables on line 3",
|
306
310
|
" for a good reason",
|
307
311
|
].join("\n")) }
|
308
312
|
end
|
@@ -323,4 +327,13 @@ describe PuppetLint::Bin do
|
|
323
327
|
its(:exitstatus) { is_expected.to eq(0) }
|
324
328
|
its(:stdout) { is_expected.to match(/^.*line 6$/) }
|
325
329
|
end
|
330
|
+
|
331
|
+
context 'when an lint:endignore control comment exists with no opening lint:ignore comment' do
|
332
|
+
let(:args) { [
|
333
|
+
'spec/fixtures/test/manifests/mismatched_control_comment.pp',
|
334
|
+
] }
|
335
|
+
|
336
|
+
its(:exitstatus) { is_expected.to eq(0) }
|
337
|
+
its(:stdout) { is_expected.to match(/WARNING: lint:endignore comment with no opening lint:ignore:<check> comment found on line 1/) }
|
338
|
+
end
|
326
339
|
end
|
@@ -17,8 +17,26 @@ describe PuppetLint::Lexer do
|
|
17
17
|
expect(token.line).to eq(1)
|
18
18
|
end
|
19
19
|
|
20
|
+
it 'should get correct line number after double quoted multi line string' do
|
21
|
+
token = @lexer.new_token(:STRING, "test\ntest", 9)
|
22
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
23
|
+
expect(token.line).to eq(2)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should get correct line number after a multi line comment' do
|
27
|
+
token = @lexer.new_token(:MLCOMMENT, "test\ntest", 9)
|
28
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
29
|
+
expect(token.line).to eq(2)
|
30
|
+
end
|
31
|
+
|
20
32
|
it 'should calculate the line number for a multi line string' do
|
21
|
-
@lexer.
|
33
|
+
token = @lexer.new_token(:SSTRING, "test\ntest", 9)
|
34
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
35
|
+
expect(token.line).to eq(2)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should calculate line number for string that ends with newline' do
|
39
|
+
token = @lexer.new_token(:SSTRING, "test\n", 5)
|
22
40
|
token = @lexer.new_token(:TEST, 'test', 4)
|
23
41
|
expect(token.line).to eq(2)
|
24
42
|
end
|
@@ -37,8 +55,9 @@ describe PuppetLint::Lexer do
|
|
37
55
|
it 'should calculate the column number for a multi line string' do
|
38
56
|
@lexer.instance_variable_set('@line_no', 4)
|
39
57
|
@lexer.instance_variable_set('@column', "gronk".size)
|
58
|
+
token = @lexer.new_token(:SSTRING, "test\ntest", 9)
|
40
59
|
token = @lexer.new_token(:TEST, 'test', 4)
|
41
|
-
expect(token.column).to eq(
|
60
|
+
expect(token.column).to eq(4)
|
42
61
|
end
|
43
62
|
end
|
44
63
|
|
@@ -629,6 +648,12 @@ describe PuppetLint::Lexer do
|
|
629
648
|
expect(token.type).to eq(:CLASSREF)
|
630
649
|
expect(token.value).to eq('::One')
|
631
650
|
end
|
651
|
+
|
652
|
+
it 'should match terms that start with Types' do
|
653
|
+
token = @lexer.tokenise('Regexp_foo').first
|
654
|
+
expect(token.type).to eq(:CLASSREF)
|
655
|
+
expect(token.value).to eq('Regexp_foo')
|
656
|
+
end
|
632
657
|
end
|
633
658
|
|
634
659
|
context ':NAME' do
|
@@ -655,6 +680,12 @@ describe PuppetLint::Lexer do
|
|
655
680
|
expect(token.type).to eq(:NAME)
|
656
681
|
expect(token.value).to eq('::1one::2two::3three')
|
657
682
|
end
|
683
|
+
|
684
|
+
it 'should match barewords beginning with an underscore' do
|
685
|
+
token = @lexer.tokenise('_bareword').first
|
686
|
+
expect(token.type).to eq(:NAME)
|
687
|
+
expect(token.value).to eq('_bareword')
|
688
|
+
end
|
658
689
|
end
|
659
690
|
|
660
691
|
context ':NUMBER' do
|
@@ -773,6 +804,12 @@ describe PuppetLint::Lexer do
|
|
773
804
|
expect(token.type).to eq(:SSTRING)
|
774
805
|
expect(token.value).to eq(%{foo\\\\})
|
775
806
|
end
|
807
|
+
|
808
|
+
it "should match single quoted string containing a line break" do
|
809
|
+
token = @lexer.tokenise("'\n'").first
|
810
|
+
expect(token.type).to eq(:SSTRING)
|
811
|
+
expect(token.value).to eq("\n")
|
812
|
+
end
|
776
813
|
end
|
777
814
|
|
778
815
|
context ':REGEX' do
|
@@ -809,6 +846,17 @@ describe PuppetLint::Lexer do
|
|
809
846
|
tokens = @lexer.tokenise('$x = $a/$b/$c')
|
810
847
|
expect(tokens.select { |r| r.type == :REGEX }).to be_empty
|
811
848
|
end
|
849
|
+
|
850
|
+
it 'should properly parse when regex follows an if' do
|
851
|
+
tokens = @lexer.tokenise('if /^icinga_service_icon_.*/ in $location_info { }')
|
852
|
+
expect(tokens[2].type).to eq(:REGEX)
|
853
|
+
end
|
854
|
+
|
855
|
+
it 'should properly parse when a regex follows an elsif' do
|
856
|
+
tokens = @lexer.tokenise('if /a/ in $location_info { } elsif /b/ in $location_info { }')
|
857
|
+
expect(tokens[2].type).to eq(:REGEX)
|
858
|
+
expect(tokens[14].type).to eq(:REGEX)
|
859
|
+
end
|
812
860
|
end
|
813
861
|
|
814
862
|
context ':STRING' do
|
@@ -817,5 +865,11 @@ describe PuppetLint::Lexer do
|
|
817
865
|
@lexer.tokenise("exec { \"/bin/echo \\\\\\\"${environment}\\\\\\\"\": }")
|
818
866
|
}.to_not raise_error
|
819
867
|
end
|
868
|
+
|
869
|
+
it "should match double quoted string containing a line break" do
|
870
|
+
token = @lexer.tokenise(%Q{"\n"}).first
|
871
|
+
expect(token.type).to eq(:STRING)
|
872
|
+
expect(token.value).to eq("\n")
|
873
|
+
end
|
820
874
|
end
|
821
875
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'code_on_top_scope' do
|
4
|
+
describe 'comments outside class block' do
|
5
|
+
let(:code) { "
|
6
|
+
# Baz
|
7
|
+
class foo:bar {
|
8
|
+
}"
|
9
|
+
}
|
10
|
+
|
11
|
+
its(:problems) { should be_empty }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'new lines outside of class-define block' do
|
15
|
+
let(:code) { "
|
16
|
+
|
17
|
+
class foo:bar {
|
18
|
+
}
|
19
|
+
|
20
|
+
"
|
21
|
+
}
|
22
|
+
|
23
|
+
its(:problems) { should be_empty }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'code outside class block' do
|
27
|
+
let(:code) { "
|
28
|
+
include('something')
|
29
|
+
|
30
|
+
# Baz
|
31
|
+
class foo:bar {
|
32
|
+
}
|
33
|
+
|
34
|
+
define whatever {
|
35
|
+
}"
|
36
|
+
}
|
37
|
+
|
38
|
+
its(:problems) {
|
39
|
+
should contain_warning("code outside of class or define block - include")
|
40
|
+
should have(4).problems
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'names_containing_uppercase' do
|
4
|
+
|
5
|
+
context 'defined type named FooBar' do
|
6
|
+
let(:code) { 'define FooBar { }' }
|
7
|
+
let(:path) { 'foobar/manifests/init.pp' }
|
8
|
+
let(:class_msg) { "defined type 'FooBar' contains illegal uppercase" }
|
9
|
+
|
10
|
+
it 'should only detect a single problem' do
|
11
|
+
expect(problems).to have(1).problem
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should create an error' do
|
15
|
+
expect(problems).to contain_error(class_msg).on_line(1).in_column(8)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'class named FooBar' do
|
20
|
+
let(:code) { 'class FooBar { }' }
|
21
|
+
let(:path) { 'foobar/manifests/init.pp' }
|
22
|
+
let(:class_msg) { "class 'FooBar' contains illegal uppercase" }
|
23
|
+
|
24
|
+
it 'should only detect a single problem' do
|
25
|
+
expect(problems).to have(1).problem
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should create an error' do
|
29
|
+
expect(problems).to contain_error(class_msg).on_line(1).in_column(7)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'class named Foo::BarFoo' do
|
34
|
+
let(:code) { 'class Foo::BarFoo { }' }
|
35
|
+
let(:path) { 'foo/manifests/barfoo.pp' }
|
36
|
+
let(:class_msg) { "class 'Foo::BarFoo' contains illegal uppercase" }
|
37
|
+
|
38
|
+
it 'should only detect a single problem' do
|
39
|
+
expect(problems).to have(1).problem
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should create an error' do
|
43
|
+
expect(problems).to contain_error(class_msg).on_line(1).in_column(7)
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'check fix -' do
|
47
|
+
before do
|
48
|
+
PuppetLint.configuration.fix = true
|
49
|
+
end
|
50
|
+
|
51
|
+
after do
|
52
|
+
PuppetLint.configuration.fix = false
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:fixed) { code.downcase }
|
56
|
+
|
57
|
+
it 'should create an error' do
|
58
|
+
expect(problems).to contain_fixed(class_msg).on_line(1).in_column(7)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should downcase the class name' do
|
62
|
+
expect(manifest).to eq(fixed)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -73,5 +73,54 @@ describe 'parameter_order' do
|
|
73
73
|
expect(problems).to have(0).problems
|
74
74
|
end
|
75
75
|
end
|
76
|
+
|
77
|
+
context "#{type} parameter w/a hash containing a variable and no optional parameters" do
|
78
|
+
let(:code) { "
|
79
|
+
$var1 = 'test'
|
80
|
+
|
81
|
+
#{type} test (
|
82
|
+
$entries = {
|
83
|
+
'200 xxx' => {
|
84
|
+
param1 => $var1,
|
85
|
+
param2 => 'value2',
|
86
|
+
param3 => 'value3',
|
87
|
+
}
|
88
|
+
},
|
89
|
+
$mandatory => undef,
|
90
|
+
) { }
|
91
|
+
"}
|
92
|
+
|
93
|
+
it { expect(problems).to have(0).problem }
|
94
|
+
end
|
95
|
+
|
96
|
+
context "#{type} parameter w/a hash containing a variable followed by an optional parameter" do
|
97
|
+
let(:code) { "
|
98
|
+
$var1 = 'test'
|
99
|
+
|
100
|
+
#{type} test (
|
101
|
+
$entries = {
|
102
|
+
'200 xxx' => {
|
103
|
+
param1 => $var1,
|
104
|
+
param2 => 'value2',
|
105
|
+
param3 => 'value3',
|
106
|
+
}
|
107
|
+
},
|
108
|
+
$optional,
|
109
|
+
$mandatory => undef,
|
110
|
+
) { }
|
111
|
+
"}
|
112
|
+
|
113
|
+
it { expect(problems).to contain_warning(msg).on_line(12).in_column(11) }
|
114
|
+
end
|
115
|
+
|
116
|
+
context "#{type} parameter w/array containing a variable" do
|
117
|
+
let(:code) {"
|
118
|
+
#{type} test (
|
119
|
+
$var1 = [$::hostname, 'host'],
|
120
|
+
) { }
|
121
|
+
"}
|
122
|
+
|
123
|
+
it { expect(problems).to have(0).problem }
|
124
|
+
end
|
76
125
|
end
|
77
126
|
end
|
@@ -3,72 +3,161 @@ require 'spec_helper'
|
|
3
3
|
describe 'ensure_first_param' do
|
4
4
|
let(:msg) { "ensure found on line but it's not the first attribute" }
|
5
5
|
|
6
|
-
context '
|
7
|
-
|
6
|
+
context 'with fix disabled' do
|
7
|
+
context 'ensure as only attr in a single line resource' do
|
8
|
+
let(:code) { "file { 'foo': ensure => present }" }
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
it 'should not detect any problems' do
|
11
|
+
expect(problems).to have(0).problems
|
12
|
+
end
|
11
13
|
end
|
12
|
-
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
context 'ensure as only attr in a multi line resource' do
|
16
|
+
let(:code) { "
|
17
|
+
file { 'foo':
|
18
|
+
ensure => present,
|
19
|
+
}"
|
20
|
+
}
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
it 'should not detect any problems' do
|
23
|
+
expect(problems).to have(0).problems
|
24
|
+
end
|
23
25
|
end
|
24
|
-
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
context 'ensure as second attr in a multi line resource' do
|
28
|
+
let(:code) { "
|
29
|
+
file { 'foo':
|
30
|
+
mode => '0000',
|
31
|
+
ensure => present,
|
32
|
+
}"
|
33
|
+
}
|
34
|
+
|
35
|
+
it 'should only detect a single problem' do
|
36
|
+
expect(problems).to have(1).problem
|
37
|
+
end
|
33
38
|
|
34
|
-
|
35
|
-
|
39
|
+
it 'should create a warning' do
|
40
|
+
expect(problems).to contain_warning(msg).on_line(4).in_column(11)
|
41
|
+
end
|
36
42
|
end
|
37
43
|
|
38
|
-
|
39
|
-
|
44
|
+
context 'ensure as first attr in a multi line resource' do
|
45
|
+
let(:code) { "
|
46
|
+
file { 'foo':
|
47
|
+
ensure => present,
|
48
|
+
mode => '0000',
|
49
|
+
}"
|
50
|
+
}
|
51
|
+
|
52
|
+
it 'should not detect any problems' do
|
53
|
+
expect(problems).to have(0).problems
|
54
|
+
end
|
40
55
|
end
|
41
|
-
end
|
42
56
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
57
|
+
context 'ensure as a hash key in classes does not need to be first' do
|
58
|
+
let(:code) { "
|
59
|
+
class thing {
|
60
|
+
class {'thang':
|
61
|
+
stuff => {
|
62
|
+
'stuffing' => {
|
63
|
+
ensure => 'present',
|
64
|
+
blah => 'bleah',
|
65
|
+
}
|
66
|
+
},
|
67
|
+
}
|
68
|
+
}"
|
69
|
+
}
|
50
70
|
|
51
|
-
|
52
|
-
|
71
|
+
it 'should not detect any problems' do
|
72
|
+
expect(problems).to have(0).problems
|
73
|
+
end
|
53
74
|
end
|
54
75
|
end
|
55
76
|
|
56
|
-
context '
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
77
|
+
context 'with fix enabled' do
|
78
|
+
before do
|
79
|
+
PuppetLint.configuration.fix = true
|
80
|
+
end
|
81
|
+
|
82
|
+
after do
|
83
|
+
PuppetLint.configuration.fix = false
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'ensure as only attr in a single line resource' do
|
87
|
+
let(:code) { "file { 'foo': ensure => present }" }
|
88
|
+
|
89
|
+
it 'should not detect any problems' do
|
90
|
+
expect(problems).to have(0).problems
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'ensure as only attr in a multi line resource' do
|
95
|
+
let(:code) { "
|
96
|
+
file { 'foo':
|
97
|
+
ensure => present,
|
98
|
+
}"
|
99
|
+
}
|
100
|
+
|
101
|
+
it 'should not detect any problems' do
|
102
|
+
expect(problems).to have(0).problems
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'ensure as second attr in a multi line resource' do
|
107
|
+
let(:code) { "
|
108
|
+
file { 'foo':
|
109
|
+
mode => '0000',
|
110
|
+
ensure => present,
|
111
|
+
}"
|
112
|
+
}
|
113
|
+
|
114
|
+
it 'should only detect a single problem' do
|
115
|
+
expect(problems).to have(1).problem
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should create a warning' do
|
119
|
+
expect(problems).to contain_fixed(msg).on_line(4).in_column(11)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should make ensure the first attr' do
|
123
|
+
expect(manifest).to eq("
|
124
|
+
file { 'foo':
|
125
|
+
ensure => present,
|
126
|
+
mode => '0000',
|
127
|
+
}")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'ensure as first attr in a multi line resource' do
|
132
|
+
let(:code) { "
|
133
|
+
file { 'foo':
|
134
|
+
ensure => present,
|
135
|
+
mode => '0000',
|
136
|
+
}"
|
137
|
+
}
|
138
|
+
|
139
|
+
it 'should not detect any problems' do
|
140
|
+
expect(problems).to have(0).problems
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'ensure as a hash key in classes does not need to be first' do
|
145
|
+
let(:code) { "
|
146
|
+
class thing {
|
147
|
+
class {'thang':
|
148
|
+
stuff => {
|
149
|
+
'stuffing' => {
|
150
|
+
ensure => 'present',
|
151
|
+
blah => 'bleah',
|
152
|
+
}
|
153
|
+
},
|
154
|
+
}
|
155
|
+
}"
|
156
|
+
}
|
157
|
+
|
158
|
+
it 'should not detect any problems' do
|
159
|
+
expect(problems).to have(0).problems
|
160
|
+
end
|
72
161
|
end
|
73
162
|
end
|
74
163
|
end
|