1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
|
#! /usr/bin/env ruby
require 'spec_helper'
require 'puppet/pops'
# relative to this spec file (./) does not work as this file is loaded by rspec
require File.join(File.dirname(__FILE__), '/parser_rspec_helper')
describe "egrammar parsing containers" do
include ParserRspecHelper
context "When parsing file scope" do
it "$a = 10 $b = 20" do
dump(parse("$a = 10 $b = 20")).should == [
"(block",
" (= $a 10)",
" (= $b 20)",
")"
].join("\n")
end
it "$a = 10" do
dump(parse("$a = 10")).should == "(= $a 10)"
end
end
context "When parsing class" do
it "class foo {}" do
dump(parse("class foo {}")).should == "(class foo ())"
end
it "class foo { class bar {} }" do
dump(parse("class foo { class bar {}}")).should == [
"(class foo (block",
" (class foo::bar ())",
"))"
].join("\n")
end
it "class foo::bar {}" do
dump(parse("class foo::bar {}")).should == "(class foo::bar ())"
end
it "class foo inherits bar {}" do
dump(parse("class foo inherits bar {}")).should == "(class foo (inherits bar) ())"
end
it "class foo($a) {}" do
dump(parse("class foo($a) {}")).should == "(class foo (parameters a) ())"
end
it "class foo($a, $b) {}" do
dump(parse("class foo($a, $b) {}")).should == "(class foo (parameters a b) ())"
end
it "class foo($a, $b=10) {}" do
dump(parse("class foo($a, $b=10) {}")).should == "(class foo (parameters a (= b 10)) ())"
end
it "class foo($a, $b) inherits belgo::bar {}" do
dump(parse("class foo($a, $b) inherits belgo::bar{}")).should == "(class foo (inherits belgo::bar) (parameters a b) ())"
end
it "class foo {$a = 10 $b = 20}" do
dump(parse("class foo {$a = 10 $b = 20}")).should == [
"(class foo (block",
" (= $a 10)",
" (= $b 20)",
"))"
].join("\n")
end
context "it should handle '3x weirdness'" do
it "class class {} # a class named 'class'" do
# Not as much weird as confusing that it is possible to name a class 'class'. Can have
# a very confusing effect when resolving relative names, getting the global hardwired "Class"
# instead of some foo::class etc.
# This is allowed in 3.x.
expect {
dump(parse("class class {}")).should == "(class class ())"
}.to raise_error(/not a valid classname/)
end
it "class default {} # a class named 'default'" do
# The weirdness here is that a class can inherit 'default' but not declare a class called default.
# (It will work with relative names i.e. foo::default though). The whole idea with keywords as
# names is flawed to begin with - it generally just a very bad idea.
expect { dump(parse("class default {}")).should == "(class default ())" }.to raise_error(Puppet::ParseError)
end
it "class foo::default {} # a nested name 'default'" do
dump(parse("class foo::default {}")).should == "(class foo::default ())"
end
it "class class inherits default {} # inherits default", :broken => true do
expect {
dump(parse("class class inherits default {}")).should == "(class class (inherits default) ())"
}.to raise_error(/not a valid classname/)
end
it "class class inherits default {} # inherits default" do
# TODO: See previous test marked as :broken=>true, it is actually this test (result) that is wacky,
# this because a class is named at parse time (since class evaluation is lazy, the model must have the
# full class name for nested classes - only, it gets this wrong when a class is named "class" - or at least
# I think it is wrong.)
#
expect {
dump(parse("class class inherits default {}")).should == "(class class::class (inherits default) ())"
}.to raise_error(/not a valid classname/)
end
it "class foo inherits class" do
expect {
dump(parse("class foo inherits class {}")).should == "(class foo (inherits class) ())"
}.to raise_error(/not a valid classname/)
end
end
context 'it should allow keywords as attribute names' do
['and', 'case', 'class', 'default', 'define', 'else', 'elsif', 'if', 'in', 'inherits', 'node', 'or',
'undef', 'unless', 'type', 'attr', 'function', 'private'].each do |keyword|
it "such as #{keyword}" do
expect {parse("class x ($#{keyword}){} class { x: #{keyword} => 1 }")}.to_not raise_error
end
end
end
end
context "When the parser parses define" do
it "define foo {}" do
dump(parse("define foo {}")).should == "(define foo ())"
end
it "class foo { define bar {}}" do
dump(parse("class foo {define bar {}}")).should == [
"(class foo (block",
" (define foo::bar ())",
"))"
].join("\n")
end
it "define foo { define bar {}}" do
# This is illegal, but handled as part of validation
dump(parse("define foo { define bar {}}")).should == [
"(define foo (block",
" (define bar ())",
"))"
].join("\n")
end
it "define foo::bar {}" do
dump(parse("define foo::bar {}")).should == "(define foo::bar ())"
end
it "define foo($a) {}" do
dump(parse("define foo($a) {}")).should == "(define foo (parameters a) ())"
end
it "define foo($a, $b) {}" do
dump(parse("define foo($a, $b) {}")).should == "(define foo (parameters a b) ())"
end
it "define foo($a, $b=10) {}" do
dump(parse("define foo($a, $b=10) {}")).should == "(define foo (parameters a (= b 10)) ())"
end
it "define foo {$a = 10 $b = 20}" do
dump(parse("define foo {$a = 10 $b = 20}")).should == [
"(define foo (block",
" (= $a 10)",
" (= $b 20)",
"))"
].join("\n")
end
context "it should handle '3x weirdness'" do
it "define class {} # a define named 'class'" do
# This is weird because Class already exists, and instantiating this define will probably not
# work
expect {
dump(parse("define class {}")).should == "(define class ())"
}.to raise_error(/not a valid classname/)
end
it "define default {} # a define named 'default'" do
# Check unwanted ability to define 'default'.
# The expression below is not allowed (which is good).
#
expect { dump(parse("define default {}")).should == "(define default ())"}.to raise_error(Puppet::ParseError)
end
end
context 'it should allow keywords as attribute names' do
['and', 'case', 'class', 'default', 'define', 'else', 'elsif', 'if', 'in', 'inherits', 'node', 'or',
'undef', 'unless', 'type', 'attr', 'function', 'private'].each do |keyword|
it "such as #{keyword}" do
expect {parse("define x ($#{keyword}){} x { y: #{keyword} => 1 }")}.to_not raise_error
end
end
end
end
context "When parsing node" do
it "node foo {}" do
dump(parse("node foo {}")).should == "(node (matches 'foo') ())"
end
it "node foo, {} # trailing comma" do
dump(parse("node foo, {}")).should == "(node (matches 'foo') ())"
end
it "node kermit.example.com {}" do
dump(parse("node kermit.example.com {}")).should == "(node (matches 'kermit.example.com') ())"
end
it "node kermit . example . com {}" do
dump(parse("node kermit . example . com {}")).should == "(node (matches 'kermit.example.com') ())"
end
it "node foo, x::bar, default {}" do
dump(parse("node foo, x::bar, default {}")).should == "(node (matches 'foo' 'x::bar' :default) ())"
end
it "node 'foo' {}" do
dump(parse("node 'foo' {}")).should == "(node (matches 'foo') ())"
end
it "node foo inherits x::bar {}" do
dump(parse("node foo inherits x::bar {}")).should == "(node (matches 'foo') (parent 'x::bar') ())"
end
it "node foo inherits 'bar' {}" do
dump(parse("node foo inherits 'bar' {}")).should == "(node (matches 'foo') (parent 'bar') ())"
end
it "node foo inherits default {}" do
dump(parse("node foo inherits default {}")).should == "(node (matches 'foo') (parent :default) ())"
end
it "node /web.*/ {}" do
dump(parse("node /web.*/ {}")).should == "(node (matches /web.*/) ())"
end
it "node /web.*/, /do\.wop.*/, and.so.on {}" do
dump(parse("node /web.*/, /do\.wop.*/, 'and.so.on' {}")).should == "(node (matches /web.*/ /do\.wop.*/ 'and.so.on') ())"
end
it "node wat inherits /apache.*/ {}" do
dump(parse("node wat inherits /apache.*/ {}")).should == "(node (matches 'wat') (parent /apache.*/) ())"
end
it "node foo inherits bar {$a = 10 $b = 20}" do
dump(parse("node foo inherits bar {$a = 10 $b = 20}")).should == [
"(node (matches 'foo') (parent 'bar') (block",
" (= $a 10)",
" (= $b 20)",
"))"
].join("\n")
end
end
end
|