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
|
require 'spec_helper'
require 'puppet/pops'
require 'stringio'
require 'puppet_spec/scope'
describe "lookup function" do
include PuppetSpec::Scope
before(:each) do
Puppet[:binder] = true
Puppet[:parser] = 'future'
end
it "must be called with at least a name to lookup" do
scope = scope_with_injections_from(bound(bindings))
expect do
scope.function_lookup([])
end.to raise_error(ArgumentError, /Wrong number of arguments/)
end
it "looks up a value that exists" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['a_value'])).to eq('something')
end
it "searches for first found if given several names" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup([['b_value', 'a_value', 'c_value']])).to eq('something')
end
it "override wins over bound" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
options = {:override => { 'a_value' => 'something_overridden' }}
expect(scope.function_lookup(['a_value', options])).to eq('something_overridden')
end
it "extra option is used if nothing is found" do
scope = scope_with_injections_from(bound(bind_single("another_value", "something")))
options = {:extra => { 'a_value' => 'something_extra' }}
expect(scope.function_lookup(['a_value', options])).to eq('something_extra')
end
it "hiera is called to lookup if value is not bound" do
Puppet::Parser::Scope.any_instance.stubs(:function_hiera).returns('from_hiera')
scope = scope_with_injections_from(bound(bind_single("another_value", "something")))
expect(scope.function_lookup(['a_value'])).to eq('from_hiera')
end
it "returns nil when the requested value is not bound and undef is accepted" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['not_bound_value',{'accept_undef' => true}])).to eq(nil)
end
it "fails if the requested value is not bound and undef is not allowed" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect do
scope.function_lookup(['not_bound_value'])
end.to raise_error(/did not find a value for the name 'not_bound_value'/)
end
it "returns the given default value when the requested value is not bound" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['not_bound_value','String', 'cigar'])).to eq('cigar')
end
it "accepts values given in a hash of options" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['not_bound_value',{'type' => 'String', 'default' => 'cigar'}])).to eq('cigar')
end
it "raises an error when the bound type is not assignable to the requested type" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect do
scope.function_lookup(['a_value', 'Integer'])
end.to raise_error(ArgumentError, /incompatible type, expected: Integer, got: String/)
end
it "returns the value if the bound type is assignable to the requested type" do
typed_bindings = bindings
typed_bindings.bind().string().name("a_value").to("something")
scope = scope_with_injections_from(bound(typed_bindings))
expect(scope.function_lookup(['a_value', 'Data'])).to eq("something")
end
it "yields to a given lambda and returns the result" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['a_value', ast_lambda(scope, '|$x|{something_else}')])).to eq('something_else')
end
it "fails if given lambda produces undef" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect do
scope.function_lookup(['a_value', ast_lambda(scope, '|$x|{undef}')])
end.to raise_error(/did not find a value for the name 'a_value'/)
end
it "yields name and result to a given lambda" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['a_value', ast_lambda(scope, '|$name, $result|{[$name, $result]}')])).to eq(['a_value', 'something'])
end
it "yields name and result and default to a given lambda" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['a_value', {'default' => 'cigar'},
ast_lambda(scope, '|$name, $result, $d|{[$name, $result, $d]}')])).to eq(['a_value', 'something', 'cigar'])
end
it "yields to a given lambda and returns the result when giving name and type" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['a_value', 'String', ast_lambda(scope, '|$x|{something_else}')])).to eq('something_else')
end
it "yields :undef when value is not found and using a lambda" do
scope = scope_with_injections_from(bound(bind_single("a_value", "something")))
expect(scope.function_lookup(['not_bound_value', ast_lambda(scope, '|$x|{ if $x == undef {good} else {bad}}')])).to eq('good')
end
def scope_with_injections_from(binder)
injector = Puppet::Pops::Binder::Injector.new(binder)
scope = create_test_scope_for_node('testing')
scope.compiler.injector = injector
scope
end
def bindings
Puppet::Pops::Binder::BindingsFactory.named_bindings("testing")
end
def bind_single(name, value)
local_bindings = Puppet::Pops::Binder::BindingsFactory.named_bindings("testing")
local_bindings.bind().name(name).to(value)
local_bindings
end
def bound(local_bindings)
layered_bindings = Puppet::Pops::Binder::BindingsFactory.layered_bindings(Puppet::Pops::Binder::BindingsFactory.named_layer('test layer', local_bindings.model))
Puppet::Pops::Binder::Binder.new(layered_bindings)
end
def ast_lambda(scope, puppet_source)
puppet_source = "fake_func() " + puppet_source
evaluator = Puppet::Pops::Parser::EvaluatingParser.new()
model = evaluator.parse_string(puppet_source, __FILE__).current
evaluator.closure(model.body.lambda, scope)
end
end
|