-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathruntime.test.ts
113 lines (97 loc) · 1.86 KB
/
runtime.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import type { Interface } from 'node:readline/promises';
import type { RA } from '../../utils/types.js';
import { runtime } from '../runtime.js';
const reSpecialLine = /^(> |\. )(.+)$/gmu;
const processLines = (line: string): RA<string> =>
line.replaceAll(reSpecialLine, '$1\n$2').split('\n');
/**
* Give some input to the interpreter line by line and assert the output
* matched the expected output.
*
* This is creating a fake IO stream object to fool the interpreter code into
* using a mocked IO stream.
*/
async function fakeInterpreter(commands: string): Promise<void> {
const lines = processLines(commands);
let position = 0;
const stream = {
question: async (prompt: string): Promise<string> => {
if (prompt.length > 0) console.log(prompt);
const output = lines[position];
position += 1;
return output;
},
close: (): void => {
if (position === lines.length)
throw new Error('Expected more input, but got EOF');
},
} as unknown as Interface;
jest.spyOn(console, 'log').mockImplementation((output) => {
expect(output).toEqual(lines[position]);
position += 1;
});
jest.spyOn(console, 'error').mockImplementation((output) => {
expect(output).toEqual(lines[position]);
position += 1;
});
return runtime(stream);
}
test('Interpreter', async () =>
fakeInterpreter(`
int a
0
input a
> 4
4
output a * 2
8
undefined
int loop(int until) {
. output until;
. for(int i; i<until; i++) {
. output i;
. }
. }
(int->int)
loop(4)
4
0
1
2
3
undefined
int do() {
. while(true) {
. int i;
. input i;
. if(i == 0) { return 5; }
. else { output i + 4 / 2; }
. }
. }
(->int)
output do();
> 3
5
> 2
4
> 0
5
undefined
int do(fn ()->int f) {
. output f();
. output f();
. }
(->int->int)
int val() {
. return 4;
. }
(->int)
val;
(->int)
do(val);
4
4
undefined
return
undefined
`));