Skip to content

Commit c5ae47a

Browse files
committed
Added: tests
1 parent ae12235 commit c5ae47a

File tree

7 files changed

+222
-123
lines changed

7 files changed

+222
-123
lines changed

src/array/is_empty.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { assertEquals } from 'https://deno.land/std@0.203.0/assert/assert_equals.ts';
2+
import isEmpty from './is_empty.ts';
3+
4+
Deno.test(
5+
'Calculate median value of number array.',
6+
async (test) => {
7+
await test.step({
8+
name: 'Empty array []',
9+
fn: () => {
10+
assertEquals(
11+
isEmpty([]),
12+
true,
13+
);
14+
},
15+
});
16+
17+
await test.step({
18+
name: 'Array with empty string',
19+
fn: () => {
20+
assertEquals(
21+
isEmpty(['']),
22+
true,
23+
);
24+
},
25+
});
26+
27+
await test.step({
28+
name: 'Array with multiple empty strings',
29+
fn: () => {
30+
assertEquals(
31+
isEmpty([
32+
'',
33+
''
34+
]),
35+
true,
36+
);
37+
},
38+
});
39+
40+
await test.step({
41+
name: 'Array with string',
42+
fn: () => {
43+
assertEquals(
44+
isEmpty([' ']),
45+
false,
46+
);
47+
},
48+
});
49+
},
50+
);

src/array/is_empty.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* This function checks if the input array is empty (only contains empty strings).
3+
*
4+
* @example
5+
* ```ts
6+
* console.log(isEmpty([' ']))
7+
* // false
8+
*
9+
* console.log(isEmpty(['']))
10+
* // true
11+
*
12+
* console.log(isEmpty([
13+
* '',
14+
* ''
15+
* ]))
16+
* // true
17+
* ```
18+
* @param input The input array to check
19+
* @return If the array is empty
20+
*/
21+
export default function isEmpty(input : string[]) : boolean {
22+
return input.join('') === '';
23+
}

