spec/calculator_spec.rb in dentaku-3.4.2 vs spec/calculator_spec.rb in dentaku-3.5.0

- old
+ new

@@ -1,9 +1,10 @@ require 'spec_helper' require 'dentaku' describe Dentaku::Calculator do let(:calculator) { described_class.new } + let(:with_case_sensitivity) { described_class.new(case_sensitive: true) } let(:with_memory) { described_class.new.store(apples: 3) } let(:with_aliases) { described_class.new(aliases: { round: ['rrround'] }) } let(:without_nested_data) { described_class.new(nested_data_support: false) } it 'evaluates an expression' do @@ -184,10 +185,15 @@ end it "finds no dependencies in array literals" do expect(calculator.dependencies([1, 2, 3])).to eq([]) end + + it "finds dependencies in item expressions" do + expect(calculator.dependencies('MAP(vals, val, val + step)')).to eq(['vals', 'step']) + expect(calculator.dependencies('ALL(people, person, person.age < adult)')).to eq(['people', 'adult']) + end end describe 'solve!' do it "evaluates properly with variables, even if some in memory" do expect(with_memory.solve!( @@ -255,14 +261,19 @@ end end describe 'solve' do it "returns :undefined when variables are unbound" do - expressions = {more_apples: "apples + 1"} - expect(calculator.solve(expressions)).to eq(more_apples: :undefined) + expressions = {more_apples: "apples + 1", compare_apples: "apples > 1"} + expect(calculator.solve(expressions)).to eq(more_apples: :undefined, compare_apples: :undefined) end + it "returns :undefined when variables are nil" do + expressions = {more_apples: "apples + 1", compare_apples: "apples > 1"} + expect(calculator.store(apples: nil).solve(expressions)).to eq(more_apples: :undefined, compare_apples: :undefined) + end + it "allows passing in a custom value to an error handler" do expressions = {more_apples: "apples + 1"} expect(calculator.solve(expressions) { :foo }) .to eq(more_apples: :foo) end @@ -302,10 +313,24 @@ make_money: :undefined, have_money: :undefined ) }.not_to raise_error end + + it "integrates with custom functions" do + calculator.add_function(:custom, :integer, -> { 1 }) + + result = calculator.solve( + a: "1", + b: "CUSTOM() - a" + ) + + expect(result).to eq( + a: 1, + b: 0 + ) + end end 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) @@ -664,10 +689,35 @@ quantity: 10, fruit: 'banana') expect(value).to eq(5) end + it 'handles nested case statements with case-sensitivity' do + formula = <<-FORMULA + CASE fruit + WHEN 'apple' + THEN 1 * quantity + WHEN 'banana' + THEN + CASE QUANTITY + WHEN 1 THEN 2 + WHEN 10 THEN + CASE type + WHEN 'organic' THEN 5 + END + END + END + FORMULA + value = with_case_sensitivity.evaluate( + formula, + type: 'organic', + quantity: 1, + QUANTITY: 10, + fruit: 'banana') + expect(value).to eq(5) + end + it 'handles multiple nested case statements' do formula = <<-FORMULA CASE fruit WHEN 'apple' THEN @@ -707,9 +757,15 @@ unless [:atanh, :frexp, :lgamma].include?(method) expect(calculator.evaluate("#{method}(1) + 1")).to be_within(0.00001).of(Math.send(method, 1) + 1) end end end + end + + it 'are defined with a properly named class that represents it to support AST marshaling' do + expect { + Marshal.dump(calculator.ast('SQRT(20)')) + }.not_to raise_error end end describe 'disable_cache' do before do