#! /usr/bin/env ruby require 'spec_helper' require 'puppet/pops' require 'puppet/pops/evaluator/evaluator_impl' # relative to this spec file (./) does not work as this file is loaded by rspec require File.join(File.dirname(__FILE__), '/evaluator_rspec_helper') describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do include EvaluatorRspecHelper context "When the evaluator performs comparisons" do context "of string values" do it "'a' == 'a' == true" do; evaluate(literal('a') == literal('a')).should == true ; end it "'a' == 'b' == false" do; evaluate(literal('a') == literal('b')).should == false ; end it "'a' != 'a' == false" do; evaluate(literal('a').ne(literal('a'))).should == false ; end it "'a' != 'b' == true" do; evaluate(literal('a').ne(literal('b'))).should == true ; end it "'a' < 'b' == true" do; evaluate(literal('a') < literal('b')).should == true ; end it "'a' < 'a' == false" do; evaluate(literal('a') < literal('a')).should == false ; end it "'b' < 'a' == false" do; evaluate(literal('b') < literal('a')).should == false ; end it "'a' <= 'b' == true" do; evaluate(literal('a') <= literal('b')).should == true ; end it "'a' <= 'a' == true" do; evaluate(literal('a') <= literal('a')).should == true ; end it "'b' <= 'a' == false" do; evaluate(literal('b') <= literal('a')).should == false ; end it "'a' > 'b' == false" do; evaluate(literal('a') > literal('b')).should == false ; end it "'a' > 'a' == false" do; evaluate(literal('a') > literal('a')).should == false ; end it "'b' > 'a' == true" do; evaluate(literal('b') > literal('a')).should == true ; end it "'a' >= 'b' == false" do; evaluate(literal('a') >= literal('b')).should == false ; end it "'a' >= 'a' == true" do; evaluate(literal('a') >= literal('a')).should == true ; end it "'b' >= 'a' == true" do; evaluate(literal('b') >= literal('a')).should == true ; end context "with mixed case" do it "'a' == 'A' == true" do; evaluate(literal('a') == literal('A')).should == true ; end it "'a' != 'A' == false" do; evaluate(literal('a').ne(literal('A'))).should == false ; end it "'a' > 'A' == false" do; evaluate(literal('a') > literal('A')).should == false ; end it "'a' >= 'A' == true" do; evaluate(literal('a') >= literal('A')).should == true ; end it "'A' < 'a' == false" do; evaluate(literal('A') < literal('a')).should == false ; end it "'A' <= 'a' == true" do; evaluate(literal('A') <= literal('a')).should == true ; end end end context "of integer values" do it "1 == 1 == true" do; evaluate(literal(1) == literal(1)).should == true ; end it "1 == 2 == false" do; evaluate(literal(1) == literal(2)).should == false ; end it "1 != 1 == false" do; evaluate(literal(1).ne(literal(1))).should == false ; end it "1 != 2 == true" do; evaluate(literal(1).ne(literal(2))).should == true ; end it "1 < 2 == true" do; evaluate(literal(1) < literal(2)).should == true ; end it "1 < 1 == false" do; evaluate(literal(1) < literal(1)).should == false ; end it "2 < 1 == false" do; evaluate(literal(2) < literal(1)).should == false ; end it "1 <= 2 == true" do; evaluate(literal(1) <= literal(2)).should == true ; end it "1 <= 1 == true" do; evaluate(literal(1) <= literal(1)).should == true ; end it "2 <= 1 == false" do; evaluate(literal(2) <= literal(1)).should == false ; end it "1 > 2 == false" do; evaluate(literal(1) > literal(2)).should == false ; end it "1 > 1 == false" do; evaluate(literal(1) > literal(1)).should == false ; end it "2 > 1 == true" do; evaluate(literal(2) > literal(1)).should == true ; end it "1 >= 2 == false" do; evaluate(literal(1) >= literal(2)).should == false ; end it "1 >= 1 == true" do; evaluate(literal(1) >= literal(1)).should == true ; end it "2 >= 1 == true" do; evaluate(literal(2) >= literal(1)).should == true ; end end context "of mixed value types" do it "1 == 1.0 == true" do; evaluate(literal(1) == literal(1.0)).should == true ; end it "1 < 1.1 == true" do; evaluate(literal(1) < literal(1.1)).should == true ; end it "1.0 == 1 == true" do; evaluate(literal(1.0) == literal(1)).should == true ; end it "1.0 < 2 == true" do; evaluate(literal(1.0) < literal(2)).should == true ; end it "'1.0' < 'a' == true" do; evaluate(literal('1.0') < literal('a')).should == true ; end it "'1.0' < '' == true" do; evaluate(literal('1.0') < literal('')).should == false ; end it "'1.0' < ' ' == true" do; evaluate(literal('1.0') < literal(' ')).should == false ; end it "'a' > '1.0' == true" do; evaluate(literal('a') > literal('1.0')).should == true ; end end context "of unsupported mixed value types" do it "'1' < 1.1 == true" do expect{ evaluate(literal('1') < literal(1.1))}.to raise_error(/String < Float/) end it "'1.0' < 1.1 == true" do expect{evaluate(literal('1.0') < literal(1.1))}.to raise_error(/String < Float/) end end context "of regular expressions" do it "/.*/ == /.*/ == true" do; evaluate(literal(/.*/) == literal(/.*/)).should == true ; end it "/.*/ != /a.*/ == true" do; evaluate(literal(/.*/).ne(literal(/a.*/))).should == true ; end end context "of booleans" do it "true == true == true" do; evaluate(literal(true) == literal(true)).should == true ; end; it "false == false == true" do; evaluate(literal(false) == literal(false)).should == true ; end; it "true == false != true" do; evaluate(literal(true) == literal(false)).should == false ; end; it "false == '' == false" do; evaluate(literal(false) == literal('')).should == false ; end; it "undef == '' == false" do; evaluate(literal(:undef) == literal('')).should == false ; end; it "undef == undef == true" do; evaluate(literal(:undef) == literal(:undef)).should == true ; end; it "nil == undef == true" do; evaluate(literal(nil) == literal(:undef)).should == true ; end; end context "of collections" do it "[1,2,3] == [1,2,3] == true" do evaluate(literal([1,2,3]) == literal([1,2,3])).should == true evaluate(literal([1,2,3]).ne(literal([1,2,3]))).should == false evaluate(literal([1,2,4]) == literal([1,2,3])).should == false evaluate(literal([1,2,4]).ne(literal([1,2,3]))).should == true end it "{'a'=>1, 'b'=>2} == {'a'=>1, 'b'=>2} == true" do evaluate(literal({'a'=>1, 'b'=>2}) == literal({'a'=>1, 'b'=>2})).should == true evaluate(literal({'a'=>1, 'b'=>2}).ne(literal({'a'=>1, 'b'=>2}))).should == false evaluate(literal({'a'=>1, 'b'=>2}) == literal({'x'=>1, 'b'=>2})).should == false evaluate(literal({'a'=>1, 'b'=>2}).ne(literal({'x'=>1, 'b'=>2}))).should == true end end context "of non comparable types" do # TODO: Change the exception type it "false < true == error" do; expect { evaluate(literal(true) < literal(false))}.to raise_error(Puppet::ParseError); end it "false <= true == error" do; expect { evaluate(literal(true) <= literal(false))}.to raise_error(Puppet::ParseError); end it "false > true == error" do; expect { evaluate(literal(true) > literal(false))}.to raise_error(Puppet::ParseError); end it "false >= true == error" do; expect { evaluate(literal(true) >= literal(false))}.to raise_error(Puppet::ParseError); end it "/a/ < /b/ == error" do; expect { evaluate(literal(/a/) < literal(/b/))}.to raise_error(Puppet::ParseError); end it "/a/ <= /b/ == error" do; expect { evaluate(literal(/a/) <= literal(/b/))}.to raise_error(Puppet::ParseError); end it "/a/ > /b/ == error" do; expect { evaluate(literal(/a/) > literal(/b/))}.to raise_error(Puppet::ParseError); end it "/a/ >= /b/ == error" do; expect { evaluate(literal(/a/) >= literal(/b/))}.to raise_error(Puppet::ParseError); end it "[1,2,3] < [1,2,3] == error" do expect{ evaluate(literal([1,2,3]) < literal([1,2,3]))}.to raise_error(Puppet::ParseError) end it "[1,2,3] > [1,2,3] == error" do expect{ evaluate(literal([1,2,3]) > literal([1,2,3]))}.to raise_error(Puppet::ParseError) end it "[1,2,3] >= [1,2,3] == error" do expect{ evaluate(literal([1,2,3]) >= literal([1,2,3]))}.to raise_error(Puppet::ParseError) end it "[1,2,3] <= [1,2,3] == error" do expect{ evaluate(literal([1,2,3]) <= literal([1,2,3]))}.to raise_error(Puppet::ParseError) end it "{'a'=>1, 'b'=>2} < {'a'=>1, 'b'=>2} == error" do expect{ evaluate(literal({'a'=>1, 'b'=>2}) < literal({'a'=>1, 'b'=>2}))}.to raise_error(Puppet::ParseError) end it "{'a'=>1, 'b'=>2} > {'a'=>1, 'b'=>2} == error" do expect{ evaluate(literal({'a'=>1, 'b'=>2}) > literal({'a'=>1, 'b'=>2}))}.to raise_error(Puppet::ParseError) end it "{'a'=>1, 'b'=>2} <= {'a'=>1, 'b'=>2} == error" do expect{ evaluate(literal({'a'=>1, 'b'=>2}) <= literal({'a'=>1, 'b'=>2}))}.to raise_error(Puppet::ParseError) end it "{'a'=>1, 'b'=>2} >= {'a'=>1, 'b'=>2} == error" do expect{ evaluate(literal({'a'=>1, 'b'=>2}) >= literal({'a'=>1, 'b'=>2}))}.to raise_error(Puppet::ParseError) end end end context "When the evaluator performs Regular Expression matching" do it "'a' =~ /.*/ == true" do; evaluate(literal('a') =~ literal(/.*/)).should == true ; end it "'a' =~ '.*' == true" do; evaluate(literal('a') =~ literal(".*")).should == true ; end it "'a' !~ /b.*/ == true" do; evaluate(literal('a').mne(literal(/b.*/))).should == true ; end it "'a' !~ 'b.*' == true" do; evaluate(literal('a').mne(literal("b.*"))).should == true ; end it "'a' =~ Pattern['.*'] == true" do evaluate(literal('a') =~ fqr('Pattern')[literal(".*")]).should == true end it "$a = Pattern['.*']; 'a' =~ $a == true" do expr = block(var('a').set(fqr('Pattern')['foo']), literal('foo') =~ var('a')) evaluate(expr).should == true end it 'should fail if LHS is not a string' do expect { evaluate(literal(666) =~ literal(/6/))}.to raise_error(Puppet::ParseError) end end context "When evaluator evaluates the 'in' operator" do it "should find elements in an array" do evaluate(literal(1).in(literal([1,2,3]))).should == true evaluate(literal(4).in(literal([1,2,3]))).should == false end it "should find keys in a hash" do evaluate(literal('a').in(literal({'x'=>1, 'a'=>2, 'y'=> 3}))).should == true evaluate(literal('z').in(literal({'x'=>1, 'a'=>2, 'y'=> 3}))).should == false end it "should find substrings in a string" do evaluate(literal('ana').in(literal('bananas'))).should == true evaluate(literal('xxx').in(literal('bananas'))).should == false end it "should find substrings in a string (regexp)" do evaluate(literal(/ana/).in(literal('bananas'))).should == true evaluate(literal(/xxx/).in(literal('bananas'))).should == false end it "should find substrings in a string (ignoring case)" do evaluate(literal('ANA').in(literal('bananas'))).should == true evaluate(literal('ana').in(literal('BANANAS'))).should == true evaluate(literal('xxx').in(literal('BANANAS'))).should == false end it "should find sublists in a list" do evaluate(literal([2,3]).in(literal([1,[2,3],4]))).should == true evaluate(literal([2,4]).in(literal([1,[2,3],4]))).should == false end it "should find sublists in a list (case insensitive)" do evaluate(literal(['a','b']).in(literal(['A',['A','B'],'C']))).should == true evaluate(literal(['x','y']).in(literal(['A',['A','B'],'C']))).should == false end it "should find keys in a hash" do evaluate(literal('a').in(literal({'a' => 10, 'b' => 20}))).should == true evaluate(literal('x').in(literal({'a' => 10, 'b' => 20}))).should == false end it "should find keys in a hash (case insensitive)" do evaluate(literal('A').in(literal({'a' => 10, 'b' => 20}))).should == true evaluate(literal('X').in(literal({'a' => 10, 'b' => 20}))).should == false end it "should find keys in a hash (regexp)" do evaluate(literal(/xxx/).in(literal({'abcxxxabc' => 10, 'xyz' => 20}))).should == true evaluate(literal(/yyy/).in(literal({'abcxxxabc' => 10, 'xyz' => 20}))).should == false end it "should find numbers as numbers" do evaluate(literal(15).in(literal([1,0xf,2]))).should == true end it "should not find numbers as strings" do evaluate(literal(15).in(literal([1, '0xf',2]))).should == false evaluate(literal('15').in(literal([1, 0xf,2]))).should == false end it "should not find numbers embedded in strings, nor digits in numbers" do evaluate(literal(15).in(literal([1, '115', 2]))).should == false evaluate(literal(1).in(literal([11, 111, 2]))).should == false evaluate(literal('1').in(literal([11, 111, 2]))).should == false end it 'should find an entry with compatible type in an Array' do evaluate(fqr('Array')[fqr('Integer')].in(literal(['a', [1,2,3], 'b']))).should == true evaluate(fqr('Array')[fqr('Integer')].in(literal(['a', [1,2,'not integer'], 'b']))).should == false end it 'should find an entry with compatible type in a Hash' do evaluate(fqr('Integer').in(literal({1 => 'a', 'a' => 'b'}))).should == true evaluate(fqr('Integer').in(literal({'a' => 'a', 'a' => 'b'}))).should == false end end end