Skip to content

Commit f414eb3

Browse files
committed
chore(test): update tests with latest api
1 parent 77c80cd commit f414eb3

5 files changed

Lines changed: 261 additions & 139 deletions

File tree

tests/context.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { describe, test, expect, beforeEach } from 'vitest'
2+
import { Context, createContext } from '../src/context';
3+
import { compute } from '../src';
4+
5+
6+
let ctx: Context
7+
8+
beforeEach(() => {
9+
ctx = createContext({
10+
variables: { x: 1 },
11+
preferences: {
12+
angles: 'deg'
13+
}
14+
})
15+
})
16+
17+
18+
describe('preferences', () => {
19+
test('angles in degrees', () => {
20+
const result = compute(ctx, 'sin(30)')
21+
expect(result[0].value).toEqual(0.5)
22+
})
23+
24+
test('angles in radians', () => {
25+
ctx.preferences.angles = 'rad'
26+
const result = compute(ctx, 'cos(pi/3)')
27+
expect(result[0].value).toBeCloseTo(0.5)
28+
})
29+
30+
test('fraction digits', () => {
31+
ctx.preferences.fractionDigits = 3
32+
const result = compute(ctx, '2 / 3')
33+
expect(result[0].value).toEqual(0.667)
34+
})
35+
36+
test('precision in results', () => {
37+
ctx.preferences.precision = 4
38+
const result = compute(ctx, '3pi - 1')
39+
expect(result[0].value).toEqual(8.426)
40+
})
41+
42+
});
43+
44+
describe('pre-defined variables', () => {
45+
46+
test('variables - read and write', () => {
47+
const result = compute(ctx, 'y = 2(x + 1)')
48+
expect(result[0].value).toBe(4)
49+
expect(ctx.variables.get('y')).toEqual(4)
50+
})
51+
52+
test('constants - read and write', () => {
53+
ctx.constants.set('y', 6)
54+
expect(() => compute(ctx, 'y = 2(x + 1)')).toThrow()
55+
expect(() => compute(ctx, 'x = 3y')).not.toThrow()
56+
})
57+
})
58+
59+
describe('pre-defined functions', () => {
60+
test('custom math function', () => {
61+
ctx.functions.set('double', (x: number) => x * 2)
62+
expect(() => compute(ctx, 'double(3)')).not.toThrow()
63+
expect(compute(ctx, 'double(3)')[0].value).toEqual(6)
64+
})
65+
})

tests/evaluator.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { describe, test, expect, beforeEach } from 'vitest'
2+
import { tokenize } from '../src/lexer';
3+
import { parse } from '../src/parser';
4+
import { Context, createContext } from '../src/context';
5+
import { evaluate } from '../src/evaluator';
6+
import { createSolutionStack, Solution } from '../src/evaluator/solution';
7+
8+
9+
10+
let ctx: Context
11+
let solution: Solution
12+
13+
beforeEach(() => {
14+
ctx = createContext({
15+
variables: { x: 1 },
16+
preferences: {
17+
angles: 'deg'
18+
}
19+
})
20+
solution = createSolutionStack()
21+
})
22+
23+
24+
describe('evaluator', () => {
25+
test('simple ast tree', () => {
26+
const expr = '1+2+x';
27+
const tokens = tokenize(ctx, expr);
28+
const ast = parse(tokens);
29+
expect(() => evaluate(ctx, ast.body[0], solution)).not.toThrow();
30+
expect(evaluate(ctx, ast.body[0], solution)).toBe(4);
31+
});
32+
33+
test('complex ast tree', () => {
34+
const expr = `1 + add(x + 3, cos(60) + 0.25, 0.25)`;
35+
const tokens = tokenize(ctx, expr);
36+
const ast = parse(tokens);
37+
expect(() => evaluate(ctx, ast.body[0], solution)).not.toThrow();
38+
expect(evaluate(ctx, ast.body[0], solution)).toBe(6);
39+
});
40+
});
41+
42+
describe('solution generator', () => {
43+
test('step by step solution for simple expression', () => {
44+
const expr = `3pi - 1`;
45+
const tokens = tokenize(ctx, expr);
46+
const ast = parse(tokens);
47+
ctx.preferences.precision = 4
48+
evaluate(ctx, ast.body[0], solution)
49+
expect(solution.steps).toStrictEqual([
50+
"(3 * 3.142) - 1",
51+
"9.426 - 1",
52+
"8.426"
53+
]);
54+
});
55+
})

tests/interpreter.test.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

tests/lexer.test.ts

