spec/calculator_spec.rb in dentaku-2.0.10 vs spec/calculator_spec.rb in dentaku-2.0.11

- old
+ new

@@ -30,10 +30,13 @@ expect(calculator.evaluate('15 % 8')).to eq(7) expect(calculator.evaluate('(((695759/735000)^(1/(1981-1991)))-1)*1000').round(4)).to eq(5.5018) expect(calculator.evaluate('0.253/0.253')).to eq(1) expect(calculator.evaluate('0.253/d', d: 0.253)).to eq(1) expect(calculator.evaluate('10 + x', x: 'abc')).to be_nil + expect(calculator.evaluate('t + 1*24*60*60', t: Time.local(2017, 1, 1))).to eq(Time.local(2017, 1, 2)) + expect(calculator.evaluate("2 | 3 * 9")).to eq (27) + expect(calculator.evaluate("2 & 3 * 9")).to eq (2) end describe 'memory' do it { expect(calculator).to be_empty } it { expect(with_memory).not_to be_empty } @@ -57,10 +60,16 @@ it 'stores formulas' do calculator.store_formula('area', 'length * width') expect(calculator.evaluate!('area', length: 5, width: 5)).to eq 25 end + + it 'stores nested hashes' do + calculator.store({a: {basket: {of: 'apples'}}, b: 2}) + expect(calculator.evaluate!('a.basket.of')).to eq 'apples' + expect(calculator.evaluate!('b')).to eq 2 + end end describe 'dependencies' do it "finds dependencies in a generic statement" do expect(calculator.dependencies("bob + dole / 3")).to eq(['bob', 'dole']) @@ -167,10 +176,18 @@ it 'evaluates a statement with no variables' do expect(calculator.evaluate('5+3')).to eq(8) expect(calculator.evaluate('(1+1+1)/3*100')).to eq(100) end + it 'evaluates negation' do + expect(calculator.evaluate('-negative', negative: -1)).to eq(1) + expect(calculator.evaluate('-negative', negative: '-1')).to eq(1) + expect(calculator.evaluate('-negative - 1', negative: '-1')).to eq(0) + expect(calculator.evaluate('-negative - 1', negative: '1')).to eq(-2) + expect(calculator.evaluate('-(negative) - 1', negative: '1')).to eq(-2) + end + it 'fails to evaluate unbound statements' do unbound = 'foo * 1.5' expect { calculator.evaluate!(unbound) }.to raise_error(Dentaku::UnboundVariableError) expect { calculator.evaluate!(unbound) }.to raise_error do |error| expect(error.unbound_variables).to eq ['foo'] @@ -178,10 +195,15 @@ expect(calculator.evaluate(unbound)).to be_nil expect(calculator.evaluate(unbound) { :bar }).to eq :bar expect(calculator.evaluate(unbound) { |e| e }).to eq unbound end + it 'fails to evaluate incomplete statements' do + incomplete = 'true AND' + expect { calculator.evaluate!(incomplete) }.to raise_error(Dentaku::ParseError) + end + it 'evaluates unbound statements given a binding in memory' do expect(calculator.evaluate('foo * 1.5', foo: 2)).to eq(3) expect(calculator.bind(monkeys: 3).evaluate('monkeys < 7')).to be_truthy expect(calculator.evaluate('monkeys / 1.5')).to eq(2) end @@ -221,10 +243,24 @@ expect(calculator.evaluate('some_boolean OR 7 > 5', some_boolean: true)).to be_truthy expect(calculator.evaluate('some_boolean OR 7 < 5', some_boolean: true)).to be_truthy expect(calculator.evaluate('some_boolean OR 7 < 5', some_boolean: false)).to be_falsey end + it 'compares Time variables' do + expect(calculator.evaluate('t1 < t2', t1: Time.local(2017, 1, 1).to_datetime, t2: Time.local(2017, 1, 2).to_datetime)).to be_truthy + expect(calculator.evaluate('t1 < t2', t1: Time.local(2017, 1, 2).to_datetime, t2: Time.local(2017, 1, 1).to_datetime)).to be_falsy + expect(calculator.evaluate('t1 > t2', t1: Time.local(2017, 1, 1).to_datetime, t2: Time.local(2017, 1, 2).to_datetime)).to be_falsy + expect(calculator.evaluate('t1 > t2', t1: Time.local(2017, 1, 2).to_datetime, t2: Time.local(2017, 1, 1).to_datetime)).to be_truthy + end + + it 'compares Time literals with Time variables' do + expect(calculator.evaluate('t1 < 2017-01-02', t1: Time.local(2017, 1, 1).to_datetime)).to be_truthy + expect(calculator.evaluate('t1 < 2017-01-02', t1: Time.local(2017, 1, 3).to_datetime)).to be_falsy + expect(calculator.evaluate('t1 > 2017-01-02', t1: Time.local(2017, 1, 1).to_datetime)).to be_falsy + expect(calculator.evaluate('t1 > 2017-01-02', t1: Time.local(2017, 1, 3).to_datetime)).to be_truthy + end + describe 'functions' do it 'include IF' do expect(calculator.evaluate('if(foo < 8, 10, 20)', foo: 2)).to eq(10) expect(calculator.evaluate('if(foo < 8, 10, 20)', foo: 9)).to eq(20) expect(calculator.evaluate('if (foo < 8, 10, 20)', foo: 2)).to eq(10) @@ -279,20 +315,20 @@ expect(calculator.evaluate('rounddown(1.234, 2)')).to eq(1.23) end end end - describe 'explicit NULL' do - it 'can be used in IF statements' do + describe 'nil values' do + it 'can be used explicitly' do expect(calculator.evaluate('IF(null, 1, 2)')).to eq(2) end - it 'can be used in IF statements when passed in' do + it 'can be assigned to a variable' do expect(calculator.evaluate('IF(foo, 1, 2)', foo: nil)).to eq(2) end - it 'nil values are carried across middle terms' do + it 'are carried across middle terms' do results = calculator.solve!( choice: 'IF(bar, 1, 2)', bar: 'foo', foo: nil) expect(results).to eq( @@ -300,11 +336,11 @@ bar: nil, foo: nil ) end - it 'raises errors when used in arithmetic operation' do + it 'raise errors when used in arithmetic operations' do expect { calculator.solve!(more_apples: "apples + 1", apples: nil) }.to raise_error(Dentaku::ArgumentError) end end @@ -473,12 +509,12 @@ expect(calculator.ast_cache.keys.sort).to eq(['1+1']) end end describe 'string functions' do - it 'concatenates two strings' do + it 'concatenates strings' do expect( - calculator.evaluate('CONCAT(s1, s2)', 's1' => 'abc', 's2' => 'def') + calculator.evaluate('CONCAT(s1, s2, s3)', 's1' => 'ab', 's2' => 'cd', 's3' => 'ef') ).to eq 'abcdef' end end end