summaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
authorBrice Figureau <brice-puppet@daysofwonder.com>2009-07-28 19:56:34 +0200
committerJames Turnbull <james@lovedthanlost.net>2009-08-01 11:15:29 +1000
commit3ebf148bf3d82d25e690aec6ec49975e0837e604 (patch)
treeb94504992e575d8b4181440b90bdf510cf67ef8c /spec
parentef68967f2b72e609a9d69e53771a61fd9f522149 (diff)
downloadpuppet-3ebf148bf3d82d25e690aec6ec49975e0837e604.tar.gz
puppet-3ebf148bf3d82d25e690aec6ec49975e0837e604.tar.xz
puppet-3ebf148bf3d82d25e690aec6ec49975e0837e604.zip
Enhance selector and case statements to match with regexp
The case and selector statements define ephemeral vars, like 'if'. Usage: case statement: $var = "foobar" case $var { "foo": { notify { "got a foo": } } /(.*)bar$/: { notify{ "hey we got a $1": } } } and for selector: $val = $test ? { /^match.*$/ => "matched", default => "default" } Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
Diffstat (limited to 'spec')
-rwxr-xr-xspec/unit/parser/ast/casestatement.rb143
-rwxr-xr-xspec/unit/parser/ast/selector.rb156
2 files changed, 299 insertions, 0 deletions
diff --git a/spec/unit/parser/ast/casestatement.rb b/spec/unit/parser/ast/casestatement.rb
new file mode 100755
index 000000000..554e295bc
--- /dev/null
+++ b/spec/unit/parser/ast/casestatement.rb
@@ -0,0 +1,143 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::CaseStatement do
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ end
+
+ describe "when evaluating" do
+
+ before :each do
+ @test = stub 'test'
+ @test.stubs(:safeevaluate).with(@scope).returns("value")
+
+ @option1 = stub 'option1', :eachopt => nil, :default? => false
+ @option2 = stub 'option2', :eachopt => nil, :default? => false
+
+ @options = stub 'options'
+ @options.stubs(:each).multiple_yields(@option1, @option2)
+
+ @casestmt = Puppet::Parser::AST::CaseStatement.new :test => @test, :options => @options
+ end
+
+ it "should evaluate test" do
+ @test.expects(:safeevaluate).with(@scope)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should downcase the evaluated test value if allowed" do
+ Puppet.stubs(:[]).with(:casesensitive).returns(false)
+ value = stub 'test'
+ @test.stubs(:safeevaluate).with(@scope).returns(value)
+
+ value.expects(:downcase)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should scan each option" do
+ @options.expects(:each).multiple_yields(@option1, @option2)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ describe "when scanning options" do
+ before :each do
+ @opval1 = stub_everything 'opval1'
+ @option1.stubs(:eachopt).yields(@opval1)
+
+ @opval2 = stub_everything 'opval2'
+ @option2.stubs(:eachopt).yields(@opval2)
+ end
+
+ it "should evaluate each sub-option" do
+ @option1.expects(:eachopt)
+ @option2.expects(:eachopt)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should evaluate first matching option" do
+ @opval2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true)
+ @option2.expects(:safeevaluate).with(@scope)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should evaluate_match with sensitive parameter" do
+ Puppet.stubs(:[]).with(:casesensitive).returns(true)
+ @opval1.expects(:evaluate_match).with { |*arg| arg[2][:sensitive] == true }
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should return the first matching evaluated option" do
+ @opval2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true)
+ @option2.stubs(:safeevaluate).with(@scope).returns(:result)
+
+ @casestmt.evaluate(@scope).should == :result
+ end
+
+ it "should evaluate the default option if none matched" do
+ @option1.stubs(:default?).returns(true)
+ @option1.expects(:safeevaluate).with(@scope)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should return the default evaluated option if none matched" do
+ @option1.stubs(:default?).returns(true)
+ @option1.stubs(:safeevaluate).with(@scope).returns(:result)
+
+ @casestmt.evaluate(@scope).should == :result
+ end
+
+ it "should return nil if nothing matched" do
+ @casestmt.evaluate(@scope).should be_nil
+ end
+
+ it "should match and set scope ephemeral variables" do
+ @opval1.expects(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should evaluate this regex option if it matches" do
+ @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+
+ @option1.expects(:safeevaluate).with(@scope)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should return this evaluated regex option if it matches" do
+ @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+ @option1.stubs(:safeevaluate).with(@scope).returns(:result)
+
+ @casestmt.evaluate(@scope).should == :result
+ end
+
+ it "should unset scope ephemeral variables after option evaluation" do
+ @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+ @option1.stubs(:safeevaluate).with(@scope).returns(:result)
+
+ @scope.expects(:unset_ephemeral_var)
+
+ @casestmt.evaluate(@scope)
+ end
+
+ it "should not leak ephemeral variables even if evaluation fails" do
+ @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+ @option1.stubs(:safeevaluate).with(@scope).raises
+
+ @scope.expects(:unset_ephemeral_var)
+
+ lambda { @casestmt.evaluate(@scope) }.should raise_error
+ end
+ end
+
+ end
+end
diff --git a/spec/unit/parser/ast/selector.rb b/spec/unit/parser/ast/selector.rb
new file mode 100755
index 000000000..8b0057784
--- /dev/null
+++ b/spec/unit/parser/ast/selector.rb
@@ -0,0 +1,156 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::Selector do
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ end
+
+ describe "when evaluating" do
+
+ before :each do
+ @param = stub 'param'
+ @param.stubs(:safeevaluate).with(@scope).returns("value")
+
+ @value1 = stub 'value1'
+ @param1 = stub_everything 'param1'
+ @param1.stubs(:safeevaluate).with(@scope).returns(@param1)
+ @param1.stubs(:respond_to?).with(:downcase).returns(false)
+ @value1.stubs(:param).returns(@param1)
+ @value1.stubs(:value).returns(@value1)
+
+ @value2 = stub 'value2'
+ @param2 = stub_everything 'param2'
+ @param2.stubs(:safeevaluate).with(@scope).returns(@param2)
+ @param2.stubs(:respond_to?).with(:downcase).returns(false)
+ @value2.stubs(:param).returns(@param2)
+ @value2.stubs(:value).returns(@value2)
+
+ @values = stub 'values', :instance_of? => true
+ @values.stubs(:each).multiple_yields(@value1, @value2)
+
+ @selector = Puppet::Parser::AST::Selector.new :param => @param, :values => @values
+ @selector.stubs(:fail)
+ end
+
+ it "should evaluate param" do
+ @param.expects(:safeevaluate).with(@scope)
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should downcase the evaluated param value if allowed" do
+ Puppet.stubs(:[]).with(:casesensitive).returns(false)
+ value = stub 'param'
+ @param.stubs(:safeevaluate).with(@scope).returns(value)
+
+ value.expects(:downcase)
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should scan each option" do
+ @values.expects(:each).multiple_yields(@value1, @value2)
+
+ @selector.evaluate(@scope)
+ end
+
+ describe "when scanning values" do
+ it "should evaluate first matching option" do
+ @param2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true)
+ @value2.expects(:safeevaluate).with(@scope)
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should return the first matching evaluated option" do
+ @param2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true)
+ @value2.stubs(:safeevaluate).with(@scope).returns(:result)
+
+ @selector.evaluate(@scope).should == :result
+ end
+
+ it "should evaluate the default option if none matched" do
+ @param1.stubs(:is_a?).with(Puppet::Parser::AST::Default).returns(true)
+ @value1.expects(:safeevaluate).with(@scope).returns(@param1)
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should return the default evaluated option if none matched" do
+ result = stub 'result'
+ @param1.stubs(:is_a?).with(Puppet::Parser::AST::Default).returns(true)
+ @value1.stubs(:safeevaluate).returns(result)
+
+ @selector.evaluate(@scope).should == result
+ end
+
+ it "should return nil if nothing matched" do
+ @selector.evaluate(@scope).should be_nil
+ end
+
+ it "should delegate matching to evaluate_match" do
+ @param1.expects(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should transmit the sensitive parameter to evaluate_match" do
+ Puppet.stubs(:[]).with(:casesensitive).returns(:sensitive)
+ @param1.expects(:evaluate_match).with { |*arg| arg[2][:sensitive] == :sensitive }
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should transmit the AST file and line to evaluate_match" do
+ @selector.file = :file
+ @selector.line = :line
+ @param1.expects(:evaluate_match).with { |*arg| arg[2][:file] == :file and arg[2][:line] == :line }
+
+ @selector.evaluate(@scope)
+ end
+
+
+ it "should evaluate the matching param" do
+ @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+
+ @value1.expects(:safeevaluate).with(@scope)
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should return this evaluated option if it matches" do
+ @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+ @value1.stubs(:safeevaluate).with(@scope).returns(:result)
+
+ @selector.evaluate(@scope).should == :result
+ end
+
+ it "should unset scope ephemeral variables after option evaluation" do
+ @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+ @value1.stubs(:safeevaluate).with(@scope).returns(:result)
+
+ @scope.expects(:unset_ephemeral_var)
+
+ @selector.evaluate(@scope)
+ end
+
+ it "should not leak ephemeral variables even if evaluation fails" do
+ @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true)
+ @value1.stubs(:safeevaluate).with(@scope).raises
+
+ @scope.expects(:unset_ephemeral_var)
+
+ lambda { @selector.evaluate(@scope) }.should raise_error
+ end
+
+ it "should fail if there is no default" do
+ @selector.expects(:fail)
+
+ @selector.evaluate(@scope)
+ end
+ end
+
+ end
+end