spec/calculator_spec.rb in dentaku-3.5.1 vs spec/calculator_spec.rb in dentaku-3.5.2
- old
+ new
@@ -20,10 +20,11 @@
expect(calculator.evaluate('2 ^ - 1')).to eq(0.5)
expect(calculator.evaluate('2 ^ -(3 - 2)')).to eq(0.5)
expect(calculator.evaluate('(2 + 3) - 1')).to eq(4)
expect(calculator.evaluate('(-2 + 3) - 1')).to eq(0)
expect(calculator.evaluate('(-2 - 3) - 1')).to eq(-6)
+ expect(calculator.evaluate('1353+91-1-3322-22')).to eq(-1901)
expect(calculator.evaluate('1 + -(2 ^ 2)')).to eq(-3)
expect(calculator.evaluate('3 + -num', num: 2)).to eq(1)
expect(calculator.evaluate('-num + 3', num: 2)).to eq(1)
expect(calculator.evaluate('10 ^ 2')).to eq(100)
expect(calculator.evaluate('0 * 10 ^ -5')).to eq(0)
@@ -327,10 +328,15 @@
have_money: :undefined
)
}.not_to raise_error
end
+ it 'allows to compare "-" or "-."' do
+ expect { calculator.solve("IF('-' = '-', 0, 1)") }.not_to raise_error
+ expect { calculator.solve("IF('-.'= '-.', 0, 1)") }.not_to raise_error
+ end
+
it "integrates with custom functions" do
calculator.add_function(:custom, :integer, -> { 1 })
result = calculator.solve(
a: "1",
@@ -438,25 +444,48 @@
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
- it 'supports date arithmetic' do
- expect(calculator.evaluate!('2020-01-01 + 30').to_date).to eq(Time.local(2020, 1, 31).to_date)
- expect(calculator.evaluate!('2020-01-01 - 1').to_date).to eq(Time.local(2019, 12, 31).to_date)
- expect(calculator.evaluate!('2020-01-01 - 2019-12-31')).to eq(1)
- expect(calculator.evaluate!('2020-01-01 + duration(1, day)').to_date).to eq(Time.local(2020, 1, 2).to_date)
- expect(calculator.evaluate!('2020-01-01 - duration(1, day)').to_date).to eq(Time.local(2019, 12, 31).to_date)
- expect(calculator.evaluate!('2020-01-01 + duration(30, days)').to_date).to eq(Time.local(2020, 1, 31).to_date)
- expect(calculator.evaluate!('2020-01-01 + duration(1, month)').to_date).to eq(Time.local(2020, 2, 1).to_date)
- expect(calculator.evaluate!('2020-01-01 - duration(1, month)').to_date).to eq(Time.local(2019, 12, 1).to_date)
- expect(calculator.evaluate!('2020-01-01 + duration(30, months)').to_date).to eq(Time.local(2022, 7, 1).to_date)
- expect(calculator.evaluate!('2020-01-01 + duration(1, year)').to_date).to eq(Time.local(2021, 1, 1).to_date)
- expect(calculator.evaluate!('2020-01-01 - duration(1, year)').to_date).to eq(Time.local(2019, 1, 1).to_date)
- expect(calculator.evaluate!('2020-01-01 + duration(30, years)').to_date).to eq(Time.local(2050, 1, 1).to_date)
+ describe 'disabling date literals' do
+ it 'does not parse formulas with minus signs as dates' do
+ calculator = described_class.new(raw_date_literals: false)
+ expect(calculator.evaluate!('2020-01-01')).to eq(2018)
+ end
end
+ describe 'supports date arithmetic' do
+ it 'from hardcoded string' do
+ expect(calculator.evaluate!('2020-01-01 + 30').to_date).to eq(Time.local(2020, 1, 31).to_date)
+ expect(calculator.evaluate!('2020-01-01 - 1').to_date).to eq(Time.local(2019, 12, 31).to_date)
+ expect(calculator.evaluate!('2020-01-01 - 2019-12-31')).to eq(1)
+ expect(calculator.evaluate!('2020-01-01 + duration(1, day)').to_date).to eq(Time.local(2020, 1, 2).to_date)
+ expect(calculator.evaluate!('2020-01-01 - duration(1, day)').to_date).to eq(Time.local(2019, 12, 31).to_date)
+ expect(calculator.evaluate!('2020-01-01 + duration(30, days)').to_date).to eq(Time.local(2020, 1, 31).to_date)
+ expect(calculator.evaluate!('2020-01-01 + duration(1, month)').to_date).to eq(Time.local(2020, 2, 1).to_date)
+ expect(calculator.evaluate!('2020-01-01 - duration(1, month)').to_date).to eq(Time.local(2019, 12, 1).to_date)
+ expect(calculator.evaluate!('2020-01-01 + duration(30, months)').to_date).to eq(Time.local(2022, 7, 1).to_date)
+ expect(calculator.evaluate!('2020-01-01 + duration(1, year)').to_date).to eq(Time.local(2021, 1, 1).to_date)
+ expect(calculator.evaluate!('2020-01-01 - duration(1, year)').to_date).to eq(Time.local(2019, 1, 1).to_date)
+ 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'
+
+ 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'))
+ end
+
+ it 'from date object' do
+ value = Date.parse('2023-01-01').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'))
+ end
+ 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)
@@ -469,10 +498,17 @@
expect(calculator.evaluate('round(8.75, 1)')).to eq(BigDecimal('8.8'))
expect(calculator.evaluate('ROUND(apples * 0.93)', apples: 10)).to eq(9)
end
+ it 'include ABS' do
+ expect(calculator.evaluate('abs(-2.2)')).to eq(2.2)
+ expect(calculator.evaluate('abs(5)')).to eq(5)
+
+ expect(calculator.evaluate('ABS(x * -1)', x: 10)).to eq(10)
+ end
+
it 'include NOT' do
expect(calculator.evaluate('NOT(some_boolean)', some_boolean: true)).to be_falsey
expect(calculator.evaluate('NOT(some_boolean)', some_boolean: false)).to be_truthy
expect(calculator.evaluate('NOT(some_boolean) AND 7 > 5', some_boolean: true)).to be_falsey
@@ -756,13 +792,13 @@
fruit: 'apple')
expect(value).to eq(3)
end
end
- describe 'math functions' do
+ describe 'math support' do
Math.methods(false).each do |method|
- it method do
+ it "includes `#{method}`" do
if Math.method(method).arity == 2
expect(calculator.evaluate("#{method}(x,y)", x: 1, y: '2')).to eq(Math.send(method, 1, 2))
expect(calculator.evaluate("#{method}(x,y) + 1", x: 1, y: '2')).to be_within(0.00001).of(Math.send(method, 1, 2) + 1)
expect { calculator.evaluate!("#{method}(x)", x: 1) }.to raise_error(Dentaku::ParseError)
else
@@ -772,13 +808,18 @@
end
end
end
end
- it 'are defined with a properly named class that represents it to support AST marshaling' do
+ it 'defines a properly named class to support AST marshaling' do
expect {
Marshal.dump(calculator.ast('SQRT(20)'))
}.not_to raise_error
+ end
+
+ it 'properly handles a Math::DomainError' do
+ expect(calculator.evaluate('asin(2)')).to be_nil
+ expect { calculator.evaluate!('asin(2)') }.to raise_error(Dentaku::MathDomainError)
end
end
describe 'disable_cache' do
before do