spec/calculator_spec.rb in dentaku-3.5.2 vs spec/calculator_spec.rb in dentaku-3.5.3
- old
+ new
@@ -157,17 +157,31 @@
it 'stores formulas' do
calculator.store_formula('area', 'length * width')
expect(calculator.evaluate!('area', length: 5, width: 5)).to eq(25)
end
+ it 'stores dates' do
+ calculator.store("d1", Date.parse("2024/01/02"))
+ calculator.store("d2", Date.parse("2024/01/06"))
+ expect(calculator.solve(diff: "d1 - d2")).to eq(diff: -4)
+ 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!('a.basket')).to eq(of: 'apples')
expect(calculator.evaluate!('b')).to eq(2)
end
+ it 'stores nested hashes with quotes' do
+ calculator.store(a: {basket: {of: 'apples'}}, b: 2)
+ expect(calculator.evaluate!('`a.basket.of`')).to eq('apples')
+ expect(calculator.evaluate!('`a.basket`')).to eq(of: 'apples')
+ expect(calculator.evaluate!('`b`')).to eq(2)
+ end
+
it 'stores arrays' do
calculator.store(a: [1, 2, 3])
expect(calculator.evaluate!('a[0]')).to eq(1)
expect(calculator.evaluate!('a[x]', x: 1)).to eq(2)
expect(calculator.evaluate!('a[x+1]', x: 1)).to eq(3)
@@ -178,18 +192,26 @@
expect(calculator.evaluate!('{1,2,3}')).to eq([1, 2, 3])
end
end
describe 'dependencies' do
+ it 'respects quoted identifiers in dependencies' do
+ expect(calculator.dependencies("`bob the builder` + `dole the digger` / 3")).to eq(['bob the builder', 'dole the digger'])
+ end
+
it "finds dependencies in a generic statement" do
expect(calculator.dependencies("bob + dole / 3")).to eq(['bob', 'dole'])
end
it "ignores dependencies passed in context" do
expect(calculator.dependencies("a + b", a: 1)).to eq(['b'])
end
+ it "ignores dependencies passed in context for quoted identifiers" do
+ expect(calculator.dependencies("`a-c` + b", "a-c": 1)).to eq(['b'])
+ end
+
it "finds dependencies in formula arguments" do
allow(Dentaku).to receive(:cache_ast?) { true }
expect(calculator.dependencies("CONCAT(bob, dole)")).to eq(['bob', 'dole'])
end
@@ -209,14 +231,15 @@
end
describe 'solve!' do
it "evaluates properly with variables, even if some in memory" do
expect(with_memory.solve!(
+ "monthly fruit budget": "weekly_fruit_budget * 4",
weekly_fruit_budget: "weekly_apple_budget + pear * 4",
weekly_apple_budget: "apples * 7",
pear: "1"
- )).to eq(pear: 1, weekly_apple_budget: 21, weekly_fruit_budget: 25)
+ )).to eq(pear: 1, weekly_apple_budget: 21, weekly_fruit_budget: 25, "monthly fruit budget": 100)
end
it "prefers variables over values in memory if they have no dependencies" do
expect(with_memory.solve!(
weekly_fruit_budget: "weekly_apple_budget + pear * 4",
@@ -410,10 +433,17 @@
expect(calculator.evaluate('foo1 * 2', 'foo1' => 4)).to eq(8)
expect(calculator.evaluate('1foo * 2', '1foo' => 2)).to eq(4)
expect(calculator.evaluate('fo1o * 2', fo1o: 4)).to eq(8)
end
+ it 'accepts special characters in quoted identifiers' do
+ expect(calculator.evaluate('`foo1 bar` * 2', "foo1 bar": 2)).to eq(4)
+ expect(calculator.evaluate('`foo1-bar` * 2', 'foo1-bar' => 4)).to eq(8)
+ expect(calculator.evaluate('`1foo (bar)` * 2', '1foo (bar)' => 2)).to eq(4)
+ expect(calculator.evaluate('`fo1o *bar*` * 2', 'fo1o *bar*': 4)).to eq(8)
+ end
+
it 'compares string literals with string variables' do
expect(calculator.evaluate('fruit = "apple"', fruit: 'apple')).to be_truthy
expect(calculator.evaluate('fruit = "apple"', fruit: 'pear')).to be_falsey
end
@@ -469,20 +499,24 @@
expect(calculator.evaluate!('2020-01-01 + duration(30, years)').to_date).to eq(Time.local(2050, 1, 1).to_date)
end
it 'from string variable' do
value = '2023-01-01'
+ value2 = '2022-12-31'
- expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eql(Date.parse('2023-02-01'))
- expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eql(Date.parse('2022-12-01'))
+ expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eq(Date.parse('2023-02-01'))
+ expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eq(Date.parse('2022-12-01'))
+ expect(calculator.evaluate!('value - value2', { value: value, value2: value2 })).to eq(1)
end
it 'from date object' do
value = Date.parse('2023-01-01').to_date
+ value2 = Date.parse('2022-12-31').to_date
- expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eql(Date.parse('2023-02-01'))
- expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eql(Date.parse('2022-12-01'))
+ expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eq(Date.parse('2023-02-01'))
+ expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eq(Date.parse('2022-12-01'))
+ expect(calculator.evaluate!('value - value2', { value: value, value2: value2 })).to eq(1)
end
end
describe 'functions' do
it 'include IF' do
@@ -518,9 +552,16 @@
it 'evaluates functions with negative numbers' do
expect(calculator.evaluate('if (-1 < 5, -1, 5)')).to eq(-1)
expect(calculator.evaluate('if (-1 = -1, -1, 5)')).to eq(-1)
expect(calculator.evaluate('round(-1.23, 1)')).to eq(BigDecimal('-1.2'))
expect(calculator.evaluate('NOT(some_boolean) AND -1 > 3', some_boolean: true)).to be_falsey
+ end
+
+ it 'calculates intercept correctly' do
+ x_values = [1, 2, 3, 4, 5]
+ y_values = [2, 3, 5, 4, 6]
+ result = calculator.evaluate('INTERCEPT(x_values, y_values)', x_values: x_values, y_values: y_values)
+ expect(result).to be_within(0.001).of(1.3)
end
describe "any" do
it "enumerates values and returns true if any evaluation is truthy" do
expect(calculator.evaluate!('any(xs, x, x > 3)', xs: [1, 2, 3, 4])).to be_truthy