|
1 | 1 | require 'spec_helper'
|
2 | 2 | require 'puppet/pops'
|
3 | 3 | require 'puppet_spec/compiler'
|
| 4 | +require 'puppet_spec/files' |
| 5 | +require 'puppet/loaders' |
4 | 6 |
|
5 | 7 | module Puppet::Pops
|
6 | 8 | module Types
|
7 | 9 |
|
8 | 10 | describe 'the type mismatch describer' do
|
9 |
| - include PuppetSpec::Compiler |
| 11 | + include PuppetSpec::Compiler, PuppetSpec::Files |
| 12 | + |
| 13 | + context 'with deferred functions' do |
| 14 | + let(:env_name) { 'spec' } |
| 15 | + let(:code_dir) { Puppet[:environmentpath] } |
| 16 | + let(:env_dir) { File.join(code_dir, env_name) } |
| 17 | + let(:env) { Puppet::Node::Environment.create(env_name.to_sym, [File.join(populated_code_dir, env_name, 'modules')]) } |
| 18 | + let(:node) { Puppet::Node.new('fooname', environment: env) } |
| 19 | + let(:populated_code_dir) do |
| 20 | + dir_contained_in(code_dir, env_name => env_content) |
| 21 | + PuppetSpec::Files.record_tmp(env_dir) |
| 22 | + code_dir |
| 23 | + end |
| 24 | + |
| 25 | + let(:env_content) { |
| 26 | + { |
| 27 | + 'lib' => { |
| 28 | + 'puppet' => { |
| 29 | + 'functions' => { |
| 30 | + 'string_return.rb' => <<-RUBY.unindent, |
| 31 | + Puppet::Functions.create_function(:string_return) do |
| 32 | + dispatch :string_return do |
| 33 | + param 'String', :arg1 |
| 34 | + return_type 'String' |
| 35 | + end |
| 36 | + def string_return(arg1) |
| 37 | + arg1 |
| 38 | + end |
| 39 | + end |
| 40 | + RUBY |
| 41 | + 'variant_return.rb' => <<-RUBY.unindent, |
| 42 | + Puppet::Functions.create_function(:variant_return) do |
| 43 | + dispatch :variant_return do |
| 44 | + param 'String', :arg1 |
| 45 | + return_type 'Variant[Integer,Float]' |
| 46 | + end |
| 47 | + def variant_return(arg1) |
| 48 | + arg1 |
| 49 | + end |
| 50 | + end |
| 51 | + RUBY |
| 52 | + 'no_return.rb' => <<-RUBY.unindent, |
| 53 | + Puppet::Functions.create_function(:no_return) do |
| 54 | + dispatch :no_return do |
| 55 | + param 'String', :arg1 |
| 56 | + end |
| 57 | + def variant_return(arg1) |
| 58 | + arg1 |
| 59 | + end |
| 60 | + end |
| 61 | + RUBY |
| 62 | + } |
| 63 | + } |
| 64 | + } |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | + before(:each) do |
| 69 | + Puppet.push_context(:loaders => Puppet::Pops::Loaders.new(env)) |
| 70 | + end |
| 71 | + |
| 72 | + after(:each) do |
| 73 | + Puppet.pop_context |
| 74 | + end |
| 75 | + |
| 76 | + it 'will compile when the parameter type matches the function return_type' do |
| 77 | + code = <<-CODE |
| 78 | + $d = Deferred("string_return", ['/a/non/existing/path']) |
| 79 | + class testclass(String $classparam) { |
| 80 | + } |
| 81 | + class { 'testclass': |
| 82 | + classparam => $d |
| 83 | + } |
| 84 | + CODE |
| 85 | + expect { eval_and_collect_notices(code, node) }.to_not raise_error |
| 86 | + end |
| 87 | + |
| 88 | + it "will compile when a Variant parameter's types matches the return type" do |
| 89 | + code = <<-CODE |
| 90 | + $d = Deferred("string_return", ['/a/non/existing/path']) |
| 91 | + class testclass(Variant[String, Float] $classparam) { |
| 92 | + } |
| 93 | + class { 'testclass': |
| 94 | + classparam => $d |
| 95 | + } |
| 96 | + CODE |
| 97 | + expect { eval_and_collect_notices(code, node) }.to_not raise_error |
| 98 | + end |
| 99 | + |
| 100 | + it "will compile with a union of a Variant parameters' types and Variant return types" do |
| 101 | + code = <<-CODE |
| 102 | + $d = Deferred("variant_return", ['/a/non/existing/path']) |
| 103 | + class testclass(Variant[Any,Float] $classparam) { |
| 104 | + } |
| 105 | + class { 'testclass': |
| 106 | + classparam => $d |
| 107 | + } |
| 108 | + CODE |
| 109 | + expect { eval_and_collect_notices(code, node) }.to_not raise_error |
| 110 | + end |
| 111 | + |
| 112 | + it 'will warn when there is no defined return_type for the function definition' do |
| 113 | + code = <<-CODE |
| 114 | + $d = Deferred("no_return", ['/a/non/existing/path']) |
| 115 | + class testclass(Variant[String,Boolean] $classparam) { |
| 116 | + } |
| 117 | + class { 'testclass': |
| 118 | + classparam => $d |
| 119 | + } |
| 120 | + CODE |
| 121 | + expect(Puppet).to receive(:warn_once).with(anything, anything, /.+function no_return has no return_type/).at_least(:once) |
| 122 | + expect { eval_and_collect_notices(code, node) }.to_not raise_error |
| 123 | + end |
| 124 | + |
| 125 | + it 'will report a mismatch between a deferred function return type and class parameter value' do |
| 126 | + code = <<-CODE |
| 127 | + $d = Deferred("string_return", ['/a/non/existing/path']) |
| 128 | + class testclass(Integer $classparam) { |
| 129 | + } |
| 130 | + class { 'testclass': |
| 131 | + classparam => $d |
| 132 | + } |
| 133 | + CODE |
| 134 | + expect { eval_and_collect_notices(code, node) }.to raise_error(Puppet::Error, /.+'classparam' expects an Integer value, got String/) |
| 135 | + end |
| 136 | + |
| 137 | + it 'will report an argument error when no matching arity is found' do |
| 138 | + code = <<-CODE |
| 139 | + $d = Deferred("string_return", ['/a/non/existing/path', 'second-invalid-arg']) |
| 140 | + class testclass(Integer $classparam) { |
| 141 | + } |
| 142 | + class { 'testclass': |
| 143 | + classparam => $d |
| 144 | + } |
| 145 | + CODE |
| 146 | + expect { eval_and_collect_notices(code,node) }.to raise_error(Puppet::Error, /.+ No matching arity found for string_return/) |
| 147 | + end |
| 148 | + |
| 149 | + it 'will error with no matching Variant class parameters and return_type' do |
| 150 | + code = <<-CODE |
| 151 | + $d = Deferred("string_return", ['/a/non/existing/path']) |
| 152 | + class testclass(Variant[Integer,Float] $classparam) { |
| 153 | + } |
| 154 | + class { 'testclass': |
| 155 | + classparam => $d |
| 156 | + } |
| 157 | + CODE |
| 158 | + expect { eval_and_collect_notices(code,node) }.to raise_error(Puppet::Error, /.+'classparam' expects a value of type Integer or Float, got String/) |
| 159 | + end |
| 160 | + |
| 161 | + # This test exposes a shortcoming in the #message function for Puppet::Pops::Type::TypeMismatch |
| 162 | + # where the `actual` is not introspected for the list of Variant types, so the error message |
| 163 | + # shows that the list of expected types does not match Variant, instead of a list of actual types. |
| 164 | + it 'will error with no matching Variant class parameters and Variant return_type' do |
| 165 | + code = <<-CODE |
| 166 | + $d = Deferred("variant_return", ['/a/non/existing/path']) |
| 167 | + class testclass(Variant[String,Boolean] $classparam) { |
| 168 | + } |
| 169 | + class { 'testclass': |
| 170 | + classparam => $d |
| 171 | + } |
| 172 | + CODE |
| 173 | + expect { eval_and_collect_notices(code, node) }.to raise_error(Puppet::Error, /.+'classparam' expects a value of type String or Boolean, got Variant/) |
| 174 | + end |
| 175 | + end |
10 | 176 |
|
11 | 177 | it 'will report a mismatch between a hash and a struct with details' do
|
12 | 178 | code = <<-CODE
|
|
0 commit comments