Skip to content

Commit

Permalink
feat: new fn calculate field (#66)
Browse files Browse the repository at this point in the history
* feat: new fn fieldCalculate

* chore: add debug

* feat: new fn logicCalculate

* chore: 补充注释

* rf: remove eval

* feat: 支持混合运算符优先级

* feat: 浮点误差功能

* rf: 将小数计算单独作为一个文件

* rf: 完善 fieldCalculate 及添加测试

* feat: 完善精度控制

* chore: logicCalculate benchmark

* 完善测试用例

完善测试用例

* 修改lint错误

修改lint错误

* 修改命名问题,添加额外的类型包裹

* fix: 修复整数时缺乏乘法计算的问题

* 修改assertThrows

修改assertThrows

* 完善beIncludes测试

完善beIncludes测试

* test: 补充 logicCalculate 测试

* 使用 !logicCalculate

使用 !logicCalculate

* fix: 避免错误数据

* fix: 调整相对值的类型, 调整代码结构

* chore: 补充函数注释说明

* 采用定长方法

采用定长方法

---------

Co-authored-by: CarrieGMM <[email protected]>
  • Loading branch information
iugo and CarrieGMM authored Apr 3, 2024
1 parent b00f586 commit d4e4c34
Show file tree
Hide file tree
Showing 13 changed files with 3,514 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
314 changes: 314 additions & 0 deletions js/calculate-field-all.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
import { fieldCalculate } from './calculate-field.ts';
import { assertEquals } from 'https://deno.land/[email protected]/assert/assert_equals.ts';
import { assertThrows } from 'https://deno.land/[email protected]/assert/assert_throws.ts';
Deno.test('testAddAndSub-true', () => {
const data = {
a: '100',
a1: 1,
b: '2',
b1: 2,
c: '3',
c1: 3,
};
//数值之间是否有空格,有影响?

// * 字符串*字符串
assertEquals(fieldCalculate(data, 'a + b'.split(' ')), 102);
// * 数字*字符串
assertEquals(fieldCalculate(data, 'a + a1'.split(' ')), 101);
// * 数字*数字
assertEquals(fieldCalculate(data, 'a1 + b1'.split(' ')), 3);

assertEquals(fieldCalculate(data, '1.5 + 2.5'.split(' ')), 4);

assertEquals(fieldCalculate(data, '0.001 + 0.0002'.split(' ')), 0.0012);

assertEquals(fieldCalculate(data, '1 + 0.0002'.split(' ')), 1.0002);

// - 字符串-字符串
assertEquals(fieldCalculate(data, 'a - b'.split(' ')), 98);
// - 数字-字符串
assertEquals(fieldCalculate(data, 'a - a1'.split(' ')), 99);
// - 数字-数字
assertEquals(fieldCalculate(data, 'a1 - b1'.split(' ')), -1);

assertEquals(fieldCalculate(data, '1.5 - 2.5'.split(' ')), -1);

assertEquals(fieldCalculate(data, '2 - 0.05'.split(' ')), 1.95);

assertEquals(fieldCalculate(data, '0.003 - 0.002'.split(' ')), 0.001);
});

//存在bug,但是代码未处理
Deno.test('testMulAndDiv-true', () => {
const data = {
a: '100',
a1: 1,
b: '2',
b1: 2,
c: '3',
c1: 3,
};

assertEquals(fieldCalculate(data, 'a * b'.split(' ')), 200);

assertEquals(fieldCalculate(data, 'a * a1'.split(' ')), 100);

assertEquals(fieldCalculate(data, 'a1 * b1'.split(' ')), 2);

assertEquals(fieldCalculate(data, '1.5 * 2'.split(' ')), 3);

assertEquals(fieldCalculate(data, '0.5 * 0.22'.split(' ')), 0.11);

assertEquals(fieldCalculate(data, '1.2 * 0.5'.split(' ')), 0.6);

assertEquals(fieldCalculate(data, 'a / b'.split(' ')), 50);

assertEquals(fieldCalculate(data, 'a / a1'.split(' ')), 100);

assertEquals(fieldCalculate(data, 'a1 / b1'.split(' ')), 1 / 2);

assertEquals(fieldCalculate(data, 'a1 / 0'.split(' ')), Infinity);

assertEquals(fieldCalculate(data, '3 / 0.02'.split(' ')), 150);

assertEquals(fieldCalculate(data, '3.0 / 1.5'.split(' ')), 2);

assertEquals(fieldCalculate(data, '0 / 1.5'.split(' ')), 0);

assertEquals(fieldCalculate(data, '0.4 / 0.02'.split(' ')), 20);
});

//此处 assertEquals(fieldCalculate(data, '1.5 * 2'.split(' ')), 3);
Deno.test('testMulAndDiv-true-1', () => {
const data = {
a: '100',
a1: 1,
b: '2',
b1: 2,
c: '3',
c1: 3,
d: '0.5',
};
assertEquals(fieldCalculate(data, '1.5 * 2'.split(' ')), 3);
assertEquals(fieldCalculate(data, 'd * 2'.split(' ')), 1);
});

Deno.test('testRemain-true', () => {
const data = {
a: '100',
a1: 3,
b: '2',
b1: 2,
c: '3',
c1: 3,
};
// * 字符串*字符串
assertEquals(fieldCalculate(data, 'a % b'.split(' ')), 0);
// * 数字*字符串
assertEquals(fieldCalculate(data, 'a % a1'.split(' ')), 1);
// * 数字*数字
assertEquals(fieldCalculate(data, 'a1 % b1'.split(' ')), 1);
});

// 测试括号
Deno.test('testBracket-true', () => {
const data = {
a: '100',
a1: 3,
b: '2',
b1: 2,
c: '3',
c1: 3,
d: 'asdf',
};

// 正确使用;
assertEquals(fieldCalculate(data, '( a1 % b1 ) * 10'.split(' ')), 10);
assertEquals(
fieldCalculate(data, '( ( 2 + 3 ) + a1 % b1 ) * 10'.split(' ')),
60,
);
assertEquals(
fieldCalculate(data, '2 + ( 2 % 3 ) - 10'.split(' ')),
-6,
);
assertEquals(
fieldCalculate(data, ' 2 + 3 % 5'.split(' ')),
5,
);
assertEquals(
fieldCalculate(data, '( 2 + 3 ) * ( 5 - 2 )'.split(' ')),
15,
);

assertEquals(
fieldCalculate(data, '( ( 2 + 3 ) * 2 ) - 1'.split(' ')),
9,
);

assertEquals(
fieldCalculate(data, '10 - ( ( 5 - 2 ) * 2 )'.split(' ')),
4,
);
});

Deno.test('testBracket-Throws-1', () => {
const data = {
a: '100',
a1: 3,
b: '2',
b1: 2,
c: '3',
c1: 3,
d: 'asdf',
};
//只有( (a undefined is not a number
assertThrows(() => {
const calculateField = '( a % b'.split(' ');
fieldCalculate(data, calculateField);
}, 'd');
});
Deno.test('testBracket-Throws-2', () => {
const data = {
a: '100',
a1: 3,
b: '2',
b1: 2,
c: '3',
c1: 3,
d: 'asdf',
};
// 只有)
assertThrows(() => {
const calculateField = ') a % b'.split(' ');
fieldCalculate(data, calculateField);
}, 'd');
});
Deno.test('testBracket-Throws-3', () => {
const data = {
a: '100',
a1: 3,
b: '2',
b1: 2,
c: '3',
c1: 3,
d: 'asdf',
};
//()中没有内容
assertThrows(() => {
const calculateField = '() a % a1'.split(' ');
fieldCalculate(data, calculateField);
}, 'd');
});

//复杂运算测试用例
Deno.test('test-complex-true', () => {
const data = {
a: '100',
a1: 33,
b: '2',
b1: 22,
c: '3',
c1: 3,
d: 'asdf',
};
// 正确使用
assertEquals(fieldCalculate(data, 'a + b - c'.split(' ')), 99);
assertEquals(fieldCalculate(data, 'a * b / 50'.split(' ')), 4);
assertEquals(fieldCalculate(data, '( a + b ) * c / 50'.split(' ')), 306 / 50);
assertEquals(
fieldCalculate(data, '( a + b ) * 100 / 2 + 50'.split(' ')),
5150,
);
assertEquals(
fieldCalculate(data, '( ( a + b ) * 100 / 2 + 50 ) / 25'.split(' ')),
206,
);

assertEquals(
fieldCalculate(data, '( ( a + b ) * 100 / 2 + 50 ) - 25 * 2'.split(' ')),
5100,
);

assertEquals(
fieldCalculate(
data,
'( ( ( a + b ) * 100 / 2 + 50 ) - 25 * 2 ) / c'.split(' '),
),
1700,
);

assertEquals(
fieldCalculate(
data,
'( ( ( a + b ) * 100 / 2 + 50 ) - 25 * 2 ) / ( c * 5 ) % 20'.split(' '),
),
0,
);
assertEquals(
fieldCalculate(
data,
'( ( ( ( a + b ) * 100 / 2 + 50 ) - 25 * 2 ) / c ) + 0.1'.split(' '),
),
1700.1,
);

assertEquals(
fieldCalculate(
data,
' ( a + b ) * 100 / 2 + 50 - 25 * 2 * c + 0.111111111'.split(' '),
),
5000.111111111,
);

assertEquals(
fieldCalculate(
data,
' ( a + b ) * 100 / 2 + 50 - 25 * 2 * c + 0.111111111 - 0.11'.split(' '),
),
5000.001111111,
);
});

//测试溢出
Deno.test('test-overflow', () => {
const data = {
a: '9999999999999999999999999999999999999999',
};
// 溢出问题
assertEquals(fieldCalculate(data, 'a + 10'.split(' ')), 1e+40);
});

//测试非法字符
Deno.test('test-error-1', () => {
const data = {
a: '9999999999999999999999999999999999999999',
};
// 错误
assertThrows(() => {
const calculateField = '2 + 2a'.split(' ');
fieldCalculate(data, calculateField);
}, '2a');
});

//此处连个运算符的方式,预期应提出错误,代码未修改
Deno.test('test-error-2', () => {
const data = {
a: '9999999999999999999999999999999999999999',
};
// 错误
assertThrows(() => {
const calculateField = '2 + + 3'.split(' ');
fieldCalculate(data, calculateField);
}, 'invalid data');
});

//测试非法字符
Deno.test('test-error', () => {
// 错误
assertThrows(() => {
const calculateField = 'a * 3'.split(' ');
fieldCalculate({}, calculateField);
}, 'not found');
});
32 changes: 32 additions & 0 deletions js/calculate-field.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { fieldCalculate, fieldCalculateEval } from './calculate-field.ts';

const data = {
a: '1',
b: '2',
c: '3',
};

Deno.bench('fieldCalculate-format', () => {
fieldCalculate(data, '( a + b ) * c'.split(' ')), 9;
fieldCalculate(data, 'c * ( a + b )'.split(' ')), 9;
fieldCalculate(data, '( a + b ) * 5'.split(' ')), 15;
fieldCalculate(data, '( a + b ) * 5 * ( a + c )'.split(' ')), 60;
fieldCalculate(data, '0.1 * 0.2'.split(' ')), 0.02;
fieldCalculate(data, '0.1 + 0.2'.split(' ')), 0.3;
fieldCalculate(data, '10000.1 + 0.2'.split(' ')), 10000.3;
fieldCalculate(data, '0.3 - 0.1'.split(' ')), 0.2;
fieldCalculate(data, '0.3 / 0.1'.split(' ')), 3;
fieldCalculate({ ...data, a: 10 }, '( a + b ) * 4'.split(' ')), 48;
});
Deno.bench('fieldCalculate-eval', () => {
fieldCalculateEval(data, '( a + b ) * c'.split(' ')), 9;
fieldCalculateEval(data, 'c * ( a + b )'.split(' ')), 9;
fieldCalculateEval(data, '( a + b ) * 5'.split(' ')), 15;
fieldCalculateEval(data, '( a + b ) * 5 * ( a + c )'.split(' ')), 60;
fieldCalculateEval(data, '0.1 * 0.2'.split(' ')), 0.02;
fieldCalculateEval(data, '0.1 + 0.2'.split(' ')), 0.3;
fieldCalculateEval(data, '10000.1 + 0.2'.split(' ')), 10000.3;
fieldCalculateEval(data, '0.3 - 0.1'.split(' ')), 0.2;
fieldCalculateEval(data, '0.3 / 0.1'.split(' ')), 3;
fieldCalculateEval({ ...data, a: 10 }, '( a + b ) * 4'.split(' ')), 48;
});
Loading

0 comments on commit d4e4c34

Please sign in to comment.