puppet 3.7.4 → 3.7.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +11 -6
- data/ext/build_defaults.yaml +2 -2
- data/ext/systemd/puppet.service +1 -0
- data/lib/hiera/puppet_function.rb +71 -0
- data/lib/puppet.rb +12 -0
- data/lib/puppet/application/device.rb +22 -5
- data/lib/puppet/daemon.rb +13 -4
- data/lib/puppet/defaults.rb +27 -4
- data/lib/puppet/environments.rb +1 -1
- data/lib/puppet/error.rb +4 -0
- data/lib/puppet/functions.rb +118 -65
- data/lib/puppet/functions/assert_type.rb +5 -5
- data/lib/puppet/functions/each.rb +12 -12
- data/lib/puppet/functions/epp.rb +3 -4
- data/lib/puppet/functions/filter.rb +12 -12
- data/lib/puppet/functions/hiera.rb +29 -0
- data/lib/puppet/functions/hiera_array.rb +34 -0
- data/lib/puppet/functions/hiera_hash.rb +36 -0
- data/lib/puppet/functions/hiera_include.rb +50 -0
- data/lib/puppet/functions/inline_epp.rb +2 -3
- data/lib/puppet/functions/map.rb +12 -12
- data/lib/puppet/functions/reduce.rb +6 -6
- data/lib/puppet/functions/scanf.rb +3 -3
- data/lib/puppet/functions/slice.rb +10 -9
- data/lib/puppet/functions/with.rb +3 -4
- data/lib/puppet/graph/simple_graph.rb +5 -5
- data/lib/puppet/metatype/manager.rb +1 -1
- data/lib/puppet/node/environment.rb +1 -1
- data/lib/puppet/parser/ast/arithmetic_operator.rb +1 -1
- data/lib/puppet/parser/ast/collexpr.rb +1 -1
- data/lib/puppet/parser/compiler.rb +3 -3
- data/lib/puppet/parser/functions/create_resources.rb +1 -9
- data/lib/puppet/parser/functions/defined.rb +1 -1
- data/lib/puppet/parser/functions/hiera.rb +20 -11
- data/lib/puppet/parser/functions/hiera_array.rb +23 -13
- data/lib/puppet/parser/functions/hiera_hash.rb +25 -15
- data/lib/puppet/parser/functions/hiera_include.rb +20 -9
- data/lib/puppet/parser/functions/lookup.rb +1 -1
- data/lib/puppet/parser/functions/realize.rb +1 -1
- data/lib/puppet/parser/functions/scanf.rb +21 -12
- data/lib/puppet/parser/parser_factory.rb +2 -2
- data/lib/puppet/parser/relationship.rb +1 -1
- data/lib/puppet/parser/scope.rb +34 -7
- data/lib/puppet/pops.rb +2 -0
- data/lib/puppet/pops/binder/lookup.rb +24 -7
- data/lib/puppet/pops/binder/producers.rb +2 -2
- data/lib/puppet/pops/evaluator/closure.rb +1 -1
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +109 -17
- data/lib/puppet/pops/evaluator/puppet_proc.rb +69 -0
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +175 -0
- data/lib/puppet/pops/evaluator/runtime3_support.rb +15 -128
- data/lib/puppet/pops/functions/dispatch.rb +21 -17
- data/lib/puppet/pops/functions/dispatcher.rb +3 -3
- data/lib/puppet/pops/functions/function.rb +46 -14
- data/lib/puppet/pops/issues.rb +2 -2
- data/lib/puppet/pops/model/model_label_provider.rb +1 -1
- data/lib/puppet/pops/parser/egrammar.ra +2 -0
- data/lib/puppet/pops/parser/eparser.rb +732 -724
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
- data/lib/puppet/pops/parser/lexer2.rb +20 -22
- data/lib/puppet/pops/types/class_loader.rb +1 -1
- data/lib/puppet/pops/types/type_calculator.rb +104 -37
- data/lib/puppet/pops/types/type_factory.rb +1 -1
- data/lib/puppet/pops/types/types.rb +4 -1
- data/lib/puppet/pops/types/types_meta.rb +2 -2
- data/lib/puppet/pops/validation/checker4_0.rb +5 -3
- data/lib/puppet/provider/service/systemd.rb +1 -0
- data/lib/puppet/provider/yumrepo/inifile.rb +4 -1
- data/lib/puppet/resource.rb +3 -2
- data/lib/puppet/resource/catalog.rb +3 -2
- data/lib/puppet/resource/type.rb +1 -1
- data/lib/puppet/settings/environment_conf.rb +12 -4
- data/lib/puppet/type/package.rb +23 -13
- data/lib/puppet/util/autoload.rb +7 -7
- data/lib/puppet/util/errors.rb +4 -2
- data/lib/puppet/util/network_device/config.rb +5 -0
- data/lib/puppet/version.rb +1 -1
- data/lib/puppetx.rb +2 -2
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee.rb +8 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee_ws.rb +8 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/metadata.json +9 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller.rb +5 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller_ws.rb +12 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/metadata.json +9 -0
- data/spec/integration/parser/environment_spec.rb +47 -0
- data/spec/integration/parser/future_compiler_spec.rb +11 -6
- data/spec/unit/application/device_spec.rb +52 -14
- data/spec/unit/daemon_spec.rb +0 -2
- data/spec/unit/environments_spec.rb +2 -2
- data/spec/unit/functions/assert_type_spec.rb +4 -25
- data/spec/unit/functions/hiera_spec.rb +127 -0
- data/spec/unit/functions/with_spec.rb +9 -4
- data/spec/unit/functions4_spec.rb +98 -35
- data/spec/unit/hiera/backend/puppet_backend_spec.rb +1 -1
- data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
- data/spec/unit/parser/functions/defined_spec.rb +5 -0
- data/spec/unit/parser/functions/lookup_spec.rb +5 -1
- data/spec/unit/parser/functions/scanf_spec.rb +30 -0
- data/spec/unit/parser/scope_spec.rb +5 -0
- data/spec/unit/pops/binder/injector_spec.rb +1 -1
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +33 -5
- data/spec/unit/pops/loaders/loaders_spec.rb +22 -1
- data/spec/unit/pops/parser/lexer2_spec.rb +28 -16
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +21 -0
- data/spec/unit/pops/types/type_calculator_spec.rb +141 -19
- data/spec/unit/pops/types/type_factory_spec.rb +2 -2
- data/spec/unit/pops/validator/validator_spec.rb +25 -3
- data/spec/unit/provider/service/systemd_spec.rb +20 -4
- data/spec/unit/provider/user/hpux_spec.rb +1 -1
- data/spec/unit/provider/yumrepo/inifile_spec.rb +1 -0
- data/spec/unit/settings/environment_conf_spec.rb +12 -1
- data/spec/unit/type/package_spec.rb +0 -20
- data/spec/unit/util/network_device/config_spec.rb +6 -0
- metadata +3422 -3405
@@ -34,7 +34,7 @@ describe Hiera::Backend::Puppet_backend do
|
|
34
34
|
with_config(:puppet => {:datasource => "rspec"},
|
35
35
|
:hierarchy => ["%{foo}", "common"])
|
36
36
|
|
37
|
-
@mockscope.expects(:lookupvar).with("foo").returns(nil)
|
37
|
+
@mockscope.expects(:lookupvar).at_least_once.with("foo").returns(nil)
|
38
38
|
|
39
39
|
@backend.hierarchy(@scope, nil).should == ["rspec::common", "ntp::config::rspec", "ntp::rspec"]
|
40
40
|
end
|
@@ -63,7 +63,7 @@ describe 'function for dynamically creating resources' do
|
|
63
63
|
it 'should fail to add non-existing type' do
|
64
64
|
expect do
|
65
65
|
@scope.function_create_resources(['create-resource-foo', { 'foo' => {} }])
|
66
|
-
end.to raise_error(
|
66
|
+
end.to raise_error(/Invalid resource type create-resource-foo/)
|
67
67
|
end
|
68
68
|
|
69
69
|
it 'should be able to add edges' do
|
@@ -169,7 +169,7 @@ describe 'function for dynamically creating resources' do
|
|
169
169
|
compile_to_catalog(<<-MANIFEST)
|
170
170
|
create_resources('class', {'blah'=>{'one'=>'two'}})
|
171
171
|
MANIFEST
|
172
|
-
end.to raise_error(
|
172
|
+
end.to raise_error(/Could not find declared class blah at line 1 on node foonode/)
|
173
173
|
end
|
174
174
|
|
175
175
|
it 'should be able to add edges' do
|
@@ -55,6 +55,11 @@ describe "the 'defined' function" do
|
|
55
55
|
expect(@scope.function_defined(['$x'])).to be_true
|
56
56
|
end
|
57
57
|
|
58
|
+
it "is true when ::variable exists in scope" do
|
59
|
+
@compiler.topscope['x'] = 'something'
|
60
|
+
expect(@scope.function_defined(['$::x'])).to be_true
|
61
|
+
end
|
62
|
+
|
58
63
|
it "is true when at least one variable exists in scope" do
|
59
64
|
@scope['x'] = 'something'
|
60
65
|
expect(@scope.function_defined(['$y', '$x', '$z'])).to be_true
|
@@ -17,6 +17,10 @@ describe "lookup function" do
|
|
17
17
|
expect do
|
18
18
|
scope.function_lookup([])
|
19
19
|
end.to raise_error(ArgumentError, /Wrong number of arguments/)
|
20
|
+
|
21
|
+
expect do
|
22
|
+
scope.function_lookup([1,2])
|
23
|
+
end.to raise_error(Puppet::ParseError, /given 'name' argument, has wrong type/)
|
20
24
|
end
|
21
25
|
|
22
26
|
it "looks up a value that exists" do
|
@@ -42,7 +46,7 @@ describe "lookup function" do
|
|
42
46
|
end
|
43
47
|
|
44
48
|
it "hiera is called to lookup if value is not bound" do
|
45
|
-
|
49
|
+
Hiera.any_instance.stubs(:lookup).returns('from_hiera')
|
46
50
|
scope = scope_with_injections_from(bound(bind_single("another_value", "something")))
|
47
51
|
expect(scope.function_lookup(['a_value'])).to eq('from_hiera')
|
48
52
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe "the scanf function" do
|
5
|
+
before :all do
|
6
|
+
Puppet::Parser::Functions.autoloader.loadall
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:node) { Puppet::Node.new('localhost') }
|
10
|
+
let(:compiler) { Puppet::Parser::Compiler.new(node) }
|
11
|
+
let(:scope) { Puppet::Parser::Scope.new(compiler) }
|
12
|
+
|
13
|
+
it 'scans a value and returns an array' do
|
14
|
+
expect(scope.function_scanf(['42', '%i'])[0] == 42)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns empty array if nothing was scanned' do
|
18
|
+
expect(scope.function_scanf(['no', '%i']) == [])
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'produces result up to first unsuccessful scan' do
|
22
|
+
expect(scope.function_scanf(['42 no', '%i'])[0] == 42)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'errors when not given enough arguments' do
|
26
|
+
expect do
|
27
|
+
scope.function_scanf(['42'])
|
28
|
+
end.to raise_error(/.*scanf\(\): Wrong number of arguments given/m)
|
29
|
+
end
|
30
|
+
end
|
@@ -281,6 +281,11 @@ describe Puppet::Parser::Scope do
|
|
281
281
|
it "should raise an error when unknown qualified variable is looked up" do
|
282
282
|
expect { @scope['nowhere::john_doe'] }.to raise_error(/Undefined variable/)
|
283
283
|
end
|
284
|
+
|
285
|
+
it "should not raise an error when built in variable is looked up" do
|
286
|
+
expect { @scope['caller_module_name'] }.to_not raise_error
|
287
|
+
expect { @scope['module_name'] }.to_not raise_error
|
288
|
+
end
|
284
289
|
end
|
285
290
|
end
|
286
291
|
|
@@ -752,7 +752,7 @@ describe 'Injector' do
|
|
752
752
|
end
|
753
753
|
|
754
754
|
it "should be possible to post process lookup with a ruby proc" do
|
755
|
-
transformer = lambda {|
|
755
|
+
transformer = lambda {|value| value + 1 }
|
756
756
|
bindings.bind.name('an_int').to(42).producer_options( :transformer => transformer)
|
757
757
|
injector(lbinder).lookup(scope, 'an_int').should == 43
|
758
758
|
end
|
@@ -508,8 +508,14 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do
|
|
508
508
|
Type[Integer] : { yes } }" => 'yes',
|
509
509
|
# supports unfold
|
510
510
|
"case ringo {
|
511
|
-
*[paul, john, ringo, george] : { 'beatle' } }"
|
511
|
+
*[paul, john, ringo, george] : { 'beatle' } }" => 'beatle',
|
512
512
|
|
513
|
+
"case undef {
|
514
|
+
undef : { 'yes' } }" => 'yes',
|
515
|
+
|
516
|
+
"case undef {
|
517
|
+
*undef : { 'no' }
|
518
|
+
default :{ 'yes' }}" => 'yes',
|
513
519
|
}.each do |source, result|
|
514
520
|
it "should parse and evaluate the expression '#{source}' to #{result}" do
|
515
521
|
parser.evaluate_string(scope, source, __FILE__).should == result
|
@@ -526,6 +532,8 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do
|
|
526
532
|
"'banana' ? { /.*(ana).*/ => $1 }" => 'ana',
|
527
533
|
"[2] ? { Array[String] => yes, Array => yes}" => 'yes',
|
528
534
|
"ringo ? *[paul, john, ringo, george] => 'beatle'" => 'beatle',
|
535
|
+
"undef ? undef => 'yes'" => 'yes',
|
536
|
+
"undef ? {*undef => 'no', default => 'yes'}" => 'yes',
|
529
537
|
}.each do |source, result|
|
530
538
|
it "should parse and evaluate the expression '#{source}' to #{result}" do
|
531
539
|
parser.evaluate_string(scope, source, __FILE__).should == result
|
@@ -920,8 +928,8 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do
|
|
920
928
|
param 'Integer', 'count'
|
921
929
|
required_block_param
|
922
930
|
end
|
923
|
-
def test(count
|
924
|
-
|
931
|
+
def test(count)
|
932
|
+
yield(*[].fill(10, 0, count))
|
925
933
|
end
|
926
934
|
end
|
927
935
|
the_func = fc.new({}, env_loader)
|
@@ -937,8 +945,8 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do
|
|
937
945
|
param 'Any', 'lambda_arg'
|
938
946
|
required_block_param
|
939
947
|
end
|
940
|
-
def test(lambda_arg
|
941
|
-
|
948
|
+
def test(lambda_arg)
|
949
|
+
yield(lambda_arg)
|
942
950
|
end
|
943
951
|
end
|
944
952
|
the_func = fc.new({}, env_loader)
|
@@ -1050,6 +1058,26 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do
|
|
1050
1058
|
expect(parser.evaluate_string(scope, source, __FILE__)).to eql('10')
|
1051
1059
|
end
|
1052
1060
|
|
1061
|
+
it 'should accept a numeric variable expressed as $n' do
|
1062
|
+
source = '$x = "abc123def" =~ /(abc)(123)(def)/; "${$2}"'
|
1063
|
+
expect(parser.evaluate_string(scope, source, __FILE__)).to eql('123')
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
it 'should accept a numeric variable expressed as just an integer' do
|
1067
|
+
source = '$x = "abc123def" =~ /(abc)(123)(def)/; "${2}"'
|
1068
|
+
expect(parser.evaluate_string(scope, source, __FILE__)).to eql('123')
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
it 'should accept a numeric variable expressed as $n in an access operation' do
|
1072
|
+
source = '$x = "abc123def" =~ /(abc)(123)(def)/; "${$0[4,3]}"'
|
1073
|
+
expect(parser.evaluate_string(scope, source, __FILE__)).to eql('23d')
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
it 'should accept a numeric variable expressed as just an integer in an access operation' do
|
1077
|
+
source = '$x = "abc123def" =~ /(abc)(123)(def)/; "${0[4,3]}"'
|
1078
|
+
expect(parser.evaluate_string(scope, source, __FILE__)).to eql('23d')
|
1079
|
+
end
|
1080
|
+
|
1053
1081
|
{
|
1054
1082
|
'"value is ${a*2} yo"' => :error,
|
1055
1083
|
}.each do |source, result|
|
@@ -27,6 +27,7 @@ describe 'loaders' do
|
|
27
27
|
include PuppetSpec::Files
|
28
28
|
|
29
29
|
let(:module_without_metadata) { File.join(config_dir('wo_metadata_module'), 'modules') }
|
30
|
+
let(:mix_4x_and_3x_functions) { config_dir('mix_4x_and_3x_functions') }
|
30
31
|
let(:module_with_metadata) { File.join(config_dir('single_module'), 'modules') }
|
31
32
|
let(:dependent_modules_with_metadata) { config_dir('dependent_modules_with_metadata') }
|
32
33
|
let(:empty_test_env) { environment_for() }
|
@@ -99,6 +100,26 @@ describe 'loaders' do
|
|
99
100
|
expect(function.call({})).to eql("usee::callee() was told 'passed value' + I am user::caller()")
|
100
101
|
end
|
101
102
|
|
103
|
+
context 'with scope' do
|
104
|
+
let(:env) { environment_for(mix_4x_and_3x_functions) }
|
105
|
+
let(:scope) { Puppet::Parser::Compiler.new(Puppet::Node.new("test", :environment => env)).newscope(nil) }
|
106
|
+
let(:loader) { Puppet::Pops::Loaders.new(env).private_loader_for_module('user') }
|
107
|
+
|
108
|
+
it 'can call 3x function in dependent module from a 4x function' do
|
109
|
+
Puppet.override({ :current_environment => scope.environment, :global_scope => scope }) do
|
110
|
+
function = loader.load_typed(typed_name(:function, 'user::caller')).value
|
111
|
+
expect(function.call(scope)).to eql("usee::callee() got 'first' - usee::callee() got 'second'")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'can call 3x function and propagate caller scope from a 4x function' do
|
116
|
+
Puppet.override({ :current_environment => scope.environment, :global_scope => scope }) do
|
117
|
+
function = loader.load_typed(typed_name(:function, 'user::caller_ws')).value
|
118
|
+
expect(function.call(scope, 'passed in scope')).to eql("usee::callee_ws() got 'passed in scope'")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
102
123
|
it 'can load a function more than once from modules' do
|
103
124
|
env = environment_for(dependent_modules_with_metadata)
|
104
125
|
loaders = Puppet::Pops::Loaders.new(env)
|
@@ -112,7 +133,7 @@ describe 'loaders' do
|
|
112
133
|
end
|
113
134
|
|
114
135
|
def environment_for(*module_paths)
|
115
|
-
Puppet::Node::Environment.create(:'*test*', module_paths
|
136
|
+
Puppet::Node::Environment.create(:'*test*', module_paths)
|
116
137
|
end
|
117
138
|
|
118
139
|
def typed_name(type, name)
|
@@ -118,10 +118,8 @@ describe 'Lexer2' do
|
|
118
118
|
end
|
119
119
|
|
120
120
|
[ '_x::y', 'x::_y'].each do |string|
|
121
|
-
it "should consider the bare word '#{string}' to be a
|
122
|
-
|
123
|
-
tokens_scanned_from(string)
|
124
|
-
}.to raise_error(/Illegal fully qualified name/)
|
121
|
+
it "should consider the bare word '#{string}' to be a WORD" do
|
122
|
+
tokens_scanned_from(string).should match_tokens2(:WORD)
|
125
123
|
end
|
126
124
|
end
|
127
125
|
|
@@ -209,21 +207,33 @@ describe 'Lexer2' do
|
|
209
207
|
end
|
210
208
|
end
|
211
209
|
|
212
|
-
{ '"a$x b"'
|
213
|
-
|
214
|
-
|
210
|
+
{ '"a$x b"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>2 }],
|
211
|
+
[:VARIABLE, 'x', {:line => 1, :pos=>3, :length=>2 }],
|
212
|
+
[:DQPOST, ' b', {:line => 1, :pos=>5, :length=>3 }]],
|
215
213
|
|
216
|
-
'"a$x.b"'
|
217
|
-
|
218
|
-
|
214
|
+
'"a$x.b"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>2 }],
|
215
|
+
[:VARIABLE, 'x', {:line => 1, :pos=>3, :length=>2 }],
|
216
|
+
[:DQPOST, '.b', {:line => 1, :pos=>5, :length=>3 }]],
|
219
217
|
|
220
|
-
'"$x.b"'
|
221
|
-
|
222
|
-
|
218
|
+
'"$x.b"' => [[:DQPRE, '', {:line => 1, :pos=>1, :length=>1 }],
|
219
|
+
[:VARIABLE, 'x', {:line => 1, :pos=>2, :length=>2 }],
|
220
|
+
[:DQPOST, '.b', {:line => 1, :pos=>4, :length=>3 }]],
|
223
221
|
|
224
|
-
'"a$x"'
|
225
|
-
|
226
|
-
|
222
|
+
'"a$x"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>2 }],
|
223
|
+
[:VARIABLE, 'x', {:line => 1, :pos=>3, :length=>2 }],
|
224
|
+
[:DQPOST, '', {:line => 1, :pos=>5, :length=>1 }]],
|
225
|
+
|
226
|
+
'"a${x}"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>4 }],
|
227
|
+
[:VARIABLE, 'x', {:line => 1, :pos=>5, :length=>1 }],
|
228
|
+
[:DQPOST, '', {:line => 1, :pos=>7, :length=>1 }]],
|
229
|
+
|
230
|
+
'"a${_x}"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>4 }],
|
231
|
+
[:VARIABLE, '_x', {:line => 1, :pos=>5, :length=>2 }],
|
232
|
+
[:DQPOST, '', {:line => 1, :pos=>8, :length=>1 }]],
|
233
|
+
|
234
|
+
'"a${y::_x}"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>4 }],
|
235
|
+
[:VARIABLE, 'y::_x', {:line => 1, :pos=>5, :length=>5 }],
|
236
|
+
[:DQPOST, '', {:line => 1, :pos=>11, :length=>1 }]],
|
227
237
|
}.each do |source, expected|
|
228
238
|
it "should lex an interpolated variable 'x' from #{source}" do
|
229
239
|
tokens_scanned_from(source).should match_tokens2(*expected)
|
@@ -301,6 +311,8 @@ describe 'Lexer2' do
|
|
301
311
|
"]" => ["] /./", [:RBRACK, :DIV, :DOT, :DIV]],
|
302
312
|
"|>" => ["|> /./", [:RCOLLECT, :DIV, :DOT, :DIV]],
|
303
313
|
"|>>" => ["|>> /./", [:RRCOLLECT, :DIV, :DOT, :DIV]],
|
314
|
+
"$x" => ["$x /1/", [:VARIABLE, :DIV, :NUMBER, :DIV]],
|
315
|
+
"a-b" => ["a-b /1/", [:WORD, :DIV, :NUMBER, :DIV]],
|
304
316
|
'"a$a"' => ['"a$a" /./', [:DQPRE, :VARIABLE, :DQPOST, :DIV, :DOT, :DIV]],
|
305
317
|
}.each do |token, entry|
|
306
318
|
it "should not lex regexp after '#{token}'" do
|
@@ -114,4 +114,25 @@ describe "egrammar parsing heredoc" do
|
|
114
114
|
].join("\n")
|
115
115
|
end
|
116
116
|
|
117
|
+
it 'parses multiple heredocs on the same line' do
|
118
|
+
src = <<-CODE
|
119
|
+
notice({ @(foo) => @(bar) })
|
120
|
+
hello
|
121
|
+
-foo
|
122
|
+
world
|
123
|
+
-bar
|
124
|
+
notice '!'
|
125
|
+
CODE
|
126
|
+
expect(dump(parse(src))).to eq([
|
127
|
+
'(block',
|
128
|
+
' (invoke notice ({} ((@()',
|
129
|
+
' (sublocated \' hello\')',
|
130
|
+
' ) (@()',
|
131
|
+
' (sublocated \' world\')',
|
132
|
+
' ))))',
|
133
|
+
' (invoke notice \'!\')',
|
134
|
+
')'
|
135
|
+
].join("\n"))
|
136
|
+
end
|
137
|
+
|
117
138
|
end
|
@@ -85,6 +85,14 @@ describe 'The type calculator' do
|
|
85
85
|
Puppet::Pops::Types::TypeFactory.any()
|
86
86
|
end
|
87
87
|
|
88
|
+
def optional_t(t)
|
89
|
+
Puppet::Pops::Types::TypeFactory.optional(t)
|
90
|
+
end
|
91
|
+
|
92
|
+
def undef_t
|
93
|
+
Puppet::Pops::Types::TypeFactory.undef
|
94
|
+
end
|
95
|
+
|
88
96
|
def unit_t
|
89
97
|
# Cannot be created via factory, the type is private to the type system
|
90
98
|
Puppet::Pops::Types::PUnitType.new
|
@@ -99,7 +107,7 @@ describe 'The type calculator' do
|
|
99
107
|
# Do not include the special type Unit in this list
|
100
108
|
def all_types
|
101
109
|
[ Puppet::Pops::Types::PAnyType,
|
102
|
-
Puppet::Pops::Types::
|
110
|
+
Puppet::Pops::Types::PUndefType,
|
103
111
|
Puppet::Pops::Types::PDataType,
|
104
112
|
Puppet::Pops::Types::PScalarType,
|
105
113
|
Puppet::Pops::Types::PStringType,
|
@@ -175,7 +183,7 @@ describe 'The type calculator' do
|
|
175
183
|
result << Puppet::Pops::Types::PDataType
|
176
184
|
result << array_t(types::PDataType.new)
|
177
185
|
result << types::TypeFactory.hash_of_data
|
178
|
-
result << Puppet::Pops::Types::
|
186
|
+
result << Puppet::Pops::Types::PUndefType
|
179
187
|
tmp = tuple_t(types::PDataType.new)
|
180
188
|
result << (tmp)
|
181
189
|
tmp.size_type = range_t(0, nil)
|
@@ -223,8 +231,8 @@ describe 'The type calculator' do
|
|
223
231
|
calculator.infer(/^a regular expression$/).class.should == Puppet::Pops::Types::PRegexpType
|
224
232
|
end
|
225
233
|
|
226
|
-
it 'nil translates to
|
227
|
-
calculator.infer(nil).class.should == Puppet::Pops::Types::
|
234
|
+
it 'nil translates to PUndefType' do
|
235
|
+
calculator.infer(nil).class.should == Puppet::Pops::Types::PUndefType
|
228
236
|
end
|
229
237
|
|
230
238
|
it ':undef translates to PRuntimeType' do
|
@@ -355,8 +363,48 @@ describe 'The type calculator' do
|
|
355
363
|
it 'with fixnum values translates to PHashType[key, PIntegerType]' do
|
356
364
|
calculator.infer({:first => 1, :second => 2}).element_type.class.should == Puppet::Pops::Types::PIntegerType
|
357
365
|
end
|
358
|
-
end
|
359
366
|
|
367
|
+
it 'when empty infers a type that answers true to is_the_empty_hash?' do
|
368
|
+
expect(calculator.infer({}).is_the_empty_hash?).to be_true
|
369
|
+
expect(calculator.infer_set({}).is_the_empty_hash?).to be_true
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'when empty is assignable to any PHashType' do
|
373
|
+
expect(calculator.assignable?(hash_t(string_t, string_t), calculator.infer({}))).to be_true
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'when empty is not assignable to a PHashType with from size > 0' do
|
377
|
+
expect(calculator.assignable?(constrained_t(hash_t(string_t,string_t), 1, 1), calculator.infer({}))).to be_false
|
378
|
+
end
|
379
|
+
|
380
|
+
context 'using infer_set' do
|
381
|
+
it "with 'first' and 'second' keys translates to PStructType[{first=>value,second=>value}]" do
|
382
|
+
t = calculator.infer_set({'first' => 1, 'second' => 2})
|
383
|
+
expect(t.class).to eq(Puppet::Pops::Types::PStructType)
|
384
|
+
expect(t.elements.size).to eq(2)
|
385
|
+
expect(t.elements.map { |e| e.name }.sort).to eq(['first', 'second'])
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'with string keys and string and array values translates to PStructType[{key1=>PStringType,key2=>PTupleType}]' do
|
389
|
+
t = calculator.infer_set({ 'mode' => 'read', 'path' => ['foo', 'fee' ] })
|
390
|
+
expect(t.class).to eq(Puppet::Pops::Types::PStructType)
|
391
|
+
expect(t.elements.size).to eq(2)
|
392
|
+
els = t.elements.map { |e| e.type }.sort {|a,b| a.to_s <=> b.to_s }
|
393
|
+
els[0].class.should == Puppet::Pops::Types::PStringType
|
394
|
+
els[1].class.should == Puppet::Pops::Types::PTupleType
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'with mixed string and non-string keys translates to PHashType' do
|
398
|
+
t = calculator.infer_set({ 1 => 'first', 'second' => 'second' })
|
399
|
+
expect(t.class).to eq(Puppet::Pops::Types::PHashType)
|
400
|
+
end
|
401
|
+
|
402
|
+
it 'with empty string keys translates to PHashType' do
|
403
|
+
t = calculator.infer_set({ '' => 'first', 'second' => 'second' })
|
404
|
+
expect(t.class).to eq(Puppet::Pops::Types::PHashType)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
360
408
|
end
|
361
409
|
|
362
410
|
context 'patterns' do
|
@@ -683,6 +731,22 @@ describe 'The type calculator' do
|
|
683
731
|
t = Puppet::Pops::Types::PHashType.new()
|
684
732
|
tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
|
685
733
|
end
|
734
|
+
|
735
|
+
it 'Struct is assignable to Hash with Pattern that matches all keys' do
|
736
|
+
struct_t({'x' => integer_t, 'y' => integer_t}).should be_assignable_to(hash_t(pattern_t(/^\w+$/), factory.any))
|
737
|
+
end
|
738
|
+
|
739
|
+
it 'Struct is assignable to Hash with Enum that matches all keys' do
|
740
|
+
struct_t({'x' => integer_t, 'y' => integer_t}).should be_assignable_to(hash_t(enum_t('x', 'y', 'z'), factory.any))
|
741
|
+
end
|
742
|
+
|
743
|
+
it 'Struct is not assignable to Hash with Pattern unless all keys match' do
|
744
|
+
struct_t({'a' => integer_t, 'A' => integer_t}).should_not be_assignable_to(hash_t(pattern_t(/^[A-Z]+$/), factory.any))
|
745
|
+
end
|
746
|
+
|
747
|
+
it 'Struct is not assignable to Hash with Enum unless all keys match' do
|
748
|
+
struct_t({'a' => integer_t, 'y' => integer_t}).should_not be_assignable_to(hash_t(enum_t('x', 'y', 'z'), factory.any))
|
749
|
+
end
|
686
750
|
end
|
687
751
|
|
688
752
|
context "for Tuple, such that" do
|
@@ -739,7 +803,7 @@ describe 'The type calculator' do
|
|
739
803
|
Bignum => Puppet::Pops::Types::PIntegerType.new,
|
740
804
|
Float => Puppet::Pops::Types::PFloatType.new,
|
741
805
|
Numeric => Puppet::Pops::Types::PNumericType.new,
|
742
|
-
NilClass => Puppet::Pops::Types::
|
806
|
+
NilClass => Puppet::Pops::Types::PUndefType.new,
|
743
807
|
TrueClass => Puppet::Pops::Types::PBooleanType.new,
|
744
808
|
FalseClass => Puppet::Pops::Types::PBooleanType.new,
|
745
809
|
String => Puppet::Pops::Types::PStringType.new,
|
@@ -1025,6 +1089,30 @@ describe 'The type calculator' do
|
|
1025
1089
|
calculator.assignable?(struct2, struct1).should == true
|
1026
1090
|
end
|
1027
1091
|
|
1092
|
+
it 'should accept matching structs with less elements when unmatched elements are optional' do
|
1093
|
+
struct1 = struct_t({'a'=>Integer, 'b'=>Integer, 'c'=>optional_t(Integer)})
|
1094
|
+
struct2 = struct_t({'a'=>Integer, 'b'=>Integer})
|
1095
|
+
calculator.assignable?(struct1, struct2).should == true
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
it 'should reject matching structs with more elements even if excess elements are optional' do
|
1099
|
+
struct1 = struct_t({'a'=>Integer, 'b'=>Integer})
|
1100
|
+
struct2 = struct_t({'a'=>Integer, 'b'=>Integer, 'c'=>optional_t(Integer)})
|
1101
|
+
calculator.assignable?(struct1, struct2).should == false
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
it 'should accept matching structs where one is more general than the other with respect to optional' do
|
1105
|
+
struct1 = struct_t({'a'=>Integer, 'b'=>Integer, 'c'=>optional_t(Integer)})
|
1106
|
+
struct2 = struct_t({'a'=>Integer, 'b'=>Integer, 'c'=>Integer})
|
1107
|
+
calculator.assignable?(struct1, struct2).should == true
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
it 'should reject matching structs where one is more special than the other with respect to optional' do
|
1111
|
+
struct1 = struct_t({'a'=>Integer, 'b'=>Integer, 'c'=>Integer})
|
1112
|
+
struct2 = struct_t({'a'=>Integer, 'b'=>Integer, 'c'=>optional_t(Integer)})
|
1113
|
+
calculator.assignable?(struct1, struct2).should == false
|
1114
|
+
end
|
1115
|
+
|
1028
1116
|
it 'should accept matching structs where one is more general than the other' do
|
1029
1117
|
struct1 = struct_t({'a'=>Integer, 'b'=>Integer})
|
1030
1118
|
struct2 = struct_t({'a'=>Numeric, 'b'=>Numeric})
|
@@ -1041,6 +1129,13 @@ describe 'The type calculator' do
|
|
1041
1129
|
calculator.assignable?(struct1, hsh).should == true
|
1042
1130
|
calculator.assignable?(hsh, struct1).should == true
|
1043
1131
|
end
|
1132
|
+
|
1133
|
+
it 'should accept empty hash with key_type undef' do
|
1134
|
+
struct1 = struct_t({'a'=>optional_t(Integer)})
|
1135
|
+
hsh = hash_t(undef_t, undef_t)
|
1136
|
+
factory.constrain_size(hsh, 0, 0)
|
1137
|
+
calculator.assignable?(struct1, hsh).should == true
|
1138
|
+
end
|
1044
1139
|
end
|
1045
1140
|
|
1046
1141
|
it 'should recognize ruby type inheritance' do
|
@@ -1117,7 +1212,7 @@ describe 'The type calculator' do
|
|
1117
1212
|
include_context "types_setup"
|
1118
1213
|
|
1119
1214
|
it 'should consider undef to be instance of Any, NilType, and optional' do
|
1120
|
-
calculator.instance?(Puppet::Pops::Types::
|
1215
|
+
calculator.instance?(Puppet::Pops::Types::PUndefType.new(), nil).should == true
|
1121
1216
|
calculator.instance?(Puppet::Pops::Types::PAnyType.new(), nil).should == true
|
1122
1217
|
calculator.instance?(Puppet::Pops::Types::POptionalType.new(), nil).should == true
|
1123
1218
|
end
|
@@ -1139,7 +1234,7 @@ describe 'The type calculator' do
|
|
1139
1234
|
it 'should not consider undef to be an instance of any other type than Any, NilType and Data' do
|
1140
1235
|
types_to_test = all_types - [
|
1141
1236
|
Puppet::Pops::Types::PAnyType,
|
1142
|
-
Puppet::Pops::Types::
|
1237
|
+
Puppet::Pops::Types::PUndefType,
|
1143
1238
|
Puppet::Pops::Types::PDataType,
|
1144
1239
|
Puppet::Pops::Types::POptionalType,
|
1145
1240
|
]
|
@@ -1252,12 +1347,39 @@ describe 'The type calculator' do
|
|
1252
1347
|
calculator.instance?(tuple, [1, 'a', 1]).should == false
|
1253
1348
|
end
|
1254
1349
|
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1350
|
+
context 'and t is Struct' do
|
1351
|
+
it 'should consider hash[cont] as instance of Struct[cont-t]' do
|
1352
|
+
struct = struct_t({'a'=>Integer, 'b'=>String, 'c'=>Float})
|
1353
|
+
calculator.instance?(struct, {'a'=>1, 'b'=>'a', 'c'=>3.14}).should == true
|
1354
|
+
calculator.instance?(struct, {'a'=>1.2, 'b'=>'a', 'c'=>3.14}).should == false
|
1355
|
+
calculator.instance?(struct, {'a'=>1, 'b'=>1, 'c'=>3.14}).should == false
|
1356
|
+
calculator.instance?(struct, {'a'=>1, 'b'=>'a', 'c'=>1}).should == false
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
it 'should consider empty hash as instance of Struct[x=>Optional[String]]' do
|
1360
|
+
struct = struct_t({'a'=>optional_t(String)})
|
1361
|
+
calculator.instance?(struct, {}).should == true
|
1362
|
+
end
|
1363
|
+
|
1364
|
+
it 'should consider hash[cont] as instance of Struct[cont-t,optionals]' do
|
1365
|
+
struct = struct_t({'a'=>Integer, 'b'=>String, 'c'=>optional_t(Float)})
|
1366
|
+
calculator.instance?(struct, {'a'=>1, 'b'=>'a'}).should == true
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
it 'should consider hash[cont] as instance of Struct[cont-t,variants with optionals]' do
|
1370
|
+
struct = struct_t({'a'=>Integer, 'b'=>String, 'c'=>variant_t(String, optional_t(Float))})
|
1371
|
+
calculator.instance?(struct, {'a'=>1, 'b'=>'a'}).should == true
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
it 'should not consider hash[cont,cont2] as instance of Struct[cont-t]' do
|
1375
|
+
struct = struct_t({'a'=>Integer, 'b'=>String})
|
1376
|
+
calculator.instance?(struct, {'a'=>1, 'b'=>'a', 'c'=>'x'}).should == false
|
1377
|
+
end
|
1378
|
+
|
1379
|
+
it 'should not consider hash[cont,cont2] as instance of Struct[cont-t,optional[cont3-t]' do
|
1380
|
+
struct = struct_t({'a'=>Integer, 'b'=>String, 'c'=>optional_t(Float)})
|
1381
|
+
calculator.instance?(struct, {'a'=>1, 'b'=>'a', 'c'=>'x'}).should == false
|
1382
|
+
end
|
1261
1383
|
end
|
1262
1384
|
|
1263
1385
|
context 'and t is Data' do
|
@@ -1343,8 +1465,8 @@ describe 'The type calculator' do
|
|
1343
1465
|
end
|
1344
1466
|
end
|
1345
1467
|
|
1346
|
-
it 'should yield \'
|
1347
|
-
calculator.type(NilClass).class.should == Puppet::Pops::Types::
|
1468
|
+
it 'should yield \'PUndefType\' for NilClass' do
|
1469
|
+
calculator.type(NilClass).class.should == Puppet::Pops::Types::PUndefType
|
1348
1470
|
end
|
1349
1471
|
|
1350
1472
|
it 'should yield \'PStringType\' for String' do
|
@@ -1607,7 +1729,7 @@ describe 'The type calculator' do
|
|
1607
1729
|
context 'when processing meta type' do
|
1608
1730
|
it 'should infer PType as the type of all other types' do
|
1609
1731
|
ptype = Puppet::Pops::Types::PType
|
1610
|
-
calculator.infer(Puppet::Pops::Types::
|
1732
|
+
calculator.infer(Puppet::Pops::Types::PUndefType.new() ).is_a?(ptype).should() == true
|
1611
1733
|
calculator.infer(Puppet::Pops::Types::PDataType.new() ).is_a?(ptype).should() == true
|
1612
1734
|
calculator.infer(Puppet::Pops::Types::PScalarType.new() ).is_a?(ptype).should() == true
|
1613
1735
|
calculator.infer(Puppet::Pops::Types::PStringType.new() ).is_a?(ptype).should() == true
|
@@ -1632,7 +1754,7 @@ describe 'The type calculator' do
|
|
1632
1754
|
|
1633
1755
|
it 'should infer PType as the type of all other types' do
|
1634
1756
|
ptype = Puppet::Pops::Types::PType
|
1635
|
-
calculator.string(calculator.infer(Puppet::Pops::Types::
|
1757
|
+
calculator.string(calculator.infer(Puppet::Pops::Types::PUndefType.new() )).should == "Type[Undef]"
|
1636
1758
|
calculator.string(calculator.infer(Puppet::Pops::Types::PDataType.new() )).should == "Type[Data]"
|
1637
1759
|
calculator.string(calculator.infer(Puppet::Pops::Types::PScalarType.new() )).should == "Type[Scalar]"
|
1638
1760
|
calculator.string(calculator.infer(Puppet::Pops::Types::PStringType.new() )).should == "Type[String]"
|
@@ -1775,7 +1897,7 @@ describe 'The type calculator' do
|
|
1775
1897
|
inferred_type.class.should == Puppet::Pops::Types::PTupleType
|
1776
1898
|
element_types = inferred_type.types
|
1777
1899
|
element_types[0].class.should == Puppet::Pops::Types::PStringType
|
1778
|
-
element_types[1].class.should == Puppet::Pops::Types::
|
1900
|
+
element_types[1].class.should == Puppet::Pops::Types::PUndefType
|
1779
1901
|
end
|
1780
1902
|
end
|
1781
1903
|
|