diff options
Diffstat (limited to 'spec/unit/parser')
21 files changed, 1481 insertions, 243 deletions
diff --git a/spec/unit/parser/ast/arithmetic_operator_spec.rb b/spec/unit/parser/ast/arithmetic_operator_spec.rb index de6941fb7..cdd01e375 100755 --- a/spec/unit/parser/ast/arithmetic_operator_spec.rb +++ b/spec/unit/parser/ast/arithmetic_operator_spec.rb @@ -24,7 +24,7 @@ describe Puppet::Parser::AST::ArithmeticOperator do end it "should fail for an unknown operator" do - lambda { operator = ast::ArithmeticOperator.new :lval => @one, :operator => "%", :rval => @two }.should raise_error + lambda { operator = ast::ArithmeticOperator.new :lval => @one, :operator => "^", :rval => @two }.should raise_error end it "should call Puppet::Parser::Scope.number?" do @@ -35,7 +35,7 @@ describe Puppet::Parser::AST::ArithmeticOperator do end - %w{ + - * / << >>}.each do |op| + %w{ + - * / % << >>}.each do |op| it "should call ruby Numeric '#{op}'" do one = stub 'one' two = stub 'two' @@ -61,4 +61,100 @@ describe Puppet::Parser::AST::ArithmeticOperator do operator.evaluate(@scope).should == 4.33 end + context "when applied to array" do + before :each do + Puppet[:parser] = 'future' + end + + it "+ should concatenate an array" do + one = stub 'one', :safeevaluate => [1,2,3] + two = stub 'two', :safeevaluate => [4,5] + operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two + operator.evaluate(@scope).should == [1,2,3,4,5] + end + + it "<< should append array to an array" do + one = stub 'one', :safeevaluate => [1,2,3] + two = stub 'two', :safeevaluate => [4,5] + operator = ast::ArithmeticOperator.new :lval => one, :operator => "<<", :rval => two + operator.evaluate(@scope).should == [1,2,3, [4,5]] + end + + it "<< should append object to an array" do + one = stub 'one', :safeevaluate => [1,2,3] + two = stub 'two', :safeevaluate => 'a b c' + operator = ast::ArithmeticOperator.new :lval => one, :operator => "<<", :rval => two + operator.evaluate(@scope).should == [1,2,3, 'a b c'] + end + + context "and input is invalid" do + it "should raise error for + if left is not an array" do + one = stub 'one', :safeevaluate => 4 + two = stub 'two', :safeevaluate => [4,5] + operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two + lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/left/) + end + + it "should raise error for << if left is not an array" do + one = stub 'one', :safeevaluate => 4 + two = stub 'two', :safeevaluate => [4,5] + operator = ast::ArithmeticOperator.new :lval => one, :operator => "<<", :rval => two + lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/left/) + end + + it "should raise error for + if right is not an array" do + one = stub 'one', :safeevaluate => [1,2] + two = stub 'two', :safeevaluate => 45 + operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two + lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/right/) + end + + %w{ - * / % >>}.each do |op| + it "should raise error for '#{op}'" do + one = stub 'one', :safeevaluate => [1,2,3] + two = stub 'two', :safeevaluate => [4,5] + operator = ast::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two + lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error + end + end + end + + context "when applied to hash" do + before :each do + Puppet[:parser] = 'future' + end + + it "+ should merge two hashes" do + one = stub 'one', :safeevaluate => {'a' => 1, 'b' => 2} + two = stub 'two', :safeevaluate => {'c' => 3 } + operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two + operator.evaluate(@scope).should == {'a' => 1, 'b' => 2, 'c' => 3} + end + + context "and input is invalid" do + it "should raise error for + if left is not a hash" do + one = stub 'one', :safeevaluate => 4 + two = stub 'two', :safeevaluate => {'a' => 1} + operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two + lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/left/) + end + + it "should raise error for + if right is not a hash" do + one = stub 'one', :safeevaluate => {'a' => 1} + two = stub 'two', :safeevaluate => 1 + operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two + lambda { operator.evaluate(@scope).should == {'a'=>1, 1=>nil} }.should raise_error(/right/) + end + + %w{ - * / % << >>}.each do |op| + it "should raise error for '#{op}'" do + one = stub 'one', :safeevaluate => {'a' => 1, 'b' => 2} + two = stub 'two', :safeevaluate => {'c' => 3 } + operator = ast::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two + lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error + end + end + end + end + end end diff --git a/spec/unit/parser/collector_spec.rb b/spec/unit/parser/collector_spec.rb index 132bddbc5..5d4af0c11 100755 --- a/spec/unit/parser/collector_spec.rb +++ b/spec/unit/parser/collector_spec.rb @@ -288,6 +288,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources", :if => Puppet[:storeconfigs_backend] = "active_record" end + after :each do + Puppet::Rails.teardown + end + it "should return all matching resources from the current compile and mark them non-virtual and non-exported" do one = Puppet::Parser::Resource.new('notify', 'one', :virtual => true, @@ -304,10 +308,6 @@ describe Puppet::Parser::Collector, "when collecting exported resources", :if => @collector.evaluate.should == [one, two] one.should_not be_virtual two.should_not be_virtual - - # REVISIT: Apparently we never actually marked local resources as - # non-exported. So, this is what the previous test asserted, and checking - # what it claims to do causes test failures. --daniel 2011-08-23 end it "should mark all returned resources as not virtual" do diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index 2c4b5221b..d64e57e8b 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -152,7 +152,7 @@ describe Puppet::Parser::Compiler do it "should transform node class hashes into a class list" do node = Puppet::Node.new("mynode") - node.classes = {'foo'=>{'one'=>'1'}, 'bar'=>{'two'=>'2'}} + node.classes = {'foo'=>{'one'=>'p1'}, 'bar'=>{'two'=>'p2'}} compiler = Puppet::Parser::Compiler.new(node) compiler.classlist.should =~ ['foo', 'bar'] @@ -231,7 +231,7 @@ describe Puppet::Parser::Compiler do end it "should evaluate any parameterized classes named in the node" do - classes = {'foo'=>{'1'=>'one'}, 'bar'=>{'2'=>'two'}} + classes = {'foo'=>{'p1'=>'one'}, 'bar'=>{'p2'=>'two'}} @node.stubs(:classes).returns(classes) @compiler.expects(:evaluate_classes).with(classes, @compiler.topscope) @compiler.compile @@ -609,7 +609,7 @@ describe Puppet::Parser::Compiler do # Define the given class with default parameters def define_class(name, parameters) @node.classes[name] = parameters - klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => @ast_obj, '2' => @ast_obj}) + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'p1' => @ast_obj, 'p2' => @ast_obj}) @compiler.topscope.known_resource_types.add klass end @@ -627,20 +627,20 @@ describe Puppet::Parser::Compiler do it "should provide default values for parameters that have no values specified" do define_class('foo', {}) compile() - @catalog.resource(:class, 'foo')['1'].should == "foo" + @catalog.resource(:class, 'foo')['p1'].should == "foo" end it "should use any provided values" do - define_class('foo', {'1' => 'real_value'}) + define_class('foo', {'p1' => 'real_value'}) compile() - @catalog.resource(:class, 'foo')['1'].should == "real_value" + @catalog.resource(:class, 'foo')['p1'].should == "real_value" end it "should support providing some but not all values" do - define_class('foo', {'1' => 'real_value'}) + define_class('foo', {'p1' => 'real_value'}) compile() - @catalog.resource(:class, 'Foo')['1'].should == "real_value" - @catalog.resource(:class, 'Foo')['2'].should == "foo" + @catalog.resource(:class, 'Foo')['p1'].should == "real_value" + @catalog.resource(:class, 'Foo')['p2'].should == "foo" end it "should ensure each node class is in catalog and has appropriate tags" do @@ -648,7 +648,7 @@ describe Puppet::Parser::Compiler do @node.classes = klasses ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') klasses.each do |name| - klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'p1' => ast_obj, 'p2' => ast_obj}) @compiler.topscope.known_resource_types.add klass end catalog = @compiler.compile @@ -659,11 +659,11 @@ describe Puppet::Parser::Compiler do end it "should fail if required parameters are missing" do - klass = {'foo'=>{'1'=>'one'}} + klass = {'foo'=>{'a'=>'one'}} @node.classes = klass - klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) + klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'a' => nil, 'b' => nil}) @compiler.topscope.known_resource_types.add klass - lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Must pass 2 to Class[Foo]") + lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Must pass b to Class[Foo]") end it "should fail if invalid parameters are passed" do diff --git a/spec/unit/parser/eparser_adapter_spec.rb b/spec/unit/parser/eparser_adapter_spec.rb new file mode 100644 index 000000000..051633434 --- /dev/null +++ b/spec/unit/parser/eparser_adapter_spec.rb @@ -0,0 +1,407 @@ +#! /usr/bin/env ruby +require 'spec_helper' +require 'puppet/parser/e_parser_adapter' + +describe Puppet::Parser do + + Puppet::Parser::AST + + before :each do + @known_resource_types = Puppet::Resource::TypeCollection.new("development") + @classic_parser = Puppet::Parser::Parser.new "development" + @parser = Puppet::Parser::EParserAdapter.new(@classic_parser) + @classic_parser.stubs(:known_resource_types).returns @known_resource_types + @true_ast = Puppet::Parser::AST::Boolean.new :value => true + end + + it "should require an environment at initialization" do + expect { + Puppet::Parser::EParserAdapter.new + }.to raise_error(ArgumentError, /wrong number of arguments/) + end + + describe "when parsing append operator" do + + it "should not raise syntax errors" do + expect { @parser.parse("$var += something") }.to_not raise_error + end + + it "should raise syntax error on incomplete syntax " do + expect { + @parser.parse("$var += ") + }.to raise_error(Puppet::ParseError, /Syntax error at end of file/) + end + + it "should create ast::VarDef with append=true" do + vardef = @parser.parse("$var += 2").code[0] + vardef.should be_a(Puppet::Parser::AST::VarDef) + vardef.append.should == true + end + + it "should work with arrays too" do + vardef = @parser.parse("$var += ['test']").code[0] + vardef.should be_a(Puppet::Parser::AST::VarDef) + vardef.append.should == true + end + + end + + describe "when parsing selector" do + it "should support hash access on the left hand side" do + expect { @parser.parse("$h = { 'a' => 'b' } $a = $h['a'] ? { 'b' => 'd', default => undef }") }.to_not raise_error + end + end + + describe "parsing 'unless'" do + it "should create the correct ast objects" do + Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } + @parser.parse("unless false { $var = 1 }") + end + + it "should not raise an error with empty statements" do + expect { @parser.parse("unless false { }") }.to_not raise_error + end + + #test for bug #13296 + it "should not override 'unless' as a parameter inside resources" do + lambda { @parser.parse("exec {'/bin/echo foo': unless => '/usr/bin/false',}") }.should_not raise_error + end + end + + describe "when parsing parameter names" do + Puppet::Parser::Lexer::KEYWORDS.sort_tokens.each do |keyword| + it "should allow #{keyword} as a keyword" do + lambda { @parser.parse("exec {'/bin/echo foo': #{keyword} => '/usr/bin/false',}") }.should_not raise_error + end + end + end + + describe "when parsing 'if'" do + it "not, it should create the correct ast objects" do + Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } + @parser.parse("if ! true { $var = 1 }") + end + + it "boolean operation, it should create the correct ast objects" do + Puppet::Parser::AST::BooleanOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Boolean) and h[:lval].is_a?(Puppet::Parser::AST::Boolean) and h[:operator]=="or" + } + @parser.parse("if true or true { $var = 1 }") + + end + + it "comparison operation, it should create the correct ast objects" do + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="<" + } + @parser.parse("if 1 < 2 { $var = 1 }") + + end + + end + + describe "when parsing if complex expressions" do + it "should create a correct ast tree" do + aststub = stub_everything 'ast' + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]==">" + }.returns(aststub) + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="==" + }.returns(aststub) + Puppet::Parser::AST::BooleanOperator.expects(:new).with { + |h| h[:rval]==aststub and h[:lval]==aststub and h[:operator]=="and" + } + @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }") + end + + it "should raise an error on incorrect expression" do + expect { + @parser.parse("if (1 > 2 > ) or (1 == 2) { $var = 1 }") + }.to raise_error(Puppet::ParseError, /Syntax error at '\)'/) + end + + end + + describe "when parsing resource references" do + + it "should not raise syntax errors" do + expect { @parser.parse('exec { test: param => File["a"] }') }.to_not raise_error + end + + it "should not raise syntax errors with multiple references" do + expect { @parser.parse('exec { test: param => File["a","b"] }') }.to_not raise_error + end + + it "should create an ast::ResourceReference" do + # NOTE: In egrammar, type and name are unified immediately to lower case whereas the regular grammar + # keeps the UC name in some contexts - it gets downcased later as the name of the type is in lower case. + # + Puppet::Parser::AST::ResourceReference.expects(:new).with { |arg| + arg[:line]==1 and arg[:pos] ==25 and arg[:type]=="file" and arg[:title].is_a?(Puppet::Parser::AST::ASTArray) + } + @parser.parse('exec { test: command => File["a","b"] }') + end + end + + describe "when parsing resource overrides" do + + it "should not raise syntax errors" do + expect { @parser.parse('Resource["title"] { param => value }') }.to_not raise_error + end + + it "should not raise syntax errors with multiple overrides" do + expect { @parser.parse('Resource["title1","title2"] { param => value }') }.to_not raise_error + end + + it "should create an ast::ResourceOverride" do + ro = @parser.parse('Resource["title1","title2"] { param => value }').code[0] + ro.should be_a(Puppet::Parser::AST::ResourceOverride) + ro.line.should == 1 + ro.object.should be_a(Puppet::Parser::AST::ResourceReference) + ro.parameters[0].should be_a(Puppet::Parser::AST::ResourceParam) + end + + end + + describe "when parsing if statements" do + + it "should not raise errors with empty if" do + expect { @parser.parse("if true { }") }.to_not raise_error + end + + it "should not raise errors with empty else" do + expect { @parser.parse("if false { notice('if') } else { }") }.to_not raise_error + end + + it "should not raise errors with empty if and else" do + expect { @parser.parse("if false { } else { }") }.to_not raise_error + end + + it "should create a nop node for empty branch" do + Puppet::Parser::AST::Nop.expects(:new).twice + @parser.parse("if true { }") + end + + it "should create a nop node for empty else branch" do + Puppet::Parser::AST::Nop.expects(:new) + @parser.parse("if true { notice('test') } else { }") + end + + it "should build a chain of 'ifs' if there's an 'elsif'" do + expect { @parser.parse(<<-PP) }.to_not raise_error + if true { notice('test') } elsif true {} else { } + PP + end + + end + + describe "when parsing function calls" do + it "should not raise errors with no arguments" do + expect { @parser.parse("tag()") }.to_not raise_error + end + + it "should not raise errors with rvalue function with no args" do + expect { @parser.parse("$a = template()") }.to_not raise_error + end + + it "should not raise errors with arguments" do + expect { @parser.parse("notice(1)") }.to_not raise_error + end + + it "should not raise errors with multiple arguments" do + expect { @parser.parse("notice(1,2)") }.to_not raise_error + end + + it "should not raise errors with multiple arguments and a trailing comma" do + expect { @parser.parse("notice(1,2,)") }.to_not raise_error + end + + end + + describe "when parsing arrays" do + it "should parse an array" do + expect { @parser.parse("$a = [1,2]") }.to_not raise_error + end + + it "should not raise errors with a trailing comma" do + expect { @parser.parse("$a = [1,2,]") }.to_not raise_error + end + + it "should accept an empty array" do + expect { @parser.parse("$var = []\n") }.to_not raise_error + end + end + + describe "when parsing classes" do + before :each do + @krt = Puppet::Resource::TypeCollection.new("development") + @classic_parser = Puppet::Parser::Parser.new "development" + @parser = Puppet::Parser::EParserAdapter.new(@classic_parser) + @classic_parser.stubs(:known_resource_types).returns @krt + end + + it "should not create new classes" do + @parser.parse("class foobar {}").code[0].should be_a(Puppet::Parser::AST::Hostclass) + @krt.hostclass("foobar").should be_nil + end + + it "should correctly set the parent class when one is provided" do + @parser.parse("class foobar inherits yayness {}").code[0].instantiate('')[0].parent.should == "yayness" + end + + it "should correctly set the parent class for multiple classes at a time" do + statements = @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}").code + statements[0].instantiate('')[0].parent.should == "yayness" + statements[1].instantiate('')[0].parent.should == "bar" + end + + it "should define the code when some is provided" do + @parser.parse("class foobar { $var = val }").code[0].code.should_not be_nil + end + + it "should accept parameters with trailing comma" do + @parser.parse("file { '/example': ensure => file, }").should be + end + + it "should accept parametrized classes with trailing comma" do + @parser.parse("class foobar ($var1 = 0,) { $var = val }").code[0].code.should_not be_nil + end + + it "should define parameters when provided" do + foobar = @parser.parse("class foobar($biz,$baz) {}").code[0].instantiate('')[0] + foobar.arguments.should == {"biz" => nil, "baz" => nil} + end + end + + describe "when parsing resources" do + before :each do + @krt = Puppet::Resource::TypeCollection.new("development") + @classic_parser = Puppet::Parser::Parser.new "development" + @parser = Puppet::Parser::EParserAdapter.new(@classic_parser) + @classic_parser.stubs(:known_resource_types).returns @krt + end + + it "should be able to parse class resources" do + @krt.add(Puppet::Resource::Type.new(:hostclass, "foobar", :arguments => {"biz" => nil})) + expect { @parser.parse("class { foobar: biz => stuff }") }.to_not raise_error + end + + it "should correctly mark exported resources as exported" do + @parser.parse("@@file { '/file': }").code[0].exported.should be_true + end + + it "should correctly mark virtual resources as virtual" do + @parser.parse("@file { '/file': }").code[0].virtual.should be_true + end + end + + describe "when parsing nodes" do + it "should be able to parse a node with a single name" do + node = @parser.parse("node foo { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 1 + node.names[0].value.should == "foo" + end + + it "should be able to parse a node with two names" do + node = @parser.parse("node foo, bar { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 2 + node.names[0].value.should == "foo" + node.names[1].value.should == "bar" + end + + it "should be able to parse a node with three names" do + node = @parser.parse("node foo, bar, baz { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 3 + node.names[0].value.should == "foo" + node.names[1].value.should == "bar" + node.names[2].value.should == "baz" + end + end + + it "should fail if trying to collect defaults" do + expect { + @parser.parse("@Port { protocols => tcp }") + }.to raise_error(Puppet::ParseError, /Defaults are not virtualizable/) + end + + context "when parsing collections" do + it "should parse basic collections" do + @parser.parse("Port <| |>").code. + should be_all {|x| x.is_a? Puppet::Parser::AST::Collection } + end + + it "should parse fully qualified collections" do + @parser.parse("Port::Range <| |>").code. + should be_all {|x| x.is_a? Puppet::Parser::AST::Collection } + end + end + + it "should not assign to a fully qualified variable" do + expect { + @parser.parse("$one::two = yay") + }.to raise_error(Puppet::ParseError, /Cannot assign to variables in other namespaces/) + end + + it "should parse assignment of undef" do + tree = @parser.parse("$var = undef") + tree.code.children[0].should be_an_instance_of Puppet::Parser::AST::VarDef + tree.code.children[0].value.should be_an_instance_of Puppet::Parser::AST::Undef + end + + it "should treat classes as case insensitive" do + @classic_parser.known_resource_types.import_ast(@parser.parse("class yayness {}"), '') + @classic_parser.known_resource_types.hostclass('yayness'). + should == @classic_parser.find_hostclass("", "YayNess") + end + + it "should treat defines as case insensitive" do + @classic_parser.known_resource_types.import_ast(@parser.parse("define funtest {}"), '') + @classic_parser.known_resource_types.hostclass('funtest'). + should == @classic_parser.find_hostclass("", "fUntEst") + end + context "when parsing method calls" do + it "should parse method call with one param lambda" do + expect { @parser.parse("$a.foreach {|$a| debug $a }") }.to_not raise_error + end + it "should parse method call with two param lambda" do + expect { @parser.parse("$a.foreach {|$a,$b| debug $a }") }.to_not raise_error + end + it "should parse method call with two param lambda and default value" do + expect { @parser.parse("$a.foreach {|$a,$b=1| debug $a }") }.to_not raise_error + end + it "should parse method call without lambda (statement)" do + expect { @parser.parse("$a.foreach") }.to_not raise_error + end + it "should parse method call without lambda (expression)" do + expect { @parser.parse("$x = $a.foreach + 1") }.to_not raise_error + end + context "a receiver expression of type" do + it "variable should be allowed" do + expect { @parser.parse("$a.foreach") }.to_not raise_error + end + it "hasharrayaccess should be allowed" do + expect { @parser.parse("$a[0][1].foreach") }.to_not raise_error + end + it "quoted text should be allowed" do + expect { @parser.parse("\"monkey\".foreach") }.to_not raise_error + expect { @parser.parse("'monkey'.foreach") }.to_not raise_error + end + it "selector text should be allowed" do + expect { @parser.parse("$a ? { 'banana'=>[1,2,3]}.foreach") }.to_not raise_error + end + it "function call should be allowed" do + expect { @parser.parse("duh(1,2,3).foreach") }.to_not raise_error + end + it "method call should be allowed" do + expect { @parser.parse("$a.foo.bar") }.to_not raise_error + end + it "chained method calls with lambda should be allowed" do + expect { @parser.parse("$a.foo{||}.bar{||}") }.to_not raise_error + end + end + end +end diff --git a/spec/unit/parser/functions/extlookup_spec.rb b/spec/unit/parser/functions/extlookup_spec.rb index fae32fa97..ecd7a817a 100755 --- a/spec/unit/parser/functions/extlookup_spec.rb +++ b/spec/unit/parser/functions/extlookup_spec.rb @@ -1,6 +1,5 @@ #! /usr/bin/env ruby require 'spec_helper' -require 'tempfile' describe "the extlookup function" do include PuppetSpec::Files @@ -33,36 +32,40 @@ describe "the extlookup function" do end it "should lookup the key in a supplied datafile" do - t = Tempfile.new('extlookup.csv') do + dir = tmpdir("extlookup_spec") + File.open("#{dir}/extlookup.csv", "w") do |t| t.puts 'key,value' t.puts 'nonkey,nonvalue' - t.close - - result = @scope.function_extlookup([ "key", "default", t.path]) - result.should == "value" end + + @scope.stubs(:[]).with('::extlookup_datadir').returns(dir) + @scope.stubs(:[]).with('::extlookup_precedence').returns(nil) + result = @scope.function_extlookup([ "key", "default", "extlookup"]) + result.should == "value" end it "should return an array if the datafile contains more than two columns" do - t = Tempfile.new('extlookup.csv') do + dir = tmpdir("extlookup_spec") + File.open("#{dir}/extlookup.csv", "w") do |t| t.puts 'key,value1,value2' t.puts 'nonkey,nonvalue,nonvalue' - t.close - - result = @scope.function_extlookup([ "key", "default", t.path]) - result.should == ["value1", "value2"] end + + @scope.stubs(:[]).with('::extlookup_datadir').returns(dir) + @scope.stubs(:[]).with('::extlookup_precedence').returns(nil) + result = @scope.function_extlookup([ "key", "default", "extlookup"]) + result.should == ["value1", "value2"] end it "should raise an error if there's no matching key and no default" do - t = Tempfile.new('extlookup.csv') do - t.puts 'key,value' + dir = tmpdir("extlookup_spec") + File.open("#{dir}/extlookup.csv", "w") do |t| t.puts 'nonkey,nonvalue' - t.close - - result = @scope.function_extlookup([ "key", nil, t.path]) - result.should == "value" end + + @scope.stubs(:[]).with('::extlookup_datadir').returns(dir) + @scope.stubs(:[]).with('::extlookup_precedence').returns(nil) + lambda { @scope.function_extlookup([ "key", nil, "extlookup"]) }.should raise_error(Puppet::ParseError, /No match found.*key/) end describe "should look in $extlookup_datadir for data files listed by $extlookup_precedence" do diff --git a/spec/unit/parser/functions/fqdn_rand_spec.rb b/spec/unit/parser/functions/fqdn_rand_spec.rb index 1facda6e8..e28dbff26 100755 --- a/spec/unit/parser/functions/fqdn_rand_spec.rb +++ b/spec/unit/parser/functions/fqdn_rand_spec.rb @@ -55,4 +55,9 @@ describe "the fqdn_rand function" do val2 = @scope.function_fqdn_rand([10000000,42]) val1.should_not eql(val2) end + + it "should use the Puppet::Util function" do + Puppet::Util.expects(:deterministic_rand).with(177093203648075535190027737376590689559,4) + @scope.function_fqdn_rand([4]) + end end diff --git a/spec/unit/parser/functions/hiera_include_spec.rb b/spec/unit/parser/functions/hiera_include_spec.rb index f06d8c69c..a71bdb6c5 100644 --- a/spec/unit/parser/functions/hiera_include_spec.rb +++ b/spec/unit/parser/functions/hiera_include_spec.rb @@ -1,6 +1,4 @@ require 'spec_helper' -require 'hiera_puppet' -require 'puppet/parser/functions/hiera_include' describe 'Puppet::Parser::Functions#hiera_include' do let :scope do Puppet::Parser::Scope.new_for_test_harness('foo') end diff --git a/spec/unit/parser/functions/hiera_spec.rb b/spec/unit/parser/functions/hiera_spec.rb index 0abcb1b28..f22eee9d4 100755 --- a/spec/unit/parser/functions/hiera_spec.rb +++ b/spec/unit/parser/functions/hiera_spec.rb @@ -1,5 +1,3 @@ -#! /usr/bin/env ruby - require 'spec_helper' describe 'Puppet::Parser::Functions#hiera' do diff --git a/spec/unit/parser/functions_spec.rb b/spec/unit/parser/functions_spec.rb index 1430ff26f..41ef54436 100755 --- a/spec/unit/parser/functions_spec.rb +++ b/spec/unit/parser/functions_spec.rb @@ -2,6 +2,9 @@ require 'spec_helper' describe Puppet::Parser::Functions do + def callable_functions_from(mod) + Class.new { include mod }.new + end it "should have a method for returning an environment-specific module" do Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.new("myenv")).should be_instance_of(Module) @@ -16,15 +19,15 @@ describe Puppet::Parser::Functions do end describe "when calling newfunction" do + let(:function_module) { Module.new } before do - @module = Module.new - Puppet::Parser::Functions.stubs(:environment_module).returns @module + Puppet::Parser::Functions.stubs(:environment_module).returns(function_module) end it "should create the function in the environment module" do Puppet::Parser::Functions.newfunction("name", :type => :rvalue) { |args| } - @module.should be_method_defined :function_name + function_module.should be_method_defined :function_name end it "should warn if the function already exists" do @@ -37,12 +40,22 @@ describe Puppet::Parser::Functions do it "should raise an error if the function type is not correct" do lambda { Puppet::Parser::Functions.newfunction("name", :type => :unknown) { |args| } }.should raise_error Puppet::DevError, "Invalid statement type :unknown" end + + it "instruments the function to profiles the execution" do + messages = [] + Puppet::Util::Profiler.current = Puppet::Util::Profiler::WallClock.new(proc { |msg| messages << msg }, "id") + + Puppet::Parser::Functions.newfunction("name", :type => :rvalue) { |args| } + callable_functions_from(function_module).function_name([]) + + messages.first.should =~ /Called name/ + end end describe "when calling function to test function existence" do + let(:function_module) { Module.new } before do - @module = Module.new - Puppet::Parser::Functions.stubs(:environment_module).returns @module + Puppet::Parser::Functions.stubs(:environment_module).returns(function_module) end it "should return false if the function doesn't exist" do @@ -65,40 +78,39 @@ describe Puppet::Parser::Functions do end describe "when calling function to test arity" do - before :each do - Puppet::Node::Environment.stubs(:current).returns(nil) - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) - @scope = Puppet::Parser::Scope.new(@compiler) + let(:function_module) { Module.new } + before do + Puppet::Parser::Functions.stubs(:environment_module).returns(function_module) end it "should raise an error if the function is called with too many arguments" do Puppet::Parser::Functions.newfunction("name", :arity => 2) { |args| } - lambda { @scope.function_name([1,2,3]) }.should raise_error ArgumentError + lambda { callable_functions_from(function_module).function_name([1,2,3]) }.should raise_error ArgumentError end it "should raise an error if the function is called with too few arguments" do Puppet::Parser::Functions.newfunction("name", :arity => 2) { |args| } - lambda { @scope.function_name([1]) }.should raise_error ArgumentError + lambda { callable_functions_from(function_module).function_name([1]) }.should raise_error ArgumentError end it "should not raise an error if the function is called with correct number of arguments" do Puppet::Parser::Functions.newfunction("name", :arity => 2) { |args| } - lambda { @scope.function_name([1,2]) }.should_not raise_error ArgumentError + lambda { callable_functions_from(function_module).function_name([1,2]) }.should_not raise_error ArgumentError end it "should raise an error if the variable arg function is called with too few arguments" do Puppet::Parser::Functions.newfunction("name", :arity => -3) { |args| } - lambda { @scope.function_name([1]) }.should raise_error ArgumentError + lambda { callable_functions_from(function_module).function_name([1]) }.should raise_error ArgumentError end it "should not raise an error if the variable arg function is called with correct number of arguments" do Puppet::Parser::Functions.newfunction("name", :arity => -3) { |args| } - lambda { @scope.function_name([1,2]) }.should_not raise_error ArgumentError + lambda { callable_functions_from(function_module).function_name([1,2]) }.should_not raise_error ArgumentError end it "should not raise an error if the variable arg function is called with more number of arguments" do Puppet::Parser::Functions.newfunction("name", :arity => -3) { |args| } - lambda { @scope.function_name([1,2,3]) }.should_not raise_error ArgumentError + lambda { callable_functions_from(function_module).function_name([1,2,3]) }.should_not raise_error ArgumentError end end diff --git a/spec/unit/parser/methods/collect_spec.rb b/spec/unit/parser/methods/collect_spec.rb new file mode 100644 index 000000000..13cd9eda6 --- /dev/null +++ b/spec/unit/parser/methods/collect_spec.rb @@ -0,0 +1,110 @@ +require 'puppet' +require 'spec_helper' +require 'puppet_spec/compiler' + +require 'unit/parser/methods/shared' + +describe 'the collect method' do + include PuppetSpec::Compiler + + before :each do + Puppet[:parser] = "future" + end + + context "using future parser" do + context "in Ruby style should be callable as" do + it 'collect on an array (multiplying each value by 2)' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + $a.collect {|$x| $x*2}.foreach {|$v| + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_4")['ensure'].should == 'present' + catalog.resource(:file, "/file_6")['ensure'].should == 'present' + end + + it 'collect on a hash selecting keys' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>1,'b'=>2,'c'=>3} + $a.collect {|$x| $x[0]}.foreach {|$k| + file { "/file_$k": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_a")['ensure'].should == 'present' + catalog.resource(:file, "/file_b")['ensure'].should == 'present' + catalog.resource(:file, "/file_c")['ensure'].should == 'present' + end + it 'foreach on a hash selecting value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>1,'b'=>2,'c'=>3} + $a.collect {|$x| $x[1]}.foreach {|$k| + file { "/file_$k": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + end + context "in Java style should be callable as" do + shared_examples_for 'java style' do + it 'collect on an array (multiplying each value by 2)' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + $a.collect |$x| #{farr}{ $x*2}.foreach |$v| #{farr}{ + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_4")['ensure'].should == 'present' + catalog.resource(:file, "/file_6")['ensure'].should == 'present' + end + + it 'collect on a hash selecting keys' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>1,'b'=>2,'c'=>3} + $a.collect |$x| #{farr}{ $x[0]}.foreach |$k| #{farr}{ + file { "/file_$k": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_a")['ensure'].should == 'present' + catalog.resource(:file, "/file_b")['ensure'].should == 'present' + catalog.resource(:file, "/file_c")['ensure'].should == 'present' + end + + it 'foreach on a hash selecting value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>1,'b'=>2,'c'=>3} + $a.collect |$x| #{farr} {$x[1]}.foreach |$k|#{farr}{ + file { "/file_$k": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + end + describe 'without fat arrow' do + it_should_behave_like 'java style' do + let(:farr) { '' } + end + end + describe 'with fat arrow' do + it_should_behave_like 'java style' do + let(:farr) { '=>' } + end + end + end + end + + it_should_behave_like 'all iterative functions argument checks', 'collect' + it_should_behave_like 'all iterative functions hash handling', 'collect' +end diff --git a/spec/unit/parser/methods/each_spec.rb b/spec/unit/parser/methods/each_spec.rb new file mode 100644 index 000000000..4d276e95d --- /dev/null +++ b/spec/unit/parser/methods/each_spec.rb @@ -0,0 +1,91 @@ +require 'puppet' +require 'spec_helper' +require 'puppet_spec/compiler' +require 'rubygems' + +describe 'the each method' do + include PuppetSpec::Compiler + + before :each do + Puppet[:parser] = 'future' + end + + context "should be callable as" do + it 'each on an array selecting each value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + $a.each |$v| { + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + it 'each on an array selecting each value - function call style' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + each ($a) |$index, $v| => { + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + + it 'each on an array with index' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [present, absent, present] + $a.each |$k,$v| { + file { "/file_${$k+1}": ensure => $v } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'absent' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + + it 'each on a hash selecting entries' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>'present','b'=>'absent','c'=>'present'} + $a.each |$e| { + file { "/file_${e[0]}": ensure => $e[1] } + } + MANIFEST + + catalog.resource(:file, "/file_a")['ensure'].should == 'present' + catalog.resource(:file, "/file_b")['ensure'].should == 'absent' + catalog.resource(:file, "/file_c")['ensure'].should == 'present' + end + it 'each on a hash selecting key and value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>present,'b'=>absent,'c'=>present} + $a.each |$k, $v| { + file { "/file_$k": ensure => $v } + } + MANIFEST + + catalog.resource(:file, "/file_a")['ensure'].should == 'present' + catalog.resource(:file, "/file_b")['ensure'].should == 'absent' + catalog.resource(:file, "/file_c")['ensure'].should == 'present' + end + end + context "should produce receiver" do + it 'each checking produced value using single expression' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1, 3, 2] + $b = $a.each |$x| { "unwanted" } + file { "/file_${b[1]}": + ensure => present + } + MANIFEST + + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + + end +end diff --git a/spec/unit/parser/methods/foreach_spec.rb b/spec/unit/parser/methods/foreach_spec.rb new file mode 100755 index 000000000..72a9379a4 --- /dev/null +++ b/spec/unit/parser/methods/foreach_spec.rb @@ -0,0 +1,91 @@ +require 'puppet' +require 'spec_helper' +require 'puppet_spec/compiler' +require 'rubygems' + +describe 'the foreach method' do + include PuppetSpec::Compiler + + before :each do + Puppet[:parser] = 'future' + end + + context "should be callable as" do + it 'foreach on an array selecting each value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + $a.foreach {|$v| + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + it 'foreach on an array selecting each value - function call style' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + foreach ($a) {|$v| + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + + it 'foreach on an array with index' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [present, absent, present] + $a.foreach {|$k,$v| + file { "/file_${$k+1}": ensure => $v } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'absent' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + + it 'foreach on a hash selecting entries' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>'present','b'=>'absent','c'=>'present'} + $a.foreach {|$e| + file { "/file_${e[0]}": ensure => $e[1] } + } + MANIFEST + + catalog.resource(:file, "/file_a")['ensure'].should == 'present' + catalog.resource(:file, "/file_b")['ensure'].should == 'absent' + catalog.resource(:file, "/file_c")['ensure'].should == 'present' + end + it 'foreach on a hash selecting key and value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'a'=>present,'b'=>absent,'c'=>present} + $a.foreach {|$k, $v| + file { "/file_$k": ensure => $v } + } + MANIFEST + + catalog.resource(:file, "/file_a")['ensure'].should == 'present' + catalog.resource(:file, "/file_b")['ensure'].should == 'absent' + catalog.resource(:file, "/file_c")['ensure'].should == 'present' + end + end + context "should produce receiver" do + it 'each checking produced value using single expression' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1, 3, 2] + $b = $a.each |$x| { $x } + file { "/file_${b[1]}": + ensure => present + } + MANIFEST + + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + + end +end diff --git a/spec/unit/parser/methods/reduce_spec.rb b/spec/unit/parser/methods/reduce_spec.rb new file mode 100644 index 000000000..99ecfd18d --- /dev/null +++ b/spec/unit/parser/methods/reduce_spec.rb @@ -0,0 +1,67 @@ +require 'puppet' +require 'spec_helper' +require 'puppet_spec/compiler' + +describe 'the reduce method' do + include PuppetSpec::Compiler + + before :all do + # enable switching back + @saved_parser = Puppet[:parser] + # These tests only work with future parser + end + after :all do + # switch back to original + Puppet[:parser] = @saved_parser + end + + before :each do + node = Puppet::Node.new("floppy", :environment => 'production') + @compiler = Puppet::Parser::Compiler.new(node) + @scope = Puppet::Parser::Scope.new(@compiler) + @topscope = @scope.compiler.topscope + @scope.parent = @topscope + Puppet[:parser] = 'future' + end + + context "should be callable as" do + it 'reduce on an array' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + $b = $a.reduce {|$memo, $x| $memo + $x } + file { "/file_$b": ensure => present } + MANIFEST + + catalog.resource(:file, "/file_6")['ensure'].should == 'present' + end + it 'reduce on an array with start value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1,2,3] + $b = $a.reduce(4) {|$memo, $x| $memo + $x } + file { "/file_$b": ensure => present } + MANIFEST + + catalog.resource(:file, "/file_10")['ensure'].should == 'present' + end + it 'reduce on a hash' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {a=>1, b=>2, c=>3} + $start = [ignored, 4] + $b = $a.reduce {|$memo, $x| ['sum', $memo[1] + $x[1]] } + file { "/file_${$b[0]}_${$b[1]}": ensure => present } + MANIFEST + + catalog.resource(:file, "/file_sum_6")['ensure'].should == 'present' + end + it 'reduce on a hash with start value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {a=>1, b=>2, c=>3} + $start = ['ignored', 4] + $b = $a.reduce($start) {|$memo, $x| ['sum', $memo[1] + $x[1]] } + file { "/file_${$b[0]}_${$b[1]}": ensure => present } + MANIFEST + + catalog.resource(:file, "/file_sum_10")['ensure'].should == 'present' + end + end +end diff --git a/spec/unit/parser/methods/reject_spec.rb b/spec/unit/parser/methods/reject_spec.rb new file mode 100644 index 000000000..e37eaebc5 --- /dev/null +++ b/spec/unit/parser/methods/reject_spec.rb @@ -0,0 +1,73 @@ +require 'puppet' +require 'spec_helper' +require 'puppet_spec/compiler' + +require 'unit/parser/methods/shared' + +describe 'the reject method' do + include PuppetSpec::Compiler + + before :each do + Puppet[:parser] = 'future' + end + + it 'rejects on an array (no berries)' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = ['strawberry','blueberry','orange'] + $a.reject {|$x| $x =~ /berry$/}.foreach {|$v| + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_orange")['ensure'].should == 'present' + catalog.resource(:file, "/file_strawberry").should == nil + end + + it 'produces an array when acting on an array' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = ['strawberry','blueberry','orange'] + $b = $a.reject {|$x| $x =~ /berry$/} + file { "/file_${b[0]}": ensure => present } + + MANIFEST + + catalog.resource(:file, "/file_orange")['ensure'].should == 'present' + catalog.resource(:file, "/file_strawberry").should == nil + end + + it 'rejects on a hash (all berries) by key' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'strawberry'=>'red','blueberry'=>'blue','orange'=>'orange'} + $a.reject {|$x| $x[0] =~ /berry$/}.foreach {|$v| + file { "/file_${v[0]}": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_orange")['ensure'].should == 'present' + end + + it 'produces a hash when acting on a hash' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'strawberry'=>'red','blueberry'=>'blue','grape'=>'purple'} + $b = $a.reject {|$x| $x[0] =~ /berry$/} + file { "/file_${b[grape]}": ensure => present } + + MANIFEST + + catalog.resource(:file, "/file_purple")['ensure'].should == 'present' + end + + it 'rejects on a hash (all berries) by value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'strawb'=>'red berry','blueb'=>'blue berry','orange'=>'orange fruit'} + $a.reject {|$x| $x[1] =~ /berry$/}.foreach {|$v| + file { "/file_${v[0]}": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_orange")['ensure'].should == 'present' + end + + it_should_behave_like 'all iterative functions argument checks', 'reject' + it_should_behave_like 'all iterative functions hash handling', 'reject' +end diff --git a/spec/unit/parser/methods/select_spec.rb b/spec/unit/parser/methods/select_spec.rb new file mode 100644 index 000000000..e61ee3a31 --- /dev/null +++ b/spec/unit/parser/methods/select_spec.rb @@ -0,0 +1,79 @@ +require 'puppet' +require 'spec_helper' +require 'puppet_spec/compiler' + +require 'unit/parser/methods/shared' + +describe 'the select method' do + include PuppetSpec::Compiler + + before :each do + Puppet[:parser] = 'future' + end + + it 'should select on an array (all berries)' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = ['strawberry','blueberry','orange'] + $a.select {|$x| $x =~ /berry$/}.foreach {|$v| + file { "/file_$v": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_strawberry")['ensure'].should == 'present' + catalog.resource(:file, "/file_blueberry")['ensure'].should == 'present' + end + + it 'should produce an array when acting on an array' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = ['strawberry','blueberry','orange'] + $b = $a.select {|$x| $x =~ /berry$/} + file { "/file_${b[0]}": ensure => present } + file { "/file_${b[1]}": ensure => present } + MANIFEST + + catalog.resource(:file, "/file_strawberry")['ensure'].should == 'present' + catalog.resource(:file, "/file_blueberry")['ensure'].should == 'present' + end + + it 'selects on a hash (all berries) by key' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'strawberry'=>'red','blueberry'=>'blue','orange'=>'orange'} + $a.select {|$x| $x[0] =~ /berry$/}.foreach {|$v| + file { "/file_${v[0]}": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_strawberry")['ensure'].should == 'present' + catalog.resource(:file, "/file_blueberry")['ensure'].should == 'present' + end + + it 'should produce a hash when acting on a hash' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'strawberry'=>'red','blueberry'=>'blue','orange'=>'orange'} + $b = $a.select {|$x| $x[0] =~ /berry$/} + file { "/file_${b['strawberry']}": ensure => present } + file { "/file_${b['blueberry']}": ensure => present } + file { "/file_${b['orange']}": ensure => present } + + MANIFEST + + catalog.resource(:file, "/file_red")['ensure'].should == 'present' + catalog.resource(:file, "/file_blue")['ensure'].should == 'present' + catalog.resource(:file, "/file_")['ensure'].should == 'present' + end + + it 'selects on a hash (all berries) by value' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {'strawb'=>'red berry','blueb'=>'blue berry','orange'=>'orange fruit'} + $a.select {|$x| $x[1] =~ /berry$/}.foreach {|$v| + file { "/file_${v[0]}": ensure => present } + } + MANIFEST + + catalog.resource(:file, "/file_strawb")['ensure'].should == 'present' + catalog.resource(:file, "/file_blueb")['ensure'].should == 'present' + end + + it_should_behave_like 'all iterative functions argument checks', 'select' + it_should_behave_like 'all iterative functions hash handling', 'select' +end diff --git a/spec/unit/parser/methods/shared.rb b/spec/unit/parser/methods/shared.rb new file mode 100644 index 000000000..bf9c9f05f --- /dev/null +++ b/spec/unit/parser/methods/shared.rb @@ -0,0 +1,61 @@ + +shared_examples_for 'all iterative functions hash handling' do |func| + it 'passes a hash entry as an array of the key and value' do + catalog = compile_to_catalog(<<-MANIFEST) + {a=>1}.#{func} { |$v| notify { "${v[0]} ${v[1]}": } } + MANIFEST + + catalog.resource(:notify, "a 1").should_not be_nil + end +end + +shared_examples_for 'all iterative functions argument checks' do |func| + + it 'raises an error when defined with more than 1 argument' do + expect do + compile_to_catalog(<<-MANIFEST) + [1].#{func} { |$x, $yikes| } + MANIFEST + end.to raise_error(Puppet::Error, /Too few arguments/) + end + + it 'raises an error when defined with fewer than 1 argument' do + expect do + compile_to_catalog(<<-MANIFEST) + [1].#{func} { || } + MANIFEST + end.to raise_error(Puppet::Error, /Too many arguments/) + end + + it 'raises an error when used against an unsupported type' do + expect do + compile_to_catalog(<<-MANIFEST) + "not correct".#{func} { |$v| } + MANIFEST + end.to raise_error(Puppet::Error, /must be an Array or a Hash/) + end + + it 'raises an error when called with any parameters besides a block' do + expect do + compile_to_catalog(<<-MANIFEST) + [1].#{func}(1) { |$v| } + MANIFEST + end.to raise_error(Puppet::Error, /Wrong number of arguments/) + end + + it 'raises an error when called without a block' do + expect do + compile_to_catalog(<<-MANIFEST) + [1].#{func}() + MANIFEST + end.to raise_error(Puppet::Error, /Wrong number of arguments/) + end + + it 'raises an error when called without a block' do + expect do + compile_to_catalog(<<-MANIFEST) + [1].#{func}(1) + MANIFEST + end.to raise_error(Puppet::Error, /must be a parameterized block/) + end +end diff --git a/spec/unit/parser/methods/slice_spec.rb b/spec/unit/parser/methods/slice_spec.rb new file mode 100644 index 000000000..b213415a1 --- /dev/null +++ b/spec/unit/parser/methods/slice_spec.rb @@ -0,0 +1,97 @@ +require 'puppet' +require 'spec_helper' +require 'puppet_spec/compiler' +require 'rubygems' + +describe 'methods' do + include PuppetSpec::Compiler + + before :all do + # enable switching back + @saved_parser = Puppet[:parser] + # These tests only work with future parser + Puppet[:parser] = 'future' + end + after :all do + # switch back to original + Puppet[:parser] = @saved_parser + end + + before :each do + node = Puppet::Node.new("floppy", :environment => 'production') + @compiler = Puppet::Parser::Compiler.new(node) + @scope = Puppet::Parser::Scope.new(@compiler) + @topscope = @scope.compiler.topscope + @scope.parent = @topscope + Puppet[:parser] = 'future' + end + + context "should be callable on array as" do + + it 'slice with explicit parameters' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1, present, 2, absent, 3, present] + $a.slice(2) |$k,$v| { + file { "/file_${$k}": ensure => $v } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'absent' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + it 'slice with one parameter' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1, present, 2, absent, 3, present] + $a.slice(2) |$k| { + file { "/file_${$k[0]}": ensure => $k[1] } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'absent' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + end + it 'slice with shorter last slice' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1, present, 2, present, 3, absent] + $a.slice(4) |$a, $b, $c, $d| { + file { "/file_$a.$c": ensure => $b } + } + MANIFEST + + catalog.resource(:file, "/file_1.2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3.")['ensure'].should == 'absent' + end + end + context "should be callable on hash as" do + + it 'slice with explicit parameters, missing are empty' do + catalog = compile_to_catalog(<<-MANIFEST) + $a = {1=>present, 2=>present, 3=>absent} + $a.slice(2) |$a,$b| { + file { "/file_${a[0]}.${b[0]}": ensure => $a[1] } + } + MANIFEST + + catalog.resource(:file, "/file_1.2")['ensure'].should == 'present' + catalog.resource(:file, "/file_3.")['ensure'].should == 'absent' + end + + end + context "when called without a block" do + it "should produce an array with the result" do + catalog = compile_to_catalog(<<-MANIFEST) + $a = [1, present, 2, absent, 3, present] + $a.slice(2).each |$k| { + file { "/file_${$k[0]}": ensure => $k[1] } + } + MANIFEST + + catalog.resource(:file, "/file_1")['ensure'].should == 'present' + catalog.resource(:file, "/file_2")['ensure'].should == 'absent' + catalog.resource(:file, "/file_3")['ensure'].should == 'present' + + end + end +end diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 7ff0c17b2..07ab6780c 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -100,11 +100,11 @@ describe Puppet::Parser do Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } @parser.parse("unless false { $var = 1 }") end - + it "should not raise an error with empty statements" do expect { @parser.parse("unless false { }") }.to_not raise_error end - + #test for bug #13296 it "should not override 'unless' as a parameter inside resources" do lambda { @parser.parse("exec {'/bin/echo foo': unless => '/usr/bin/false',}") }.should_not raise_error diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 86e9a8b10..8540ad20d 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -84,32 +84,34 @@ describe Puppet::Parser::Scope do end describe "when custom functions are called" do - before :each do - @env = Puppet::Node::Environment.new('testing') - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new('foo', :environment => @env)) - @scope = Puppet::Parser::Scope.new(@compiler) - end + let(:env) { Puppet::Node::Environment.new('testing') } + let(:compiler) { Puppet::Parser::Compiler.new(Puppet::Node.new('foo', :environment => env)) } + let(:scope) { Puppet::Parser::Scope.new(compiler) } - it "should load and call the method if it looks like a function and it exists" do - @scope.function_sprintf(["%b", 123]).should == "1111011" + it "calls methods prefixed with function_ as custom functions" do + scope.function_sprintf(["%b", 123]).should == "1111011" end - it "should raise and error when called without an Array" do - expect { @scope.function_sprintf("%b", 123) }.to raise_error ArgumentError, /custom functions must be called with a single array that contains the arguments/ + it "raises an error when arguments are not passed in an Array" do + expect do + scope.function_sprintf("%b", 123) + end.to raise_error ArgumentError, /custom functions must be called with a single array that contains the arguments/ end - it "should raise and error when subsequent calls are without an Array" do - @scope.function_sprintf(["first call"]) + it "raises an error on subsequent calls when arguments are not passed in an Array" do + scope.function_sprintf(["first call"]) - expect { @scope.function_sprintf("%b", 123) }.to raise_error ArgumentError, /custom functions must be called with a single array that contains the arguments/ + expect do + scope.function_sprintf("%b", 123) + end.to raise_error ArgumentError, /custom functions must be called with a single array that contains the arguments/ end - it "should raise NoMethodError if the method doesn't look like a function" do - expect { @scope.sprintf(["%b", 123]) }.to raise_error(NoMethodError) + it "raises NoMethodError when the not prefixed" do + expect { scope.sprintf(["%b", 123]) }.to raise_error(NoMethodError) end - it "should raise NoMethodError if the method looks like a function but doesn't exist" do - expect { @scope.function_fake_bs(['cows']) }.to raise_error(NoMethodError) + it "raises NoMethodError when prefixed with function_ but it doesn't exist" do + expect { scope.function_fake_bs(['cows']) }.to raise_error(NoMethodError) end end @@ -493,6 +495,27 @@ describe Puppet::Parser::Scope do end end + context "when using ephemeral as local scope" do + it "should store all variables in local scope" do + @scope.new_ephemeral true + @scope.setvar("apple", :fruit) + @scope["apple"].should == :fruit + end + + it "should remove all local scope variables on unset" do + @scope.new_ephemeral true + @scope.setvar("apple", :fruit) + @scope["apple"].should == :fruit + @scope.unset_ephemeral_var + @scope["apple"].should == nil + end + it "should be created from a hash" do + @scope.ephemeral_from({ "apple" => :fruit, "strawberry" => :berry}) + @scope["apple"].should == :fruit + @scope["strawberry"].should == :berry + end + end + describe "when setting ephemeral vars from matches" do before :each do @match = stub 'match', :is_a? => true diff --git a/spec/unit/parser/templatewrapper_spec.rb b/spec/unit/parser/templatewrapper_spec.rb index 1b95b0a73..81e0d846d 100755 --- a/spec/unit/parser/templatewrapper_spec.rb +++ b/spec/unit/parser/templatewrapper_spec.rb @@ -70,6 +70,12 @@ describe Puppet::Parser::TemplateWrapper do tw.tags.should == ["tag1","tag2"] end + it "warns about deprecated access to in-scope variables via method calls" do + Puppet.expects(:deprecation_warning).with("Variable access via 'in_scope_variable' is deprecated. Use '@in_scope_variable' instead. template[inline]:1") + scope["in_scope_variable"] = "is good" + tw.result("<%= in_scope_variable %>") + end + it "provides access to in-scope variables via method calls" do scope["in_scope_variable"] = "is good" tw.result("<%= in_scope_variable %>").should == "is good" @@ -93,11 +99,6 @@ describe Puppet::Parser::TemplateWrapper do tw.result("<%= @one %>").should == "foo" end - it "should not error out if one of the variables is a symbol" do - scope.expects(:to_hash).returns(:_timestamp => "1234") - tw.result("<%= @_timestamp %>").should == "1234" - end - %w{! . ; :}.each do |badchar| it "translates #{badchar} to _ in instance variables" do scope["one#{badchar}"] = "foo" diff --git a/spec/unit/parser/type_loader_spec.rb b/spec/unit/parser/type_loader_spec.rb index e15c05fea..2938d4563 100755 --- a/spec/unit/parser/type_loader_spec.rb +++ b/spec/unit/parser/type_loader_spec.rb @@ -2,6 +2,8 @@ require 'spec_helper' require 'puppet/parser/type_loader' +require 'puppet/parser/parser_factory' +require 'puppet/parser/e_parser_adapter' require 'puppet_spec/modules' require 'puppet_spec/files' @@ -9,222 +11,246 @@ describe Puppet::Parser::TypeLoader do include PuppetSpec::Modules include PuppetSpec::Files - before do - @loader = Puppet::Parser::TypeLoader.new(:myenv) - Puppet.expects(:deprecation_warning).never - end - - it "should support an environment" do - loader = Puppet::Parser::TypeLoader.new(:myenv) - loader.environment.name.should == :myenv - end - - it "should include the Environment Helper" do - @loader.class.ancestors.should be_include(Puppet::Node::Environment::Helper) - end - - it "should delegate its known resource types to its environment" do - @loader.known_resource_types.should be_instance_of(Puppet::Resource::TypeCollection) - end - - describe "when loading names from namespaces" do - it "should do nothing if the name to import is an empty string" do - @loader.expects(:name2files).never - @loader.try_load_fqname(:hostclass, "") { |filename, modname| raise :should_not_occur }.should be_nil + shared_examples_for 'the typeloader' do + before do + @loader = Puppet::Parser::TypeLoader.new(:myenv) + Puppet.expects(:deprecation_warning).never end - it "should attempt to import each generated name" do - @loader.expects(:import).with("foo/bar",nil).returns([]) - @loader.expects(:import).with("foo",nil).returns([]) - @loader.try_load_fqname(:hostclass, "foo::bar") { |f| false } + it "should support an environment" do + loader = Puppet::Parser::TypeLoader.new(:myenv) + loader.environment.name.should == :myenv end - end - describe "when importing" do - before do - Puppet::Parser::Files.stubs(:find_manifests).returns ["modname", %w{file}] - Puppet::Parser::Parser.any_instance.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) - Puppet::Parser::Parser.any_instance.stubs(:file=) + it "should include the Environment Helper" do + @loader.class.ancestors.should be_include(Puppet::Node::Environment::Helper) end - it "should return immediately when imports are being ignored" do - Puppet::Parser::Files.expects(:find_manifests).never - Puppet[:ignoreimport] = true - @loader.import("foo").should be_nil + it "should delegate its known resource types to its environment" do + @loader.known_resource_types.should be_instance_of(Puppet::Resource::TypeCollection) end - it "should find all manifests matching the file or pattern" do - Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| pat == "myfile" }.returns ["modname", %w{one}] - @loader.import("myfile") - end + describe "when loading names from namespaces" do + it "should do nothing if the name to import is an empty string" do + @loader.expects(:name2files).never + @loader.try_load_fqname(:hostclass, "") { |filename, modname| raise :should_not_occur }.should be_nil + end - it "should use the directory of the current file if one is set" do - Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| opts[:cwd] == make_absolute("/current") }.returns ["modname", %w{one}] - @loader.import("myfile", make_absolute("/current/file")) + it "should attempt to import each generated name" do + @loader.expects(:import).with("foo/bar",nil).returns([]) + @loader.expects(:import).with("foo",nil).returns([]) + @loader.try_load_fqname(:hostclass, "foo::bar") { |f| false } + end end - it "should pass the environment when looking for files" do - Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| opts[:environment] == @loader.environment }.returns ["modname", %w{one}] - @loader.import("myfile") - end + describe "when importing" do + before do + Puppet::Parser::Files.stubs(:find_manifests).returns ["modname", %w{file}] + parser_class.any_instance.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) + parser_class.any_instance.stubs(:file=) + end - it "should fail if no files are found" do - Puppet::Parser::Files.expects(:find_manifests).returns [nil, []] - lambda { @loader.import("myfile") }.should raise_error(Puppet::ImportError) - end + it "should return immediately when imports are being ignored" do + Puppet::Parser::Files.expects(:find_manifests).never + Puppet[:ignoreimport] = true + @loader.import("foo").should be_nil + end - it "should parse each found file" do - Puppet::Parser::Files.expects(:find_manifests).returns ["modname", [make_absolute("/one")]] - @loader.expects(:parse_file).with(make_absolute("/one")).returns(Puppet::Parser::AST::Hostclass.new('')) - @loader.import("myfile") - end + it "should find all manifests matching the file or pattern" do + Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| pat == "myfile" }.returns ["modname", %w{one}] + @loader.import("myfile") + end - it "should make each file qualified before attempting to parse it" do - Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{one}] - @loader.expects(:parse_file).with(make_absolute("/current/one")).returns(Puppet::Parser::AST::Hostclass.new('')) - @loader.import("myfile", make_absolute("/current/file")) - end + it "should use the directory of the current file if one is set" do + Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| opts[:cwd] == make_absolute("/current") }.returns ["modname", %w{one}] + @loader.import("myfile", make_absolute("/current/file")) + end - it "should not attempt to import files that have already been imported" do - Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] - Puppet::Parser::Parser.any_instance.expects(:parse).once.returns(Puppet::Parser::AST::Hostclass.new('')) - @loader.import("myfile") + it "should pass the environment when looking for files" do + Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| opts[:environment] == @loader.environment }.returns ["modname", %w{one}] + @loader.import("myfile") + end - # This will fail if it tries to reimport the file. - @loader.import("myfile") - end - end + it "should fail if no files are found" do + Puppet::Parser::Files.expects(:find_manifests).returns [nil, []] + lambda { @loader.import("myfile") }.should raise_error(Puppet::ImportError) + end - describe "when importing all" do - before do - @base = tmpdir("base") + it "should parse each found file" do + Puppet::Parser::Files.expects(:find_manifests).returns ["modname", [make_absolute("/one")]] + @loader.expects(:parse_file).with(make_absolute("/one")).returns(Puppet::Parser::AST::Hostclass.new('')) + @loader.import("myfile") + end - # Create two module path directories - @modulebase1 = File.join(@base, "first") - FileUtils.mkdir_p(@modulebase1) - @modulebase2 = File.join(@base, "second") - FileUtils.mkdir_p(@modulebase2) + it "should make each file qualified before attempting to parse it" do + Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{one}] + @loader.expects(:parse_file).with(make_absolute("/current/one")).returns(Puppet::Parser::AST::Hostclass.new('')) + @loader.import("myfile", make_absolute("/current/file")) + end - Puppet[:modulepath] = "#{@modulebase1}#{File::PATH_SEPARATOR}#{@modulebase2}" - end + it "should not attempt to import files that have already been imported" do + @loader = Puppet::Parser::TypeLoader.new(:myenv) - def mk_module(basedir, name) - PuppetSpec::Modules.create(name, basedir) + Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] + parser_class.any_instance.expects(:parse).once.returns(Puppet::Parser::AST::Hostclass.new('')) + other_parser_class.any_instance.expects(:parse).never.returns(Puppet::Parser::AST::Hostclass.new('')) + @loader.import("myfile") + + # This will fail if it tries to reimport the file. + @loader.import("myfile") + end end - # We have to pass the base path so that we can - # write to modules that are in the second search path - def mk_manifests(base, mod, type, files) - exts = {"ruby" => ".rb", "puppet" => ".pp"} - files.collect do |file| - name = mod.name + "::" + file.gsub("/", "::") - path = File.join(base, mod.name, "manifests", file + exts[type]) - FileUtils.mkdir_p(File.split(path)[0]) - - # write out the class - if type == "ruby" - File.open(path, "w") { |f| f.print "hostclass '#{name}' do\nend" } - else - File.open(path, "w") { |f| f.print "class #{name} {}" } + describe "when importing all" do + before do + @base = tmpdir("base") + + # Create two module path directories + @modulebase1 = File.join(@base, "first") + FileUtils.mkdir_p(@modulebase1) + @modulebase2 = File.join(@base, "second") + FileUtils.mkdir_p(@modulebase2) + + Puppet[:modulepath] = "#{@modulebase1}#{File::PATH_SEPARATOR}#{@modulebase2}" + end + + def mk_module(basedir, name) + PuppetSpec::Modules.create(name, basedir) + end + + # We have to pass the base path so that we can + # write to modules that are in the second search path + def mk_manifests(base, mod, type, files) + exts = {"ruby" => ".rb", "puppet" => ".pp"} + files.collect do |file| + name = mod.name + "::" + file.gsub("/", "::") + path = File.join(base, mod.name, "manifests", file + exts[type]) + FileUtils.mkdir_p(File.split(path)[0]) + + # write out the class + if type == "ruby" + File.open(path, "w") { |f| f.print "hostclass '#{name}' do\nend" } + else + File.open(path, "w") { |f| f.print "class #{name} {}" } + end + name end - name end - end - it "should load all puppet manifests from all modules in the specified environment" do - @module1 = mk_module(@modulebase1, "one") - @module2 = mk_module(@modulebase2, "two") + it "should load all puppet manifests from all modules in the specified environment" do + @module1 = mk_module(@modulebase1, "one") + @module2 = mk_module(@modulebase2, "two") - mk_manifests(@modulebase1, @module1, "puppet", %w{a b}) - mk_manifests(@modulebase2, @module2, "puppet", %w{c d}) + mk_manifests(@modulebase1, @module1, "puppet", %w{a b}) + mk_manifests(@modulebase2, @module2, "puppet", %w{c d}) - @loader.import_all + @loader.import_all - @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type) - @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type) - @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type) - @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type) - end + @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type) + end - it "should load all ruby manifests from all modules in the specified environment" do - Puppet.expects(:deprecation_warning).at_least(1) + it "should load all ruby manifests from all modules in the specified environment" do + Puppet.expects(:deprecation_warning).at_least(1) - @module1 = mk_module(@modulebase1, "one") - @module2 = mk_module(@modulebase2, "two") + @module1 = mk_module(@modulebase1, "one") + @module2 = mk_module(@modulebase2, "two") - mk_manifests(@modulebase1, @module1, "ruby", %w{a b}) - mk_manifests(@modulebase2, @module2, "ruby", %w{c d}) + mk_manifests(@modulebase1, @module1, "ruby", %w{a b}) + mk_manifests(@modulebase2, @module2, "ruby", %w{c d}) - @loader.import_all + @loader.import_all - @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type) - @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type) - @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type) - @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type) - end + @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type) + end - it "should not load manifests from duplicate modules later in the module path" do - @module1 = mk_module(@modulebase1, "one") + it "should not load manifests from duplicate modules later in the module path" do + @module1 = mk_module(@modulebase1, "one") - # duplicate - @module2 = mk_module(@modulebase2, "one") + # duplicate + @module2 = mk_module(@modulebase2, "one") - mk_manifests(@modulebase1, @module1, "puppet", %w{a}) - mk_manifests(@modulebase2, @module2, "puppet", %w{c}) + mk_manifests(@modulebase1, @module1, "puppet", %w{a}) + mk_manifests(@modulebase2, @module2, "puppet", %w{c}) - @loader.import_all + @loader.import_all - @loader.environment.known_resource_types.hostclass("one::c").should be_nil - end + @loader.environment.known_resource_types.hostclass("one::c").should be_nil + end - it "should load manifests from subdirectories" do - @module1 = mk_module(@modulebase1, "one") + it "should load manifests from subdirectories" do + @module1 = mk_module(@modulebase1, "one") - mk_manifests(@modulebase1, @module1, "puppet", %w{a a/b a/b/c}) + mk_manifests(@modulebase1, @module1, "puppet", %w{a a/b a/b/c}) - @loader.import_all + @loader.import_all - @loader.environment.known_resource_types.hostclass("one::a::b").should be_instance_of(Puppet::Resource::Type) - @loader.environment.known_resource_types.hostclass("one::a::b::c").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("one::a::b").should be_instance_of(Puppet::Resource::Type) + @loader.environment.known_resource_types.hostclass("one::a::b::c").should be_instance_of(Puppet::Resource::Type) + end end - end - describe "when parsing a file" do - before do - @parser = Puppet::Parser::Parser.new(@loader.environment) - @parser.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) - @parser.stubs(:file=) - Puppet::Parser::Parser.stubs(:new).with(@loader.environment).returns @parser - end + describe "when parsing a file" do + before do + @parser = Puppet::Parser::ParserFactory.parser(@loader.environment) + @parser.class.should == parser_class + @parser.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) + @parser.stubs(:file=) + Puppet::Parser::ParserFactory.stubs(:parser).with(@loader.environment).returns @parser + end - it "should create a new parser instance for each file using the current environment" do - Puppet::Parser::Parser.expects(:new).with(@loader.environment).returns @parser - @loader.parse_file("/my/file") - end + it "should create a new parser instance for each file using the current environment" do + Puppet::Parser::ParserFactory.expects(:parser).with(@loader.environment).returns @parser + @loader.parse_file("/my/file") + end - it "should assign the parser its file and parse" do - @parser.expects(:file=).with("/my/file") - @parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) - @loader.parse_file("/my/file") + it "should assign the parser its file and parse" do + @parser.expects(:file=).with("/my/file") + @parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) + @loader.parse_file("/my/file") + end end - end - it "should be able to add classes to the current resource type collection" do - file = tmpfile("simple_file.pp") - File.open(file, "w") { |f| f.puts "class foo {}" } - @loader.import(file) + it "should be able to add classes to the current resource type collection" do + file = tmpfile("simple_file.pp") + File.open(file, "w") { |f| f.puts "class foo {}" } + @loader.import(file) - @loader.known_resource_types.hostclass("foo").should be_instance_of(Puppet::Resource::Type) - end + @loader.known_resource_types.hostclass("foo").should be_instance_of(Puppet::Resource::Type) + end - describe "when deciding where to look for files" do - { 'foo' => ['foo'], - 'foo::bar' => ['foo/bar', 'foo'], - 'foo::bar::baz' => ['foo/bar/baz', 'foo/bar', 'foo'] - }.each do |fqname, expected_paths| - it "should look for #{fqname.inspect} in #{expected_paths.inspect}" do - @loader.instance_eval { name2files(fqname) }.should == expected_paths + describe "when deciding where to look for files" do + { 'foo' => ['foo'], + 'foo::bar' => ['foo/bar', 'foo'], + 'foo::bar::baz' => ['foo/bar/baz', 'foo/bar', 'foo'] + }.each do |fqname, expected_paths| + it "should look for #{fqname.inspect} in #{expected_paths.inspect}" do + @loader.instance_eval { name2files(fqname) }.should == expected_paths + end end end end + describe 'when using the classic parser' do + before :each do + Puppet[:parser] = 'current' + end + it_should_behave_like 'the typeloader' do + let(:parser_class) { Puppet::Parser::Parser} + let(:other_parser_class) { Puppet::Parser::EParserAdapter} + end + end + describe 'when using the future parser' do + before :each do + Puppet[:parser] = 'future' + end + it_should_behave_like 'the typeloader' do + let(:parser_class) { Puppet::Parser::EParserAdapter} + let(:other_parser_class) { Puppet::Parser::Parser} + end + end end |
