diff options
| author | Brice Figureau <brice-puppet@daysofwonder.com> | 2010-02-08 20:17:38 +0100 |
|---|---|---|
| committer | James Turnbull <james@lovedthanlost.net> | 2010-03-25 16:20:52 +1100 |
| commit | 5d10f65745ce78e71e9a4cfce7f1f60c45db2501 (patch) | |
| tree | 89b8723c1894ced7732cf298e797052e3021f8f1 /spec/unit/parser/ast | |
| parent | fbedb999e4f4cc8020bc6be4a1d8868368c3ed7f (diff) | |
Fix #3155 - prevent error when using two matching regex in cascade
The following manifest:
case $var {
/match/: {
if $var =~ /matchagain/ {
}
}
}
is failing because the "=~" operators when matching sets an ephemeral
variable in the scope. But the case regex also did it, and since they
both belong to the same scope, and Puppet variables are immutables, the
scope raises an error.
This patch fixes this issue by adding to the current scope a stack
of ephemeral symbol tables. Each new match operator or case/selector
with regex adds a new scope. When we get out of the case/if/selector
structure the scope is reset to the ephemeral level we were when
entering it.
This way the following manifest produces the correct output:
case $var {
/match(rematch)/: {
notice("1. \$0 = $0, \$1 = $1")
if $var =~ /matchagain/ {
notice("2. \$0 = $0, \$1 = $1")
}
notice("3. \$0 = $0, \$1 = $1")
}
}
notice("4. \$0 = $0")
And the output is:
1. $0 = match, $1 = rematch
2. $0 = matchagain, $1 = rematch
3. $0 = match, $1 = rematch
4. $0 =
Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
Diffstat (limited to 'spec/unit/parser/ast')
| -rwxr-xr-x | spec/unit/parser/ast/casestatement.rb | 6 | ||||
| -rwxr-xr-x | spec/unit/parser/ast/ifstatement.rb | 3 | ||||
| -rwxr-xr-x | spec/unit/parser/ast/selector.rb | 6 |
3 files changed, 10 insertions, 5 deletions
diff --git a/spec/unit/parser/ast/casestatement.rb b/spec/unit/parser/ast/casestatement.rb index 657648e9d..ea032d79b 100755 --- a/spec/unit/parser/ast/casestatement.rb +++ b/spec/unit/parser/ast/casestatement.rb @@ -111,19 +111,21 @@ describe Puppet::Parser::AST::CaseStatement do end it "should unset scope ephemeral variables after option evaluation" do + @scope.stubs(:ephemeral_level).returns(:level) @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) + @scope.expects(:unset_ephemeral_var).with(:level) @casestmt.evaluate(@scope) end it "should not leak ephemeral variables even if evaluation fails" do + @scope.stubs(:ephemeral_level).returns(:level) @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) + @scope.expects(:unset_ephemeral_var).with(:level) lambda { @casestmt.evaluate(@scope) }.should raise_error end diff --git a/spec/unit/parser/ast/ifstatement.rb b/spec/unit/parser/ast/ifstatement.rb index 10d877a4b..83121cddd 100755 --- a/spec/unit/parser/ast/ifstatement.rb +++ b/spec/unit/parser/ast/ifstatement.rb @@ -64,10 +64,11 @@ describe Puppet::Parser::AST::IfStatement do end it "should reset ephemeral statements after evaluation" do + @scope.expects(:ephemeral_level).returns(:level) Puppet::Parser::Scope.stubs(:true?).returns(true) @stmt.expects(:safeevaluate).with(@scope) - @scope.expects(:unset_ephemeral_var) + @scope.expects(:unset_ephemeral_var).with(:level) @ifstmt.evaluate(@scope) end diff --git a/spec/unit/parser/ast/selector.rb b/spec/unit/parser/ast/selector.rb index f9a1efe6c..85092fe6e 100755 --- a/spec/unit/parser/ast/selector.rb +++ b/spec/unit/parser/ast/selector.rb @@ -118,19 +118,21 @@ describe Puppet::Parser::AST::Selector do end it "should unset scope ephemeral variables after option evaluation" do + @scope.stubs(:ephemeral_level).returns(:level) @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) + @scope.expects(:unset_ephemeral_var).with(:level) @selector.evaluate(@scope) end it "should not leak ephemeral variables even if evaluation fails" do + @scope.stubs(:ephemeral_level).returns(:level) @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) + @scope.expects(:unset_ephemeral_var).with(:level) lambda { @selector.evaluate(@scope) }.should raise_error end |
