test_goto_interpreter.py 8.62 KB
Newer Older
1
2
3
4
5
6
from gotointerpreter import interpret
from unittest import mock
from unittest import TestCase


def input_continue(prompt):
7
    return ''
8
9


10
11
12
13
def str_yes(prompt):
    return 'J'


14
def input_exit(prompt):
15
    return 'EXIT'
16
17
18
19


class GOTOInterpreterTest(TestCase):
    def test_assignment_default_zero(self):
20
21
22
        self.assertEqual(0, interpret('M1:x0:=x0 + 0;M2:HALT;'))
        self.assertEqual(0, interpret('M1:x0:=x1 + 0;M2:HALT;'))
        self.assertEqual(0, interpret('M1:x0:=x2 + 0;M2:HALT;'))
23
24

    def test_assignment_non_negative(self):
25
26
27
        self.assertEqual(0, interpret('M1:x0:=x0-1;M2:HALT;'))
        self.assertEqual(0, interpret('M1:x0:=x1-1;M2:HALT;'))
        self.assertEqual(0, interpret('M1:x0:=x2-6;M2:HALT;'))
28
29

    def test_assignment_number(self):
30
31
32
        self.assertEqual(5, interpret('M1:x0:=5;M2:HALT;'))
        self.assertEqual(2, interpret('M1:x0:=2;M2:HALT;'))
        self.assertEqual(3, interpret('M1:x0:=3;M2:HALT;'))
33
34

    def test_assignment_variable(self):
35
36
37
38
        self.assertEqual(1, interpret('M1:x0:=x0+1;M2:HALT;'), 1)
        self.assertEqual(4, interpret('M1:x0:= 5; M2:x0:=x0-1; M3:HALT;'))
        self.assertEqual(1, interpret('M1:x0:=x1-1; M2:x0:=x0+1; M3:HALT;'))
        self.assertEqual(3, interpret('M1:x0:=4; M2:x0:= x0 − 1; M3:HALT;'))
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

    def test_assignment_wrong_syntax(self):
        with self.assertRaises(SyntaxError):
            interpret('M1:x1:=x2;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x1:=0+x2;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x5:=-1+x4;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x5:=-x3+x1;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x5:=x1-x3;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x2:=x1+x4;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x2:=x1+2;;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x1:=c;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:xi:=2;M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x0:=xj+1;M2:HALT;')

    def test_goto_skip_lines(self):
63
64
65
        self.assertEqual(2, interpret('M1:x0:=2;M2:GOTO M4;M3:x0:=0;M4:HALT;'))
        self.assertEqual(3, interpret('M1:x0:=3;M2:GOTO M5;M3:GOTO M1;M4:x0:=5;M5:HALT;'))
        self.assertEqual(0, interpret('M1:GOTO M3;M2:x0:=x2+5;M3:HALT;'))
66
67

    def test_if(self):
68
69
70
71
72
        self.assertEqual(10, interpret('M1:x2:=10;' +
                                       'M2:IF x2=0 THEN GOTO M6;' +
                                       'M3:x0:=x0+1;M4:x2:=x2-1;' +
                                       'M5:GOTO M2; M6:HALT;'))
        self.assertEqual(1, interpret('M1:IF x0=5 THEN GOTO M4;M2:IF x0=2 THEN GOTO M4;M3:x0:=x0+1;M4:HALT;'))
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

    def test_syntax_missing_operator(self):
        with self.assertRaises(SyntaxError):
            interpret('M1:x0:=x1 2;M2:HALT;')

    def test_markers_start_with_one(self):
        with self.assertRaises(SyntaxError):
            interpret('M0:x0:=2;M1:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M2:x0:=2;M3:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M10:x0:=2;M11:HALT;')

    def test_markers_increment_by_one(self):
        with self.assertRaises(SyntaxError):
            interpret('M1:x0:=3;M3:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:x0:=2;M1:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; M3:HALT;')

    def test_linebreaks(self):
