aexpr
Version:
Aexpr is safe javascript expression interpreter, support operators / context accessing / property accessing / lodash functions.
104 lines (87 loc) • 4.14 kB
JavaScript
const interpret = require('../src/index');
describe('unit test', () => {
it('string', () => {
expect(interpret('"abc"')).toBe('abc');
expect(interpret('" abc"')).toBe(' abc');
expect(interpret('"...abc"')).toBe('...abc');
expect(interpret('" ...abc "')).toBe(' ...abc ');
});
it('boolean', () => {
expect(interpret('true')).toBe(true);
expect(interpret('false')).toBe(false);
});
it('object', () => {
expect(typeof interpret('{"name": "jack", "age": 19, "address": "hometown street, great city", "info": {"other": true}}')).toBe('object');
});
it('calculator', () => {
expect(interpret('0')).toBe(0);
expect(interpret('1')).toBe(1);
expect(interpret('1.23')).toBe(1.23);
expect(interpret('1 + 2')).toBe(1 + 2);
expect(interpret('1 - 2')).toBe(1 - 2);
expect(interpret('3 * 2')).toBe(3 * 2);
expect(interpret('3 / 2')).toBe(3 / 2);
expect(interpret('1 / 0')).toBe(1 / 0);
expect(interpret('1 + 2 / 4 * 6')).toBe(1 + 2 / 4 * 6);
expect(interpret('1 + 2 / (4 * 6)')).toBe(1 + 2 / (4 * 6));
});
it('compare', () => {
expect(interpret('1 > 2')).toBe(1 > 2);
expect(interpret('1 < 2')).toBe(1 < 2);
expect(interpret('1 <= 2')).toBe(1 <= 2);
expect(interpret('2 <= 2')).toBe(2 <= 2);
expect(interpret('2 === 2')).toBe(2 <= 2);
});
it('logical', () => {
expect(interpret('1 && 0')).toBe(1 && 0);
expect(interpret('1 && 2')).toBe(1 && 2);
expect(interpret('1 || 0')).toBe(1 || 0);
expect(interpret('1 || 2')).toBe(1 || 2);
});
it('ternary', () => {
expect(interpret('2 > 1 ? 2 : 1')).toBe(2 > 1 ? 2 : 1);
expect(interpret('1 ? 2 : 1')).toBe(1 ? 2 : 1);
expect(interpret('1 > 2 ? "a" : "c"')).toBe(1 > 2 ? "a" : "c");
});
it('context accessing and property accessing', () => {
expect(interpret('a + b', { a: 2, b: 3 })).toBe(2 + 3);
expect(interpret('a + b / c.d', { a: 2, b: 3, c: { d: 5 } })).toBe(2 + 3 / 5);
expect(interpret('a + b / c.d.e', { a: 2, b: 3, c: { d: { e: 5 } } })).toBe(2 + 3 / 5);
});
const arr = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
it('lodash functions', () => {
expect(interpret('_.indexOf(arr, 1)', { arr: [1, 2, 3, 4] })).toBe(0);
expect(interpret(`_.findIndex(arr, { 'user': 'fred' })`, {
arr
})).toBe(1);
expect(interpret(`_.findIndex(arr, opt)`, {
arr,
opt: { 'user': 'fred' }
})).toBe(1);
expect(interpret(`_.findIndex(arr, [ 'active', true ])`, {
arr
})).toBe(2);
expect(interpret(`_.findIndex(arr, opt)`, {
arr,
opt: ['active', true]
})).toBe(2);
expect(interpret(`_.has(obj, 'a.b')`, { obj: { a: { b: 1, c: 2 } } })).toBe(true);
expect(typeof interpret(`_.now()`)).toEqual('number');
// prototype access and error throw
expect(interpret.bind(null, `_.constructor()`)).toThrow('Illegal access, _.constructor is prohibited.');
expect(interpret.bind(null, `_.__proto__.constructor`, {})).toThrow('Cannot read property \'__proto__\' of undefined');
// variable declarations and error throw
expect(interpret.bind(null, `var a = 1`)).toThrow('Parse error on line 1');
expect(interpret.bind(null, `a = 1`)).toThrow('Lexical error on line 1. Unrecognized text');
// avoid memory leak by prohibit statements like 'while'
expect(interpret.bind(null, `while(true){console.log('loop')}`)).toThrow('Parse error');
// not support function type input params
expect(interpret.bind(null, `_.findIndex(users, function(o) { return o.user == 'barney'; })`)).toThrow('Parse error');
// support ordinary input params
expect(interpret(`_.findIndex(users, { 'user': 'fred', 'active': false })`, {users: arr})).toBe(1);
});
});