#! /usr/bin/env ruby require 'spec_helper' require 'puppet/pops' require 'puppet/pops/evaluator/evaluator_impl' require 'puppet/pops/types/type_factory' # 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/AccessOperator' do include EvaluatorRspecHelper def range(from, to) Puppet::Pops::Types::TypeFactory.range(from, to) end def float_range(from, to) Puppet::Pops::Types::TypeFactory.float_range(from, to) end context 'The evaluator when operating on a String' do it 'can get a single character using a single key index to []' do expect(evaluate(literal('abc')[1])).to eql('b') end it 'can get the last character using the key -1 in []' do expect(evaluate(literal('abc')[-1])).to eql('c') end it 'can get a substring by giving two keys' do expect(evaluate(literal('abcd')[1,2])).to eql('bc') # flattens keys expect(evaluate(literal('abcd')[[1,2]])).to eql('bc') end it 'produces empty string for a substring out of range' do expect(evaluate(literal('abc')[100])).to eql('') end it 'raises an error if arity is wrong for []' do expect{evaluate(literal('abc')[])}.to raise_error(/String supports \[\] with one or two arguments\. Got 0/) expect{evaluate(literal('abc')[1,2,3])}.to raise_error(/String supports \[\] with one or two arguments\. Got 3/) end end context 'The evaluator when operating on an Array' do it 'is tested with the correct assumptions' do expect(literal([1,2,3])[1].current.is_a?(Puppet::Pops::Model::AccessExpression)).to eql(true) end it 'can get an element using a single key index to []' do expect(evaluate(literal([1,2,3])[1])).to eql(2) end it 'can get the last element using the key -1 in []' do expect(evaluate(literal([1,2,3])[-1])).to eql(3) end it 'can get a slice of elements using two keys' do expect(evaluate(literal([1,2,3,4])[1,2])).to eql([2,3]) # flattens keys expect(evaluate(literal([1,2,3,4])[[1,2]])).to eql([2,3]) end it 'produces nil for a missing entry' do expect(evaluate(literal([1,2,3])[100])).to eql(nil) end it 'raises an error if arity is wrong for []' do expect{evaluate(literal([1,2,3,4])[])}.to raise_error(/Array supports \[\] with one or two arguments\. Got 0/) expect{evaluate(literal([1,2,3,4])[1,2,3])}.to raise_error(/Array supports \[\] with one or two arguments\. Got 3/) end end context 'The evaluator when operating on a Hash' do it 'can get a single element giving a single key to []' do expect(evaluate(literal({'a'=>1,'b'=>2,'c'=>3})['b'])).to eql(2) end it 'can lookup an array' do expect(evaluate(literal({[1]=>10,[2]=>20})[[2]])).to eql(20) end it 'produces nil for a missing key' do expect(evaluate(literal({'a'=>1,'b'=>2,'c'=>3})['x'])).to eql(nil) end it 'can get multiple elements by giving multiple keys to []' do expect(evaluate(literal({'a'=>1,'b'=>2,'c'=>3, 'd'=>4})['b', 'd'])).to eql([2, 4]) end it 'compacts the result when using multiple keys' do expect(evaluate(literal({'a'=>1,'b'=>2,'c'=>3, 'd'=>4})['b', 'x'])).to eql([2]) end it 'produces an empty array if none of multiple given keys were missing' do expect(evaluate(literal({'a'=>1,'b'=>2,'c'=>3, 'd'=>4})['x', 'y'])).to eql([]) end it 'raises an error if arity is wrong for []' do expect{evaluate(literal({'a'=>1,'b'=>2,'c'=>3})[])}.to raise_error(/Hash supports \[\] with one or more arguments\. Got 0/) end end context "When applied to a type it" do let(:types) { Puppet::Pops::Types::TypeFactory } # Integer # it 'produces an Integer[from, to]' do expr = fqr('Integer')[1, 3] expect(evaluate(expr)).to eql(range(1,3)) # arguments are flattened expr = fqr('Integer')[[1, 3]] expect(evaluate(expr)).to eql(range(1,3)) end it 'produces an Integer[1]' do expr = fqr('Integer')[1] expect(evaluate(expr)).to eql(range(1,1)) end it 'produces an Integer[from,