95
        self.assertEqual(0, interpret('''
96
97
98
        M1:x1:=2;
        M2: IF x1=2 THEN GOTO M4;
        M3:HALT;
99
        M4:GOTO M3;'''))
100
101
102

    @mock.patch('loopinterpreter.input', side_effect=input_continue)
    def test_break(self, custom_input):
103
        self.assertEqual(2, interpret('M1:x0:=2;BREAK M2:HALT;'))
104
105
106

    @mock.patch('loopinterpreter.input', side_effect=input_exit)
    def test_break_exit(self, custom_input):
107
        self.assertEqual(-1, interpret('M1:GOTO M1; BREAK'))
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

    def test_assignment_missing_tokens(self):
        with self.assertRaises(SyntaxError):
            interpret('M1: x0')
        with self.assertRaises(SyntaxError):
            interpret('M1: x1 x2+2;')
        with self.assertRaises(SyntaxError):
            interpret('M1: x1 := x2+2 M2')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; M2:x1 x2+0; M3: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2:x1:=2 M3: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: x1:= M3: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; M2: x1 := x2 M3: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; M2: x1 := x2 - M3: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; M2: x1:= x2 + 1 M3: HALT;')
128

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    def test_goto_missing_tokens(self):
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO :HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M2' +
                      'M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: GOTO :HALT; M3: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3;' +
                      'M2: GOTO M3' +
                      'M3:HALT;')

    def test_goto_jump_not_defined(self):
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M2;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: GOTO M4; M3:HALT;')
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    def test_halt_missing_tokens(self):
        with self.assertRaises(SyntaxError):
            interpret('M1:HALT M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: HALT M3:HALT;')

    def test_if_missing_tokens(self):
        with self.assertRaises(SyntaxError):
            interpret('M1: IF THEN GOTO M2; M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: IF x1 THEN GOTO M2; M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: IF x2 = THEN GOTO M2; M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: IF x0 = 0 GOTO M2; M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: IF x3 = 5 THEN M2; M2:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: IF THEN GOTO M3; M3:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: IF x1 THEN GOTO M2; M3:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: IF x2 = THEN GOTO M2; M3:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: IF x0 = 0 GOTO M2; M3:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1:GOTO M3; M2: IF x3 = 5 THEN M2; M3:HALT;')
175

176
177
178
179
180
181
182
183
184
185
186
187
188
    def test_line_missing_tokens(self):
        with self.assertRaises(SyntaxError):
            interpret('M1 GOTO M2; M2: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; GOTO M3; M3:HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; M2 GOTO M3; M3: HALT;')
        with self.assertRaises(SyntaxError):
            interpret('M1: GOTO M3; M2: M3; M3: HALT;')

    def test_end_without_halt(self):
        with self.assertRaises(SyntaxError):
            interpret('M1: x0:=2;')
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

    @mock.patch('whileinterpreter.input', side_effect=str_yes)
    def test_infinite_loop(self, custom_input):
        self.assertEqual(-1, interpret('M1: x1:=100000; M2: x1:=x1-1; M3: IF x1=0 THEN GOTO M5; M4: GOTO M1; M5:HALT;',
                                       timeout=1))

    def test_given_values(self):
        self.assertEqual(5, interpret('M1: x0:=x1+0; M2: IF x2=0 THEN GOTO M6; M3: x0:=x0+1;' +
                                      'M4: x2:=x2-1; M5: GOTO M2; M6: HALT;', [2, 3]))
        self.assertEqual(4, interpret('M1: x0:=x1+0; M2: IF x2=0 THEN GOTO M6; M3: x0:=x0+1;' +
                                      'M4: x2:=x2-1; M5: GOTO M2; M6: HALT;', [0, 4]))
        self.assertEqual(1, interpret('M1: x0:=x0+1; M2: HALT;', [2,3,4]))

    def test_wrong_given_values(self):
        with self.assertRaises(ValueError):
            interpret('M1: x0:=2;', [-1])
        with self.assertRaises(ValueError):
            interpret('M1: x0:=1;', [0.2])
        with self.assertRaises(ValueError):
            interpret('M1: x0:=4;', ['EINS'])