From 260c1f4b92113a1da3b30562a11d20a79e5b08db Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Thu, 4 Dec 2014 22:33:15 +0100 Subject: [PATCH 1/2] Add new functions validate_numeric() and validate_integer(). --- README.markdown | 70 ++++++ .../parser/functions/validate_integer.rb | 128 ++++++++++ .../parser/functions/validate_numeric.rb | 90 +++++++ spec/functions/validate_integer_spec.rb | 219 ++++++++++++++++++ spec/functions/validate_numeric_spec.rb | 217 +++++++++++++++++ 5 files changed, 724 insertions(+) create mode 100644 lib/puppet/parser/functions/validate_integer.rb create mode 100644 lib/puppet/parser/functions/validate_numeric.rb create mode 100755 spec/functions/validate_integer_spec.rb create mode 100755 spec/functions/validate_numeric_spec.rb diff --git a/README.markdown b/README.markdown index 78839c6..69c5d3d 100644 --- a/README.markdown +++ b/README.markdown @@ -579,6 +579,76 @@ The first argument of this function should be the string to test, and the second *Type*: statement +* `validate_integer`: Validate that the first argument is an integer (or an array of integers). Abort catalog compilation if any of the checks fail. + + The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max. + + The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min. + If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check + if (all elements of) the first argument are greater or equal to the given minimum. + + It will fail if the first argument is not an integer or array of integers, and if arg 2 and arg 3 are not convertable to an integer. + + The following values will pass: + + ``` + validate_integer(1) + validate_integer(1, 2) + validate_integer(1, 1) + validate_integer(1, 2, 0) + validate_integer(2, 2, 2) + validate_integer(2, '', 0) + validate_integer(2, undef, 0) + $foo = undef + validate_integer(2, $foo, 0) + validate_integer([1,2,3,4,5], 6) + validate_integer([1,2,3,4,5], 6, 0) + ``` + + * Plus all of the above, but any combination of values passed as strings ('1' or "1"). + * Plus all of the above, but with (correct) combinations of negative integer values. + + The following values will fail, causing compilation to abort: + + ``` + validate_integer(true) + validate_integer(false) + validate_integer(7.0) + validate_integer({ 1 => 2 }) + $foo = undef + validate_integer($foo) + validate_integer($foobaridontexist) + + validate_integer(1, 0) + validate_integer(1, true) + validate_integer(1, '') + validate_integer(1, undef) + validate_integer(1, , 0) + validate_integer(1, 2, 3) + validate_integer(1, 3, 2) + validate_integer(1, 3, true) + ``` + + * Plus all of the above, but any combination of values passed as strings ('false' or "false"). + * Plus all of the above, but with incorrect combinations of negative integer values. + * Plus all of the above, but with non-integer crap in arrays or maximum / minimum argument. + + *Type*: statement + +* `validate_numeric`: Validate that the first argument is a numeric value (or an array of numeric values). Abort catalog compilation if any of the checks fail. + + The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max. + + The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min. + If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check + if (all elements of) the first argument are greater or equal to the given minimum. + + It will fail if the first argument is not a numeric (Integer or Float) or array of numerics, and if arg 2 and arg 3 are not convertable to a numeric. + + For passing and failing usage, see `validate_integer()`. It is all the same for validate_numeric, yet now floating point values are allowed, too. + + *Type*: statement + * `validate_re`: Performs simple validation of a string against one or more regular expressions. The first argument of this function should be the string to test, and the second argument should be a stringified regular expression (without the // delimiters) or an array of regular expressions. If none diff --git a/lib/puppet/parser/functions/validate_integer.rb b/lib/puppet/parser/functions/validate_integer.rb new file mode 100644 index 0000000..c12d676 --- /dev/null +++ b/lib/puppet/parser/functions/validate_integer.rb @@ -0,0 +1,128 @@ +module Puppet::Parser::Functions + + newfunction(:validate_integer, :doc => <<-'ENDHEREDOC') do |args| + Validate that the first argument is an integer (or an array of integers). Abort catalog compilation if any of the checks fail. + + The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max. + + The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min. + If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check + if (all elements of) the first argument are greater or equal to the given minimum. + + It will fail if the first argument is not an integer or array of integers, and if arg 2 and arg 3 are not convertable to an integer. + + The following values will pass: + + validate_integer(1) + validate_integer(1, 2) + validate_integer(1, 1) + validate_integer(1, 2, 0) + validate_integer(2, 2, 2) + validate_integer(2, '', 0) + validate_integer(2, undef, 0) + $foo = undef + validate_integer(2, $foo, 0) + validate_integer([1,2,3,4,5], 6) + validate_integer([1,2,3,4,5], 6, 0) + + Plus all of the above, but any combination of values passed as strings ('1' or "1"). + Plus all of the above, but with (correct) combinations of negative integer values. + + The following values will not: + + validate_integer(true) + validate_integer(false) + validate_integer(7.0) + validate_integer({ 1 => 2 }) + $foo = undef + validate_integer($foo) + validate_integer($foobaridontexist) + + validate_integer(1, 0) + validate_integer(1, true) + validate_integer(1, '') + validate_integer(1, undef) + validate_integer(1, , 0) + validate_integer(1, 2, 3) + validate_integer(1, 3, 2) + validate_integer(1, 3, true) + + Plus all of the above, but any combination of values passed as strings ('false' or "false"). + Plus all of the above, but with incorrect combinations of negative integer values. + Plus all of the above, but with non-integer crap in arrays or maximum / minimum argument. + + ENDHEREDOC + + # tell the user we need at least one, and optionally up to two other parameters + raise Puppet::ParseError, "validate_integer(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless args.length > 0 and args.length < 4 + + input, max, min = *args + + # check maximum parameter + if args.length > 1 + max = max.to_s + # allow max to be empty (or undefined) if we have a minimum set + if args.length > 2 and max == '' + max = nil + else + begin + max = Integer(max) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected second argument to be unset or an Integer, got #{max}:#{max.class}" + end + end + else + max = nil + end + + # check minimum parameter + if args.length > 2 + begin + min = Integer(min.to_s) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected third argument to be unset or an Integer, got #{min}:#{min.class}" + end + else + min = nil + end + + # ensure that min < max + if min and max and min > max + raise Puppet::ParseError, "validate_integer(): Expected second argument to be larger than third argument, got #{max} < #{min}" + end + + # create lamba validator function + validator = lambda do |num| + # check input < max + if max and num > max + raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}." + end + # check input > min (this will only be checked if no exception has been raised before) + if min and num < min + raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}." + end + end + + # if this is an array, handle it. + case input + when Array + # check every element of the array + input.each_with_index do |arg, pos| + begin + arg = Integer(arg.to_s) + validator.call(arg) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected element at array position #{pos} to be an Integer, got #{arg.class}" + end + end + # check the input. this will also fail any stuff other than pure, shiny integers + else + begin + input = Integer(input.to_s) + validator.call(input) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}" + end + end + end +end diff --git a/lib/puppet/parser/functions/validate_numeric.rb b/lib/puppet/parser/functions/validate_numeric.rb new file mode 100644 index 0000000..27eec30 --- /dev/null +++ b/lib/puppet/parser/functions/validate_numeric.rb @@ -0,0 +1,90 @@ +module Puppet::Parser::Functions + + newfunction(:validate_numeric, :doc => <<-'ENDHEREDOC') do |args| + Validate that the first argument is a numeric value (or an array of numeric values). Abort catalog compilation if any of the checks fail. + + The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max. + + The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min. + If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check + if (all elements of) the first argument are greater or equal to the given minimum. + + It will fail if the first argument is not a numeric (Integer or Float) or array of numerics, and if arg 2 and arg 3 are not convertable to a numeric. + + For passing and failing usage, see `validate_integer()`. It is all the same for validate_numeric, yet now floating point values are allowed, too. + + ENDHEREDOC + + # tell the user we need at least one, and optionally up to two other parameters + raise Puppet::ParseError, "validate_numeric(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless args.length > 0 and args.length < 4 + + input, max, min = *args + + # check maximum parameter + if args.length > 1 + max = max.to_s + # allow max to be empty (or undefined) if we have a minimum set + if args.length > 2 and max == '' + max = nil + else + begin + max = Float(max) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected second argument to be unset or a Numeric, got #{max}:#{max.class}" + end + end + else + max = nil + end + + # check minimum parameter + if args.length > 2 + begin + min = Float(min.to_s) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected third argument to be unset or a Numeric, got #{min}:#{min.class}" + end + else + min = nil + end + + # ensure that min < max + if min and max and min > max + raise Puppet::ParseError, "validate_numeric(): Expected second argument to be larger than third argument, got #{max} < #{min}" + end + + # create lamba validator function + validator = lambda do |num| + # check input < max + if max and num > max + raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}." + end + # check input > min (this will only be checked if no exception has been raised before) + if min and num < min + raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}." + end + end + + # if this is an array, handle it. + case input + when Array + # check every element of the array + input.each_with_index do |arg, pos| + begin + arg = Float(arg.to_s) + validator.call(arg) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected element at array position #{pos} to be a Numeric, got #{arg.class}" + end + end + # check the input. this will also fail any stuff other than pure, shiny integers + else + begin + input = Float(input.to_s) + validator.call(input) + rescue TypeError, ArgumentError + raise Puppet::ParseError, "validate_numeric(): Expected first argument to be a Numeric or Array, got #{input.class}" + end + end + end +end diff --git a/spec/functions/validate_integer_spec.rb b/spec/functions/validate_integer_spec.rb new file mode 100755 index 0000000..dff3415 --- /dev/null +++ b/spec/functions/validate_integer_spec.rb @@ -0,0 +1,219 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe Puppet::Parser::Functions.function(:validate_integer) do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + describe 'when calling validate_integer from puppet without any argument or to many' do + it "should not compile when no argument is passed" do + Puppet[:code] = "validate_integer()" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /Wrong number of arguments/) + end + it "should not compile when more than three arguments are passed" do + Puppet[:code] = "validate_integer(1, 1, 1, 1)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /Wrong number of arguments/) + end + end + + describe 'when calling validate_integer from puppet only with input' do + %w{ 1 -1 }.each do |the_number| + it "should compile when #{the_number} is an encapsulated integer" do + Puppet[:code] = "validate_integer('#{the_number}')" + scope.compiler.compile + end + it "should compile when #{the_number} is an bare integer" do + Puppet[:code] = "validate_integer(#{the_number})" + scope.compiler.compile + end + end + + %w{ [1,2,3,4,5] ['1','2','3','4','5'] }.each do |the_number| + it "should compile when multiple Integer arguments are passed in an Array" do + Puppet[:code] = "validate_integer(#{the_number})" + scope.compiler.compile + end + end + + %w{ true false iAmAString 1test 7.0 -7.0 }.each do |the_number| + it "should not compile when #{the_number} is in a string" do + Puppet[:code] = "validate_integer('#{the_number}')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be an Integer/) + end + + it "should not compile when #{the_number} is a bare word" do + Puppet[:code] = "validate_integer(#{the_number})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be an Integer/) + end + end + + it "should not compile when an Integer is part of a larger String" do + Puppet[:code] = "validate_integer('1 test')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be an Integer/) + end + + it "should not compile when an Array with a non-Integer value is passed" do + Puppet[:code] = "validate_integer([1, '-7.0'])" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /at array position 1 to be an Integer/) + end + + it "should not compile when a Hash is passed" do + Puppet[:code] = "validate_integer({ 1 => 2 })" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be an Integer or Array/) + end + + it "should not compile when an explicitly undef variable is passed" do + Puppet[:code] = <<-'ENDofPUPPETcode' + $foo = undef + validate_integer($foo) + ENDofPUPPETcode + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be an Integer/) + end + + it "should not compile when an undefined variable is passed" do + Puppet[:code] = <<-'ENDofPUPPETcode' + validate_integer($foobarbazishouldnotexist) + ENDofPUPPETcode + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be an Integer/) + end + end + + describe 'when calling validate_integer from puppet with input and a maximum' do + max = 10 + %w{ 1 -1 }.each do |the_number| + it "should compile when #{the_number} is lower than a maximum of #{max}" do + Puppet[:code] = "validate_integer(#{the_number},#{max})" + scope.compiler.compile + end + end + + it "should compile when an Integer is equal the maximum" do + Puppet[:code] = "validate_integer(#{max},#{max})" + scope.compiler.compile + end + + it "should not compile when #{max+1} is greater than a maximum of #{max}" do + Puppet[:code] = "validate_integer(#{max+1},#{max})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be smaller or equal to/) + end + + %w{ [-10,1,2,3,4,5,10] ['-10','1','2','3','4','5','10'] }.each do |the_number| + it "should compile when each element of #{the_number} is lower than a maximum of #{max}" do + Puppet[:code] = "validate_integer(#{the_number},#{max})" + scope.compiler.compile + end + end + + it "should not compile when an element of an Array [-10,1,2,3,4,5,#{max+1}] is greater than a maximum of #{max}" do + Puppet[:code] = "validate_integer([-10,1,2,3,4,5,#{max+1}],#{max})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be smaller or equal to/) + end + + %w{ true false iAmAString 1test 7.0 -7.0 }.each do |the_max| + it "should not compile when a non-Integer maximum #{the_max}, encapsulated in a String, is passed" do + Puppet[:code] = "validate_integer(1,'#{the_max}')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + + it "should not compile when a non-Integer maximum #{the_max} bare word is passed" do + Puppet[:code] = "validate_integer(1,#{the_max})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + end + + it "should not compile when an explicitly undefined variable is passed as maximum and no minimum is passed" do + Puppet[:code] = <<-'ENDofPUPPETcode' + $foo = undef + validate_integer(10, $foo) + ENDofPUPPETcode + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + it "should not compile when an explicitly undef is passed as maximum and no minimum is passed" do + Puppet[:code] = "validate_integer(10, undef)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + it "should not compile when an empty string is passed as maximum and no minimum is passed" do + Puppet[:code] = "validate_integer(10, '')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + it "should not compile when an undefined variable for a maximum is passed" do + Puppet[:code] = "validate_integer(10, $foobarbazishouldnotexist)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + end + + describe 'when calling validate_integer from puppet with input, a maximum and a minimum' do + it "should not compile when a minimum larger than maximum is passed" do + Puppet[:code] = "validate_integer(1,1,2)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /second argument to be larger than third argument/) + end + + max = 10 + min = -10 + %w{ 1 -1 }.each do |the_number| + it "should compile when each element of #{the_number} is within a range from #{min} to #{max}" do + Puppet[:code] = "validate_integer(#{the_number},#{max},#{min})" + scope.compiler.compile + end + end + + it "should compile when an Integer is equal the minimum" do + Puppet[:code] = "validate_integer(#{min},#{max},#{min})" + scope.compiler.compile + end + + it "should compile when an Integer is equal the minimum and maximum" do + Puppet[:code] = "validate_integer(#{max},#{max},#{max})" + scope.compiler.compile + end + + it "should compile when an empty maximum is passed and the Integer is greater than the minimum" do + Puppet[:code] = "validate_integer(#{max},'',#{min})" + scope.compiler.compile + end + it "should compile when an explicitly undefined maximum is passed and the Integer is greater than the minimum" do + Puppet[:code] = "validate_integer(#{max},undef,#{min})" + scope.compiler.compile + end + it "should compile when an explicitly undefined variable is passed for maximum and the Integer is greater than the minimum" do + Puppet[:code] = <<-"ENDofPUPPETcode" + $foo = undef + validate_integer(#{max}, $foo, #{min}) + ENDofPUPPETcode + scope.compiler.compile + end + it "should not compile when no maximum value is given and the Integer is greater than the minimum" do + Puppet[:code] = "validate_integer(#{max},,#{min})" + expect { scope.compiler.compile }.to raise_error(Puppet::Error, /Syntax error at ','/) + end + + it "should not compile when #{min-1} is lower than a minimum of #{min}" do + Puppet[:code] = "validate_integer(#{min-1},#{max},#{min})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be greater or equal to/) + end + + %w{ [-10,1,2,3,4,5,10] ['-10','1','2','3','4','5','10'] }.each do |the_number| + it "should compile when each element of #{the_number} is within a range from #{min} to #{max}" do + Puppet[:code] = "validate_integer(#{the_number},#{max},#{min})" + scope.compiler.compile + end + end + + it "should not compile when an element of an Array [#{min-1},1,2,3,4,5,10] is lower than a minimum of #{min}" do + Puppet[:code] = "validate_integer([#{min-1},1,2,3,4,5,10],#{max},#{min})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be greater or equal to/) + end + + %w{ true false iAmAString 1test 7.0 -7.0 }.each do |the_min| + it "should not compile when a non-Integer minimum #{the_min}, encapsulated in a String, is passed" do + Puppet[:code] = "validate_integer(1,#{max},'#{the_min}')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + + it "should not compile when a non-Integer minimum #{the_min} bare word is passed" do + Puppet[:code] = "validate_integer(1,#{max},#{the_min})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or an Integer/) + end + end + end +end diff --git a/spec/functions/validate_numeric_spec.rb b/spec/functions/validate_numeric_spec.rb new file mode 100755 index 0000000..c8b0e4d --- /dev/null +++ b/spec/functions/validate_numeric_spec.rb @@ -0,0 +1,217 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe Puppet::Parser::Functions.function(:validate_numeric) do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + describe 'when calling validate_numeric from puppet without any argument or to many' do + it "should not compile when no argument is passed" do + Puppet[:code] = "validate_numeric()" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /Wrong number of arguments/) + end + it "should not compile when more than three arguments are passed" do + Puppet[:code] = "validate_numeric(1, 1, 1, 1)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /Wrong number of arguments/) + end + end + + describe 'when calling validate_numeric from puppet only with input' do + %w{ 1 -1 1.0 -1.0 }.each do |the_number| + it "should compile when #{the_number} is an encapsulated numeric" do + Puppet[:code] = "validate_numeric('#{the_number}')" + scope.compiler.compile + end + it "should compile when #{the_number} is a bare numeric" do + Puppet[:code] = "validate_numeric(#{the_number})" + scope.compiler.compile + end + end + + %w{ [1,2,3,4,5] ['1','2','3','4','5'] [1.1,2.2,3.3,4.4,5.5] ['1.1','2.2','3.3','4.4','5.5'] }.each do |the_number| + it "should compile when multiple Numeric arguments are passed in an Array" do + Puppet[:code] = "validate_numeric(#{the_number})" + scope.compiler.compile + end + end + + %w{ true false iAmAString 1test }.each do |the_number| + it "should not compile when #{the_number} is in a string" do + Puppet[:code] = "validate_numeric('#{the_number}')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be a Numeric/) + end + + it "should not compile when #{the_number} is a bare word" do + Puppet[:code] = "validate_numeric(#{the_number})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be a Numeric/) + end + end + + it "should not compile when a Numeric is part of a larger String" do + Puppet[:code] = "validate_numeric('1.0 test')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be a Numeric/) + end + + it "should not compile when an Array with a non-Numeric value is passed" do + Puppet[:code] = "validate_numeric([1, 'test'])" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /at array position 1 to be a Numeric/) + end + + it "should not compile when a Hash is passed" do + Puppet[:code] = "validate_numeric({ 1 => 2 })" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be a Numeric or Array/) + end + + it "should not compile when an explicitly undef variable is passed" do + Puppet[:code] = <<-'ENDofPUPPETcode' + $foo = undef + validate_numeric($foo) + ENDofPUPPETcode + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be a Numeric/) + end + + it "should not compile when an undefined variable is passed" do + Puppet[:code] = 'validate_numeric($foobarbazishouldnotexist)' + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be a Numeric/) + end + end + + describe 'when calling validate_numeric from puppet with input and a maximum' do + max = 10 + %w{ 1 -1 1.0 -1.0 }.each do |the_number| + it "should compile when #{the_number} is lower than a maximum of #{max}" do + Puppet[:code] = "validate_numeric(#{the_number},#{max})" + scope.compiler.compile + end + end + + it "should compile when a Numeric is equal the maximum" do + Puppet[:code] = "validate_numeric(#{max},#{max})" + scope.compiler.compile + end + + it "should not compile when #{max+1} is greater than a maximum of #{max}" do + Puppet[:code] = "validate_numeric(#{max+1},#{max})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be smaller or equal to/) + end + + %w{ [-10,1,2,3,4,5,10] ['-10','1','2','3','4','5','10'] }.each do |the_number| + it "should compile when each element of #{the_number} is lower than a maximum of #{max}" do + Puppet[:code] = "validate_numeric(#{the_number},#{max})" + scope.compiler.compile + end + end + + it "should not compile when an element of an Array [-10,1,2,3,4,5,#{max+1}] is greater than a maximum of #{max}" do + Puppet[:code] = "validate_numeric([-10,1,2,3,4,5,#{max+1}],#{max})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be smaller or equal to/) + end + + %w{ true false iAmAString 1test }.each do |the_max| + it "should not compile when a non-Numeric maximum #{the_max}, encapsulated in a String, is passed" do + Puppet[:code] = "validate_numeric(1,'#{the_max}')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + + it "should not compile when a non-Numeric maximum #{the_max} bare word is passed" do + Puppet[:code] = "validate_numeric(1,#{the_max})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + end + + it "should not compile when an explicitly undefined variable is passed as maximum and no minimum is passed" do + Puppet[:code] = <<-'ENDofPUPPETcode' + $foo = undef + validate_numeric(10, $foo) + ENDofPUPPETcode + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + it "should not compile when an explicitly undef is passed as maximum and no minimum is passed" do + Puppet[:code] = "validate_numeric(10, undef)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + it "should not compile when an empty string is passed as maximum and no minimum is passed" do + Puppet[:code] = "validate_numeric(10, '')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + it "should not compile when an undefined variable for a maximum is passed" do + Puppet[:code] = "validate_numeric(10, $foobarbazishouldnotexist)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + end + + describe 'when calling validate_numeric from puppet with input, a maximum and a minimum' do + it "should not compile when a minimum larger than maximum is passed" do + Puppet[:code] = "validate_numeric(1,1,2)" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /second argument to be larger than third argument/) + end + + max = 10 + min = -10 + %w{ 1 -1 }.each do |the_number| + it "should compile when each element of #{the_number} is within a range from #{min} to #{max}" do + Puppet[:code] = "validate_numeric(#{the_number},#{max},#{min})" + scope.compiler.compile + end + end + + it "should compile when a Numeric is equal the minimum" do + Puppet[:code] = "validate_numeric(#{min},#{max},#{min})" + scope.compiler.compile + end + + it "should compile when a Numeric is equal the minimum and maximum" do + Puppet[:code] = "validate_numeric(#{max},#{max},#{max})" + scope.compiler.compile + end + + it "should compile when an empty maximum is passed and the Numeric is greater than the minimum" do + Puppet[:code] = "validate_numeric(#{max}.1,'',#{min})" + scope.compiler.compile + end + it "should compile when an explicitly undefined maximum is passed and the Numeric is greater than the minimum" do + Puppet[:code] = "validate_numeric(#{max}.1,undef,#{min})" + scope.compiler.compile + end + it "should compile when an explicitly undefined variable is passed for maximum and the Numeric is greater than the minimum" do + Puppet[:code] = <<-"ENDofPUPPETcode" + $foo = undef + validate_numeric(#{max}.1, $foo, #{min}) + ENDofPUPPETcode + scope.compiler.compile + end + it "should not compile when no maximum value is given and the Numeric is greater than the minimum" do + Puppet[:code] = "validate_numeric(#{max}.1,,#{min})" + expect { scope.compiler.compile }.to raise_error(Puppet::Error, /Syntax error at ','/) + end + + it "should not compile when #{min-1} is lower than a minimum of #{min}" do + Puppet[:code] = "validate_numeric(#{min-1.0},#{max},#{min})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be greater or equal to/) + end + + %w{ [-10,1,2,3,4,5,10] ['-10.0','1','2','3','4','5','10.0'] }.each do |the_number| + it "should compile when each element of #{the_number} is within a range from #{min} to #{max}" do + Puppet[:code] = "validate_numeric(#{the_number},#{max},#{min})" + scope.compiler.compile + end + end + + it "should not compile when an element of an Array [#{min-1.1},1,2,3,4,5,10.0] is lower than a minimum of #{min}" do + Puppet[:code] = "validate_numeric([#{min-1},1,2,3,4,5,10],#{max},#{min})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be greater or equal to/) + end + + %w{ true false iAmAString 1test }.each do |the_min| + it "should not compile when a non-Numeric minimum #{the_min}, encapsulated in a String, is passed" do + Puppet[:code] = "validate_numeric(1,#{max},'#{the_min}')" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + + it "should not compile when a non-Numeric minimum #{the_min} bare word is passed" do + Puppet[:code] = "validate_numeric(1,#{max},#{the_min})" + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /to be unset or a Numeric/) + end + end + end +end From 305342782998e36e48e1011d12a37c523b838bec Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Fri, 5 Dec 2014 08:48:10 +0100 Subject: [PATCH 2/2] Fixing ruby 1.8 support. --- lib/puppet/parser/functions/validate_integer.rb | 3 +++ lib/puppet/parser/functions/validate_numeric.rb | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/puppet/parser/functions/validate_integer.rb b/lib/puppet/parser/functions/validate_integer.rb index c12d676..995f8db 100644 --- a/lib/puppet/parser/functions/validate_integer.rb +++ b/lib/puppet/parser/functions/validate_integer.rb @@ -115,6 +115,9 @@ module Puppet::Parser::Functions raise Puppet::ParseError, "validate_integer(): Expected element at array position #{pos} to be an Integer, got #{arg.class}" end end + # for the sake of compatibility with ruby 1.8, we need extra handling of hashes + when Hash + raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}" # check the input. this will also fail any stuff other than pure, shiny integers else begin diff --git a/lib/puppet/parser/functions/validate_numeric.rb b/lib/puppet/parser/functions/validate_numeric.rb index 27eec30..d2e4d16 100644 --- a/lib/puppet/parser/functions/validate_numeric.rb +++ b/lib/puppet/parser/functions/validate_numeric.rb @@ -77,6 +77,9 @@ module Puppet::Parser::Functions raise Puppet::ParseError, "validate_numeric(): Expected element at array position #{pos} to be a Numeric, got #{arg.class}" end end + # for the sake of compatibility with ruby 1.8, we need extra handling of hashes + when Hash + raise Puppet::ParseError, "validate_integer(): Expected first argument to be a Numeric or Array, got #{input.class}" # check the input. this will also fail any stuff other than pure, shiny integers else begin