puppet-lint 0.2.0.pre1 → 0.2.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.
- data/.gitignore +1 -0
- data/.travis.yml +1 -14
- data/Gemfile +2 -0
- data/Rakefile +5 -0
- data/bin/puppet-lint +1 -99
- data/lib/puppet-lint.rb +4 -12
- data/lib/puppet-lint/bin.rb +115 -0
- data/lib/puppet-lint/configuration.rb +6 -2
- data/lib/puppet-lint/lexer.rb +135 -83
- data/lib/puppet-lint/lexer/token.rb +62 -0
- data/lib/puppet-lint/plugin.rb +57 -51
- data/lib/puppet-lint/plugins.rb +2 -0
- data/lib/puppet-lint/plugins/check_classes.rb +161 -45
- data/lib/puppet-lint/plugins/check_comments.rb +33 -0
- data/lib/puppet-lint/plugins/check_conditionals.rb +8 -10
- data/lib/puppet-lint/plugins/check_documentation.rb +41 -0
- data/lib/puppet-lint/plugins/check_resources.rb +28 -2
- data/lib/puppet-lint/plugins/check_strings.rb +6 -4
- data/lib/puppet-lint/plugins/check_variables.rb +1 -1
- data/lib/puppet-lint/plugins/check_whitespace.rb +26 -49
- data/lib/puppet-lint/tasks/puppet-lint.rb +2 -1
- data/lib/puppet-lint/version.rb +1 -1
- data/puppet-lint.gemspec +1 -0
- data/spec/fixtures/test/manifests/fail.pp +2 -0
- data/spec/fixtures/test/manifests/init.pp +3 -0
- data/spec/fixtures/test/manifests/warning.pp +2 -0
- data/spec/puppet-lint/bin_spec.rb +266 -0
- data/spec/puppet-lint/configuration_spec.rb +51 -0
- data/spec/puppet-lint/lexer/token_spec.rb +18 -0
- data/spec/puppet-lint/lexer_spec.rb +738 -0
- data/spec/puppet-lint/{check_classes_spec.rb → plugins/check_classes_spec.rb} +74 -7
- data/spec/puppet-lint/plugins/check_comments_spec.rb +40 -0
- data/spec/puppet-lint/{check_conditionals_spec.rb → plugins/check_conditionals_spec.rb} +19 -0
- data/spec/puppet-lint/plugins/check_documentation_spec.rb +55 -0
- data/spec/puppet-lint/{check_resources_spec.rb → plugins/check_resources_spec.rb} +65 -0
- data/spec/puppet-lint/{check_strings_spec.rb → plugins/check_strings_spec.rb} +18 -1
- data/spec/puppet-lint/{check_variables_spec.rb → plugins/check_variables_spec.rb} +0 -0
- data/spec/puppet-lint/plugins/check_whitespace_spec.rb +291 -0
- data/spec/puppet-lint_spec.rb +10 -0
- data/spec/spec_helper.rb +5 -0
- metadata +58 -24
- data/spec/puppet-lint/check_whitespace_spec.rb +0 -120
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PuppetLint::Configuration do
|
4
|
+
subject { PuppetLint::Configuration.new }
|
5
|
+
|
6
|
+
it 'should create check methods on the fly' do
|
7
|
+
subject.add_check('foo')
|
8
|
+
|
9
|
+
subject.should respond_to(:foo_enabled?)
|
10
|
+
subject.should_not respond_to(:bar_enabled?)
|
11
|
+
subject.should respond_to(:enable_foo)
|
12
|
+
subject.should respond_to(:disable_foo)
|
13
|
+
|
14
|
+
subject.disable_foo
|
15
|
+
subject.settings['foo_disabled'].should == true
|
16
|
+
subject.foo_enabled?.should == false
|
17
|
+
|
18
|
+
subject.enable_foo
|
19
|
+
subject.settings['foo_disabled'].should == false
|
20
|
+
subject.foo_enabled?.should == true
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should know what checks have been added' do
|
24
|
+
subject.checks.should include('foo')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should respond nil to unknown config options' do
|
28
|
+
subject.foobarbaz.should == nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should create options on the fly' do
|
32
|
+
subject.add_option('bar')
|
33
|
+
|
34
|
+
subject.bar.should == nil
|
35
|
+
|
36
|
+
subject.bar = 'aoeui'
|
37
|
+
subject.bar.should == 'aoeui'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should be able to set sane defaults' do
|
41
|
+
subject.defaults
|
42
|
+
|
43
|
+
subject.settings.should == {
|
44
|
+
'with_filename' => false,
|
45
|
+
'fail_on_warnings' => false,
|
46
|
+
'error_level' => :all,
|
47
|
+
'log_format' => '',
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PuppetLint::Lexer::Token do
|
4
|
+
subject do
|
5
|
+
PuppetLint::Lexer::Token.new(:NAME, 'foo', 1, 2)
|
6
|
+
end
|
7
|
+
|
8
|
+
it { should respond_to(:type) }
|
9
|
+
it { should respond_to(:value) }
|
10
|
+
it { should respond_to(:line) }
|
11
|
+
it { should respond_to(:column) }
|
12
|
+
|
13
|
+
its(:type) { should == :NAME }
|
14
|
+
its(:value) { should == 'foo' }
|
15
|
+
its(:line) { should == 1 }
|
16
|
+
its(:column) { should == 2 }
|
17
|
+
its(:inspect) { should == "<Token :NAME (foo) @1:2>" }
|
18
|
+
end
|
@@ -0,0 +1,738 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PuppetLint::Lexer do
|
4
|
+
before do
|
5
|
+
@lexer = PuppetLint::Lexer.new
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'invalid code' do
|
9
|
+
it 'should bork' do
|
10
|
+
expect { @lexer.tokenise('%') }.to raise_error(PuppetLint::LexerError)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context '#new_token' do
|
15
|
+
it 'should calculate the line number for an empty string' do
|
16
|
+
token = @lexer.new_token(:TEST, 'test', :chunk => '')
|
17
|
+
token.line.should == 1
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should calculate the line number for a multi line string' do
|
21
|
+
token = @lexer.new_token(:TEST, 'test', :chunk => "foo\nbar")
|
22
|
+
token.line.should == 2
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should calculate the column number for an empty string' do
|
26
|
+
token = @lexer.new_token(:TEST, 'test', :chunk => '')
|
27
|
+
token.column.should == 1
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should calculate the column number for a single line string' do
|
31
|
+
token = @lexer.new_token(:TEST, 'test', :chunk => 'this is a test')
|
32
|
+
token.column.should == 14
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should calculate the column number for a multi line string' do
|
36
|
+
token = @lexer.new_token(:TEST, 'test', :chunk => "foo\nbar\nbaz\ngronk")
|
37
|
+
token.column.should == 5
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context '#get_string_segment' do
|
42
|
+
it 'should get a segment with a single terminator' do
|
43
|
+
data = StringScanner.new('foo"bar')
|
44
|
+
value, terminator = @lexer.get_string_segment(data, '"')
|
45
|
+
value.should == 'foo'
|
46
|
+
terminator.should == '"'
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should get a segment with multiple terminators' do
|
50
|
+
data = StringScanner.new('foo"bar$baz')
|
51
|
+
value, terminator = @lexer.get_string_segment(data, "'$")
|
52
|
+
value.should == 'foo"bar'
|
53
|
+
terminator.should == '$'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should not get a segment with an escaped terminator' do
|
57
|
+
data = StringScanner.new('foo"bar')
|
58
|
+
value, terminator = @lexer.get_string_segment(data, '$')
|
59
|
+
value.should be_nil
|
60
|
+
terminator.should be_nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context '#interpolate_string' do
|
65
|
+
it 'should handle a string with no variables' do
|
66
|
+
@lexer.interpolate_string('foo bar baz"',1, 1)
|
67
|
+
token = @lexer.tokens.first
|
68
|
+
|
69
|
+
@lexer.tokens.length.should == 1
|
70
|
+
token.type.should == :STRING
|
71
|
+
token.value.should == 'foo bar baz'
|
72
|
+
token.line.should == 1
|
73
|
+
token.column.should == 1
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should handle a string with a newline' do
|
77
|
+
@lexer.interpolate_string(%{foo\nbar"}, 1, 1)
|
78
|
+
token = @lexer.tokens.first
|
79
|
+
|
80
|
+
@lexer.tokens.length.should == 1
|
81
|
+
token.type.should == :STRING
|
82
|
+
token.value.should == "foo\nbar"
|
83
|
+
token.line.should == 1
|
84
|
+
token.column.should == 1
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should handle a string with a single variable and suffix' do
|
88
|
+
@lexer.interpolate_string('${foo}bar"', 1, 1)
|
89
|
+
tokens = @lexer.tokens
|
90
|
+
|
91
|
+
tokens.length.should == 3
|
92
|
+
|
93
|
+
tokens[0].type.should == :DQPRE
|
94
|
+
tokens[0].value.should == ''
|
95
|
+
tokens[0].line.should == 1
|
96
|
+
tokens[0].column.should == 1
|
97
|
+
|
98
|
+
tokens[1].type.should == :VARIABLE
|
99
|
+
tokens[1].value.should == 'foo'
|
100
|
+
tokens[1].line.should == 1
|
101
|
+
tokens[1].column.should == 3
|
102
|
+
|
103
|
+
tokens[2].type.should == :DQPOST
|
104
|
+
tokens[2].value.should == 'bar'
|
105
|
+
tokens[2].line.should == 1
|
106
|
+
tokens[2].column.should == 8
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should handle a string with a single variable and surrounding text' do
|
110
|
+
@lexer.interpolate_string('foo${bar}baz"', 1, 1)
|
111
|
+
tokens = @lexer.tokens
|
112
|
+
|
113
|
+
tokens.length.should == 3
|
114
|
+
|
115
|
+
tokens[0].type.should == :DQPRE
|
116
|
+
tokens[0].value.should == 'foo'
|
117
|
+
tokens[0].line.should == 1
|
118
|
+
tokens[0].column.should == 1
|
119
|
+
|
120
|
+
tokens[1].type.should == :VARIABLE
|
121
|
+
tokens[1].value.should == 'bar'
|
122
|
+
tokens[1].line.should == 1
|
123
|
+
tokens[1].column.should == 6
|
124
|
+
|
125
|
+
tokens[2].type.should == :DQPOST
|
126
|
+
tokens[2].value.should == 'baz'
|
127
|
+
tokens[2].line.should == 1
|
128
|
+
tokens[2].column.should == 11
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should handle a string with multiple variables and surrounding text' do
|
132
|
+
@lexer.interpolate_string('foo${bar}baz${gronk}meh"', 1, 1)
|
133
|
+
tokens = @lexer.tokens
|
134
|
+
|
135
|
+
tokens.length.should == 5
|
136
|
+
|
137
|
+
tokens[0].type.should == :DQPRE
|
138
|
+
tokens[0].value.should == 'foo'
|
139
|
+
tokens[0].line.should == 1
|
140
|
+
tokens[0].column.should == 1
|
141
|
+
|
142
|
+
tokens[1].type.should == :VARIABLE
|
143
|
+
tokens[1].value.should == 'bar'
|
144
|
+
tokens[1].line.should == 1
|
145
|
+
tokens[1].column.should == 6
|
146
|
+
|
147
|
+
tokens[2].type.should == :DQMID
|
148
|
+
tokens[2].value.should == 'baz'
|
149
|
+
tokens[2].line.should == 1
|
150
|
+
tokens[2].column.should == 11
|
151
|
+
|
152
|
+
tokens[3].type.should == :VARIABLE
|
153
|
+
tokens[3].value.should == 'gronk'
|
154
|
+
tokens[3].line.should == 1
|
155
|
+
tokens[3].column.should == 15
|
156
|
+
|
157
|
+
tokens[4].type.should == :DQPOST
|
158
|
+
tokens[4].value.should == 'meh'
|
159
|
+
tokens[4].line.should == 1
|
160
|
+
tokens[4].column.should == 22
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should handle a string with only a single variable' do
|
164
|
+
@lexer.interpolate_string('${bar}"', 1, 1)
|
165
|
+
tokens = @lexer.tokens
|
166
|
+
|
167
|
+
tokens.length.should == 3
|
168
|
+
|
169
|
+
tokens[0].type.should == :DQPRE
|
170
|
+
tokens[0].value.should == ''
|
171
|
+
tokens[0].line.should == 1
|
172
|
+
tokens[0].column.should == 1
|
173
|
+
|
174
|
+
tokens[1].type.should == :VARIABLE
|
175
|
+
tokens[1].value.should == 'bar'
|
176
|
+
tokens[1].line.should == 1
|
177
|
+
tokens[1].column.should == 3
|
178
|
+
|
179
|
+
tokens[2].type.should == :DQPOST
|
180
|
+
tokens[2].value.should == ''
|
181
|
+
tokens[2].line.should == 1
|
182
|
+
tokens[2].column.should == 8
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should handle a string with only many variables' do
|
186
|
+
@lexer.interpolate_string('${bar}${gronk}"', 1, 1)
|
187
|
+
tokens = @lexer.tokens
|
188
|
+
|
189
|
+
tokens.length.should == 5
|
190
|
+
|
191
|
+
tokens[0].type.should == :DQPRE
|
192
|
+
tokens[0].value.should == ''
|
193
|
+
tokens[0].line.should == 1
|
194
|
+
tokens[0].column.should == 1
|
195
|
+
|
196
|
+
tokens[1].type.should == :VARIABLE
|
197
|
+
tokens[1].value.should == 'bar'
|
198
|
+
tokens[1].line.should == 1
|
199
|
+
tokens[1].column.should == 3
|
200
|
+
|
201
|
+
tokens[2].type.should == :DQMID
|
202
|
+
tokens[2].value.should == ''
|
203
|
+
tokens[2].line.should == 1
|
204
|
+
tokens[2].column.should == 8
|
205
|
+
|
206
|
+
tokens[3].type.should == :VARIABLE
|
207
|
+
tokens[3].value.should == 'gronk'
|
208
|
+
tokens[3].line.should == 1
|
209
|
+
tokens[3].column.should == 9
|
210
|
+
|
211
|
+
tokens[4].type.should == :DQPOST
|
212
|
+
tokens[4].value.should == ''
|
213
|
+
tokens[4].line.should == 1
|
214
|
+
tokens[4].column.should == 16
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should handle a string with only an unenclosed variable' do
|
218
|
+
@lexer.interpolate_string('$foo"', 1, 1)
|
219
|
+
tokens = @lexer.tokens
|
220
|
+
|
221
|
+
tokens.length.should == 3
|
222
|
+
|
223
|
+
tokens[0].type.should == :DQPRE
|
224
|
+
tokens[0].value.should == ''
|
225
|
+
tokens[0].line.should == 1
|
226
|
+
tokens[0].column.should == 1
|
227
|
+
|
228
|
+
tokens[1].type.should == :UNENC_VARIABLE
|
229
|
+
tokens[1].value.should == 'foo'
|
230
|
+
tokens[1].line.should == 1
|
231
|
+
tokens[1].column.should == 2
|
232
|
+
|
233
|
+
tokens[2].type.should == :DQPOST
|
234
|
+
tokens[2].value.should == ''
|
235
|
+
tokens[2].line.should == 1
|
236
|
+
tokens[2].column.should == 6
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'should handle a string with a nested string inside it' do
|
240
|
+
@lexer.interpolate_string(%q{string with ${'a nested single quoted string'} inside it"}, 1, 1)
|
241
|
+
tokens = @lexer.tokens
|
242
|
+
|
243
|
+
tokens.length.should == 3
|
244
|
+
|
245
|
+
tokens[0].type.should == :DQPRE
|
246
|
+
tokens[0].value.should == 'string with '
|
247
|
+
tokens[0].line.should == 1
|
248
|
+
tokens[0].column.should == 1
|
249
|
+
|
250
|
+
tokens[1].type.should == :SSTRING
|
251
|
+
tokens[1].value.should == 'a nested single quoted string'
|
252
|
+
tokens[1].line.should == 1
|
253
|
+
tokens[1].column.should == 16
|
254
|
+
|
255
|
+
tokens[2].type.should == :DQPOST
|
256
|
+
tokens[2].value.should == ' inside it'
|
257
|
+
tokens[2].line.should == 1
|
258
|
+
tokens[2].column.should == 48
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should handle a string with nested math' do
|
262
|
+
@lexer.interpolate_string(%q{string with ${(3+5)/4} nested math"}, 1, 1)
|
263
|
+
tokens = @lexer.tokens
|
264
|
+
|
265
|
+
tokens.length.should == 9
|
266
|
+
|
267
|
+
tokens[0].type.should == :DQPRE
|
268
|
+
tokens[0].value.should == 'string with '
|
269
|
+
tokens[0].line.should == 1
|
270
|
+
tokens[0].column.should == 1
|
271
|
+
|
272
|
+
tokens[1].type.should == :LPAREN
|
273
|
+
tokens[1].line.should == 1
|
274
|
+
tokens[1].column.should == 16
|
275
|
+
|
276
|
+
tokens[2].type.should == :NUMBER
|
277
|
+
tokens[2].value.should == '3'
|
278
|
+
tokens[2].line.should == 1
|
279
|
+
tokens[2].column.should == 17
|
280
|
+
|
281
|
+
tokens[3].type.should == :PLUS
|
282
|
+
tokens[3].line.should == 1
|
283
|
+
tokens[3].column.should == 18
|
284
|
+
|
285
|
+
tokens[4].type.should == :NUMBER
|
286
|
+
tokens[4].value.should == '5'
|
287
|
+
tokens[4].line.should == 1
|
288
|
+
tokens[4].column.should == 19
|
289
|
+
|
290
|
+
tokens[5].type.should == :RPAREN
|
291
|
+
tokens[5].line.should == 1
|
292
|
+
tokens[5].column.should == 20
|
293
|
+
|
294
|
+
tokens[6].type.should == :DIV
|
295
|
+
tokens[6].line.should == 1
|
296
|
+
tokens[6].column.should == 21
|
297
|
+
|
298
|
+
tokens[7].type.should == :NUMBER
|
299
|
+
tokens[7].value.should == '4'
|
300
|
+
tokens[7].line.should == 1
|
301
|
+
tokens[7].column.should == 22
|
302
|
+
|
303
|
+
tokens[8].type.should == :DQPOST
|
304
|
+
tokens[8].value.should == ' nested math'
|
305
|
+
tokens[8].line.should == 1
|
306
|
+
tokens[8].column.should == 24
|
307
|
+
end
|
308
|
+
|
309
|
+
it 'should handle a string with a nested array' do
|
310
|
+
@lexer.interpolate_string(%q{string with ${['an array ', $v2]} in it"}, 1, 1)
|
311
|
+
tokens = @lexer.tokens
|
312
|
+
|
313
|
+
tokens.length.should == 8
|
314
|
+
|
315
|
+
tokens[0].type.should == :DQPRE
|
316
|
+
tokens[0].value.should == 'string with '
|
317
|
+
tokens[0].line.should == 1
|
318
|
+
tokens[0].column.should == 1
|
319
|
+
|
320
|
+
tokens[1].type.should == :LBRACK
|
321
|
+
tokens[1].line.should == 1
|
322
|
+
tokens[1].column.should == 16
|
323
|
+
|
324
|
+
tokens[2].type.should == :SSTRING
|
325
|
+
tokens[2].value.should == 'an array '
|
326
|
+
tokens[2].line.should == 1
|
327
|
+
tokens[2].column.should == 17
|
328
|
+
|
329
|
+
tokens[3].type.should == :COMMA
|
330
|
+
tokens[3].line.should == 1
|
331
|
+
tokens[3].column.should == 28
|
332
|
+
|
333
|
+
tokens[4].type.should == :WHITESPACE
|
334
|
+
tokens[4].value.should == ' '
|
335
|
+
tokens[4].line.should == 1
|
336
|
+
tokens[4].column.should == 29
|
337
|
+
|
338
|
+
tokens[5].type.should == :VARIABLE
|
339
|
+
tokens[5].value.should == 'v2'
|
340
|
+
tokens[5].line.should == 1
|
341
|
+
tokens[5].column.should == 30
|
342
|
+
|
343
|
+
tokens[6].type.should == :RBRACK
|
344
|
+
tokens[6].line.should == 1
|
345
|
+
tokens[6].column.should == 33
|
346
|
+
|
347
|
+
tokens[7].type.should == :DQPOST
|
348
|
+
tokens[7].value.should == ' in it'
|
349
|
+
tokens[7].line.should == 1
|
350
|
+
tokens[7].column.should == 35
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'should handle a string of $s' do
|
354
|
+
@lexer.interpolate_string(%q{$$$$"}, 1, 1)
|
355
|
+
tokens = @lexer.tokens
|
356
|
+
|
357
|
+
tokens.length.should == 1
|
358
|
+
|
359
|
+
tokens[0].type.should == :STRING
|
360
|
+
tokens[0].value.should == '$$$$'
|
361
|
+
tokens[0].line.should == 1
|
362
|
+
tokens[0].column.should == 1
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'should handle "$foo$bar"' do
|
366
|
+
@lexer.interpolate_string(%q{$foo$bar"}, 1, 1)
|
367
|
+
tokens = @lexer.tokens
|
368
|
+
|
369
|
+
tokens.length.should == 5
|
370
|
+
|
371
|
+
tokens[0].type.should == :DQPRE
|
372
|
+
tokens[0].value.should == ''
|
373
|
+
tokens[0].line.should == 1
|
374
|
+
tokens[0].column.should == 1
|
375
|
+
|
376
|
+
tokens[1].type.should == :UNENC_VARIABLE
|
377
|
+
tokens[1].value.should == 'foo'
|
378
|
+
tokens[1].line.should == 1
|
379
|
+
tokens[1].column.should == 2
|
380
|
+
|
381
|
+
tokens[2].type.should == :DQMID
|
382
|
+
tokens[2].value.should == ''
|
383
|
+
tokens[2].line.should == 1
|
384
|
+
tokens[2].column.should == 6
|
385
|
+
|
386
|
+
tokens[3].type.should == :UNENC_VARIABLE
|
387
|
+
tokens[3].value.should == 'bar'
|
388
|
+
tokens[3].line.should == 1
|
389
|
+
tokens[3].column.should == 6
|
390
|
+
|
391
|
+
tokens[4].type.should == :DQPOST
|
392
|
+
tokens[4].value.should == ''
|
393
|
+
tokens[4].line.should == 1
|
394
|
+
tokens[4].column.should == 10
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should handle "foo$bar$"' do
|
398
|
+
@lexer.interpolate_string(%q{foo$bar$"}, 1, 1)
|
399
|
+
tokens = @lexer.tokens
|
400
|
+
|
401
|
+
tokens.length.should == 3
|
402
|
+
|
403
|
+
tokens[0].type.should == :DQPRE
|
404
|
+
tokens[0].value.should == 'foo'
|
405
|
+
tokens[0].line.should == 1
|
406
|
+
tokens[0].column.should == 1
|
407
|
+
|
408
|
+
tokens[1].type.should == :UNENC_VARIABLE
|
409
|
+
tokens[1].value.should == 'bar'
|
410
|
+
tokens[1].line.should == 1
|
411
|
+
tokens[1].column.should == 5
|
412
|
+
|
413
|
+
tokens[2].type.should == :DQPOST
|
414
|
+
tokens[2].value.should == '$'
|
415
|
+
tokens[2].line.should == 1
|
416
|
+
tokens[2].column.should == 9
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'should handle "foo$$bar"' do
|
420
|
+
@lexer.interpolate_string(%q{foo$$bar"}, 1, 1)
|
421
|
+
tokens = @lexer.tokens
|
422
|
+
|
423
|
+
tokens.length.should == 3
|
424
|
+
|
425
|
+
tokens[0].type.should == :DQPRE
|
426
|
+
tokens[0].value.should == 'foo$'
|
427
|
+
tokens[0].line.should == 1
|
428
|
+
tokens[0].column.should == 1
|
429
|
+
|
430
|
+
tokens[1].type.should == :UNENC_VARIABLE
|
431
|
+
tokens[1].value.should == 'bar'
|
432
|
+
tokens[1].line.should == 1
|
433
|
+
tokens[1].column.should == 6
|
434
|
+
|
435
|
+
tokens[2].type.should == :DQPOST
|
436
|
+
tokens[2].value.should == ''
|
437
|
+
tokens[2].line.should == 1
|
438
|
+
tokens[2].column.should == 10
|
439
|
+
end
|
440
|
+
|
441
|
+
it 'should handle an empty string' do
|
442
|
+
@lexer.interpolate_string(%q{"}, 1, 1)
|
443
|
+
tokens = @lexer.tokens
|
444
|
+
|
445
|
+
tokens.length.should == 1
|
446
|
+
|
447
|
+
tokens[0].type.should == :STRING
|
448
|
+
tokens[0].value.should == ''
|
449
|
+
tokens[0].line.should == 1
|
450
|
+
tokens[0].column.should == 1
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'should handle "$foo::::bar"' do
|
454
|
+
@lexer.interpolate_string(%q{$foo::::bar"}, 1, 1)
|
455
|
+
tokens = @lexer.tokens
|
456
|
+
|
457
|
+
tokens.length.should == 3
|
458
|
+
|
459
|
+
tokens[0].type.should == :DQPRE
|
460
|
+
tokens[0].value.should == ''
|
461
|
+
tokens[0].line.should == 1
|
462
|
+
tokens[0].column.should == 1
|
463
|
+
|
464
|
+
tokens[1].type.should == :UNENC_VARIABLE
|
465
|
+
tokens[1].value.should == 'foo'
|
466
|
+
tokens[1].line.should == 1
|
467
|
+
tokens[1].column.should == 2
|
468
|
+
|
469
|
+
tokens[2].type.should == :DQPOST
|
470
|
+
tokens[2].value.should == '::::bar'
|
471
|
+
tokens[2].line.should == 1
|
472
|
+
tokens[2].column.should == 6
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
[
|
477
|
+
'case',
|
478
|
+
'class',
|
479
|
+
'default',
|
480
|
+
'define',
|
481
|
+
'import',
|
482
|
+
'if',
|
483
|
+
'elsif',
|
484
|
+
'else',
|
485
|
+
'inherits',
|
486
|
+
'node',
|
487
|
+
'and',
|
488
|
+
'or',
|
489
|
+
'undef',
|
490
|
+
'true',
|
491
|
+
'false',
|
492
|
+
'in',
|
493
|
+
'unless',
|
494
|
+
].each do |keyword|
|
495
|
+
it "should handle '#{keyword}' as a keyword" do
|
496
|
+
token = @lexer.tokenise(keyword).first
|
497
|
+
token.type.should == keyword.upcase.to_sym
|
498
|
+
token.value.should == keyword
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
[
|
503
|
+
[:LBRACK, '['],
|
504
|
+
[:RBRACK, ']'],
|
505
|
+
[:LBRACE, '{'],
|
506
|
+
[:RBRACE, '}'],
|
507
|
+
[:LPAREN, '('],
|
508
|
+
[:RPAREN, ')'],
|
509
|
+
[:EQUALS, '='],
|
510
|
+
[:ISEQUAL, '=='],
|
511
|
+
[:GREATEREQUAL, '>='],
|
512
|
+
[:GREATERTHAN, '>'],
|
513
|
+
[:LESSTHAN, '<'],
|
514
|
+
[:LESSEQUAL, '<='],
|
515
|
+
[:NOTEQUAL, '!='],
|
516
|
+
[:NOT, '!'],
|
517
|
+
[:COMMA, ','],
|
518
|
+
[:DOT, '.'],
|
519
|
+
[:COLON, ':'],
|
520
|
+
[:AT, '@'],
|
521
|
+
[:LLCOLLECT, '<<|'],
|
522
|
+
[:RRCOLLECT, '|>>'],
|
523
|
+
[:LCOLLECT, '<|'],
|
524
|
+
[:RCOLLECT, '|>'],
|
525
|
+
[:SEMIC, ';'],
|
526
|
+
[:QMARK, '?'],
|
527
|
+
[:BACKSLASH, '\\'],
|
528
|
+
[:FARROW, '=>'],
|
529
|
+
[:PARROW, '+>'],
|
530
|
+
[:APPENDS, '+='],
|
531
|
+
[:PLUS, '+'],
|
532
|
+
[:MINUS, '-'],
|
533
|
+
[:DIV, '/'],
|
534
|
+
[:TIMES, '*'],
|
535
|
+
[:LSHIFT, '<<'],
|
536
|
+
[:RSHIFT, '>>'],
|
537
|
+
[:MATCH, '=~'],
|
538
|
+
[:NOMATCH, '!~'],
|
539
|
+
[:IN_EDGE, '->'],
|
540
|
+
[:OUT_EDGE, '<-'],
|
541
|
+
[:IN_EDGE_SUB, '~>'],
|
542
|
+
[:OUT_EDGE_SUB, '<~'],
|
543
|
+
].each do |name, string|
|
544
|
+
it "should have a token named '#{name.to_s}'" do
|
545
|
+
token = @lexer.tokenise(string).first
|
546
|
+
token.type.should == name
|
547
|
+
token.value.should == string
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
context ':CLASSREF' do
|
552
|
+
it 'should match single capitalised alphanumeric term' do
|
553
|
+
token = @lexer.tokenise('One').first
|
554
|
+
token.type.should == :CLASSREF
|
555
|
+
token.value.should == 'One'
|
556
|
+
end
|
557
|
+
|
558
|
+
it 'should match two capitalised alphanumeric terms sep by ::' do
|
559
|
+
token = @lexer.tokenise('One::Two').first
|
560
|
+
token.type.should == :CLASSREF
|
561
|
+
token.value.should == 'One::Two'
|
562
|
+
end
|
563
|
+
|
564
|
+
it 'should match many capitalised alphanumeric terms sep by ::' do
|
565
|
+
token = @lexer.tokenise('One::Two::Three::Four::Five').first
|
566
|
+
token.type.should == :CLASSREF
|
567
|
+
token.value.should == 'One::Two::Three::Four::Five'
|
568
|
+
end
|
569
|
+
|
570
|
+
it 'should match capitalised terms prefixed by ::' do
|
571
|
+
token = @lexer.tokenise('::One').first
|
572
|
+
token.type.should == :CLASSREF
|
573
|
+
token.value.should == '::One'
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
context ':NAME' do
|
578
|
+
it 'should match lowercase alphanumeric terms' do
|
579
|
+
token = @lexer.tokenise('one-two').first
|
580
|
+
token.type.should == :NAME
|
581
|
+
token.value.should == 'one-two'
|
582
|
+
end
|
583
|
+
|
584
|
+
it 'should match lowercase alphanumeric terms sep by ::' do
|
585
|
+
token = @lexer.tokenise('one::two').first
|
586
|
+
token.type.should == :NAME
|
587
|
+
token.value.should == 'one::two'
|
588
|
+
end
|
589
|
+
|
590
|
+
it 'should match many lowercase alphanumeric terms sep by ::' do
|
591
|
+
token = @lexer.tokenise('one::two::three::four::five').first
|
592
|
+
token.type.should == :NAME
|
593
|
+
token.value.should == 'one::two::three::four::five'
|
594
|
+
end
|
595
|
+
|
596
|
+
it 'should match lowercase alphanumeric terms prefixed by ::' do
|
597
|
+
token = @lexer.tokenise('::1one::2two::3three').first
|
598
|
+
token.type.should == :NAME
|
599
|
+
token.value.should == '::1one::2two::3three'
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
context ':NUMBER' do
|
604
|
+
it 'should match numeric terms' do
|
605
|
+
token = @lexer.tokenise('1234567890').first
|
606
|
+
token.type.should == :NUMBER
|
607
|
+
token.value.should == '1234567890'
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'should match float terms' do
|
611
|
+
token = @lexer.tokenise('12345.6789').first
|
612
|
+
token.type.should == :NUMBER
|
613
|
+
token.value.should == '12345.6789'
|
614
|
+
end
|
615
|
+
|
616
|
+
it 'should match hexadecimal terms' do
|
617
|
+
token = @lexer.tokenise('0xCAFE1029').first
|
618
|
+
token.type.should == :NUMBER
|
619
|
+
token.value.should == '0xCAFE1029'
|
620
|
+
end
|
621
|
+
|
622
|
+
it 'should match float with exponent terms' do
|
623
|
+
token = @lexer.tokenise('10e23').first
|
624
|
+
token.type.should == :NUMBER
|
625
|
+
token.value.should == '10e23'
|
626
|
+
end
|
627
|
+
|
628
|
+
it 'should match float with negative exponent terms' do
|
629
|
+
token = @lexer.tokenise('10e-23').first
|
630
|
+
token.type.should == :NUMBER
|
631
|
+
token.value.should == '10e-23'
|
632
|
+
end
|
633
|
+
|
634
|
+
it 'should match float with exponent terms' do
|
635
|
+
token = @lexer.tokenise('1.234e5').first
|
636
|
+
token.type.should == :NUMBER
|
637
|
+
token.value.should == '1.234e5'
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
context ':COMMENT' do
|
642
|
+
it 'should match everything on a line after #' do
|
643
|
+
token = @lexer.tokenise('foo # bar baz')[2]
|
644
|
+
token.type.should == :COMMENT
|
645
|
+
token.value.should == 'bar baz'
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
context ':MLCOMMENT' do
|
650
|
+
it 'should match comments on a single line' do
|
651
|
+
token = @lexer.tokenise('/* foo bar */').first
|
652
|
+
token.type.should == :MLCOMMENT
|
653
|
+
token.value.should == 'foo bar'
|
654
|
+
end
|
655
|
+
|
656
|
+
it 'should match comments on multiple lines' do
|
657
|
+
token = @lexer.tokenise("/*\n * foo bar\n*/").first
|
658
|
+
token.type.should == :MLCOMMENT
|
659
|
+
token.value.should == 'foo bar'
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
context ':SLASH_COMMENT' do
|
664
|
+
it 'should match everyone on a line after //' do
|
665
|
+
token = @lexer.tokenise('foo // bar baz')[2]
|
666
|
+
token.type.should == :SLASH_COMMENT
|
667
|
+
token.value.should == 'bar baz'
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
context ':SSTRING' do
|
672
|
+
it 'should match a single quoted string' do
|
673
|
+
token = @lexer.tokenise("'single quoted string'").first
|
674
|
+
token.type.should == :SSTRING
|
675
|
+
token.value.should == 'single quoted string'
|
676
|
+
end
|
677
|
+
|
678
|
+
it "should match a single quoted string with an escaped '" do
|
679
|
+
token = @lexer.tokenise(%q{'single quoted string with "\\'"'}).first
|
680
|
+
token.type.should == :SSTRING
|
681
|
+
token.value.should == 'single quoted string with "\\\'"'
|
682
|
+
end
|
683
|
+
|
684
|
+
it "should match a single quoted string with an escaped $" do
|
685
|
+
token = @lexer.tokenise(%q{'single quoted string with "\$"'}).first
|
686
|
+
token.type.should == :SSTRING
|
687
|
+
token.value.should == 'single quoted string with "\\$"'
|
688
|
+
end
|
689
|
+
|
690
|
+
it "should match a single quoted string with an escaped ." do
|
691
|
+
token = @lexer.tokenise(%q{'single quoted string with "\."'}).first
|
692
|
+
token.type.should == :SSTRING
|
693
|
+
token.value.should == 'single quoted string with "\\."'
|
694
|
+
end
|
695
|
+
|
696
|
+
it "should match a single quoted string with an escaped \\n" do
|
697
|
+
token = @lexer.tokenise(%q{'single quoted string with "\n"'}).first
|
698
|
+
token.type.should == :SSTRING
|
699
|
+
token.value.should == 'single quoted string with "\\n"'
|
700
|
+
end
|
701
|
+
|
702
|
+
it "should match a single quoted string with an escaped \\" do
|
703
|
+
token = @lexer.tokenise(%q{'single quoted string with "\\\\"'}).first
|
704
|
+
token.type.should == :SSTRING
|
705
|
+
token.value.should == 'single quoted string with "\\\\"'
|
706
|
+
end
|
707
|
+
|
708
|
+
it "should match an empty string" do
|
709
|
+
token = @lexer.tokenise("''").first
|
710
|
+
token.type.should == :SSTRING
|
711
|
+
token.value.should == ''
|
712
|
+
end
|
713
|
+
end
|
714
|
+
|
715
|
+
context ':REGEX' do
|
716
|
+
it 'should match anything enclosed in //' do
|
717
|
+
token = @lexer.tokenise('/this is a regex/').first
|
718
|
+
token.type.should == :REGEX
|
719
|
+
token.value.should == 'this is a regex'
|
720
|
+
end
|
721
|
+
|
722
|
+
it 'should not match if there is \n in the regex' do
|
723
|
+
token = @lexer.tokenise("/this is \n a regex/").first
|
724
|
+
token.type.should_not == :REGEX
|
725
|
+
end
|
726
|
+
|
727
|
+
it 'should not consider \/ to be the end of the regex' do
|
728
|
+
token = @lexer.tokenise('/this is \/ a regex/').first
|
729
|
+
token.type.should == :REGEX
|
730
|
+
token.value.should == 'this is \\/ a regex'
|
731
|
+
end
|
732
|
+
|
733
|
+
it 'should not match chained division' do
|
734
|
+
tokens = @lexer.tokenise('$x = $a/$b/$c')
|
735
|
+
tokens.select { |r| r.type == :REGEX }.should == []
|
736
|
+
end
|
737
|
+
end
|
738
|
+
end
|