Lines changed: 78 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,95 @@
1-
import { TokenType, tokenize } from '../src/lexer';
1+
import { describe, test, expect, beforeEach } from 'vitest'
2+
import { tokenize } from '../src/lexer';
3+
import { TOKEN } from '../src/lexer/tokens';
4+
import { Context, createContext } from '../src/context';
5+
6+
let ctx: Context
7+
8+
beforeEach(() => {
9+
ctx = createContext()
10+
})
211

312
describe('lexer', () => {
413
test('basic expression', () => {
5-
expect(tokenize(`1+2-3/4*sin(5)`)).toMatchObject([
6-
{ value: '1', type: TokenType.Number },
7-
{ value: '+', type: TokenType.BinaryOperator },
8-
{ value: '2', type: TokenType.Number },
9-
{ value: '-', type: TokenType.BinaryOperator },
10-
{ value: '3', type: TokenType.Number },
11-
{ value: '/', type: TokenType.BinaryOperator },
12-
{ value: '4', type: TokenType.Number },
13-
{ value: '*', type: TokenType.BinaryOperator },
14-
{ value: 'sin', type: TokenType.Function },
15-
{ value: '(', type: TokenType.OpenParen },
16-
{ value: '5', type: TokenType.Number },
17-
{ value: ')', type: TokenType.ClosedParen },
18-
{ value: 'EOF', type: TokenType.EOF }
14+
expect(tokenize(ctx, `1+2-3/4*sin(5)`)).toMatchObject([
15+
{ value: '1', type: TOKEN.NUMBER },
16+
{ value: '+', type: TOKEN.OPERATOR },
17+
{ value: '2', type: TOKEN.NUMBER },
18+
{ value: '-', type: TOKEN.OPERATOR },
19+
{ value: '3', type: TOKEN.NUMBER },
20+
{ value: '/', type: TOKEN.OPERATOR },
21+
{ value: '4', type: TOKEN.NUMBER },
22+
{ value: '*', type: TOKEN.OPERATOR },
23+
{ value: 'sin', type: TOKEN.FUNCTION },
24+
{ value: '(', type: TOKEN.LPAREN },
25+
{ value: '5', type: TOKEN.NUMBER },
26+
{ value: ')', type: TOKEN.RPAREN },
27+
{ value: '\n', type: TOKEN.NEWLINE },
28+
{ value: 'EOF', type: TOKEN.EOF }
1929
]);
2030
});
2131
test('nested expressions', () => {
22-
expect(tokenize(`(1 + (2/4) - (1/2)) * 3`)).toMatchObject([
23-
{ value: '(', type: TokenType.OpenParen },
24-
{ value: '1', type: TokenType.Number },
25-
{ value: '+', type: TokenType.BinaryOperator },
26-
{ value: '(', type: TokenType.OpenParen },
27-
{ value: '2', type: TokenType.Number },
28-
{ value: '/', type: TokenType.BinaryOperator },
29-
{ value: '4', type: TokenType.Number },
30-
{ value: ')', type: TokenType.ClosedParen },
31-
{ value: '-', type: TokenType.BinaryOperator },
32-
{ value: '(', type: TokenType.OpenParen },
33-
{ value: '1', type: TokenType.Number },
34-
{ value: '/', type: TokenType.BinaryOperator },
35-
{ value: '2', type: TokenType.Number },
36-
{ value: ')', type: TokenType.ClosedParen },
37-
{ value: ')', type: TokenType.ClosedParen },
38-
{ value: '*', type: TokenType.BinaryOperator },
39-
{ value: '3', type: TokenType.Number },
40-
{ value: 'EOF', type: TokenType.EOF }
32+
expect(tokenize(ctx, `(1 + (2/4) - (1/2)) * 3`)).toMatchObject([
33+
{ value: '(', type: TOKEN.LPAREN },
34+
{ value: '1', type: TOKEN.NUMBER },
35+
{ value: '+', type: TOKEN.OPERATOR },
36+
{ value: '(', type: TOKEN.LPAREN },
37+
{ value: '2', type: TOKEN.NUMBER },
38+
{ value: '/', type: TOKEN.OPERATOR },
39+
{ value: '4', type: TOKEN.NUMBER },
40+
{ value: ')', type: TOKEN.RPAREN },
41+
{ value: '-', type: TOKEN.OPERATOR },
42+
{ value: '(', type: TOKEN.LPAREN },
43+
{ value: '1', type: TOKEN.NUMBER },
44+
{ value: '/', type: TOKEN.OPERATOR },
45+
{ value: '2', type: TOKEN.NUMBER },
46+
{ value: ')', type: TOKEN.RPAREN },
47+
{ value: ')', type: TOKEN.RPAREN },
48+
{ value: '*', type: TOKEN.OPERATOR },
49+
{ value: '3', type: TOKEN.NUMBER },
50+
{ value: '\n', type: TOKEN.NEWLINE },
51+
{ value: 'EOF', type: TOKEN.EOF }
4152
]);
4253
});
4354
test('identifiers', () => {
44-
expect(tokenize(`tan(a) + cos(b) + sin(c)`)).toMatchObject([
45-
{ value: 'tan', type: TokenType.Function },
46-
{ value: '(', type: TokenType.OpenParen },
47-
{ value: 'a', type: TokenType.Identifier },
48-
{ value: ')', type: TokenType.ClosedParen },
49-
{ value: '+', type: TokenType.BinaryOperator },
50-
{ value: 'cos', type: TokenType.Function },
51-
{ value: '(', type: TokenType.OpenParen },
52-
{ value: 'b', type: TokenType.Identifier },
53-
{ value: ')', type: TokenType.ClosedParen },
54-
{ value: '+', type: TokenType.BinaryOperator },
55-
{ value: 'sin', type: TokenType.Function },
56-
{ value: '(', type: TokenType.OpenParen },
57-
{ value: 'c', type: TokenType.Identifier },
58-
{ value: ')', type: TokenType.ClosedParen },
59-
{ value: 'EOF', type: TokenType.EOF }
55+
expect(tokenize(ctx, `tan(a) + cos(b) + sin(c)`)).toMatchObject([
56+
{ value: 'tan', type: TOKEN.FUNCTION },
57+
{ value: '(', type: TOKEN.LPAREN },
58+
{ value: 'a', type: TOKEN.IDENTIFIER },
59+
{ value: ')', type: TOKEN.RPAREN },
60+
{ value: '+', type: TOKEN.OPERATOR },
61+
{ value: 'cos', type: TOKEN.FUNCTION },
62+
{ value: '(', type: TOKEN.LPAREN },
63+
{ value: 'b', type: TOKEN.IDENTIFIER },
64+
{ value: ')', type: TOKEN.RPAREN },
65+
{ value: '+', type: TOKEN.OPERATOR },
66+
{ value: 'sin', type: TOKEN.FUNCTION },
67+
{ value: '(', type: TOKEN.LPAREN },
68+
{ value: 'c', type: TOKEN.IDENTIFIER },
69+
{ value: ')', type: TOKEN.RPAREN },
70+
{ value: '\n', type: TOKEN.NEWLINE },
71+
{ value: 'EOF', type: TOKEN.EOF }
6072
]);
6173
});
6274
test('variadic parameters', () => {
63-
expect(tokenize(`add(1+2,3,4)`)).toMatchObject([
64-
{ value: 'add', type: TokenType.Function },
65-
{ value: '(', type: TokenType.OpenParen },
66-
{ value: '1', type: TokenType.Number },
67-
{ value: '+', type: TokenType.BinaryOperator },
68-
{ value: '2', type: TokenType.Number },
69-
{ value: ',', type: TokenType.Comma },
70-
{ value: '3', type: TokenType.Number },
71-
{ value: ',', type: TokenType.Comma },
72-
{ value: '4', type: TokenType.Number },
73-
{ value: ')', type: TokenType.ClosedParen },
74-
{ value: 'EOF', type: TokenType.EOF }
75+
expect(tokenize(ctx, `add(1+2,3,4)`)).toMatchObject([
76+
{ value: 'add', type: TOKEN.FUNCTION },
77+
{ value: '(', type: TOKEN.LPAREN },
78+
{ value: '1', type: TOKEN.NUMBER },
79+
{ value: '+', type: TOKEN.OPERATOR },
80+
{ value: '2', type: TOKEN.NUMBER },
81+
{ value: ',', type: TOKEN.COMMA },
82+
{ value: '3', type: TOKEN.NUMBER },
83+
{ value: ',', type: TOKEN.COMMA },
84+
{ value: '4', type: TOKEN.NUMBER },
85+
{ value: ')', type: TOKEN.RPAREN },
86+
{ value: '\n', type: TOKEN.NEWLINE },
87+
{ value: 'EOF', type: TOKEN.EOF }
7588
]);
7689
});
7790
test('invalid expression', () => {
78-
expect(() => tokenize(`sin(x`)).toThrow();
79-
expect(() => tokenize(`2. + 3`)).toThrow();
80-
expect(() => tokenize(`1+2, 3`)).toThrow();
91+
expect(() => tokenize(ctx, `sin(x`)).toThrow();
92+
expect(() => tokenize(ctx, `2. + 3`)).toThrow();
93+
expect(() => tokenize(ctx, `1+2, 3`)).toThrow();
8194
});
8295
});

0 commit comments

Comments
 (0)