Skip to content

Commit a32f983

Browse files
authored
Merge pull request #743 from rodjek/checks_spec
Add unit tests for PuppetLint::Checks
2 parents dfb4c68 + 2583441 commit a32f983

File tree

4 files changed

+240
-5
lines changed

4 files changed

+240
-5
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ group :test do
2727
end
2828

2929
gem 'rubocop', '0.49.1' if RUBY_VERSION > '2.0'
30+
gem 'simplecov', :require => false
3031
end
3132

3233
group :development do

lib/puppet-lint/checks.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,7 @@ def load_data(path, content)
4747

4848
# Internal: Run the lint checks over the manifest code.
4949
#
50-
# fileinfo - A Hash containing the following:
51-
# :fullpath - The expanded path to the file as a String.
52-
# :filename - The name of the file as a String.
53-
# :path - The original path to the file as passed to puppet-lint as
54-
# a String.
50+
# fileinfo - The path to the file as passed to puppet-lint as a String.
5551
# data - The String manifest code to be checked.
5652
#
5753
# Returns an Array of problem Hashes.
@@ -60,6 +56,7 @@ def run(fileinfo, data)
6056

6157
enabled_checks.each do |check|
6258
klass = PuppetLint.configuration.check_object[check].new
59+
# FIXME: shadowing #problems
6360
problems = klass.run
6461

6562
if PuppetLint.configuration.fix
@@ -96,6 +93,7 @@ def run(fileinfo, data)
9693
'```',
9794
"#{e.class}: #{e.message}",
9895
e.backtrace.join("\n"),
96+
'```',
9997
].join("\n")
10098

10199
exit 1

