From: Brice Figureau <[email protected]>

The following manifest doesn't work:
$foo = undef
case $foo {
  undef: { notice("undef") }
  default: { notice("defined") }
}

This is because "undef" scope variable are returned as an empty
string.

This patch introduces a behavior change:
Now, unassigned variable usage returns also undef.

This might produce some issues in existing manifests, although
care has been taken to allow correct behavior in the most commonly
used patterns.

For instance:
case $bar {
  undef: { notice("undef") }
  default: { notice("defined") }
}
will print "undef".

But matching undef in case/selector/if will also match "".
case $bar {
  "": { notice("empty") }
  default: { notice("defined") }
}
will print "empty".

Of course "" doesn't match undef :-)

Signed-off-by: Brice Figureau <[email protected]>
Signed-off-by: James Turnbull <[email protected]>
---
 lib/puppet/parser/ast/leaf.rb               |    7 +++-
 spec/unit/parser/ast/arithmetic_operator.rb |    4 +-
 spec/unit/parser/ast/comparison_operator.rb |    4 +-
 spec/unit/parser/ast/leaf.rb                |   49 +++++++++++++++++++++++---
 test/language/ast/variable.rb               |    2 +-
 5 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb
index 07bba1b..b583149 100644
--- a/lib/puppet/parser/ast/leaf.rb
+++ b/lib/puppet/parser/ast/leaf.rb
@@ -16,6 +16,8 @@ class Puppet::Parser::AST
             if ! options[:sensitive] && obj.respond_to?(:downcase)
                 obj = obj.downcase
             end
+            # "" == undef for case/selector/if
+            return true if obj == "" and value == :undef
             obj == value
         end
 
@@ -125,7 +127,10 @@ class Puppet::Parser::AST
         # not include syntactical constructs, like '$' and '{}').
         def evaluate(scope)
             parsewrap do
-                return scope.lookupvar(@value)
+                if (var = scope.lookupvar(@value, false)) == :undefined
+                    var = :undef
+                end
+                var
             end
         end
 
diff --git a/spec/unit/parser/ast/arithmetic_operator.rb 
b/spec/unit/parser/ast/arithmetic_operator.rb
index 4a0be48..ad8d994 100755
--- a/spec/unit/parser/ast/arithmetic_operator.rb
+++ b/spec/unit/parser/ast/arithmetic_operator.rb
@@ -61,8 +61,8 @@ describe Puppet::Parser::AST::ArithmeticOperator do
     end
 
     it "should work for variables too" do
-        @scope.expects(:lookupvar).with("one").returns(1)
-        @scope.expects(:lookupvar).with("two").returns(2)
+        @scope.expects(:lookupvar).with("one", false).returns(1)
+        @scope.expects(:lookupvar).with("two", false).returns(2)
         one = ast::Variable.new( :value => "one" )
         two = ast::Variable.new( :value => "two" )
 
diff --git a/spec/unit/parser/ast/comparison_operator.rb 
b/spec/unit/parser/ast/comparison_operator.rb
index 2631179..9740243 100755
--- a/spec/unit/parser/ast/comparison_operator.rb
+++ b/spec/unit/parser/ast/comparison_operator.rb
@@ -71,8 +71,8 @@ describe Puppet::Parser::AST::ComparisonOperator do
         one = Puppet::Parser::AST::Variable.new( :value => "one" )
         two = Puppet::Parser::AST::Variable.new( :value => "two" )
 
-        @scope.expects(:lookupvar).with("one").returns(1)
-        @scope.expects(:lookupvar).with("two").returns(2)
+        @scope.expects(:lookupvar).with("one", false).returns(1)
+        @scope.expects(:lookupvar).with("two", false).returns(2)
 
         operator = Puppet::Parser::AST::ComparisonOperator.new :lval => one, 
:operator => "<", :rval => two
         operator.evaluate(@scope).should == true
diff --git a/spec/unit/parser/ast/leaf.rb b/spec/unit/parser/ast/leaf.rb
index ee1ee04..640c252 100755
--- a/spec/unit/parser/ast/leaf.rb
+++ b/spec/unit/parser/ast/leaf.rb
@@ -21,6 +21,7 @@ describe Puppet::Parser::AST::Leaf do
         end
 
         it "should match values by equality" do
+            @value.stubs(:==).returns(false)
             @leaf.stubs(:safeevaluate).with(@scope).returns(@value)
             @value.expects(:==).with("value")
 
@@ -33,6 +34,12 @@ describe Puppet::Parser::AST::Leaf do
 
             @leaf.evaluate_match("value", @scope, :insensitive => true)
         end
+
+        it "should match undef if value is an empty string" do
+            @leaf.stubs(:safeevaluate).with(@scope).returns("")
+
+            @leaf.evaluate_match(:undef, @scope).should be_true
+        end
     end
 
     describe "when converting to string" do
@@ -72,12 +79,18 @@ describe Puppet::Parser::AST::String do
     end
 end
 
-describe Puppet::Parser::AST::Variable do
-    describe "when converting to string" do
-        it "should transform its value to a variable" do
-            value = stub 'value', :is_a? => true, :to_s => "myvar"
-            Puppet::Parser::AST::Variable.new( :value => value ).to_s.should 
== "\$myvar"
-        end
+describe Puppet::Parser::AST::Undef do
+    before :each do
+        @scope = stub 'scope'
+        @undef = Puppet::Parser::AST::Undef.new(:value => :undef)
+    end
+
+    it "should match undef with undef" do
+        @undef.evaluate_match(:undef, @scope).should be_true
+    end
+
+    it "should not match undef with an empty string" do
+        @undef.evaluate_match("", @scope).should be_false
     end
 end
 
@@ -158,6 +171,30 @@ describe Puppet::Parser::AST::Regex do
     end
 end
 
+describe Puppet::Parser::AST::Variable do
+    before :each do
+        @scope = stub 'scope'
+        @var = Puppet::Parser::AST::Variable.new(:value => "myvar")
+    end
+
+    it "should lookup the variable in scope" do
+        @scope.expects(:lookupvar).with("myvar", false).returns(:myvalue)
+        @var.safeevaluate(@scope).should == :myvalue
+    end
+
+    it "should return undef if the variable wasn't set" do
+        @scope.expects(:lookupvar).with("myvar", false).returns(:undefined)
+        @var.safeevaluate(@scope).should == :undef
+    end
+
+    describe "when converting to string" do
+        it "should transform its value to a variable" do
+            value = stub 'value', :is_a? => true, :to_s => "myvar"
+            Puppet::Parser::AST::Variable.new( :value => value ).to_s.should 
== "\$myvar"
+        end
+    end
+end
+
 describe Puppet::Parser::AST::HostName do
     before :each do
         @scope = stub 'scope'
diff --git a/test/language/ast/variable.rb b/test/language/ast/variable.rb
index 17e078b..49b1dbb 100755
--- a/test/language/ast/variable.rb
+++ b/test/language/ast/variable.rb
@@ -22,7 +22,7 @@ class TestVariable < Test::Unit::TestCase
     end
 
     def test_evaluate
-        assert_equal("", @var.evaluate(@scope), "did not return empty string 
on unset var")
+        assert_equal(:undef, @var.evaluate(@scope), "did not return :undef on 
unset var")
         @scope.setvar(@name, "something")
         assert_equal("something", @var.evaluate(@scope), "incorrect variable 
value")
     end
-- 
1.6.5.2

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.


Reply via email to