(#12357) Add ability to display an error message from validate_re

I've seen a number of times the following error displayed to the end
user:

    validate_re(): "" does not match "^true$|^false$" at /p/t/f.pp:40

This is an absolutely horrific error message.  I'm to blame for it.
Users stumble over this quite often and they shouldn't have to go read
the code to sort out what's happening.

This patch makes an effort to fix the problem by adding a third,
optional, argument to validate_re().  This third argument will be the
message thrown back in the exception which will be displayed to the end
user.

This sets the stage for nicer error messages coming from modules we
write.

This patch is backwards compatible but is a new feature.
This commit is contained in:
Jeff McCune 2012-03-07 15:01:11 -08:00
parent 898ff80fa7
commit 41b07232e4
2 changed files with 90 additions and 5 deletions

View file

@ -1,5 +1,4 @@
module Puppet::Parser::Functions
newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args|
Perform simple validation of a string against one or more regular
expressions. The first argument of this function should be a string to
@ -8,6 +7,9 @@ module Puppet::Parser::Functions
of the regular expressions match the string passed in, compilation will
abort with a parse error.
If a third argument is specified, this will be the error message raised and
seen by the user.
The following strings will validate against the regular expressions:
validate_re('one', '^one$')
@ -17,17 +19,20 @@ module Puppet::Parser::Functions
validate_re('one', [ '^two', '^three' ])
A helpful error message can be returned like this:
validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
ENDHEREDOC
if args.length != 2 then
raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2)")
if (args.length < 2) or (args.length > 3) then
raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)")
end
msg = "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
raise Puppet::ParseError, (msg) unless args[1].any? do |re_str|
args[0] =~ Regexp.compile(re_str)
end
end
end

View file

@ -0,0 +1,80 @@
require 'spec_helper'
describe Puppet::Parser::Functions.function(:validate_re) do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
let(:scope) do
scope = Puppet::Parser::Scope.new
end
# The subject of these examplres is the method itself.
subject do
scope.method :function_validate_re
end
context 'Using Puppet::Parser::Scope.new' do
describe 'Garbage inputs' do
inputs = [
[ nil ],
[ [ nil ] ],
[ { 'foo' => 'bar' } ],
[ { } ],
[ '' ],
[ "one", "one", "MSG to User", "4th arg" ],
]
inputs.each do |input|
it "validate_re(#{input.inspect}) should fail" do
expect { subject.call [input] }.to raise_error Puppet::ParseError
end
end
end
describe 'Valid inputs' do
inputs = [
[ '/full/path/to/something', '^/full' ],
[ '/full/path/to/something', 'full' ],
[ '/full/path/to/something', ['full', 'absent'] ],
[ '/full/path/to/something', ['full', 'absent'], 'Message to the user' ],
]
inputs.each do |input|
it "validate_re(#{input.inspect}) should not fail" do
expect { subject.call input }.not_to raise_error
end
end
end
describe "Valid inputs which should raise an exception without a message" do
# The intent here is to make sure valid inputs raise exceptions when they
# don't specify an error message to display. This is the behvior in
# 2.2.x and prior.
inputs = [
[ "hello", [ "bye", "later", "adios" ] ],
[ "greetings", "salutations" ],
]
inputs.each do |input|
it "validate_re(#{input.inspect}) should fail" do
expect { subject.call input }.to raise_error /validate_re.*?does not match/
end
end
end
describe "Nicer Error Messages" do
# The intent here is to make sure the function returns the 3rd argument
# in the exception thrown
inputs = [
[ "hello", [ "bye", "later", "adios" ], "MSG to User" ],
[ "greetings", "salutations", "Error, greetings does not match salutations" ],
]
inputs.each do |input|
it "validate_re(#{input.inspect}) should fail" do
expect { subject.call input }.to raise_error /#{input[2]}/
end
end
end
end
end