puppet 4.4.2 → 4.5.0
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.
- data/CONTRIBUTING.md +5 -5
- data/Gemfile +2 -2
- data/LICENSE +2 -2
- data/README.md +5 -0
- data/ext/project_data.yaml +2 -0
- data/lib/hiera_puppet.rb +6 -14
- data/lib/puppet/application/agent.rb +2 -3
- data/lib/puppet/data_providers/hiera_config.rb +2 -4
- data/lib/puppet/data_providers/hiera_interpolate.rb +12 -154
- data/lib/puppet/data_providers/json_data_provider_factory.rb +0 -7
- data/lib/puppet/data_providers/yaml_data_provider_factory.rb +2 -8
- data/lib/puppet/defaults.rb +70 -7
- data/lib/puppet/functions.rb +69 -0
- data/lib/puppet/functions/dig.rb +39 -0
- data/lib/puppet/functions/lest.rb +53 -0
- data/lib/puppet/functions/lookup.rb +40 -27
- data/lib/puppet/functions/new.rb +502 -0
- data/lib/puppet/functions/regsubst.rb +11 -10
- data/lib/puppet/functions/then.rb +74 -0
- data/lib/puppet/functions/type.rb +4 -4
- data/lib/puppet/functions/with.rb +1 -1
- data/lib/puppet/indirector/catalog/compiler.rb +2 -0
- data/lib/puppet/indirector/resource_type/parser.rb +5 -0
- data/lib/puppet/indirector/rest.rb +5 -1
- data/lib/puppet/loaders.rb +2 -0
- data/lib/puppet/metatype/manager.rb +19 -2
- data/lib/puppet/module_tool/applications/application.rb +1 -1
- data/lib/puppet/module_tool/skeleton/templates/generator/Gemfile +6 -2
- data/lib/puppet/module_tool/skeleton/templates/generator/Rakefile +19 -4
- data/lib/puppet/module_tool/skeleton/templates/generator/{tests → examples}/init.pp.erb +1 -1
- data/lib/puppet/module_tool/skeleton/templates/generator/spec/classes/init_spec.rb.erb +0 -1
- data/lib/puppet/network/http/api/master/v3/environment.rb +6 -2
- data/lib/puppet/parser/ast/pops_bridge.rb +20 -3
- data/lib/puppet/parser/compiler/catalog_validator/relationship_validator.rb +24 -2
- data/lib/puppet/parser/e4_parser_adapter.rb +13 -12
- data/lib/puppet/parser/environment_compiler.rb +2 -2
- data/lib/puppet/parser/resource.rb +14 -5
- data/lib/puppet/parser/scope.rb +18 -15
- data/lib/puppet/plugins/data_providers/data_provider.rb +19 -8
- data/lib/puppet/pops.rb +6 -0
- data/lib/puppet/pops/adapters.rb +5 -1
- data/lib/puppet/pops/evaluator/access_operator.rb +52 -14
- data/lib/puppet/pops/evaluator/compare_operator.rb +34 -4
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +75 -22
- data/lib/puppet/pops/evaluator/literal_evaluator.rb +7 -6
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +13 -1
- data/lib/puppet/pops/evaluator/runtime3_support.rb +14 -4
- data/lib/puppet/pops/functions/dispatcher.rb +1 -1
- data/lib/puppet/pops/issues.rb +18 -2
- data/lib/puppet/pops/loader/base_loader.rb +48 -7
- data/lib/puppet/pops/loader/dependency_loader.rb +27 -2
- data/lib/puppet/pops/loader/loader.rb +12 -0
- data/lib/puppet/pops/loader/predefined_loader.rb +29 -0
- data/lib/puppet/pops/loader/runtime3_type_loader.rb +57 -0
- data/lib/puppet/pops/loader/static_loader.rb +92 -5
- data/lib/puppet/pops/loader/type_definition_instantiator.rb +25 -3
- data/lib/puppet/pops/loaders.rb +84 -14
- data/lib/puppet/pops/lookup/explainer.rb +38 -1
- data/lib/puppet/pops/lookup/interpolation.rb +115 -0
- data/lib/puppet/pops/lookup/sub_lookup.rb +86 -0
- data/lib/puppet/pops/model/ast_transformer.rb +8 -1
- data/lib/puppet/pops/model/factory.rb +31 -8
- data/lib/puppet/pops/model/model.rb +8 -0
- data/lib/puppet/pops/model/model_label_provider.rb +1 -0
- data/lib/puppet/pops/model/model_meta.rb +7 -1
- data/lib/puppet/pops/model/model_tree_dumper.rb +4 -0
- data/lib/puppet/pops/parser/egrammar.ra +24 -7
- data/lib/puppet/pops/parser/eparser.rb +863 -798
- data/lib/puppet/pops/parser/evaluating_parser.rb +4 -0
- data/lib/puppet/pops/parser/locator.rb +8 -4
- data/lib/puppet/pops/pcore.rb +30 -0
- data/lib/puppet/pops/types/class_loader.rb +2 -4
- data/lib/puppet/pops/types/implementation_registry.rb +146 -0
- data/lib/puppet/pops/types/iterable.rb +4 -4
- data/lib/puppet/pops/types/p_object_type.rb +846 -0
- data/lib/puppet/pops/types/p_runtime_type.rb +102 -0
- data/lib/puppet/pops/types/p_sem_ver_range_type.rb +164 -0
- data/lib/puppet/pops/types/p_sem_ver_type.rb +113 -0
- data/lib/puppet/pops/types/puppet_object.rb +21 -0
- data/lib/puppet/pops/types/ruby_generator.rb +258 -0
- data/lib/puppet/pops/types/string_converter.rb +922 -0
- data/lib/puppet/pops/types/type_calculator.rb +29 -5
- data/lib/puppet/pops/types/type_conversion_error.rb +15 -0
- data/lib/puppet/pops/types/type_factory.rb +49 -16
- data/lib/puppet/pops/types/type_formatter.rb +335 -112
- data/lib/puppet/pops/types/type_mismatch_describer.rb +110 -29
- data/lib/puppet/pops/types/type_parser.rb +205 -197
- data/lib/puppet/pops/types/types.rb +481 -103
- data/lib/puppet/pops/validation.rb +1 -1
- data/lib/puppet/pops/validation/checker4_0.rb +66 -4
- data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
- data/lib/puppet/pops/visitor.rb +3 -1
- data/lib/puppet/property.rb +1 -1
- data/lib/puppet/provider/augeas/augeas.rb +1 -1
- data/lib/puppet/provider/package/pip.rb +64 -20
- data/lib/puppet/provider/package/rpm.rb +112 -0
- data/lib/puppet/provider/package/yum.rb +7 -68
- data/lib/puppet/provider/service/daemontools.rb +3 -3
- data/lib/puppet/provider/service/init.rb +4 -2
- data/lib/puppet/provider/service/runit.rb +3 -3
- data/lib/puppet/provider/service/smf.rb +6 -3
- data/lib/puppet/provider/service/systemd.rb +59 -73
- data/lib/puppet/reference/providers.rb +1 -2
- data/lib/puppet/resource.rb +54 -37
- data/lib/puppet/resource/catalog.rb +31 -29
- data/lib/puppet/resource/type_collection.rb +23 -8
- data/lib/puppet/settings.rb +4 -2
- data/lib/puppet/settings/base_setting.rb +9 -3
- data/lib/puppet/settings/symbolic_enum_setting.rb +17 -0
- data/lib/puppet/test/test_helper.rb +0 -1
- data/lib/puppet/type.rb +9 -3
- data/lib/puppet/type/exec.rb +17 -17
- data/lib/puppet/type/file.rb +12 -0
- data/lib/puppet/type/file/content.rb +6 -6
- data/lib/puppet/type/file/ensure.rb +4 -4
- data/lib/puppet/type/file/source.rb +4 -4
- data/lib/puppet/type/file/target.rb +2 -2
- data/lib/puppet/type/mount.rb +18 -1
- data/lib/puppet/type/package.rb +3 -3
- data/lib/puppet/type/schedule.rb +4 -4
- data/lib/puppet/type/service.rb +15 -0
- data/lib/puppet/type/sshkey.rb +5 -3
- data/lib/puppet/type/tidy.rb +3 -3
- data/lib/puppet/type/zone.rb +5 -5
- data/lib/puppet/util/feature.rb +1 -1
- data/lib/puppet/util/monkey_patches.rb +8 -0
- data/lib/puppet/util/network_device/cisco/device.rb +16 -6
- data/lib/puppet/util/network_device/cisco/interface.rb +5 -6
- data/lib/puppet/util/plist.rb +3 -3
- data/lib/puppet/version.rb +1 -1
- data/spec/fixtures/unit/application/environments/production/data/common.yaml +13 -0
- data/spec/fixtures/unit/data_providers/environments/production/modules/abc/lib/puppet/functions/abc/data.rb +2 -1
- data/spec/fixtures/unit/data_providers/environments/production/modules/abc/manifests/init.pp +2 -1
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/data/empty_key.json +1 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/hiera.yaml +5 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/manifests/init.pp +2 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/metadata.json +9 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/data/empty_key.yaml +1 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/hiera.yaml +5 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/manifests/init.pp +2 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/metadata.json +9 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_yaml/data/empty.yaml +1 -0
- data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/lib/puppet/type/usee_type.rb +5 -0
- data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/manifests/init.pp +6 -0
- data/spec/fixtures/unit/provider/service/smf/svcs.out +4 -3
- data/spec/integration/module_tool/tar/mini_spec.rb +27 -27
- data/spec/integration/parser/catalog_spec.rb +14 -2
- data/spec/integration/parser/compiler_spec.rb +94 -3
- data/spec/integration/parser/resource_expressions_spec.rb +1 -1
- data/spec/integration/resource/type_collection_spec.rb +8 -0
- data/spec/lib/puppet_spec/compiler.rb +11 -4
- data/spec/shared_contexts/types_setup.rb +4 -0
- data/spec/unit/application/lookup_spec.rb +91 -9
- data/spec/unit/appmgmt_spec.rb +44 -35
- data/spec/unit/capability_spec.rb +33 -53
- data/spec/unit/data_providers/function_data_provider_spec.rb +19 -1
- data/spec/unit/data_providers/hiera_data_provider_spec.rb +1 -1
- data/spec/unit/defaults_spec.rb +18 -0
- data/spec/unit/functions/assert_type_spec.rb +1 -1
- data/spec/unit/functions/dig_spec.rb +58 -0
- data/spec/unit/functions/lest_spec.rb +34 -0
- data/spec/unit/functions/lookup_spec.rb +108 -2
- data/spec/unit/functions/new_spec.rb +543 -0
- data/spec/unit/functions/regsubst_spec.rb +8 -0
- data/spec/unit/functions/then_spec.rb +40 -0
- data/spec/unit/functions4_spec.rb +78 -10
- data/spec/unit/hiera_puppet_spec.rb +49 -8
- data/spec/unit/indirector/resource_type/parser_spec.rb +5 -0
- data/spec/unit/indirector/rest_spec.rb +12 -0
- data/spec/unit/network/http/api/master/v3/environment_spec.rb +60 -0
- data/spec/unit/node/environment_spec.rb +10 -0
- data/spec/unit/parser/compiler_spec.rb +20 -1
- data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
- data/spec/unit/parser/functions/shared.rb +1 -1
- data/spec/unit/parser/resource_spec.rb +8 -1
- data/spec/unit/parser/scope_spec.rb +45 -0
- data/spec/unit/pops/evaluator/access_ops_spec.rb +14 -0
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +13 -5
- data/spec/unit/pops/loaders/static_loader_spec.rb +92 -1
- data/spec/unit/{data_providers/hiera_interpolation_spec.rb → pops/lookup/interpolation_spec.rb} +7 -5
- data/spec/unit/pops/parser/lexer2_spec.rb +2 -9
- data/spec/unit/pops/parser/parse_application_spec.rb +3 -8
- data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +19 -0
- data/spec/unit/pops/parser/parse_capabilities_spec.rb +3 -10
- data/spec/unit/pops/parser/parse_site_spec.rb +19 -10
- data/spec/unit/pops/parser/parser_rspec_helper.rb +0 -4
- data/spec/unit/pops/types/enumeration_spec.rb +13 -12
- data/spec/unit/pops/types/iterable_spec.rb +2 -2
- data/spec/unit/pops/types/p_object_type_spec.rb +1060 -0
- data/spec/unit/pops/types/p_sem_ver_type_spec.rb +285 -0
- data/spec/unit/pops/types/recursion_guard_spec.rb +19 -17
- data/spec/unit/pops/types/ruby_generator_spec.rb +261 -0
- data/spec/unit/pops/types/string_converter_spec.rb +904 -0
- data/spec/unit/pops/types/type_calculator_spec.rb +430 -406
- data/spec/unit/pops/types/type_factory_spec.rb +119 -104
- data/spec/unit/pops/types/type_formatter_spec.rb +73 -6
- data/spec/unit/pops/types/type_mismatch_describer_spec.rb +2 -2
- data/spec/unit/pops/types/type_parser_spec.rb +54 -15
- data/spec/unit/pops/types/types_spec.rb +113 -8
- data/spec/unit/pops/validator/validator_spec.rb +84 -10
- data/spec/unit/provider/package/pip3_spec.rb +9 -270
- data/spec/unit/provider/package/pip_spec.rb +85 -30
- data/spec/unit/provider/package/rpm_spec.rb +160 -3
- data/spec/unit/provider/package/yum_spec.rb +23 -134
- data/spec/unit/provider/service/smf_spec.rb +14 -2
- data/spec/unit/provider/service/systemd_spec.rb +33 -41
- data/spec/unit/resource/capability_finder_spec.rb +10 -2
- data/spec/unit/settings/file_setting_spec.rb +6 -0
- data/spec/unit/transaction/additional_resource_generator_spec.rb +80 -65
- data/spec/unit/type/mount_spec.rb +51 -10
- data/spec/unit/type/service_spec.rb +16 -0
- data/spec/unit/type_spec.rb +14 -0
- data/spec/unit/util/feature_spec.rb +1 -1
- data/spec/unit/util/monkey_patches_spec.rb +60 -0
- data/spec/unit/util/network_device/cisco/device_spec.rb +1 -1
- metadata +63 -11
- data/lib/puppet/pops/types/types_meta.rb +0 -0
- data/spec/integration/provider/package_spec.rb +0 -35
@@ -256,7 +256,7 @@ describe 'The iterable support' do
|
|
256
256
|
end
|
257
257
|
|
258
258
|
it 'will produce the string Iterator[T] on to_s on an iterator instance with element type T' do
|
259
|
-
expect(Iterable.on(18).to_s).to eq('Iterator[Integer]
|
259
|
+
expect(Iterable.on(18).to_s).to eq('Iterator[Integer]-Value')
|
260
260
|
end
|
261
261
|
end
|
262
|
-
end
|
262
|
+
end
|
@@ -0,0 +1,1060 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'puppet/pops'
|
3
|
+
require 'puppet_spec/compiler'
|
4
|
+
|
5
|
+
module Puppet::Pops
|
6
|
+
module Types
|
7
|
+
describe 'The Object Type' do
|
8
|
+
include PuppetSpec::Compiler
|
9
|
+
|
10
|
+
let(:parser) { TypeParser.new }
|
11
|
+
let(:pp_parser) { Parser::EvaluatingParser.new }
|
12
|
+
let(:loader) { Loader::BaseLoader.new(nil, 'type_parser_unit_test_loader') }
|
13
|
+
let(:factory) { TypeFactory }
|
14
|
+
|
15
|
+
def type_object_t(name, body_string)
|
16
|
+
object = PObjectType.new(name, pp_parser.parse_string("{#{body_string}}").current.body)
|
17
|
+
loader.set_entry(Loader::Loader::TypedName.new(:type, name.downcase), object)
|
18
|
+
object
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_object(name, body_string)
|
22
|
+
type_object_t(name, body_string)
|
23
|
+
parser.parse(name, loader)
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when dealing with attributes' do
|
27
|
+
it 'raises an error when the attribute type is not a type' do
|
28
|
+
obj = <<-OBJECT
|
29
|
+
attributes => {
|
30
|
+
a => 23
|
31
|
+
}
|
32
|
+
OBJECT
|
33
|
+
expect { parse_object('MyObject', obj) }.to raise_error(TypeAssertionError,
|
34
|
+
/attribute MyObject\[a\] had wrong type, expected a Type value, got Integer/)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'raises an error if the type is missing' do
|
38
|
+
obj = <<-OBJECT
|
39
|
+
attributes => {
|
40
|
+
a => { kind => derived }
|
41
|
+
}
|
42
|
+
OBJECT
|
43
|
+
expect { parse_object('MyObject', obj) }.to raise_error(TypeAssertionError,
|
44
|
+
/expected a value for key 'type'/)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'raises an error when value is of incompatible type' do
|
48
|
+
obj = <<-OBJECT
|
49
|
+
attributes => {
|
50
|
+
a => { type => Integer, value => 'three' }
|
51
|
+
}
|
52
|
+
OBJECT
|
53
|
+
expect { parse_object('MyObject', obj) }.to raise_error(TypeAssertionError,
|
54
|
+
/attribute MyObject\[a\] value had wrong type, expected an Integer value, got String/)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'raises an error if the kind is invalid' do
|
58
|
+
obj = <<-OBJECT
|
59
|
+
attributes => {
|
60
|
+
a => { type => String, kind => derivd }
|
61
|
+
}
|
62
|
+
OBJECT
|
63
|
+
expect { parse_object('MyObject', obj) }.to raise_error(TypeAssertionError,
|
64
|
+
/expected a match for Enum\['constant', 'derived', 'given_or_derived'\], got 'derivd'/)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'stores value in attribute' do
|
68
|
+
tp = parse_object('MyObject', <<-OBJECT)
|
69
|
+
attributes => {
|
70
|
+
a => { type => Integer, value => 3 }
|
71
|
+
}
|
72
|
+
OBJECT
|
73
|
+
attr = tp['a']
|
74
|
+
expect(attr).to be_a(PObjectType::PAttribute)
|
75
|
+
expect(attr.value).to eql(3)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'attribute with defined value responds true to value?' do
|
79
|
+
tp = parse_object('MyObject', <<-OBJECT)
|
80
|
+
attributes => {
|
81
|
+
a => { type => Integer, value => 3 }
|
82
|
+
}
|
83
|
+
OBJECT
|
84
|
+
attr = tp['a']
|
85
|
+
expect(attr.value?).to be_truthy
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'attribute without defined value responds false to value?' do
|
89
|
+
tp = parse_object('MyObject', <<-OBJECT)
|
90
|
+
attributes => {
|
91
|
+
a => Integer
|
92
|
+
}
|
93
|
+
OBJECT
|
94
|
+
attr = tp['a']
|
95
|
+
expect(attr.value?).to be_falsey
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'raises an error when value is requested from an attribute that has no value' do
|
99
|
+
tp = parse_object('MyObject', <<-OBJECT)
|
100
|
+
attributes => {
|
101
|
+
a => Integer
|
102
|
+
}
|
103
|
+
OBJECT
|
104
|
+
expect { tp['a'].value }.to raise_error(Puppet::Error, 'attribute MyObject[a] has no value')
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'that are constants' do
|
108
|
+
it 'sets final => true' do
|
109
|
+
tp = parse_object('MyObject', <<-OBJECT)
|
110
|
+
attributes => {
|
111
|
+
a => {
|
112
|
+
type => Integer,
|
113
|
+
kind => constant,
|
114
|
+
value => 3
|
115
|
+
}
|
116
|
+
}
|
117
|
+
OBJECT
|
118
|
+
expect(tp['a'].final?).to be_truthy
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'raises an error when no value is declared' do
|
122
|
+
obj = <<-OBJECT
|
123
|
+
attributes => {
|
124
|
+
a => {
|
125
|
+
type => Integer,
|
126
|
+
kind => constant
|
127
|
+
}
|
128
|
+
}
|
129
|
+
OBJECT
|
130
|
+
expect { parse_object('MyObject', obj) }.to raise_error(Puppet::ParseError,
|
131
|
+
"attribute MyObject[a] of kind 'constant' requires a value")
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'raises an error when final => false' do
|
135
|
+
obj = <<-OBJECT
|
136
|
+
attributes => {
|
137
|
+
a => {
|
138
|
+
type => Integer,
|
139
|
+
kind => constant,
|
140
|
+
final => false
|
141
|
+
}
|
142
|
+
}
|
143
|
+
OBJECT
|
144
|
+
expect { parse_object('MyObject', obj) }.to raise_error(Puppet::ParseError,
|
145
|
+
"attribute MyObject[a] of kind 'constant' cannot be combined with final => false")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'when dealing with functions' do
|
151
|
+
it 'raises an error when the function type is a Type[Callable]' do
|
152
|
+
obj = <<-OBJECT
|
153
|
+
functions => {
|
154
|
+
a => String
|
155
|
+
}
|
156
|
+
OBJECT
|
157
|
+
expect { parse_object('MyObject', obj) }.to raise_error(TypeAssertionError,
|
158
|
+
/function MyObject\[a\] had wrong type, expected a Type\[Callable\] value, got Type\[String\]/)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'raises an error when a function has the same name as an attribute' do
|
162
|
+
obj = <<-OBJECT
|
163
|
+
attributes => {
|
164
|
+
a => Integer
|
165
|
+
},
|
166
|
+
functions => {
|
167
|
+
a => Callable
|
168
|
+
}
|
169
|
+
OBJECT
|
170
|
+
expect { parse_object('MyObject', obj) }.to raise_error(Puppet::ParseError,
|
171
|
+
'function MyObject[a] conflicts with attribute with the same name')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'when dealing with overrides' do
|
176
|
+
it 'can redefine inherited member to assignable type' do
|
177
|
+
parent = <<-OBJECT
|
178
|
+
attributes => {
|
179
|
+
a => Integer
|
180
|
+
}
|
181
|
+
OBJECT
|
182
|
+
obj = <<-OBJECT
|
183
|
+
parent => MyObject,
|
184
|
+
attributes => {
|
185
|
+
a => { type => Integer[0,10], override => true }
|
186
|
+
}
|
187
|
+
OBJECT
|
188
|
+
parse_object('MyObject', parent)
|
189
|
+
tp = parse_object('MyDerivedObject', obj)
|
190
|
+
expect(tp['a'].type).to eql(PIntegerType.new(0,10))
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'raises an error when an attribute overrides a function' do
|
194
|
+
parent = <<-OBJECT
|
195
|
+
attributes => {
|
196
|
+
a => Integer
|
197
|
+
}
|
198
|
+
OBJECT
|
199
|
+
obj = <<-OBJECT
|
200
|
+
parent => MyObject,
|
201
|
+
functions => {
|
202
|
+
a => { type => Callable, override => true }
|
203
|
+
}
|
204
|
+
OBJECT
|
205
|
+
parse_object('MyObject', parent)
|
206
|
+
expect { parse_object('MyDerivedObject', obj) }.to raise_error(Puppet::ParseError,
|
207
|
+
'function MyDerivedObject[a] attempts to override attribute MyObject[a]')
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'raises an error when the an function overrides an attribute' do
|
211
|
+
parent = <<-OBJECT
|
212
|
+
functions => {
|
213
|
+
a => Callable
|
214
|
+
}
|
215
|
+
OBJECT
|
216
|
+
obj = <<-OBJECT
|
217
|
+
parent => MyObject,
|
218
|
+
attributes => {
|
219
|
+
a => { type => Integer, override => true }
|
220
|
+
}
|
221
|
+
OBJECT
|
222
|
+
parse_object('MyObject', parent)
|
223
|
+
expect { parse_object('MyDerivedObject', obj) }.to raise_error(Puppet::ParseError,
|
224
|
+
'attribute MyDerivedObject[a] attempts to override function MyObject[a]')
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'raises an error on attempts to redefine inherited member to unassignable type' do
|
228
|
+
parent = <<-OBJECT
|
229
|
+
attributes => {
|
230
|
+
a => Integer
|
231
|
+
}
|
232
|
+
OBJECT
|
233
|
+
obj = <<-OBJECT
|
234
|
+
parent => MyObject,
|
235
|
+
attributes => {
|
236
|
+
a => { type => String, override => true }
|
237
|
+
}
|
238
|
+
OBJECT
|
239
|
+
parse_object('MyObject', parent)
|
240
|
+
expect { parse_object('MyDerivedObject', obj) }.to raise_error(Puppet::ParseError,
|
241
|
+
'attribute MyDerivedObject[a] attempts to override attribute MyObject[a] with a type that does not match')
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'raises an error when an attribute overrides a final attribute' do
|
245
|
+
parent = <<-OBJECT
|
246
|
+
attributes => {
|
247
|
+
a => { type => Integer, final => true }
|
248
|
+
}
|
249
|
+
OBJECT
|
250
|
+
obj = <<-OBJECT
|
251
|
+
parent => MyObject,
|
252
|
+
attributes => {
|
253
|
+
a => { type => Integer, override => true }
|
254
|
+
}
|
255
|
+
OBJECT
|
256
|
+
parse_object('MyObject', parent)
|
257
|
+
expect { parse_object('MyDerivedObject', obj) }.to raise_error(Puppet::ParseError,
|
258
|
+
'attribute MyDerivedObject[a] attempts to override final attribute MyObject[a]')
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'raises an error when an overriding attribute is not declared with override => true' do
|
262
|
+
parent = <<-OBJECT
|
263
|
+
attributes => {
|
264
|
+
a => Integer
|
265
|
+
}
|
266
|
+
OBJECT
|
267
|
+
obj = <<-OBJECT
|
268
|
+
parent => MyObject,
|
269
|
+
attributes => {
|
270
|
+
a => Integer
|
271
|
+
}
|
272
|
+
OBJECT
|
273
|
+
parse_object('MyObject', parent)
|
274
|
+
expect { parse_object('MyDerivedObject', obj) }.to raise_error(Puppet::ParseError,
|
275
|
+
'attribute MyDerivedObject[a] attempts to override attribute MyObject[a] without having override => true')
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'raises an error when an attribute declared with override => true does not override' do
|
279
|
+
parent = <<-OBJECT
|
280
|
+
attributes => {
|
281
|
+
a => Integer
|
282
|
+
}
|
283
|
+
OBJECT
|
284
|
+
obj = <<-OBJECT
|
285
|
+
parent => MyObject,
|
286
|
+
attributes => {
|
287
|
+
b => { type => Integer, override => true }
|
288
|
+
}
|
289
|
+
OBJECT
|
290
|
+
parse_object('MyObject', parent)
|
291
|
+
expect { parse_object('MyDerivedObject', obj) }.to raise_error(Puppet::ParseError,
|
292
|
+
"expected attribute MyDerivedObject[b] to override an inherited attribute, but no such attribute was found")
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'when dealing with equality' do
|
297
|
+
it 'the attributes can be declared as an array of names' do
|
298
|
+
obj = <<-OBJECT
|
299
|
+
attributes => {
|
300
|
+
a => Integer,
|
301
|
+
b => Integer
|
302
|
+
},
|
303
|
+
equality => [a,b]
|
304
|
+
OBJECT
|
305
|
+
tp = parse_object('MyObject', obj)
|
306
|
+
expect(tp.equality).to eq(['a','b'])
|
307
|
+
expect(tp.equality_attributes.keys).to eq(['a','b'])
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'a single [<name>] can be declared as <name>' do
|
311
|
+
obj = <<-OBJECT
|
312
|
+
attributes => {
|
313
|
+
a => Integer,
|
314
|
+
b => Integer
|
315
|
+
},
|
316
|
+
equality => a
|
317
|
+
OBJECT
|
318
|
+
tp = parse_object('MyObject', obj)
|
319
|
+
expect(tp.equality).to eq(['a'])
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'includes all non-constant attributes by default' do
|
323
|
+
obj = <<-OBJECT
|
324
|
+
attributes => {
|
325
|
+
a => Integer,
|
326
|
+
b => { type => Integer, kind => constant, value => 3 },
|
327
|
+
c => Integer
|
328
|
+
}
|
329
|
+
OBJECT
|
330
|
+
tp = parse_object('MyObject', obj)
|
331
|
+
expect(tp.equality).to be_nil
|
332
|
+
expect(tp.equality_attributes.keys).to eq(['a','c'])
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'equality_include_type is true by default' do
|
336
|
+
obj = <<-OBJECT
|
337
|
+
attributes => {
|
338
|
+
a => Integer
|
339
|
+
},
|
340
|
+
equality => a
|
341
|
+
OBJECT
|
342
|
+
expect(parse_object('MyObject', obj).equality_include_type?).to be_truthy
|
343
|
+
end
|
344
|
+
|
345
|
+
it 'will allow an empty list of attributes' do
|
346
|
+
obj = <<-OBJECT
|
347
|
+
attributes => {
|
348
|
+
a => Integer,
|
349
|
+
b => Integer
|
350
|
+
},
|
351
|
+
equality => []
|
352
|
+
OBJECT
|
353
|
+
tp = parse_object('MyObject', obj)
|
354
|
+
expect(tp.equality).to be_empty
|
355
|
+
expect(tp.equality_attributes).to be_empty
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'will extend default equality in parent' do
|
359
|
+
parent = <<-OBJECT
|
360
|
+
attributes => {
|
361
|
+
a => Integer,
|
362
|
+
b => Integer
|
363
|
+
}
|
364
|
+
OBJECT
|
365
|
+
obj = <<-OBJECT
|
366
|
+
parent => MyObject,
|
367
|
+
attributes => {
|
368
|
+
c => Integer,
|
369
|
+
d => Integer
|
370
|
+
}
|
371
|
+
OBJECT
|
372
|
+
parse_object('MyObject', parent)
|
373
|
+
tp = parse_object('MyDerivedObject', obj)
|
374
|
+
expect(tp.equality).to be_nil
|
375
|
+
expect(tp.equality_attributes.keys).to eq(['a','b','c','d'])
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'extends equality declared in parent' do
|
379
|
+
parent = <<-OBJECT
|
380
|
+
attributes => {
|
381
|
+
a => Integer,
|
382
|
+
b => Integer
|
383
|
+
},
|
384
|
+
equality => a
|
385
|
+
OBJECT
|
386
|
+
obj = <<-OBJECT
|
387
|
+
parent => MyObject,
|
388
|
+
attributes => {
|
389
|
+
c => Integer,
|
390
|
+
d => Integer
|
391
|
+
}
|
392
|
+
OBJECT
|
393
|
+
parse_object('MyObject', parent)
|
394
|
+
tp = parse_object('MyDerivedObject', obj)
|
395
|
+
expect(tp.equality).to be_nil
|
396
|
+
expect(tp.equality_attributes.keys).to eq(['a','c','d'])
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'parent defined attributes can be included in equality if not already included by a parent' do
|
400
|
+
parent = <<-OBJECT
|
401
|
+
attributes => {
|
402
|
+
a => Integer,
|
403
|
+
b => Integer
|
404
|
+
},
|
405
|
+
equality => a
|
406
|
+
OBJECT
|
407
|
+
obj = <<-OBJECT
|
408
|
+
parent => MyObject,
|
409
|
+
attributes => {
|
410
|
+
c => Integer,
|
411
|
+
d => Integer
|
412
|
+
},
|
413
|
+
equality => [b,c]
|
414
|
+
OBJECT
|
415
|
+
parse_object('MyObject', parent)
|
416
|
+
tp = parse_object('MyDerivedObject', obj)
|
417
|
+
expect(tp.equality).to eq(['b','c'])
|
418
|
+
expect(tp.equality_attributes.keys).to eq(['a','b','c'])
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'raises an error when attempting to extend default equality in parent' do
|
422
|
+
parent = <<-OBJECT
|
423
|
+
attributes => {
|
424
|
+
a => Integer,
|
425
|
+
b => Integer
|
426
|
+
}
|
427
|
+
OBJECT
|
428
|
+
obj = <<-OBJECT
|
429
|
+
parent => MyObject,
|
430
|
+
attributes => {
|
431
|
+
c => Integer,
|
432
|
+
d => Integer
|
433
|
+
},
|
434
|
+
equality => a
|
435
|
+
OBJECT
|
436
|
+
parse_object('MyObject', parent)
|
437
|
+
expect { parse_object('MyDerivedObject', obj) }.to raise_error(Puppet::ParseError,
|
438
|
+
"MyDerivedObject equality is referencing attribute MyObject[a] which is included in equality of MyObject")
|
439
|
+
end
|
440
|
+
|
441
|
+
it 'raises an error when equality references a constant attribute' do
|
442
|
+
obj = <<-OBJECT
|
443
|
+
attributes => {
|
444
|
+
a => Integer,
|
445
|
+
b => { type => Integer, kind => constant, value => 3 }
|
446
|
+
},
|
447
|
+
equality => [a,b]
|
448
|
+
OBJECT
|
449
|
+
expect { parse_object('MyObject', obj) }.to raise_error(Puppet::ParseError,
|
450
|
+
'MyObject equality is referencing constant attribute MyObject[b]. Reference to constant is not allowed in equality')
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'raises an error when equality references a function' do
|
454
|
+
obj = <<-OBJECT
|
455
|
+
attributes => {
|
456
|
+
a => Integer,
|
457
|
+
},
|
458
|
+
functions => {
|
459
|
+
b => Callable
|
460
|
+
},
|
461
|
+
equality => [a,b]
|
462
|
+
OBJECT
|
463
|
+
expect { parse_object('MyObject', obj) }.to raise_error(Puppet::ParseError,
|
464
|
+
'MyObject equality is referencing function MyObject[b]. Only attribute references are allowed')
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'raises an error when equality references a non existent attributes' do
|
468
|
+
obj = <<-OBJECT
|
469
|
+
attributes => {
|
470
|
+
a => Integer
|
471
|
+
},
|
472
|
+
equality => [a,b]
|
473
|
+
OBJECT
|
474
|
+
expect { parse_object('MyObject', obj) }.to raise_error(Puppet::ParseError,
|
475
|
+
"MyObject equality is referencing non existent attribute 'b'")
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'raises an error when equality_include_type = false and attributes are provided' do
|
479
|
+
obj = <<-OBJECT
|
480
|
+
attributes => {
|
481
|
+
a => Integer
|
482
|
+
},
|
483
|
+
equality => a,
|
484
|
+
equality_include_type => false
|
485
|
+
OBJECT
|
486
|
+
expect { parse_object('MyObject', obj) }.to raise_error(Puppet::ParseError,
|
487
|
+
'equality_include_type = false cannot be combined with non empty equality specification')
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
it 'raises an error when initialization hash contains invalid keys' do
|
492
|
+
obj = <<-OBJECT
|
493
|
+
attribrutes => {
|
494
|
+
a => Integer
|
495
|
+
}
|
496
|
+
OBJECT
|
497
|
+
expect { parse_object('MyObject', obj) }.to raise_error(TypeAssertionError, /object initializer had wrong type, unrecognized key 'attribrutes'/)
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'raises an error when attribute contains invalid keys' do
|
501
|
+
obj = <<-OBJECT
|
502
|
+
attributes => {
|
503
|
+
a => { type => Integer, knid => constant }
|
504
|
+
}
|
505
|
+
OBJECT
|
506
|
+
expect { parse_object('MyObject', obj) }.to raise_error(TypeAssertionError, /initializer for attribute MyObject\[a\] had wrong type, unrecognized key 'knid'/)
|
507
|
+
end
|
508
|
+
|
509
|
+
context 'when inheriting from a another Object type' do
|
510
|
+
let(:parent) { <<-OBJECT }
|
511
|
+
attributes => {
|
512
|
+
a => Integer
|
513
|
+
},
|
514
|
+
functions => {
|
515
|
+
b => Callable
|
516
|
+
}
|
517
|
+
OBJECT
|
518
|
+
|
519
|
+
let(:derived) { <<-OBJECT }
|
520
|
+
parent => MyObject,
|
521
|
+
attributes => {
|
522
|
+
c => String,
|
523
|
+
d => Boolean
|
524
|
+
}
|
525
|
+
OBJECT
|
526
|
+
|
527
|
+
it 'includes the inherited type and its members' do
|
528
|
+
parse_object('MyObject', parent)
|
529
|
+
t = parse_object('MyDerivedObject', derived)
|
530
|
+
members = t.members.values
|
531
|
+
expect{ |b| members.each {|m| m.name.tap(&b) }}.to yield_successive_args('c', 'd')
|
532
|
+
expect{ |b| members.each {|m| m.type.simple_name.tap(&b) }}.to yield_successive_args('String', 'Boolean')
|
533
|
+
members = t.members(true).values
|
534
|
+
expect{ |b| members.each {|m| m.name.tap(&b) }}.to yield_successive_args('a', 'b', 'c', 'd')
|
535
|
+
expect{ |b| members.each {|m| m.type.simple_name.tap(&b) }}.to(yield_successive_args('Integer', 'Callable', 'String', 'Boolean'))
|
536
|
+
end
|
537
|
+
|
538
|
+
it 'is assignable to its inherited type' do
|
539
|
+
p = parse_object('MyObject', parent)
|
540
|
+
t = parse_object('MyDerivedObject', derived)
|
541
|
+
expect(p).to be_assignable(t)
|
542
|
+
end
|
543
|
+
|
544
|
+
it 'does not consider inherited type to be assignable' do
|
545
|
+
p = parse_object('MyObject', parent)
|
546
|
+
d = parse_object('MyDerivedObject', derived)
|
547
|
+
expect(d).not_to be_assignable(p)
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'ruby access operator can retrieve parent member' do
|
551
|
+
p = parse_object('MyObject', parent)
|
552
|
+
d = parse_object('MyDerivedObject', derived)
|
553
|
+
expect(d['b'].container).to equal(p)
|
554
|
+
end
|
555
|
+
|
556
|
+
context 'that in turn inherits another Object type' do
|
557
|
+
let(:derived2) { <<-OBJECT }
|
558
|
+
parent => MyDerivedObject,
|
559
|
+
attributes => {
|
560
|
+
e => String,
|
561
|
+
f => Boolean
|
562
|
+
}
|
563
|
+
OBJECT
|
564
|
+
|
565
|
+
it 'is assignable to all inherited types' do
|
566
|
+
p = parse_object('MyObject', parent)
|
567
|
+
d1 = parse_object('MyDerivedObject', derived)
|
568
|
+
d2 = parse_object('MyDerivedObject2', derived2)
|
569
|
+
expect(p).to be_assignable(d2)
|
570
|
+
expect(d1).to be_assignable(d2)
|
571
|
+
end
|
572
|
+
|
573
|
+
it 'does not consider any of the inherited types to be assignable' do
|
574
|
+
p = parse_object('MyObject', parent)
|
575
|
+
d1 = parse_object('MyDerivedObject', derived)
|
576
|
+
d2 = parse_object('MyDerivedObject2', derived2)
|
577
|
+
expect(d2).not_to be_assignable(p)
|
578
|
+
expect(d2).not_to be_assignable(d1)
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
context 'when producing an i12n_type' do
|
584
|
+
it 'produces a struct of all attributes that are not derived or constant' do
|
585
|
+
t = parse_object('MyObject', <<-OBJECT)
|
586
|
+
attributes => {
|
587
|
+
a => { type => Integer },
|
588
|
+
b => { type => Integer, kind => given_or_derived },
|
589
|
+
c => { type => Integer, kind => derived },
|
590
|
+
d => { type => Integer, kind => constant, value => 4 }
|
591
|
+
}
|
592
|
+
OBJECT
|
593
|
+
expect(t.i12n_type).to eql(factory.struct({
|
594
|
+
'a' => factory.integer,
|
595
|
+
'b' => factory.integer
|
596
|
+
}))
|
597
|
+
end
|
598
|
+
|
599
|
+
it 'produces a struct where optional entires are denoted with an optional key' do
|
600
|
+
t = parse_object('MyObject', <<-OBJECT)
|
601
|
+
attributes => {
|
602
|
+
a => { type => Integer },
|
603
|
+
b => { type => Integer, value => 4 }
|
604
|
+
}
|
605
|
+
OBJECT
|
606
|
+
expect(t.i12n_type).to eql(factory.struct({
|
607
|
+
'a' => factory.integer,
|
608
|
+
factory.optional('b') => factory.integer
|
609
|
+
}))
|
610
|
+
end
|
611
|
+
|
612
|
+
it 'produces a struct that includes parameters from parent type' do
|
613
|
+
t1 = parse_object('MyObject', <<-OBJECT)
|
614
|
+
attributes => {
|
615
|
+
a => { type => Integer }
|
616
|
+
}
|
617
|
+
OBJECT
|
618
|
+
t2 = parse_object('MyDerivedObject', <<-OBJECT)
|
619
|
+
parent => MyObject,
|
620
|
+
attributes => {
|
621
|
+
b => { type => Integer }
|
622
|
+
}
|
623
|
+
OBJECT
|
624
|
+
expect(t1.i12n_type).to eql(factory.struct({ 'a' => factory.integer }))
|
625
|
+
expect(t2.i12n_type).to eql(factory.struct({ 'a' => factory.integer, 'b' => factory.integer }))
|
626
|
+
end
|
627
|
+
|
628
|
+
it 'produces a struct that reflects overrides made in derived type' do
|
629
|
+
t1 = parse_object('MyObject', <<-OBJECT)
|
630
|
+
attributes => {
|
631
|
+
a => { type => Integer },
|
632
|
+
b => { type => Integer }
|
633
|
+
}
|
634
|
+
OBJECT
|
635
|
+
t2 = parse_object('MyDerivedObject', <<-OBJECT)
|
636
|
+
parent => MyObject,
|
637
|
+
attributes => {
|
638
|
+
b => { type => Integer, override => true, value => 5 }
|
639
|
+
}
|
640
|
+
OBJECT
|
641
|
+
expect(t1.i12n_type).to eql(factory.struct({ 'a' => factory.integer, 'b' => factory.integer }))
|
642
|
+
expect(t2.i12n_type).to eql(factory.struct({ 'a' => factory.integer, factory.optional('b') => factory.integer }))
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
context 'with attributes and parameters of its own type' do
|
647
|
+
it 'resolves an attribute type' do
|
648
|
+
t = parse_object('MyObject', <<-OBJECT)
|
649
|
+
attributes => {
|
650
|
+
a => MyObject
|
651
|
+
}
|
652
|
+
OBJECT
|
653
|
+
expect(t['a'].type).to equal(t)
|
654
|
+
end
|
655
|
+
|
656
|
+
it 'resolves a parameter type' do
|
657
|
+
t = parse_object('MyObject', <<-OBJECT)
|
658
|
+
functions => {
|
659
|
+
a => Callable[MyObject]
|
660
|
+
}
|
661
|
+
OBJECT
|
662
|
+
expect(t['a'].type).to eql(PCallableType.new(PTupleType.new([t])))
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
context 'when using the initialization hash' do
|
667
|
+
it 'produced hash that contains features using short form (type instead of detailed hash when only type is declared)' do
|
668
|
+
obj = t = parse_object('MyObject', <<-OBJECT)
|
669
|
+
attributes => {
|
670
|
+
a => { type => Integer }
|
671
|
+
}
|
672
|
+
OBJECT
|
673
|
+
expect(obj.to_s).to eql("Object[{name => 'MyObject', attributes => {'a' => Integer}}]")
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'produced hash that does not include defaults' do
|
677
|
+
obj = t = parse_object('MyObject', <<-OBJECT)
|
678
|
+
attributes => {
|
679
|
+
a => { type => Integer, value => 23, kind => constant, final => true },
|
680
|
+
},
|
681
|
+
equality_include_type => true
|
682
|
+
OBJECT
|
683
|
+
expect(obj.to_s).to eql("Object[{name => 'MyObject', attributes => {'a' => {type => Integer, kind => constant, value => 23}}}]")
|
684
|
+
end
|
685
|
+
|
686
|
+
it 'can create an equal copy from produced hash' do
|
687
|
+
obj = t = parse_object('MyObject', <<-OBJECT)
|
688
|
+
attributes => {
|
689
|
+
a => { type => Struct[{x => Integer, y => Integer}], value => {x => 4, y => 9}, kind => constant },
|
690
|
+
b => Integer
|
691
|
+
},
|
692
|
+
functions => {
|
693
|
+
x => Callable[MyObject,Integer]
|
694
|
+
},
|
695
|
+
equality => [b]
|
696
|
+
OBJECT
|
697
|
+
obj2 = PObjectType.new(obj.i12n_hash)
|
698
|
+
expect(obj).to eql(obj2)
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
context 'when used in Puppet expressions' do
|
703
|
+
it 'two anonymous empty objects are equal' do
|
704
|
+
code = <<-CODE
|
705
|
+
$x = Object[{}]
|
706
|
+
$y = Object[{}]
|
707
|
+
notice($x == $y)
|
708
|
+
CODE
|
709
|
+
expect(eval_and_collect_notices(code)).to eql(['true'])
|
710
|
+
end
|
711
|
+
|
712
|
+
it 'two objects where one object inherits another object are different' do
|
713
|
+
code = <<-CODE
|
714
|
+
type MyFirstObject = Object[{}]
|
715
|
+
type MySecondObject = Object[{ parent => MyFirstObject }]
|
716
|
+
notice(MyFirstObject == MySecondObject)
|
717
|
+
CODE
|
718
|
+
expect(eval_and_collect_notices(code)).to eql(['false'])
|
719
|
+
end
|
720
|
+
|
721
|
+
it 'two anonymous objects that inherits the same parent are equal' do
|
722
|
+
code = <<-CODE
|
723
|
+
type MyFirstObject = Object[{}]
|
724
|
+
$x = Object[{ parent => MyFirstObject }]
|
725
|
+
$y = Object[{ parent => MyFirstObject }]
|
726
|
+
notice($x == $y)
|
727
|
+
CODE
|
728
|
+
expect(eval_and_collect_notices(code)).to eql(['true'])
|
729
|
+
end
|
730
|
+
|
731
|
+
it 'an object type is an instance of an object type type' do
|
732
|
+
code = <<-CODE
|
733
|
+
type MyObject = Object[{ attributes => { a => Integer }}]
|
734
|
+
notice(MyObject =~ Type[MyObject])
|
735
|
+
CODE
|
736
|
+
expect(eval_and_collect_notices(code)).to eql(['true'])
|
737
|
+
end
|
738
|
+
|
739
|
+
it 'an object that inherits another object is an instance of the type of its parent' do
|
740
|
+
code = <<-CODE
|
741
|
+
type MyFirstObject = Object[{}]
|
742
|
+
type MySecondObject = Object[{ parent => MyFirstObject }]
|
743
|
+
notice(MySecondObject =~ Type[MyFirstObject])
|
744
|
+
CODE
|
745
|
+
expect(eval_and_collect_notices(code)).to eql(['true'])
|
746
|
+
end
|
747
|
+
|
748
|
+
it 'a named object is not added to the loader unless a type <name> = <definition> is made' do
|
749
|
+
code = <<-CODE
|
750
|
+
$x = Object[{ name => 'MyFirstObject' }]
|
751
|
+
notice($x == MyFirstObject)
|
752
|
+
CODE
|
753
|
+
expect { eval_and_collect_notices(code) }.to raise_error(Puppet::Error, /Resource type not found: MyFirstObject/)
|
754
|
+
end
|
755
|
+
|
756
|
+
it 'a type alias on a named object overrides the name' do
|
757
|
+
code = <<-CODE
|
758
|
+
type MyObject = Object[{ name => 'MyFirstObject', attributes => { a => { type => Integer, final => true }}}]
|
759
|
+
type MySecondObject = Object[{ parent => MyObject, attributes => { a => { type => Integer[10], override => true }}}]
|
760
|
+
notice(MySecondObject =~ Type)
|
761
|
+
CODE
|
762
|
+
expect { eval_and_collect_notices(code) }.to raise_error(Puppet::Error,
|
763
|
+
/attribute MySecondObject\[a\] attempts to override final attribute MyObject\[a\]/)
|
764
|
+
end
|
765
|
+
|
766
|
+
it 'raises an error when object when circular inheritance is detected' do
|
767
|
+
code = <<-CODE
|
768
|
+
type MyFirstObject = Object[{
|
769
|
+
parent => MySecondObject
|
770
|
+
}]
|
771
|
+
type MySecondObject = Object[{
|
772
|
+
parent => MyFirstObject
|
773
|
+
}]
|
774
|
+
notice(MySecondObject =~ Type[MyFirstObject])
|
775
|
+
CODE
|
776
|
+
expect { eval_and_collect_notices(code) }.to raise_error(Puppet::Error, /inherits from itself/)
|
777
|
+
end
|
778
|
+
|
779
|
+
it 'notices the expanded string form expected content' do
|
780
|
+
code = <<-CODE
|
781
|
+
type MyFirstObject = Object[{
|
782
|
+
attributes => {
|
783
|
+
first_a => Integer,
|
784
|
+
first_b => { type => String, kind => constant, value => 'the first constant' },
|
785
|
+
first_c => { type => String, final => true, kind => derived },
|
786
|
+
first_d => { type => String, kind => given_or_derived },
|
787
|
+
first_e => { type => String }
|
788
|
+
},
|
789
|
+
functions => {
|
790
|
+
first_x => Callable[Integer],
|
791
|
+
first_y => Callable[String]
|
792
|
+
},
|
793
|
+
equality => first_a
|
794
|
+
}]
|
795
|
+
type MySecondObject = Object[{
|
796
|
+
parent => MyFirstObject,
|
797
|
+
attributes => {
|
798
|
+
second_a => Integer,
|
799
|
+
second_b => { type => String, kind => constant, value => 'the second constant' },
|
800
|
+
first_e => { type => Enum[foo,fee,fum], final => true, override => true, value => 'fee' }
|
801
|
+
},
|
802
|
+
functions => {
|
803
|
+
second_x => Callable[Integer],
|
804
|
+
second_y => Callable[String]
|
805
|
+
},
|
806
|
+
equality => second_a
|
807
|
+
}]
|
808
|
+
notice(MyFirstObject)
|
809
|
+
notice(MySecondObject)
|
810
|
+
CODE
|
811
|
+
expect(eval_and_collect_notices(code)).to eql([
|
812
|
+
"Object[{"+
|
813
|
+
"name => 'MyFirstObject', "+
|
814
|
+
"attributes => {"+
|
815
|
+
"'first_a' => Integer, "+
|
816
|
+
"'first_b' => {type => String, kind => constant, value => 'the first constant'}, "+
|
817
|
+
"'first_c' => {type => String, final => true, kind => derived}, "+
|
818
|
+
"'first_d' => {type => String, kind => given_or_derived}, "+
|
819
|
+
"'first_e' => String"+
|
820
|
+
"}, "+
|
821
|
+
"functions => {"+
|
822
|
+
"'first_x' => Callable[Integer], "+
|
823
|
+
"'first_y' => Callable[String]"+
|
824
|
+
"}, "+
|
825
|
+
"equality => ['first_a']"+
|
826
|
+
"}]",
|
827
|
+
"Object[{"+
|
828
|
+
"name => 'MySecondObject', "+
|
829
|
+
"parent => MyFirstObject, "+
|
830
|
+
"attributes => {"+
|
831
|
+
"'second_a' => Integer, "+
|
832
|
+
"'second_b' => {type => String, kind => constant, value => 'the second constant'}, "+
|
833
|
+
"'first_e' => {type => Enum['fee', 'foo', 'fum'], final => true, override => true, value => 'fee'}"+
|
834
|
+
"}, "+
|
835
|
+
"functions => {"+
|
836
|
+
"'second_x' => Callable[Integer], "+
|
837
|
+
"'second_y' => Callable[String]"+
|
838
|
+
"}, "+
|
839
|
+
"equality => ['second_a']"+
|
840
|
+
"}]"
|
841
|
+
])
|
842
|
+
end
|
843
|
+
end
|
844
|
+
|
845
|
+
context "when used with function 'new'" do
|
846
|
+
context 'with ordered parameters' do
|
847
|
+
it 'creates an instance with initialized attributes' do
|
848
|
+
code = <<-CODE
|
849
|
+
type MyFirstObject = Object[{
|
850
|
+
attributes => {
|
851
|
+
a => Integer,
|
852
|
+
b => String
|
853
|
+
}
|
854
|
+
}]
|
855
|
+
$obj = MyFirstObject.new(3, 'hi')
|
856
|
+
notice($obj.a)
|
857
|
+
notice($obj.b)
|
858
|
+
CODE
|
859
|
+
expect(eval_and_collect_notices(code)).to eql(['3', 'hi'])
|
860
|
+
end
|
861
|
+
|
862
|
+
it 'creates an instance with default attribute values' do
|
863
|
+
code = <<-CODE
|
864
|
+
type MyFirstObject = Object[{
|
865
|
+
attributes => {
|
866
|
+
a => { type => String, value => 'the default' }
|
867
|
+
}
|
868
|
+
}]
|
869
|
+
$obj = MyFirstObject.new
|
870
|
+
notice($obj.a)
|
871
|
+
CODE
|
872
|
+
expect(eval_and_collect_notices(code)).to eql(['the default'])
|
873
|
+
end
|
874
|
+
|
875
|
+
it 'creates an instance with constant attributes' do
|
876
|
+
code = <<-CODE
|
877
|
+
type MyFirstObject = Object[{
|
878
|
+
attributes => {
|
879
|
+
a => { type => String, kind => constant, value => 'the constant' }
|
880
|
+
}
|
881
|
+
}]
|
882
|
+
$obj = MyFirstObject.new
|
883
|
+
notice($obj.a)
|
884
|
+
CODE
|
885
|
+
expect(eval_and_collect_notices(code)).to eql(['the constant'])
|
886
|
+
end
|
887
|
+
|
888
|
+
it 'creates an instance with overridden attribute defaults' do
|
889
|
+
code = <<-CODE
|
890
|
+
type MyFirstObject = Object[{
|
891
|
+
attributes => {
|
892
|
+
a => { type => String, value => 'the default' }
|
893
|
+
}
|
894
|
+
}]
|
895
|
+
$obj = MyFirstObject.new('not default')
|
896
|
+
notice($obj.a)
|
897
|
+
CODE
|
898
|
+
expect(eval_and_collect_notices(code)).to eql(['not default'])
|
899
|
+
end
|
900
|
+
|
901
|
+
it 'fails on an attempt to provide a constant attribute value' do
|
902
|
+
code = <<-CODE
|
903
|
+
type MyFirstObject = Object[{
|
904
|
+
attributes => {
|
905
|
+
a => { type => String, kind => constant, value => 'the constant' }
|
906
|
+
}
|
907
|
+
}]
|
908
|
+
$obj = MyFirstObject.new('not constant')
|
909
|
+
notice($obj.a)
|
910
|
+
CODE
|
911
|
+
expect { eval_and_collect_notices(code) }.to raise_error(Puppet::Error, /expects no arguments/)
|
912
|
+
end
|
913
|
+
|
914
|
+
it 'fails when a required key is missing' do
|
915
|
+
code = <<-CODE
|
916
|
+
type MyFirstObject = Object[{
|
917
|
+
attributes => {
|
918
|
+
a => String
|
919
|
+
}
|
920
|
+
}]
|
921
|
+
$obj = MyFirstObject.new
|
922
|
+
notice($obj.a)
|
923
|
+
CODE
|
924
|
+
expect { eval_and_collect_notices(code) }.to raise_error(Puppet::Error, /expects 1 argument, got none/)
|
925
|
+
end
|
926
|
+
|
927
|
+
it 'creates a derived instance with initialized attributes' do
|
928
|
+
code = <<-CODE
|
929
|
+
type MyFirstObject = Object[{
|
930
|
+
attributes => {
|
931
|
+
a => Integer,
|
932
|
+
b => { type => String, kind => constant, value => 'the first constant' },
|
933
|
+
c => String
|
934
|
+
}
|
935
|
+
}]
|
936
|
+
type MySecondObject = Object[{
|
937
|
+
parent => MyFirstObject,
|
938
|
+
attributes => {
|
939
|
+
d => { type => Integer, value => 34 }
|
940
|
+
}
|
941
|
+
}]
|
942
|
+
$obj = MySecondObject.new(3, 'hi')
|
943
|
+
notice($obj.a)
|
944
|
+
notice($obj.b)
|
945
|
+
notice($obj.c)
|
946
|
+
notice($obj.d)
|
947
|
+
CODE
|
948
|
+
expect(eval_and_collect_notices(code)).to eql(['3', 'the first constant', 'hi', '34'])
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
context 'with named parameters' do
|
953
|
+
it 'creates an instance with initialized attributes' do
|
954
|
+
code = <<-CODE
|
955
|
+
type MyFirstObject = Object[{
|
956
|
+
attributes => {
|
957
|
+
a => Integer,
|
958
|
+
b => String
|
959
|
+
}
|
960
|
+
}]
|
961
|
+
$obj = MyFirstObject.new({b => 'hi', a => 3})
|
962
|
+
notice($obj.a)
|
963
|
+
notice($obj.b)
|
964
|
+
CODE
|
965
|
+
expect(eval_and_collect_notices(code)).to eql(['3', 'hi'])
|
966
|
+
end
|
967
|
+
|
968
|
+
it 'creates an instance with default attribute values' do
|
969
|
+
code = <<-CODE
|
970
|
+
type MyFirstObject = Object[{
|
971
|
+
attributes => {
|
972
|
+
a => { type => String, value => 'the default' }
|
973
|
+
}
|
974
|
+
}]
|
975
|
+
$obj = MyFirstObject.new({})
|
976
|
+
notice($obj.a)
|
977
|
+
CODE
|
978
|
+
expect(eval_and_collect_notices(code)).to eql(['the default'])
|
979
|
+
end
|
980
|
+
|
981
|
+
it 'creates an instance with constant attributes' do
|
982
|
+
code = <<-CODE
|
983
|
+
type MyFirstObject = Object[{
|
984
|
+
attributes => {
|
985
|
+
a => { type => String, kind => constant, value => 'the constant' }
|
986
|
+
}
|
987
|
+
}]
|
988
|
+
$obj = MyFirstObject.new({})
|
989
|
+
notice($obj.a)
|
990
|
+
CODE
|
991
|
+
expect(eval_and_collect_notices(code)).to eql(['the constant'])
|
992
|
+
end
|
993
|
+
|
994
|
+
it 'creates an instance with overridden attribute defaults' do
|
995
|
+
code = <<-CODE
|
996
|
+
type MyFirstObject = Object[{
|
997
|
+
attributes => {
|
998
|
+
a => { type => String, value => 'the default' }
|
999
|
+
}
|
1000
|
+
}]
|
1001
|
+
$obj = MyFirstObject.new({a => 'not default'})
|
1002
|
+
notice($obj.a)
|
1003
|
+
CODE
|
1004
|
+
expect(eval_and_collect_notices(code)).to eql(['not default'])
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
it 'fails on an attempt to provide a constant attribute value' do
|
1008
|
+
code = <<-CODE
|
1009
|
+
type MyFirstObject = Object[{
|
1010
|
+
attributes => {
|
1011
|
+
a => { type => String, kind => constant, value => 'the constant' }
|
1012
|
+
}
|
1013
|
+
}]
|
1014
|
+
$obj = MyFirstObject.new({a => 'not constant'})
|
1015
|
+
notice($obj.a)
|
1016
|
+
CODE
|
1017
|
+
expect { eval_and_collect_notices(code) }.to raise_error(Puppet::Error, /unrecognized key 'a'/)
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
it 'fails when a required key is missing' do
|
1021
|
+
code = <<-CODE
|
1022
|
+
type MyFirstObject = Object[{
|
1023
|
+
attributes => {
|
1024
|
+
a => String
|
1025
|
+
}
|
1026
|
+
}]
|
1027
|
+
$obj = MyFirstObject.new({})
|
1028
|
+
notice($obj.a)
|
1029
|
+
CODE
|
1030
|
+
expect { eval_and_collect_notices(code) }.to raise_error(Puppet::Error, /expects size to be 1, got 0/)
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
it 'creates a derived instance with initialized attributes' do
|
1034
|
+
code = <<-CODE
|
1035
|
+
type MyFirstObject = Object[{
|
1036
|
+
attributes => {
|
1037
|
+
a => Integer,
|
1038
|
+
b => { type => String, kind => constant, value => 'the first constant' },
|
1039
|
+
c => String
|
1040
|
+
}
|
1041
|
+
}]
|
1042
|
+
type MySecondObject = Object[{
|
1043
|
+
parent => MyFirstObject,
|
1044
|
+
attributes => {
|
1045
|
+
d => { type => Integer, value => 34 }
|
1046
|
+
}
|
1047
|
+
}]
|
1048
|
+
$obj = MySecondObject.new({c => 'hi', a => 3})
|
1049
|
+
notice($obj.a)
|
1050
|
+
notice($obj.b)
|
1051
|
+
notice($obj.c)
|
1052
|
+
notice($obj.d)
|
1053
|
+
CODE
|
1054
|
+
expect(eval_and_collect_notices(code)).to eql(['3', 'the first constant', 'hi', '34'])
|
1055
|
+
end
|
1056
|
+
end
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
end
|