puppet 4.2.3 → 4.3.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/Gemfile +3 -0
- data/README.md +1 -1
- data/ext/debian/puppet.init +0 -1
- data/ext/debian/puppet.logrotate +14 -5
- data/ext/osx/puppet.plist +0 -2
- data/ext/redhat/client.init +13 -5
- data/ext/redhat/logrotate +15 -3
- data/ext/redhat/puppet.spec.erb +5 -1
- data/ext/redhat/server.init +1 -1
- data/ext/systemd/puppet.service +1 -0
- data/lib/puppet.rb +12 -0
- data/lib/puppet/agent.rb +4 -4
- data/lib/puppet/agent/locker.rb +11 -2
- data/lib/puppet/application/agent.rb +5 -1
- data/lib/puppet/application/apply.rb +4 -0
- data/lib/puppet/application/filebucket.rb +78 -4
- data/lib/puppet/application/lookup.rb +356 -0
- data/lib/puppet/application/master.rb +3 -0
- data/lib/puppet/configurer.rb +9 -5
- data/lib/puppet/context.rb +16 -1
- data/lib/puppet/context/trusted_information.rb +21 -1
- data/lib/puppet/daemon.rb +17 -13
- data/lib/puppet/data_binding.rb +4 -2
- data/lib/puppet/data_providers.rb +12 -13
- data/lib/puppet/data_providers/data_adapter.rb +7 -68
- data/lib/puppet/data_providers/data_function_support.rb +5 -26
- data/lib/puppet/data_providers/function_env_data_provider.rb +0 -10
- data/lib/puppet/data_providers/function_module_data_provider.rb +0 -22
- data/lib/puppet/data_providers/hiera_config.rb +106 -0
- data/lib/puppet/data_providers/hiera_env_data_provider.rb +18 -0
- data/lib/puppet/data_providers/hiera_interpolate.rb +97 -0
- data/lib/puppet/data_providers/hiera_module_data_provider.rb +23 -0
- data/lib/puppet/data_providers/hiera_support.rb +37 -0
- data/lib/puppet/data_providers/json_data_provider_factory.rb +31 -0
- data/lib/puppet/data_providers/lookup_adapter.rb +200 -0
- data/lib/puppet/data_providers/yaml_data_provider_factory.rb +32 -0
- data/lib/puppet/defaults.rb +12 -2
- data/lib/puppet/error.rb +4 -0
- data/lib/puppet/face/module/changes.rb +2 -1
- data/lib/puppet/feature/cfacter.rb +1 -0
- data/lib/puppet/file_bucket/dipper.rb +58 -2
- data/lib/puppet/functions.rb +2 -4
- data/lib/puppet/functions/assert_type.rb +48 -12
- data/lib/puppet/functions/defined.rb +79 -48
- data/lib/puppet/functions/each.rb +85 -27
- data/lib/puppet/functions/filter.rb +58 -23
- data/lib/puppet/functions/hiera.rb +76 -3
- data/lib/puppet/functions/hiera_array.rb +65 -3
- data/lib/puppet/functions/hiera_hash.rb +74 -2
- data/lib/puppet/functions/hiera_include.rb +75 -2
- data/lib/puppet/functions/lookup.rb +19 -17
- data/lib/puppet/functions/map.rb +56 -21
- data/lib/puppet/functions/match.rb +29 -12
- data/lib/puppet/functions/reduce.rb +95 -58
- data/lib/puppet/functions/versioncmp.rb +36 -0
- data/lib/puppet/functions/with.rb +15 -7
- data/lib/puppet/indirector/catalog/compiler.rb +3 -3
- data/lib/puppet/indirector/catalog/static_compiler.rb +46 -30
- data/lib/puppet/indirector/data_binding/none.rb +4 -1
- data/lib/puppet/indirector/file_bucket_file/file.rb +58 -1
- data/lib/puppet/indirector/hiera.rb +4 -0
- data/lib/puppet/indirector/json.rb +1 -1
- data/lib/puppet/indirector/msgpack.rb +1 -1
- data/lib/puppet/indirector/request.rb +7 -8
- data/lib/puppet/indirector/resource_type/parser.rb +5 -3
- data/lib/puppet/info_service.rb +7 -0
- data/lib/puppet/info_service/class_information_service.rb +111 -0
- data/lib/puppet/module_tool/metadata.rb +32 -9
- data/lib/puppet/module_tool/skeleton/templates/generator/README.md.erb +42 -38
- data/lib/puppet/network/authconfig.rb +21 -1
- data/lib/puppet/network/authorization.rb +8 -1
- data/lib/puppet/network/http/api/master/v3.rb +7 -1
- data/lib/puppet/network/http/api/master/v3/environment.rb +59 -0
- data/lib/puppet/node/environment.rb +9 -2
- data/lib/puppet/parser.rb +3 -0
- data/lib/puppet/parser/ast/pops_bridge.rb +39 -1
- data/lib/puppet/parser/compiler.rb +302 -12
- data/lib/puppet/parser/compiler/catalog_validator.rb +33 -0
- data/lib/puppet/parser/compiler/catalog_validator/env_relationship_validator.rb +64 -0
- data/lib/puppet/parser/compiler/catalog_validator/relationship_validator.rb +38 -0
- data/lib/puppet/parser/compiler/catalog_validator/site_validator.rb +20 -0
- data/lib/puppet/parser/environment_compiler.rb +165 -0
- data/lib/puppet/parser/functions/assert_type.rb +46 -16
- data/lib/puppet/parser/functions/defined.rb +105 -68
- data/lib/puppet/parser/functions/each.rb +85 -27
- data/lib/puppet/parser/functions/filter.rb +59 -23
- data/lib/puppet/parser/functions/hiera.rb +83 -27
- data/lib/puppet/parser/functions/hiera_array.rb +71 -28
- data/lib/puppet/parser/functions/hiera_hash.rb +81 -30
- data/lib/puppet/parser/functions/hiera_include.rb +81 -40
- data/lib/puppet/parser/functions/map.rb +55 -20
- data/lib/puppet/parser/functions/match.rb +27 -12
- data/lib/puppet/parser/functions/reduce.rb +97 -60
- data/lib/puppet/parser/functions/with.rb +16 -8
- data/lib/puppet/parser/resource.rb +98 -19
- data/lib/puppet/plugins/configuration.rb +3 -2
- data/lib/puppet/plugins/data_providers.rb +12 -60
- data/lib/puppet/plugins/data_providers/data_provider.rb +283 -0
- data/lib/puppet/plugins/data_providers/registry.rb +84 -0
- data/lib/puppet/pops.rb +19 -17
- data/lib/puppet/pops/adapters.rb +12 -0
- data/lib/puppet/pops/binder/binder.rb +2 -2
- data/lib/puppet/pops/binder/bindings_checker.rb +1 -1
- data/lib/puppet/pops/binder/bindings_label_provider.rb +3 -1
- data/lib/puppet/pops/binder/bindings_loader.rb +6 -2
- data/lib/puppet/pops/binder/bindings_model_meta.rb +2 -2
- data/lib/puppet/pops/binder/config/binder_config.rb +1 -1
- data/lib/puppet/pops/binder/injector.rb +4 -4
- data/lib/puppet/pops/binder/key_factory.rb +3 -9
- data/lib/puppet/pops/binder/scheme_handler/module_scheme.rb +68 -9
- data/lib/puppet/pops/evaluator/access_operator.rb +27 -60
- data/lib/puppet/pops/evaluator/closure.rb +8 -8
- data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +1 -1
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -5
- data/lib/puppet/pops/evaluator/literal_evaluator.rb +87 -0
- data/lib/puppet/pops/evaluator/relationship_operator.rb +7 -1
- data/lib/puppet/pops/functions/dispatcher.rb +3 -3
- data/lib/puppet/pops/issues.rb +1 -1
- data/lib/puppet/pops/label_provider.rb +1 -1
- data/lib/puppet/pops/lookup.rb +25 -47
- data/lib/puppet/pops/lookup/explainer.rb +402 -0
- data/lib/puppet/pops/lookup/invocation.rb +117 -0
- data/lib/puppet/pops/merge_strategy.rb +73 -5
- data/lib/puppet/pops/model/factory.rb +34 -0
- data/lib/puppet/pops/model/model_label_provider.rb +10 -1
- data/lib/puppet/pops/model/model_meta.rb +15 -0
- data/lib/puppet/pops/model/model_tree_dumper.rb +18 -0
- data/lib/puppet/pops/parser/code_merger.rb +13 -1
- data/lib/puppet/pops/parser/egrammar.ra +56 -3
- data/lib/puppet/pops/parser/eparser.rb +1549 -1352
- data/lib/puppet/pops/parser/lexer2.rb +31 -6
- data/lib/puppet/pops/parser/locator.rb +1 -1
- data/lib/puppet/pops/parser/parser_support.rb +25 -13
- data/lib/puppet/pops/types/enumeration.rb +1 -2
- data/lib/puppet/pops/types/type_asserter.rb +16 -15
- data/lib/puppet/pops/types/type_assertion_error.rb +1 -0
- data/lib/puppet/pops/types/type_calculator.rb +171 -1020
- data/lib/puppet/pops/types/type_factory.rb +87 -148
- data/lib/puppet/pops/types/type_mismatch_describer.rb +743 -0
- data/lib/puppet/pops/types/type_parser.rb +116 -127
- data/lib/puppet/pops/types/types.rb +1394 -255
- data/lib/puppet/pops/types/types_meta.rb +0 -234
- data/lib/puppet/pops/validation.rb +7 -2
- data/lib/puppet/pops/validation/checker4_0.rb +28 -0
- data/lib/puppet/provider/augeas/augeas.rb +50 -0
- data/lib/puppet/provider/group/directoryservice.rb +10 -0
- data/lib/puppet/provider/package/dnf.rb +41 -0
- data/lib/puppet/provider/package/gem.rb +7 -2
- data/lib/puppet/provider/package/rpm.rb +1 -0
- data/lib/puppet/provider/package/windows/exe_package.rb +10 -8
- data/lib/puppet/provider/package/windows/msi_package.rb +4 -3
- data/lib/puppet/provider/package/windows/package.rb +9 -1
- data/lib/puppet/provider/package/yum.rb +14 -9
- data/lib/puppet/provider/service/bsd.rb +1 -1
- data/lib/puppet/provider/service/debian.rb +21 -0
- data/lib/puppet/provider/service/init.rb +6 -0
- data/lib/puppet/provider/service/rcng.rb +51 -0
- data/lib/puppet/provider/service/redhat.rb +2 -1
- data/lib/puppet/provider/service/smf.rb +43 -2
- data/lib/puppet/provider/service/src.rb +27 -0
- data/lib/puppet/provider/service/systemd.rb +15 -3
- data/lib/puppet/provider/sshkey/parsed.rb +19 -9
- data/lib/puppet/reference/report.rb +9 -12
- data/lib/puppet/reports.rb +5 -1
- data/lib/puppet/resource.rb +50 -73
- data/lib/puppet/resource/capability_finder.rb +95 -0
- data/lib/puppet/resource/catalog.rb +47 -7
- data/lib/puppet/resource/status.rb +0 -2
- data/lib/puppet/resource/type.rb +238 -44
- data/lib/puppet/resource/type_collection.rb +60 -2
- data/lib/puppet/settings.rb +2 -2
- data/lib/puppet/ssl/certificate_authority/interface.rb +2 -2
- data/lib/puppet/ssl/oids.rb +9 -1
- data/lib/puppet/transaction.rb +4 -1
- data/lib/puppet/transaction/additional_resource_generator.rb +71 -8
- data/lib/puppet/transaction/resource_harness.rb +9 -4
- data/lib/puppet/type.rb +74 -3
- data/lib/puppet/type/augeas.rb +8 -0
- data/lib/puppet/type/file/source.rb +14 -12
- data/lib/puppet/type/user.rb +4 -2
- data/lib/puppet/util/windows/security.rb +4 -1
- data/lib/puppet/util/windows/taskscheduler.rb +1 -1
- data/lib/puppet/version.rb +1 -1
- data/spec/fixtures/unit/application/environments/production/data/common.yaml +3 -0
- data/spec/fixtures/unit/application/environments/production/environment.conf +1 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/data/bad.json +3 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/environment.conf +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/hiera.yaml +5 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/manifests/site.pp +5 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/data/bad.yaml +3 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/environment.conf +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/hiera.yaml +5 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/manifests/site.pp +5 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_defaults/data/common.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_defaults/environment.conf +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_defaults/manifests/site.pp +1 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_defaults/modules/one/data/common.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_defaults/modules/one/manifests/init.pp +5 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_defaults/modules/one/metadata.json +9 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/first.json +3 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/name.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/second.json +3 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/single.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data2/single.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/environment.conf +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/hiera.yaml +18 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_env_config/manifests/site.pp +5 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_misc/data/common.yaml +46 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_misc/environment.conf +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_misc/manifests/site.pp +1 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_misc/modules/one/data/common.yaml +30 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_misc/modules/one/manifests/init.pp +13 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_misc/modules/one/metadata.json +9 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/environment.conf +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/manifests/site.pp +1 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/first.json +3 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/name.yaml +1 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/second.json +3 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/single.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data2/single.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/hiera.yaml +18 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/manifests/init.pp +5 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/metadata.json +9 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_env_data.rb +1 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_module_data.rb +1 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/data/first.json +3 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/hiera.yaml +8 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/manifests/init.pp +5 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/metadata.json +9 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/meta/lib/puppet/functions/meta/data.rb +9 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/meta/manifests/init.pp +3 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/meta/metadata.json +9 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/lib/puppet/bindings/metawcp/default.rb +10 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/lib/puppet_x/thallgren/sample_module_data.rb +23 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/manifests/init.pp +3 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/metadata.json +9 -0
- data/spec/fixtures/unit/provider/package/yum/yum-check-update-security.txt +184 -0
- data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_get/should_yield_to_the_block.yml +24 -0
- data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_head/should_yield_to_the_block.yml +24 -0
- data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_post/should_yield_to_the_block.yml +24 -0
- data/spec/integration/data_binding_spec.rb +229 -0
- data/spec/integration/file_bucket/file_spec.rb +2 -2
- data/spec/integration/parser/compiler_spec.rb +23 -19
- data/spec/integration/parser/resource_expressions_spec.rb +4 -4
- data/spec/integration/parser/undef_param_spec.rb +1 -1
- data/spec/integration/resource/catalog_spec.rb +1 -1
- data/spec/integration/type/package_spec.rb +2 -0
- data/spec/integration/util/windows/security_spec.rb +18 -0
- data/spec/lib/matchers/include_in_order.rb +2 -2
- data/spec/shared_behaviours/iterative_functions.rb +8 -8
- data/spec/spec_helper.rb +7 -0
- data/spec/unit/agent/locker_spec.rb +4 -4
- data/spec/unit/agent_spec.rb +0 -8
- data/spec/unit/application/agent_spec.rb +5 -0
- data/spec/unit/application/apply_spec.rb +8 -0
- data/spec/unit/application/filebucket_spec.rb +87 -1
- data/spec/unit/application/lookup_spec.rb +195 -0
- data/spec/unit/appmgmt_spec.rb +657 -0
- data/spec/unit/capability_spec.rb +414 -0
- data/spec/unit/configurer_spec.rb +7 -1
- data/spec/unit/context/trusted_information_spec.rb +24 -1
- data/spec/unit/daemon_spec.rb +18 -8
- data/spec/unit/data_providers/hiera_data_provider_spec.rb +201 -0
- data/spec/unit/file_bucket/dipper_spec.rb +210 -1
- data/spec/unit/functions/assert_type_spec.rb +5 -7
- data/spec/unit/functions/defined_spec.rb +2 -2
- data/spec/unit/functions/epp_spec.rb +2 -2
- data/spec/unit/functions/lookup_spec.rb +200 -9
- data/spec/unit/functions/regsubst_spec.rb +17 -8
- data/spec/unit/functions/scanf_spec.rb +1 -1
- data/spec/unit/functions/split_spec.rb +2 -2
- data/spec/unit/functions/versioncmp_spec.rb +36 -0
- data/spec/unit/functions4_spec.rb +58 -72
- data/spec/unit/indirector/catalog/compiler_spec.rb +28 -8
- data/spec/unit/indirector/catalog/static_compiler_spec.rb +38 -20
- data/spec/unit/indirector/data_binding/none_spec.rb +2 -2
- data/spec/unit/indirector/file_bucket_file/file_spec.rb +52 -1
- data/spec/unit/indirector/request_spec.rb +8 -8
- data/spec/unit/info_service_spec.rb +236 -0
- data/spec/unit/module_tool/metadata_spec.rb +31 -2
- data/spec/unit/network/authconfig_spec.rb +62 -32
- data/spec/unit/network/authorization_spec.rb +30 -2
- data/spec/unit/network/http/connection_spec.rb +14 -19
- data/spec/unit/parser/compiler_spec.rb +86 -2
- data/spec/unit/parser/functions/create_resources_spec.rb +1 -1
- data/spec/unit/parser/resource_spec.rb +2 -20
- data/spec/unit/pops/binder/config/binder_config_spec.rb +1 -1
- data/spec/unit/pops/binder/injector_spec.rb +3 -3
- data/spec/unit/pops/evaluator/access_ops_spec.rb +13 -11
- data/spec/unit/pops/evaluator/basic_expressions_spec.rb +1 -2
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +19 -11
- data/spec/unit/pops/evaluator/literal_evaluator_spec.rb +43 -0
- data/spec/unit/pops/label_provider_spec.rb +5 -1
- data/spec/unit/pops/parser/lexer2_spec.rb +33 -7
- data/spec/unit/pops/parser/parse_application_spec.rb +40 -0
- data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +4 -0
- data/spec/unit/pops/parser/parse_capabilities_spec.rb +47 -0
- data/spec/unit/pops/parser/parse_site_spec.rb +38 -0
- data/spec/unit/pops/parser/parser_rspec_helper.rb +5 -0
- data/spec/unit/pops/parser/parser_spec.rb +18 -0
- data/spec/unit/pops/types/type_calculator_spec.rb +427 -444
- data/spec/unit/pops/types/type_factory_spec.rb +12 -12
- data/spec/unit/pops/types/type_parser_spec.rb +7 -12
- data/spec/unit/pops/validator/validator_spec.rb +25 -0
- data/spec/unit/provider/augeas/augeas_spec.rb +50 -0
- data/spec/unit/provider/group/directoryservice_spec.rb +33 -0
- data/spec/unit/provider/group/windows_adsi_spec.rb +3 -0
- data/spec/unit/provider/package/dnf_spec.rb +92 -0
- data/spec/unit/provider/package/gem_spec.rb +7 -0
- data/spec/unit/provider/package/rpm_spec.rb +25 -2
- data/spec/unit/provider/package/windows/package_spec.rb +41 -0
- data/spec/unit/provider/package/yum_spec.rb +21 -13
- data/spec/unit/provider/scheduled_task/win32_taskscheduler_spec.rb +10 -0
- data/spec/unit/provider/service/debian_spec.rb +27 -0
- data/spec/unit/provider/service/rcng_spec.rb +41 -0
- data/spec/unit/provider/service/redhat_spec.rb +8 -1
- data/spec/unit/provider/service/smf_spec.rb +30 -5
- data/spec/unit/provider/service/src_spec.rb +19 -4
- data/spec/unit/provider/service/systemd_spec.rb +78 -29
- data/spec/unit/provider/sshkey/parsed_spec.rb +23 -0
- data/spec/unit/reports_spec.rb +10 -0
- data/spec/unit/resource/capability_finder_spec.rb +56 -0
- data/spec/unit/resource/catalog_spec.rb +31 -8
- data/spec/unit/resource/type_collection_spec.rb +23 -2
- data/spec/unit/resource/type_spec.rb +1 -1
- data/spec/unit/resource_spec.rb +22 -4
- data/spec/unit/settings_spec.rb +90 -1
- data/spec/unit/ssl/certificate_authority/interface_spec.rb +4 -3
- data/spec/unit/ssl/oids_spec.rb +8 -0
- data/spec/unit/transaction/additional_resource_generator_spec.rb +78 -5
- data/spec/unit/transaction/report_spec.rb +24 -1
- data/spec/unit/type/package_spec.rb +1 -0
- data/spec/unit/type/user_spec.rb +14 -7
- data/spec/unit/type_spec.rb +1 -1
- metadata +169 -5
- data/lib/puppet/pops/evaluator/callable_mismatch_describer.rb +0 -175
- data/spec/integration/data_binding.rb +0 -104
@@ -0,0 +1,743 @@
|
|
1
|
+
module Puppet::Pops::Types
|
2
|
+
EMPTY_ARRAY = [].freeze
|
3
|
+
|
4
|
+
class TypePathElement
|
5
|
+
attr_reader :key
|
6
|
+
|
7
|
+
def initialize(key)
|
8
|
+
@key = key
|
9
|
+
end
|
10
|
+
|
11
|
+
def hash
|
12
|
+
key.hash
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(o)
|
16
|
+
self.class == o.class && key == o.key
|
17
|
+
end
|
18
|
+
|
19
|
+
alias :eql? :==
|
20
|
+
end
|
21
|
+
|
22
|
+
class MemberPathElement < TypePathElement
|
23
|
+
def to_s
|
24
|
+
"struct member #{key}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class MemberKeyPathElement < TypePathElement
|
29
|
+
def to_s
|
30
|
+
"struct member key #{key}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ParameterPathElement < TypePathElement
|
35
|
+
def to_s
|
36
|
+
"parameter '#{key}'"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class BlockPathElement < ParameterPathElement
|
41
|
+
def initialize(name = 'block')
|
42
|
+
super(name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
key
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class ArrayPathElement < TypePathElement
|
51
|
+
def to_s
|
52
|
+
"index #{key}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class VariantPathElement < TypePathElement
|
57
|
+
def to_s
|
58
|
+
"variant #{key}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class SignaturePathElement < VariantPathElement
|
63
|
+
def to_s
|
64
|
+
"#{key+1}."
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Mismatch
|
69
|
+
attr_reader :path
|
70
|
+
|
71
|
+
def initialize(path)
|
72
|
+
@path = path || EMPTY_ARRAY
|
73
|
+
end
|
74
|
+
|
75
|
+
def canonical_path
|
76
|
+
@canonical_path ||= @path.reject { |e| e.is_a?(VariantPathElement) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def message(variant, position)
|
80
|
+
"#{variant}unknown mismatch#{position}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def merge(path, o)
|
84
|
+
self.class.new(path)
|
85
|
+
end
|
86
|
+
|
87
|
+
def ==(o)
|
88
|
+
self.class == o.class && canonical_path == o.canonical_path
|
89
|
+
end
|
90
|
+
|
91
|
+
alias :eql? :==
|
92
|
+
|
93
|
+
def hash
|
94
|
+
canonical_path.hash
|
95
|
+
end
|
96
|
+
|
97
|
+
def chop_path(element_index)
|
98
|
+
return self if element_index >= @path.size
|
99
|
+
chopped_path = @path.clone
|
100
|
+
chopped_path.delete_at(element_index)
|
101
|
+
copy = self.clone
|
102
|
+
copy.instance_variable_set(:@path, chopped_path)
|
103
|
+
copy
|
104
|
+
end
|
105
|
+
|
106
|
+
def path_string
|
107
|
+
@path.join(' ')
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_s
|
111
|
+
p = @path
|
112
|
+
variant = ''
|
113
|
+
position = ''
|
114
|
+
unless p.empty?
|
115
|
+
f = p.first
|
116
|
+
if f.is_a?(SignaturePathElement)
|
117
|
+
variant = " #{f}"
|
118
|
+
p = p.drop(1)
|
119
|
+
end
|
120
|
+
position = " #{p.join(' ')}" unless p.empty?
|
121
|
+
end
|
122
|
+
message(variant, position)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# @abstract
|
127
|
+
class KeyMismatch < Mismatch
|
128
|
+
attr_reader :key
|
129
|
+
|
130
|
+
def initialize(path, key)
|
131
|
+
super(path)
|
132
|
+
@key = key
|
133
|
+
end
|
134
|
+
|
135
|
+
def ==(o)
|
136
|
+
super.==(o) && key == o.key
|
137
|
+
end
|
138
|
+
|
139
|
+
def hash
|
140
|
+
super.hash * 31 + key.hash
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class MissingKey < KeyMismatch
|
145
|
+
def message(variant, position)
|
146
|
+
"#{variant}#{position} expects a value for key '#{key}'"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class MissingParameter < KeyMismatch
|
151
|
+
def message(variant, position)
|
152
|
+
"#{variant}#{position} expects a value for parameter '#{key}'"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class ExtraneousKey < KeyMismatch
|
157
|
+
def message(variant, position)
|
158
|
+
"#{variant}#{position} has no '#{@key}' key"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class InvalidParameter < ExtraneousKey
|
163
|
+
def message(variant, position)
|
164
|
+
"#{variant}#{position} has no parameter named '#{@key}'"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class UnexpectedBlock < Mismatch
|
169
|
+
def message(variant, position)
|
170
|
+
"#{variant}#{position} does not expect a block"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class MissingRequiredBlock < Mismatch
|
175
|
+
def message(variant, position)
|
176
|
+
"#{variant}#{position} expects a block"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class ExpectedActualMismatch < Mismatch
|
181
|
+
attr_reader :expected, :actual
|
182
|
+
|
183
|
+
def initialize(path, expected, actual)
|
184
|
+
super(path)
|
185
|
+
@expected = expected
|
186
|
+
@actual = actual
|
187
|
+
end
|
188
|
+
|
189
|
+
def ==(o)
|
190
|
+
super.==(o) && expected == o.expected && actual == o.actual
|
191
|
+
end
|
192
|
+
|
193
|
+
def hash
|
194
|
+
hash = super.hash
|
195
|
+
hash = hash * 31 + expected.hash
|
196
|
+
hash * 31 + actual.hash
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
class TypeMismatch < ExpectedActualMismatch
|
201
|
+
include Puppet::Pops::LabelProvider
|
202
|
+
|
203
|
+
# @return A new instance with the least restrictive respective boundaries
|
204
|
+
def merge(path, o)
|
205
|
+
self.class.new(path, [expected, o.expected].flatten.uniq, actual)
|
206
|
+
end
|
207
|
+
|
208
|
+
def message(variant, position)
|
209
|
+
e = expected
|
210
|
+
a = actual
|
211
|
+
multi = false
|
212
|
+
if e.is_a?(Array)
|
213
|
+
# Use simple names when classes differ, or in other words, only include details
|
214
|
+
# when the classes are equal.
|
215
|
+
#
|
216
|
+
if e.find { |t| t.class == a.class }
|
217
|
+
e = e.map { |t| t.to_s }
|
218
|
+
a = a.to_s
|
219
|
+
else
|
220
|
+
sns = e.map { |t| t.simple_name }
|
221
|
+
e = e.map { |t| s = t.simple_name; sns.count {|x| x == s } == 1 ? s : t.to_s }
|
222
|
+
a = a.simple_name
|
223
|
+
end
|
224
|
+
case e.size
|
225
|
+
when 1
|
226
|
+
e = e[0]
|
227
|
+
when 2
|
228
|
+
e = "#{e[0]} or #{e[1]}"
|
229
|
+
multi = true
|
230
|
+
else
|
231
|
+
e = "#{e[0..e.size-2].join(', ')}, or #{e[e.size-1]}"
|
232
|
+
multi = true
|
233
|
+
end
|
234
|
+
else
|
235
|
+
if e.class != a.class
|
236
|
+
e = e.simple_name
|
237
|
+
a = a.simple_name
|
238
|
+
else
|
239
|
+
e = e.to_s
|
240
|
+
a = a.to_s
|
241
|
+
end
|
242
|
+
end
|
243
|
+
multi ? "#{variant}#{position} expects a value of type #{e}, got #{label(a)}" : "#{variant}#{position} expects #{a_an(e)} value, got #{label(a)}"
|
244
|
+
end
|
245
|
+
|
246
|
+
def label(o)
|
247
|
+
o.to_s
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
class PatternMismatch < TypeMismatch
|
252
|
+
def message(variant, position)
|
253
|
+
"#{variant}#{position} expects a match for #{expected}, got #{actual_string}"
|
254
|
+
end
|
255
|
+
|
256
|
+
def actual_string
|
257
|
+
a = actual
|
258
|
+
a.is_a?(PStringType) && a.values.size == 1 ? "'#{a.values[0]}'" : a.simple_name
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
class SizeMismatch < ExpectedActualMismatch
|
263
|
+
def from
|
264
|
+
@expected.from || 0
|
265
|
+
end
|
266
|
+
|
267
|
+
def to
|
268
|
+
@expected.to || Float::INFINITY
|
269
|
+
end
|
270
|
+
|
271
|
+
# @return A new instance with the least restrictive respective boundaries
|
272
|
+
def merge(path, o)
|
273
|
+
range = PIntegerType.new(from < o.from ? from : o.from, to > o.to ? to : o.to)
|
274
|
+
self.class.new(path, range, @actual)
|
275
|
+
end
|
276
|
+
|
277
|
+
def message(variant, position)
|
278
|
+
"#{variant}#{position} expects size to be #{range_to_s(expected, '0')}, got #{range_to_s(actual, '0')}"
|
279
|
+
end
|
280
|
+
|
281
|
+
def range_to_s(range, zero_string)
|
282
|
+
min = range.from || 0
|
283
|
+
max = range.to || Float::INFINITY
|
284
|
+
if min == max
|
285
|
+
min == 0 ? zero_string : min.to_s
|
286
|
+
elsif min == 0
|
287
|
+
max == Float::INFINITY ? 'unlimited' : "at most #{max}"
|
288
|
+
elsif max == Float::INFINITY
|
289
|
+
"at least #{min}"
|
290
|
+
else
|
291
|
+
"between #{min} and #{max}"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
class CountMismatch < SizeMismatch
|
297
|
+
def initialize(path, expected, actual)
|
298
|
+
super(path, expected, actual)
|
299
|
+
end
|
300
|
+
|
301
|
+
def message(variant, position)
|
302
|
+
min = expected.from || 0
|
303
|
+
max = expected.to || Float::INFINITY
|
304
|
+
suffix = min == 1 && (max == 1 || max == Float::INFINITY) || min == 0 && max == 1 ? '' : 's'
|
305
|
+
"#{variant}#{position} expects #{range_to_s(expected, 'no')} argument#{suffix}, got #{range_to_s(actual, 'none')}"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class TypeMismatchDescriber
|
310
|
+
def self.validate_parameters(subject, params_struct, given_hash, missing_ok = false)
|
311
|
+
singleton.validate_parameters(subject, params_struct, given_hash, missing_ok)
|
312
|
+
end
|
313
|
+
|
314
|
+
def self.validate_default_parameter(subject, param_name, param_type, value)
|
315
|
+
singleton.validate_default_parameter(subject, param_name, param_type, value)
|
316
|
+
end
|
317
|
+
|
318
|
+
def self.describe_signatures(closure, signatures, args_tuple)
|
319
|
+
singleton.describe_signatures(closure, signatures, args_tuple)
|
320
|
+
end
|
321
|
+
|
322
|
+
def self.singleton
|
323
|
+
@singleton ||= new
|
324
|
+
end
|
325
|
+
|
326
|
+
# Validates that all entries in the give_hash exists in the given param_struct, that their type conforms
|
327
|
+
# with the corresponding param_struct element and that all required values are provided.
|
328
|
+
#
|
329
|
+
# @param subject [String] string to be prepended to the exception message
|
330
|
+
# @param params_struct [PStructType] Struct to use for validation
|
331
|
+
# @param given_hash [Hash<String,Object>] the parameters to validate
|
332
|
+
# @param missing_ok [Boolean] Do not generate errors on missing parameters
|
333
|
+
#
|
334
|
+
def validate_parameters(subject, params_struct, given_hash, missing_ok = false)
|
335
|
+
errors = describe_struct_signature(params_struct, given_hash, missing_ok).flatten
|
336
|
+
case errors.size
|
337
|
+
when 0
|
338
|
+
when 1
|
339
|
+
raise Puppet::ParseError.new("#{subject}:#{errors[0]}")
|
340
|
+
else
|
341
|
+
raise Puppet::ParseError.new("#{subject}:\n #{errors.join("\n ")}")
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
# @param subject [String] string to be prepended to the exception message
|
346
|
+
# @param param_name [String] parameter name
|
347
|
+
# @param param_type [PAnyType] parameter type
|
348
|
+
# @param value [Object] value to be validated against the given type
|
349
|
+
#
|
350
|
+
def validate_default_parameter(subject, param_name, param_type, value)
|
351
|
+
unless param_type.instance?(value)
|
352
|
+
errors = describe(param_type, TypeCalculator.singleton.infer_set(value).generalize, [ParameterPathElement.new(param_name)])
|
353
|
+
case errors.size
|
354
|
+
when 0
|
355
|
+
when 1
|
356
|
+
raise Puppet::ParseError.new("#{subject}:#{errors[0]}")
|
357
|
+
else
|
358
|
+
raise Puppet::ParseError.new("#{subject}:\n #{errors.join("\n ")}")
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
# Validates that all entries in the _param_hash_ exists in the given param_struct, that their type conforms
|
364
|
+
# with the corresponding param_struct element and that all required values are provided.
|
365
|
+
# An error message is created for each problem found.
|
366
|
+
#
|
367
|
+
# @param params_struct [PStructType] Struct to use for validation
|
368
|
+
# @param param_hash [Hash<String,Object>] The parameters to validate
|
369
|
+
# @param missing_ok [Boolean] Do not generate errors on missing parameters
|
370
|
+
# @return [Array<Mismatch>] An array of found errors. An empty array indicates no errors.
|
371
|
+
def describe_struct_signature(params_struct, param_hash, missing_ok = false)
|
372
|
+
param_type_hash = params_struct.hashed_elements
|
373
|
+
result = param_hash.each_key.reject { |name| param_type_hash.include?(name) }.map { |name| InvalidParameter.new(nil, name) }
|
374
|
+
|
375
|
+
params_struct.elements.each do |elem|
|
376
|
+
name = elem.name
|
377
|
+
value = param_hash[name]
|
378
|
+
value_type = elem.value_type
|
379
|
+
if param_hash.include?(name)
|
380
|
+
result << describe(value_type, TypeCalculator.singleton.infer_set(value).generalize, [ParameterPathElement.new(name)]) unless value_type.instance?(value)
|
381
|
+
else
|
382
|
+
result << MissingParameter.new(nil, name) unless elem.key_type.assignable?(PUndefType::DEFAULT) unless missing_ok
|
383
|
+
end
|
384
|
+
end
|
385
|
+
result
|
386
|
+
end
|
387
|
+
|
388
|
+
def describe_signatures(closure, signatures, args_tuple)
|
389
|
+
error_arrays = []
|
390
|
+
signatures.each_with_index do |signature, index|
|
391
|
+
error_arrays << describe_signature_arguments(signature, args_tuple, [SignaturePathElement.new(index)])
|
392
|
+
end
|
393
|
+
|
394
|
+
# Skip block checks if all signatures have argument errors
|
395
|
+
unless error_arrays.all? { |a| !a.empty? }
|
396
|
+
block_arrays = []
|
397
|
+
signatures.each_with_index do |signature, index|
|
398
|
+
block_arrays << describe_signature_block(signature, args_tuple, [SignaturePathElement.new(index)])
|
399
|
+
end
|
400
|
+
bc_count = block_arrays.count { |a| !a.empty? }
|
401
|
+
if bc_count == block_arrays.size
|
402
|
+
# Skip argument errors when all alternatives have block errors
|
403
|
+
error_arrays = block_arrays
|
404
|
+
elsif bc_count > 0
|
405
|
+
# Merge errors giving argument errors precedence over block errors
|
406
|
+
error_arrays.each_with_index { |a, index| error_arrays[index] = block_arrays[index] if a.empty? }
|
407
|
+
end
|
408
|
+
end
|
409
|
+
return nil if error_arrays.empty?
|
410
|
+
|
411
|
+
label = closure == 'lambda' ? 'block' : "'#{closure}'"
|
412
|
+
errors = merge_descriptions(0, CountMismatch, error_arrays)
|
413
|
+
if errors.size == 1
|
414
|
+
"#{label}#{errors[0]}"
|
415
|
+
else
|
416
|
+
if signatures.size == 1
|
417
|
+
sig = signatures[0]
|
418
|
+
result = ["#{label} expected (#{signature_string(sig)})"]
|
419
|
+
result.concat(error_arrays[0].map { |e| " rejected:#{e.chop_path(0)}" })
|
420
|
+
else
|
421
|
+
result = ["#{label} expected one of:"]
|
422
|
+
signatures.each_with_index do |sg, index|
|
423
|
+
result << " (#{signature_string(sg)})"
|
424
|
+
result.concat(error_arrays[index].map { |e| " rejected:#{e.chop_path(0)}" })
|
425
|
+
end
|
426
|
+
end
|
427
|
+
result.join("\n")
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
def describe_signature_arguments(signature, args_tuple, path)
|
432
|
+
params_tuple = signature.type.param_types
|
433
|
+
params_size_t = params_tuple.size_type || TypeFactory.range(*params_tuple.size_range)
|
434
|
+
|
435
|
+
if args_tuple.is_a?(PTupleType)
|
436
|
+
arg_types = args_tuple.types
|
437
|
+
elsif args_tuple.is_a?(PArrayType)
|
438
|
+
arg_types = Array.new(params_tuple.types.size, args_tuple.element_type || PUndefType::DEFAULT)
|
439
|
+
else
|
440
|
+
return [TypeMismatch.new(path, params_tuple, args_tuple)]
|
441
|
+
end
|
442
|
+
|
443
|
+
if arg_types.last.kind_of_callable?
|
444
|
+
# Check other arguments
|
445
|
+
arg_count = arg_types.size - 1
|
446
|
+
describe_no_block_arguments(signature, arg_types, path, params_size_t, TypeFactory.range(arg_count, arg_count), arg_count)
|
447
|
+
else
|
448
|
+
args_size_t = TypeFactory.range(*args_tuple.size_range)
|
449
|
+
describe_no_block_arguments(signature, arg_types, path, params_size_t, args_size_t, arg_types.size)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
def describe_signature_block(signature, args_tuple, path)
|
454
|
+
param_block_t = signature.block_type
|
455
|
+
arg_block_t = args_tuple.is_a?(PTupleType) ? args_tuple.types.last : nil
|
456
|
+
if TypeCalculator.is_kind_of_callable?(arg_block_t)
|
457
|
+
# Can't pass a block to a callable that doesn't accept one
|
458
|
+
if param_block_t.nil?
|
459
|
+
[UnexpectedBlock.new(path)]
|
460
|
+
else
|
461
|
+
# Check that the block is of the right type
|
462
|
+
describe(param_block_t, arg_block_t, path + [BlockPathElement.new])
|
463
|
+
end
|
464
|
+
else
|
465
|
+
# Check that the block is optional
|
466
|
+
if param_block_t.nil? || param_block_t.assignable?(PUndefType::DEFAULT)
|
467
|
+
EMPTY_ARRAY
|
468
|
+
else
|
469
|
+
[MissingRequiredBlock.new(path)]
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
def describe_no_block_arguments(signature, atypes, path, expected_size, actual_size, arg_count)
|
475
|
+
# not assignable if the number of types in actual is outside number of types in expected
|
476
|
+
if expected_size.assignable?(actual_size)
|
477
|
+
etypes = signature.type.param_types.types
|
478
|
+
enames = signature.parameter_names
|
479
|
+
arg_count.times do |index|
|
480
|
+
adx = index >= etypes.size ? etypes.size - 1 : index
|
481
|
+
etype = etypes[adx]
|
482
|
+
descriptions = describe(etype, atypes[index], path + [ParameterPathElement.new(enames[adx])])
|
483
|
+
return descriptions unless descriptions.empty?
|
484
|
+
end
|
485
|
+
EMPTY_ARRAY
|
486
|
+
else
|
487
|
+
[CountMismatch.new(path, expected_size, actual_size)]
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def describe_PVariantType(expected, actual, path)
|
492
|
+
variant_descriptions = []
|
493
|
+
expected.types.each_with_index do |vt, index|
|
494
|
+
d = describe(vt, actual, path + [VariantPathElement.new(index)])
|
495
|
+
return EMPTY_ARRAY if d.empty?
|
496
|
+
variant_descriptions << d
|
497
|
+
end
|
498
|
+
merge_descriptions(path.length, SizeMismatch, variant_descriptions)
|
499
|
+
end
|
500
|
+
|
501
|
+
def merge_descriptions(varying_path_position, size_mismatch_class, variant_descriptions)
|
502
|
+
descriptions = variant_descriptions.flatten
|
503
|
+
[size_mismatch_class, MissingRequiredBlock, UnexpectedBlock, TypeMismatch].each do |mismatch_class|
|
504
|
+
mismatches = descriptions.select { |desc| desc.is_a?(mismatch_class) }
|
505
|
+
if mismatches.size == variant_descriptions.size
|
506
|
+
# If they all have the same canonical path, then we can compact this into one
|
507
|
+
generic_mismatch = mismatches.inject do |prev, curr|
|
508
|
+
break nil unless prev.canonical_path == curr.canonical_path
|
509
|
+
prev.merge(prev.path, curr)
|
510
|
+
end
|
511
|
+
unless generic_mismatch.nil?
|
512
|
+
# Report the generic mismatch and skip the rest
|
513
|
+
descriptions = [generic_mismatch]
|
514
|
+
break
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
descriptions = descriptions.uniq
|
519
|
+
descriptions.size == 1 ? [descriptions[0].chop_path(varying_path_position)] : descriptions
|
520
|
+
end
|
521
|
+
|
522
|
+
def describe_POptionalType(expected, actual, path)
|
523
|
+
actual.is_a?(PUndefType) ? [] : describe(expected.optional_type, actual, path)
|
524
|
+
end
|
525
|
+
|
526
|
+
def describe_PEnumType(expected, actual, path)
|
527
|
+
[PatternMismatch.new(path, expected, actual)]
|
528
|
+
end
|
529
|
+
|
530
|
+
def describe_PPatternType(expected, actual, path)
|
531
|
+
[PatternMismatch.new(path, expected, actual)]
|
532
|
+
end
|
533
|
+
|
534
|
+
def describe_PStructType(expected, actual, path)
|
535
|
+
elements = expected.elements
|
536
|
+
descriptions = []
|
537
|
+
if actual.is_a?(PStructType)
|
538
|
+
h2 = actual.hashed_elements.clone
|
539
|
+
elements.each do |e1|
|
540
|
+
key = e1.name
|
541
|
+
e2 = h2.delete(key)
|
542
|
+
if e2.nil?
|
543
|
+
descriptions << MissingKey.new(path, key) unless e1.key_type.assignable?(PUndefType::DEFAULT)
|
544
|
+
else
|
545
|
+
descriptions.concat(describe(e1.key_type, e2.key_type, path + [MemberKeyPathElement.new(key)])) unless e1.key_type.assignable?(e2.key_type)
|
546
|
+
descriptions.concat(describe(e1.value_type, e2.value_type, path + [MemberPathElement.new(key)])) unless e1.value_type.assignable?(e2.value_type)
|
547
|
+
end
|
548
|
+
end
|
549
|
+
h2.each_key { |key| descriptions << ExtraneousKey.new(path, key) }
|
550
|
+
elsif actual.is_a?(PHashType)
|
551
|
+
actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE
|
552
|
+
expected_size = PIntegerType.new(elements.count { |e| !e.type.assignable?(PUndefType::DEFAULT) }, elements.size)
|
553
|
+
if expected_size.assignable?(actual_size)
|
554
|
+
if actual_size.to == 0 || PStringType::NON_EMPTY.assignable?(actual.key_type)
|
555
|
+
descriptions.concat(describe(e.type, actual.element_type, path + [MemberPathElement.new(e.key)]))
|
556
|
+
else
|
557
|
+
descriptions << TypeMismatch(path, @non_empty_string_, actual.key_type)
|
558
|
+
end
|
559
|
+
else
|
560
|
+
descriptions << SizeMismatch(path, expected_size, actual_size)
|
561
|
+
end
|
562
|
+
else
|
563
|
+
descriptions << TypeMismatch.new(path, expected, actual)
|
564
|
+
end
|
565
|
+
descriptions
|
566
|
+
end
|
567
|
+
|
568
|
+
def describe_PTupleType(expected, actual, path)
|
569
|
+
describe_tuple(expected, actual, path, SizeMismatch)
|
570
|
+
end
|
571
|
+
|
572
|
+
def describe_argument_tuple(expected, actual, path)
|
573
|
+
describe_tuple(expected, actual, path, CountMismatch)
|
574
|
+
end
|
575
|
+
|
576
|
+
def describe_tuple(expected, actual, path, size_mismatch_class)
|
577
|
+
return if expected == actual || expected.types.empty? && (actual.is_a?(PArrayType))
|
578
|
+
expected_size = expected.size_type || TypeFactory.range(*expected.size_range)
|
579
|
+
|
580
|
+
if actual.is_a?(PTupleType)
|
581
|
+
actual_size = actual.size_type || TypeFactory.range(*actual.size_range)
|
582
|
+
|
583
|
+
# not assignable if the number of types in actual is outside number of types in expected
|
584
|
+
if expected_size.assignable?(actual_size)
|
585
|
+
etypes = expected.types
|
586
|
+
descriptions = []
|
587
|
+
actual.types.each_with_index do |atype, index|
|
588
|
+
adx = index >= etypes.size ? etypes.size - 1 : index
|
589
|
+
etype = etypes[adx]
|
590
|
+
descriptions.concat(describe(etypes[adx], atype, path + [ArrayPathElement.new(adx)]))
|
591
|
+
end
|
592
|
+
descriptions
|
593
|
+
else
|
594
|
+
[size_mismatch_class.new(path, expected_size, actual_size)]
|
595
|
+
end
|
596
|
+
elsif actual.is_a?(PArrayType)
|
597
|
+
t2_entry = actual.element_type
|
598
|
+
|
599
|
+
if t2_entry.nil?
|
600
|
+
# Array of anything can not be assigned (unless tuple is tuple of anything) - this case
|
601
|
+
# was handled at the top of this method.
|
602
|
+
#
|
603
|
+
[TypeMismatch.new(path, expected, actual)]
|
604
|
+
else
|
605
|
+
expected_size = expected.size_type || TypeFactory.range(*expected.size_range)
|
606
|
+
actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE
|
607
|
+
if expected_size.assignable?(actual_size)
|
608
|
+
descriptions = []
|
609
|
+
expected.types.each_with_index do |etype, index|
|
610
|
+
descriptions.concat(describe(etype, actual.element_type, path + [ArrayPathElement.new(index)]))
|
611
|
+
end
|
612
|
+
descriptions
|
613
|
+
else
|
614
|
+
[size_mismatch_class.new(path, expected_size, actual_size)]
|
615
|
+
end
|
616
|
+
end
|
617
|
+
else
|
618
|
+
[TypeMismatch.new(path, expected, actual)]
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
def describe_PCallableType(expected, actual, path)
|
623
|
+
if actual.is_a?(PCallableType)
|
624
|
+
# nil param_types means, any other Callable is assignable
|
625
|
+
if expected.param_types.nil?
|
626
|
+
EMPTY_ARRAY
|
627
|
+
else
|
628
|
+
# NOTE: these tests are made in reverse as it is calling the callable that is constrained
|
629
|
+
# (it's lower bound), not its upper bound
|
630
|
+
param_errors = describe_argument_tuple(expected.param_types, actual.param_types, path)
|
631
|
+
if param_errors.empty?
|
632
|
+
# names are ignored, they are just information
|
633
|
+
# Blocks must be compatible
|
634
|
+
this_block_t = expected.block_type || PUndefType::DEFAULT
|
635
|
+
that_block_t = actual.block_type || PUndefType::DEFAULT
|
636
|
+
if that_block_t.assignable?(this_block_t)
|
637
|
+
EMPTY_ARRAY
|
638
|
+
else
|
639
|
+
[TypeMismatch.new(path + BlockPathElement.new, this_block_t, that_block_t)]
|
640
|
+
end
|
641
|
+
else
|
642
|
+
param_errors
|
643
|
+
end
|
644
|
+
end
|
645
|
+
else
|
646
|
+
[TypeMismatch.new(path, expected, actual)]
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
def describe_PAnyType(expected, actual, path)
|
651
|
+
expected.assignable?(actual) ? EMPTY_ARRAY : [TypeMismatch.new(path, expected, actual)]
|
652
|
+
end
|
653
|
+
|
654
|
+
def describe(expected, actual, path)
|
655
|
+
case expected
|
656
|
+
when PVariantType
|
657
|
+
describe_PVariantType(expected, actual, path)
|
658
|
+
when PStructType
|
659
|
+
describe_PStructType(expected, actual, path)
|
660
|
+
when PTupleType
|
661
|
+
describe_PTupleType(expected, actual, path)
|
662
|
+
when PCallableType
|
663
|
+
describe_PCallableType(expected, actual, path)
|
664
|
+
when POptionalType
|
665
|
+
describe_POptionalType(expected, actual, path)
|
666
|
+
when PPatternType
|
667
|
+
describe_PPatternType(expected, actual, path)
|
668
|
+
when PEnumType
|
669
|
+
describe_PEnumType(expected, actual, path)
|
670
|
+
else
|
671
|
+
describe_PAnyType(expected, actual, path)
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
# Produces a string for the signature(s)
|
676
|
+
#
|
677
|
+
# @api private
|
678
|
+
def signature_string(signature)
|
679
|
+
param_types = signature.type.param_types
|
680
|
+
param_names = signature.parameter_names
|
681
|
+
|
682
|
+
from, to = param_types.size_range
|
683
|
+
if from == 0 && to == 0
|
684
|
+
# No parameters function
|
685
|
+
return ''
|
686
|
+
end
|
687
|
+
|
688
|
+
required_count = from
|
689
|
+
types =
|
690
|
+
case param_types
|
691
|
+
when Puppet::Pops::Types::PTupleType
|
692
|
+
param_types.types
|
693
|
+
when Puppet::Pops::Types::PArrayType
|
694
|
+
[param_types.element_type]
|
695
|
+
end
|
696
|
+
tc = Puppet::Pops::Types::TypeCalculator.singleton
|
697
|
+
|
698
|
+
# join type with names (types are always present, names are optional)
|
699
|
+
# separate entries with comma
|
700
|
+
#
|
701
|
+
param_names = Array.new(types.size, '') if param_names.empty?
|
702
|
+
limit = param_names.size
|
703
|
+
result = param_names.each_with_index.map do |name, index|
|
704
|
+
type = types[index] || types[-1]
|
705
|
+
indicator = ''
|
706
|
+
if to == Float::INFINITY && index == limit - 1
|
707
|
+
# Last is a repeated_param.
|
708
|
+
indicator = from == param_names.size ? '+' : '*'
|
709
|
+
elsif optional(index, required_count)
|
710
|
+
indicator = '?'
|
711
|
+
type = type.optional_type if type.is_a?(Puppet::Pops::Types::POptionalType)
|
712
|
+
end
|
713
|
+
"#{tc.string(type)} #{name}#{indicator}"
|
714
|
+
end.join(', ')
|
715
|
+
|
716
|
+
# If there is a block, include it
|
717
|
+
case signature.type.block_type
|
718
|
+
when Puppet::Pops::Types::POptionalType
|
719
|
+
result << ', ' unless result == ''
|
720
|
+
result << "#{signature.type.block_type.optional_type} #{signature.block_name}?"
|
721
|
+
when Puppet::Pops::Types::PCallableType
|
722
|
+
result << ', ' unless result == ''
|
723
|
+
result << "#{signature.type.block_type} #{signature.block_name}"
|
724
|
+
when NilClass
|
725
|
+
# nothing
|
726
|
+
end
|
727
|
+
result
|
728
|
+
end
|
729
|
+
|
730
|
+
# Why oh why Ruby do you not have a standard Math.max ?
|
731
|
+
# @api private
|
732
|
+
def max(a, b)
|
733
|
+
a >= b ? a : b
|
734
|
+
end
|
735
|
+
|
736
|
+
# @api private
|
737
|
+
def optional(index, required_count)
|
738
|
+
count = index + 1
|
739
|
+
count > required_count
|
740
|
+
end
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|