108 lines
3.4 KiB
JavaScript
108 lines
3.4 KiB
JavaScript
const { Parser } = require('expr-eval');
|
|
|
|
describe('Formula Evaluation Safety', () => {
|
|
test('Parser evaluates simple math expressions', () => {
|
|
const parser = new Parser();
|
|
const expr = parser.parse('2 + 2');
|
|
expect(expr.evaluate({})).toBe(4);
|
|
});
|
|
|
|
test('Parser evaluates formulas with variables', () => {
|
|
const parser = new Parser();
|
|
const expr = parser.parse('area_m2 * 1.5');
|
|
const result = expr.evaluate({ area_m2: 10 });
|
|
expect(result).toBe(15);
|
|
});
|
|
|
|
test('Parser evaluates nested variable access', () => {
|
|
const parser = new Parser();
|
|
const expr = parser.parse('GEOM.area_m2 * 2');
|
|
const result = expr.evaluate({ GEOM: { area_m2: 20 } });
|
|
expect(result).toBe(40);
|
|
});
|
|
|
|
test('Parser handles formulas with operator precedence', () => {
|
|
const parser = new Parser();
|
|
// expr-eval follows math precedence: * before +
|
|
const expr = parser.parse('2 + 3 * 4');
|
|
const result = expr.evaluate({});
|
|
expect(result).toBe(14); // 2 + (3*4) = 2 + 12 = 14
|
|
});
|
|
|
|
test('Parser safely handles division by zero', () => {
|
|
const parser = new Parser();
|
|
const expr = parser.parse('10 / x');
|
|
const result = expr.evaluate({ x: 0 });
|
|
expect(result).toBe(Infinity);
|
|
});
|
|
|
|
test('Parser treats unknown functions as variables', () => {
|
|
// expr-eval allows function-like syntax but treats them as variables if not defined
|
|
const parser = new Parser();
|
|
const expr = parser.parse('eval');
|
|
const result = expr.evaluate({ eval: 42 });
|
|
expect(result).toBe(42);
|
|
});
|
|
|
|
test('Parser only evaluates math expressions safely', () => {
|
|
// expr-eval doesn't execute arbitrary JavaScript
|
|
const parser = new Parser();
|
|
const expr = parser.parse('x + y');
|
|
expect(() => {
|
|
expr.evaluate({ x: 1, y: 2 });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
test('Handles missing variables gracefully', () => {
|
|
const parser = new Parser();
|
|
const expr = parser.parse('area * 2');
|
|
expect(() => {
|
|
expr.evaluate({});
|
|
}).toThrow(); // Should throw because 'area' is undefined
|
|
});
|
|
|
|
test('Formula with waste factor calculation', () => {
|
|
const parser = new Parser();
|
|
const expr = parser.parse('area_m2 * 1.2'); // 20% waste
|
|
const result = expr.evaluate({ area_m2: 100 });
|
|
expect(result).toBe(120);
|
|
});
|
|
});
|
|
|
|
describe('Material Quantity Calculations', () => {
|
|
test('Calculates material quantity with formula and rounding', () => {
|
|
const geometry = { area_m2: 25.7, vindskede_lbm: 12.3 };
|
|
const formula = 'area_m2 * 1.5';
|
|
|
|
const parser = new Parser();
|
|
const expr = parser.parse(formula);
|
|
const calculatedValue = expr.evaluate(geometry);
|
|
const quantity = Math.ceil(calculatedValue);
|
|
|
|
expect(calculatedValue).toBeCloseTo(38.55);
|
|
expect(quantity).toBe(39);
|
|
});
|
|
|
|
test('Handles zero geometry values', () => {
|
|
const geometry = { area_m2: 0, vindskede_lbm: 0 };
|
|
const formula = 'area_m2 * 2';
|
|
|
|
const parser = new Parser();
|
|
const expr = parser.parse(formula);
|
|
const result = expr.evaluate(geometry);
|
|
|
|
expect(result).toBe(0);
|
|
});
|
|
|
|
test('Complex formula with multiple geometry inputs', () => {
|
|
const geometry = { area_m2: 50, vindskede_lbm: 20 };
|
|
const formula = '(area_m2 / 10) + (vindskede_lbm * 0.5)';
|
|
|
|
const parser = new Parser();
|
|
const expr = parser.parse(formula);
|
|
const result = expr.evaluate(geometry);
|
|
|
|
expect(result).toBe(15); // (50/10) + (20*0.5) = 5 + 10
|
|
});
|
|
});
|