src/array/mod.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import forEachPair from './for_each_pair.ts'
2+
import isEmpty from './is_empty.ts'
3+
import removeDuplicates from './remove_duplicates.ts'
4+
5+
export {
6+
forEachPair,
7+
isEmpty,
8+
removeDuplicates
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import CustomError from '../../../error/custom_error.ts';
2+
3+
export default class InvalidInput extends CustomError {
4+
value : string;
5+
constructor(
6+
message : string,
7+
value : string
8+
) {
9+
super(message);
10+
this.value = value;
11+
}
12+
}

src/math/evaluate/evaluate.ts

Lines changed: 15 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,19 @@
1-
/* A Javascript program to evaluate a given
2-
expression where tokens
3-
are separated by space.
4-
*/
5-
6-
function evaluate(expression : string) : number | undefined {
7-
const tokens = expression.split('');
8-
9-
// Stack for numbers: 'values'
10-
const values : number[] = [];
11-
12-
// Stack for Operators: 'ops'
13-
const ops = [];
14-
15-
for (let i = 0; i < tokens.length; i++) {
16-
// Current token is a whitespace, skip it
17-
if (tokens[i] === ' ') {
18-
continue;
19-
}
20-
21-
// Current token is a number,
22-
// push it to stack for numbers
23-
if (tokens[i] >= '0' && tokens[i] <= '9') {
24-
let sbuf = '';
25-
26-
// There may be more than
27-
// one digits in number
28-
while (
29-
i < tokens.length &&
30-
tokens[i] >= '0' &&
31-
tokens[i] <= '9'
32-
) {
33-
sbuf = sbuf + tokens[i++];
34-
}
35-
values.push(parseInt(sbuf, 10));
36-
37-
// Right now the i points to
38-
// the character next to the digit,
39-
// since the for loop also increases
40-
// the i, we would skip one
41-
// token position; we need to
42-
// decrease the value of i by 1 to
43-
// correct the offset.
44-
i--;
45-
} // Current token is an opening
46-
// brace, push it to 'ops'
47-
else if (tokens[i] === '(') {
48-
ops.push(tokens[i]);
49-
} // Closing brace encountered,
50-
// solve entire brace
51-
else if (tokens[i] === ')') {
52-
while (ops[ops.length - 1] !== '(') {
53-
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
54-
}
55-
ops.pop();
56-
} // Current token is an operator.
57-
else if (
58-
tokens[i] === '+' ||
59-
tokens[i] === '-' ||
60-
tokens[i] === '*' ||
61-
tokens[i] === '/'
62-
) {
63-
// While top of 'ops' has same
64-
// or greater precedence to current
65-
// token, which is an operator.
66-
// Apply operator on top of 'ops'
67-
// to top two elements in values stack
68-
while (
69-
ops.length > 0 &&
70-
hasPrecedence(tokens[i], ops[ops.length - 1])
71-
) {
72-
values.push(applyOp(ops.pop() ?? '', values.pop(), values.pop()));
73-
}
74-
75-
// Push current token to 'ops'.
76-
ops.push(tokens[i]);
1+
import parseString from './parse_string.ts';
2+
import { tokenValues } from './tokens.ts';
3+
4+
export default function evaluate(expression : string) : number {
5+
const parts = parseString(expression, tokenValues);
6+
7+
parts.forEach((part) => {
8+
switch (part) {
9+
case value:
10+
11+
break;
12+
13+
default:
14+
break;
7715
}
78-
}
79-
80-
// Entire expression has been
81-
// parsed at this point, apply remaining
82-
// ops to remaining values
83-
while (ops.length > 0) {
84-
values.push(applyOp(ops.pop() ?? '', values.pop() ?? 0, values.pop() ?? 0));
85-
}
86-
87-
// Top of 'values' contains
88-
// result, return it
89-
return values.pop();
90-
}
91-
92-
// Returns true if 'op2' has
93-
// higher or same precedence as 'op1',
94-
// otherwise returns false.
95-
function hasPrecedence(op1 : string, op2 : string) : boolean {
96-
if (op2 === '(' || op2 === ')') {
97-
return false;
98-
}
99-
if (
100-
(op1 === '*' || op1 === '/') &&
101-
(op2 === '+' || op2 === '-')
102-
) {
103-
return false;
104-
} else {
105-
return true;
106-
}
107-
}
16+
})
10817

109-
// A utility method to apply an
110-
// operator 'op' on operands 'a'
111-
// and 'b'. Return the result.
112-
function applyOp(op : string, b : number, a : number) : number {
113-
switch (op) {
114-
case '+':
115-
return a + b;
116-
case '-':
117-
return a - b;
118-
case '*':
119-
return a * b;
120-
case '/':
121-
if (b === 0) {
122-
throw new Error('Cannot divide by zero');
123-
}
124-
return a / b
125-
}
12618
return 0;
12719
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
2+
import { assertEquals } from 'https://deno.land/std@0.203.0/assert/assert_equals.ts';
3+
import parseString from './parse_string.ts';
4+
5+
Deno.test(
6+
'Split string between tokens.',
7+
async (test) => {
8+
await test.step({
9+
name: 'Empty string without tokens',
10+
fn: () => {
11+
assertEquals(
12+
parseString(
13+
'',
14+
[]
15+
),
16+
[]
17+
);
18+
},
19+
});
20+
21+
await test.step({
22+
name: 'Empty string with empty tokens',
23+
fn: () => {
24+
assertEquals(
25+
parseString(
26+
'',
27+
['']
28+
),
29+
[]
30+
);
31+
},
32+
});
33+
34+
await test.step({
35+
name: 'Empty string with tokens',
36+
fn: () => {
37+
assertEquals(
38+
parseString(
39+
'',
40+
['-']
41+
),
42+
[]
43+
);
44+
},
45+
});
46+
47+
await test.step({
48+
name: 'String without tokens',
49+
fn: () => {
50+
assertEquals(
51+
parseString(
52+
'100*(2^12/(7-5))/14.2',
53+
[]
54+
),
55+
['100*(2^12/(7-5))/14.2']
56+
);
57+
},
58+
});
59+
60+
await test.step({
61+
name: 'String without empty tokens',
62+
fn: () => {
63+
assertEquals(
64+
parseString(
65+
'100*(2^12/(7-5))/14.2',
66+
['']
67+
),
68+
['100*(2^12/(7-5))/14.2']
69+
);
70+
},
71+
});
72+
73+
await test.step({
74+
name: 'String with tokens',
75+
fn: () => {
76+
assertEquals(
77+
parseString(
78+
'100*(2^12/(7-5))/14.2',
79+
['-']
80+
),
81+
[
82+
'100*(2^12/(7',
83+
'-',
84+
'5))/14.2'
85+
],
86+
);
87+
},
88+
});
89+
},
90+
);

src/math/evaluate/parse_string.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { isEmpty } from '../../array/mod.ts';
2+
import { Token } from './tokens.ts';
3+
4+
/**
5+
* This function spits a string between tokens.
6+
*
7+
* @param input The input string
8+
* @param tokens A list of char tokens
9+
* @returns The spited array
10+
*/
11+
export default function parseString(
12+
input : string,
13+
tokens : Token[]
14+
) : string[] {
15+
if (!input) {
16+
return [];
17+
}
18+
if (isEmpty(tokens)) {
19+
return [input];
20+
}
21+
const escapedTokens = `\\${tokens.join('\\')}`;
22+
return input.split(new RegExp(`(?=[${escapedTokens}])|(?<=[${escapedTokens}]+)`));
23+
}

0 commit comments

Comments
 (0)