spec/puppet-lint/checks_spec.rb

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
require 'spec_helper'
2+
3+
describe PuppetLint::Checks do
4+
subject(:instance) { described_class.new }
5+
6+
let(:path) { File.join('path', 'to', 'test.pp') }
7+
let(:content) { "notify { 'test': }" }
8+
9+
describe '#initialize' do
10+
it { is_expected.to have_attributes(:problems => []) }
11+
end
12+
13+
describe '#load_data' do
14+
let(:lexer) { PuppetLint::Lexer.new }
15+
16+
before do
17+
allow(PuppetLint::Lexer).to receive(:new).and_return(lexer)
18+
end
19+
20+
context 'when the tokeniser encounters an error' do
21+
before do
22+
allow(lexer).to receive(:tokenise).with(content).and_raise(lexer_error)
23+
instance.load_data(path, content)
24+
end
25+
26+
context 'and the reason for the error is unknown' do
27+
let(:lexer_error) { PuppetLint::LexerError.new(1, 2) }
28+
29+
it 'stores an empty tokens array' do
30+
expect(PuppetLint::Data.tokens).to be_empty
31+
end
32+
33+
it 'creates a syntax error problem for the file' do
34+
expect(instance.problems).to have(1).problem
35+
expect(instance.problems.first).to include(
36+
:kind => :error,
37+
:check => :syntax,
38+
:message => 'Syntax error',
39+
:line => 1,
40+
:column => 2,
41+
:path => anything,
42+
:fullpath => anything,
43+
:filename => anything,
44+
)
45+
end
46+
end
47+
48+
context 'and the reason for the error is known' do
49+
let(:lexer_error) { PuppetLint::LexerError.new(1, 2, 'some reason') }
50+
51+
it 'stores an empty tokens array' do
52+
expect(PuppetLint::Data.tokens).to be_empty
53+
end
54+
55+
it 'creates a syntax error problem for the file' do
56+
expect(instance.problems).to have(1).problem
57+
expect(instance.problems.first).to include(
58+
:kind => :error,
59+
:check => :syntax,
60+
:message => 'Syntax error (some reason)',
61+
:line => 1,
62+
:column => 2,
63+
:path => anything,
64+
:fullpath => anything,
65+
:filename => anything,
66+
)
67+
end
68+
end
69+
end
70+
end
71+
72+
describe '#run' do
73+
let(:fileinfo) { File.join('path', 'to', 'test.pp') }
74+
let(:data) { "notify { 'test': }" }
75+
let(:enabled_checks) { [] }
76+
77+
before do
78+
allow(instance).to receive(:enabled_checks).and_return(enabled_checks)
79+
end
80+
81+
it 'loads the manifest data' do
82+
expect(instance).to receive(:load_data).with(fileinfo, data).and_call_original
83+
instance.run(fileinfo, data)
84+
end
85+
86+
context 'when there are checks enabled' do
87+
let(:enabled_checks) { [:arrow_alignment, :hard_tabs] }
88+
let(:enabled_check_classes) { enabled_checks.map { |r| PuppetLint.configuration.check_object[r] } }
89+
let(:disabled_checks) { PuppetLint.configuration.checks - enabled_checks }
90+
let(:disabled_check_classes) { disabled_checks.map { |r| PuppetLint.configuration.check_object[r] } }
91+
92+
it 'runs the enabled checks' do
93+
expect(enabled_check_classes).to all(receive(:new).and_call_original)
94+
95+
instance.run(fileinfo, data)
96+
end
97+
98+
it 'does not run the disabled checks' do
99+
# expect().to_not all(matcher) is not supported
100+
disabled_check_classes.each do |check_class|
101+
expect(check_class).to_not receive(:new)
102+
end
103+
104+
instance.run(fileinfo, data)
105+
end
106+
107+
context 'when a check finds a problem in the manifest' do
108+
let(:arrow_alignment_check) { PuppetLint.configuration.check_object[:arrow_alignment] }
109+
let(:hard_tabs_check) { PuppetLint.configuration.check_object[:hard_tabs] }
110+
let(:mock_arrow_alignment) do
111+
instance_double(
112+
PuppetLint::CheckPlugin,
113+
:run => [{ :kind => :error, :check => :arrow_alignment }],
114+
:fix_problems => [{ :kind => :fixed, :check => :arrow_alignment }],
115+
)
116+
end
117+
let(:mock_hard_tabs) do
118+
instance_double(PuppetLint::CheckPlugin, :run => [], :fix_problems => [])
119+
end
120+
let(:fix_state) { false }
121+
122+
before(:each) do
123+
allow(arrow_alignment_check).to receive(:new).and_return(mock_arrow_alignment)
124+
allow(hard_tabs_check).to receive(:new).and_return(mock_hard_tabs)
125+
allow(PuppetLint.configuration).to receive(:fix).and_return(fix_state)
126+
instance.run(fileinfo, data)
127+
end
128+
129+
it 'adds the found problems to the problems array' do
130+
expect(instance).to have_attributes(:problems => [{ :kind => :error, :check => :arrow_alignment }])
131+
end
132+
133+
context 'and fix is enabled' do
134+
let(:fix_state) { true }
135+
136+
it 'calls #fix_problems on the check and adds the results to the problems array' do
137+
expect(instance).to have_attributes(:problems => [{ :kind => :fixed, :check => :arrow_alignment }])
138+
end
139+
end
140+
end
141+
end
142+
143+
context 'when an unhandled exception is raised' do
144+
before do
145+
allow(instance).to receive(:load_data).with(fileinfo, data).and_raise(StandardError.new('test message'))
146+
allow($stdout).to receive(:puts).with(anything)
147+
end
148+
149+
it 'prints out information about the puppet-lint version and ruby environment' do
150+
expected_info = [
151+
"puppet-lint version: #{PuppetLint::VERSION}",
152+
"ruby version: #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}",
153+
"platform: #{RUBY_PLATFORM}",
154+
]
155+
pattern = expected_info.map { |r| Regexp.escape(r) }.join('\s+')
156+
expect($stdout).to receive(:puts).with(a_string_matching(%r{#{pattern}}m))
157+
158+
expect {
159+
instance.run(fileinfo, data)
160+
}.to raise_error(SystemExit) { |error|
161+
expect(error.status).to eq(1)
162+
}
163+
end
164+
165+
it 'prints out the details of the exception raised' do
166+
expect($stdout).to receive(:puts).with(a_string_matching(%r{error:\s+```\s+StandardError: test message.+```}m))
167+
168+
expect {
169+
instance.run(fileinfo, data)
170+
}.to raise_error(SystemExit) { |error|
171+
expect(error.status).to eq(1)
172+
}
173+
end
174+
175+
context 'and the file being linted is readable' do
176+
before do
177+
allow(File).to receive(:readable?).with(fileinfo).and_return(true)
178+
allow(File).to receive(:read).with(fileinfo).and_return(data)
179+
end
180+
181+
it 'adds the contents of the file to the bug report' do
182+
expect($stdout).to receive(:puts).with("file contents:\n```\n#{data}\n```")
183+
184+
expect {
185+
instance.run(fileinfo, data)
186+
}.to raise_error(SystemExit) { |error|
187+
expect(error.status).to eq(1)
188+
}
189+
end
190+
end
191+
end
192+
end
193+
194+
describe '#enabled_checks' do
195+
subject(:enabled_checks) { instance.enabled_checks }
196+
197+
let(:expected_enabled_checks) { [:arrow_alignment, :trailing_whitespace] }
198+
199+
before do
200+
PuppetLint.configuration.checks.each do |check|
201+
allow(PuppetLint.configuration).to receive("#{check}_enabled?").and_return(expected_enabled_checks.include?(check))
202+
end
203+
end
204+
205+
it 'checks the configuration for each check to see if it is enabled' do
206+
expect(enabled_checks.sort).to eq(expected_enabled_checks.sort)
207+
end
208+
end
209+
210+
describe '#manifest' do
211+
subject(:manifest) { instance.manifest }
212+
213+
let(:tokens) do
214+
[
215+
instance_double(PuppetLint::Lexer::Token, :to_manifest => '1'),
216+
instance_double(PuppetLint::Lexer::Token, :to_manifest => '2'),
217+
instance_double(PuppetLint::Lexer::Token, :to_manifest => '3'),
218+
]
219+
end
220+
221+
before do
222+
allow(PuppetLint::Data).to receive(:tokens).and_return(tokens)
223+
end
224+
225+
it 'reassembles the manifest from the tokens array' do
226+
expect(manifest).to eq('123')
227+
end
228+
end
229+
end

spec/spec_helper.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
require 'simplecov'
2+
SimpleCov.start do
3+
add_filter('/spec/')
4+
add_filter('/vendor/')
5+
add_group('Checks', 'lib/puppet-lint/plugins')
6+
end
7+
18
require 'puppet-lint'
29
require 'rspec/its'
310
require 'rspec/collection_matchers'

0 commit comments

Comments
 (0)