|
2 | 2 |
|
3 | 3 | fromforthimportevaluate, StackUnderflowError |
4 | 4 |
|
5 | | - |
6 | 5 | # Tests adapted from `problem-specifications//canonical-data.json` @ v1.7.1 |
7 | 6 |
|
8 | | -classForthUtilities(unittest.TestCase): |
9 | | -# Utility functions |
10 | | -defassertRaisesWithMessage(self, exception): |
11 | | -returnself.assertRaisesRegex(exception, r".+") |
12 | 7 |
|
| 8 | +classForthTest(unittest.TestCase): |
| 9 | + |
| 10 | +# parsing and numbers |
13 | 11 |
|
14 | | -classForthParsingTest(ForthUtilities): |
15 | | -deftest_numbers_just_get_pushed_to_stack(self): |
16 | | -input_data= ["1 2 3 4 5"] |
17 | | -expected= [1, 2, 3, 4, 5] |
18 | | -self.assertEqual(evaluate(input_data), expected) |
| 12 | +deftest_numbers_just_get_pushed_onto_the_stack(self): |
| 13 | +self.assertEqual(evaluate(["1 2 3 4 5"]), [1, 2, 3, 4, 5]) |
19 | 14 |
|
| 15 | +# addition |
20 | 16 |
|
21 | | -classForthAdditionTest(ForthUtilities): |
22 | 17 | deftest_can_add_two_numbers(self): |
23 | | -input_data= ["1 2 +"] |
24 | | -expected= [3] |
25 | | -self.assertEqual(evaluate(input_data), expected) |
| 18 | +self.assertEqual(evaluate(["1 2 +"]), [3]) |
26 | 19 |
|
27 | 20 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
28 | | -input_data= ["+"] |
29 | 21 | withself.assertRaisesWithMessage(StackUnderflowError): |
30 | | -evaluate(input_data) |
| 22 | +evaluate(["+"]) |
31 | 23 |
|
32 | 24 | deftest_errors_if_there_is_only_one_value_on_the_stack(self): |
33 | | -input_data= ["1 +"] |
34 | 25 | withself.assertRaisesWithMessage(StackUnderflowError): |
35 | | -evaluate(input_data) |
| 26 | +evaluate(["1 +"]) |
36 | 27 |
|
| 28 | +# subtraction |
37 | 29 |
|
38 | | -classForthSubtractionTest(ForthUtilities): |
39 | 30 | deftest_can_subtract_two_numbers(self): |
40 | | -input_data= ["3 4 -"] |
41 | | -expected= [-1] |
42 | | -self.assertEqual(evaluate(input_data), expected) |
| 31 | +self.assertEqual(evaluate(["3 4 -"]), [-1]) |
43 | 32 |
|
44 | 33 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
45 | | -input_data= ["-"] |
46 | 34 | withself.assertRaisesWithMessage(StackUnderflowError): |
47 | | -evaluate(input_data) |
| 35 | +evaluate(["-"]) |
48 | 36 |
|
49 | 37 | deftest_errors_if_there_is_only_one_value_on_the_stack(self): |
50 | | -input_data= ["1 -"] |
51 | 38 | withself.assertRaisesWithMessage(StackUnderflowError): |
52 | | -evaluate(input_data) |
| 39 | +evaluate(["1 -"]) |
53 | 40 |
|
| 41 | +# multiplication |
54 | 42 |
|
55 | | -classForthMultiplicationTest(ForthUtilities): |
56 | 43 | deftest_can_multiply_two_numbers(self): |
57 | | -input_data= ["2 4 *"] |
58 | | -expected= [8] |
59 | | -self.assertEqual(evaluate(input_data), expected) |
| 44 | +self.assertEqual(evaluate(["2 4 *"]), [8]) |
60 | 45 |
|
61 | 46 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
62 | | -input_data= ["*"] |
63 | 47 | withself.assertRaisesWithMessage(StackUnderflowError): |
64 | | -evaluate(input_data) |
| 48 | +evaluate(["*"]) |
65 | 49 |
|
66 | 50 | deftest_errors_if_there_is_only_one_value_on_the_stack(self): |
67 | | -input_data= ["1 *"] |
68 | 51 | withself.assertRaisesWithMessage(StackUnderflowError): |
69 | | -evaluate(input_data) |
| 52 | +evaluate(["1 *"]) |
70 | 53 |
|
| 54 | +# division |
71 | 55 |
|
72 | | -classForthDivisionTest(ForthUtilities): |
73 | 56 | deftest_can_divide_two_numbers(self): |
74 | | -input_data= ["12 3 /"] |
75 | | -expected= [4] |
76 | | -self.assertEqual(evaluate(input_data), expected) |
| 57 | +self.assertEqual(evaluate(["12 3 /"]), [4]) |
77 | 58 |
|
78 | 59 | deftest_performs_integer_division(self): |
79 | | -input_data= ["8 3 /"] |
80 | | -expected= [2] |
81 | | -self.assertEqual(evaluate(input_data), expected) |
| 60 | +self.assertEqual(evaluate(["8 3 /"]), [2]) |
82 | 61 |
|
83 | 62 | deftest_errors_if_dividing_by_zero(self): |
84 | | -input_data= ["4 0 /"] |
| 63 | +# divide by zero |
85 | 64 | withself.assertRaisesWithMessage(ZeroDivisionError): |
86 | | -evaluate(input_data) |
| 65 | +evaluate(["4 0 /"]) |
87 | 66 |
|
88 | 67 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
89 | | -input_data= ["/"] |
90 | 68 | withself.assertRaisesWithMessage(StackUnderflowError): |
91 | | -evaluate(input_data) |
| 69 | +evaluate(["/"]) |
92 | 70 |
|
93 | 71 | deftest_errors_if_there_is_only_one_value_on_the_stack(self): |
94 | | -input_data= ["1 /"] |
95 | 72 | withself.assertRaisesWithMessage(StackUnderflowError): |
96 | | -evaluate(input_data) |
| 73 | +evaluate(["1 /"]) |
97 | 74 |
|
| 75 | +# combined arithmetic |
98 | 76 |
|
99 | | -classForthCombinedArithmeticTest(ForthUtilities): |
100 | 77 | deftest_addition_and_subtraction(self): |
101 | | -input_data= ["1 2 + 4 -"] |
102 | | -expected= [-1] |
103 | | -self.assertEqual(evaluate(input_data), expected) |
| 78 | +self.assertEqual(evaluate(["1 2 + 4 -"]), [-1]) |
104 | 79 |
|
105 | 80 | deftest_multiplication_and_division(self): |
106 | | -input_data= ["2 4 * 3 /"] |
107 | | -expected= [2] |
108 | | -self.assertEqual(evaluate(input_data), expected) |
| 81 | +self.assertEqual(evaluate(["2 4 * 3 /"]), [2]) |
109 | 82 |
|
| 83 | +# dup |
110 | 84 |
|
111 | | -classForthDupTest(ForthUtilities): |
112 | 85 | deftest_copies_a_value_on_the_stack(self): |
113 | | -input_data= ["1 dup"] |
114 | | -expected= [1, 1] |
115 | | -self.assertEqual(evaluate(input_data), expected) |
| 86 | +self.assertEqual(evaluate(["1 dup"]), [1, 1]) |
116 | 87 |
|
117 | 88 | deftest_copies_the_top_value_on_the_stack(self): |
118 | | -input_data= ["1 2 dup"] |
119 | | -expected= [1, 2, 2] |
120 | | -self.assertEqual(evaluate(input_data), expected) |
| 89 | +self.assertEqual(evaluate(["1 2 dup"]), [1, 2, 2]) |
121 | 90 |
|
122 | 91 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
123 | | -input_data= ["dup"] |
124 | 92 | withself.assertRaisesWithMessage(StackUnderflowError): |
125 | | -evaluate(input_data) |
| 93 | +evaluate(["dup"]) |
126 | 94 |
|
| 95 | +# drop |
127 | 96 |
|
128 | | -classForthDropTest(ForthUtilities): |
129 | 97 | deftest_removes_the_top_value_on_the_stack_if_it_is_the_only_one(self): |
130 | | -input_data= ["1 drop"] |
131 | | -expected= [] |
132 | | -self.assertEqual(evaluate(input_data), expected) |
| 98 | +self.assertEqual(evaluate(["1 drop"]), []) |
133 | 99 |
|
134 | | -deftest_removes_the_top_value_on_the_stack_if_it_not_the_only_one(self): |
135 | | -input_data= ["3 4 drop"] |
136 | | -expected= [3] |
137 | | -self.assertEqual(evaluate(input_data), expected) |
| 100 | +deftest_removes_the_top_value_on_the_stack_if_it_is_not_the_only_one(self): |
| 101 | +self.assertEqual(evaluate(["1 2 drop"]), [1]) |
138 | 102 |
|
139 | 103 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
140 | | -input_data= ["drop"] |
141 | 104 | withself.assertRaisesWithMessage(StackUnderflowError): |
142 | | -evaluate(input_data) |
| 105 | +evaluate(["drop"]) |
143 | 106 |
|
| 107 | +# swap |
144 | 108 |
|
145 | | -classForthSwapTest(ForthUtilities): |
146 | | -deftest_swaps_only_two_values_on_stack(self): |
147 | | -input_data= ["1 2 swap"] |
148 | | -expected= [2, 1] |
149 | | -self.assertEqual(evaluate(input_data), expected) |
| 109 | +deftest_swaps_the_top_two_values_on_the_stack_if_they_are_the_only_ones(self): |
| 110 | +self.assertEqual(evaluate(["1 2 swap"]), [2, 1]) |
150 | 111 |
|
151 | | -deftest_swaps_two_two_values_on_stack(self): |
152 | | -input_data= ["1 2 3 swap"] |
153 | | -expected= [1, 3, 2] |
154 | | -self.assertEqual(evaluate(input_data), expected) |
| 112 | +deftest_swaps_the_top_two_values_on_the_stack_if_they_are_not_the_only_ones(self): |
| 113 | +self.assertEqual(evaluate(["1 2 3 swap"]), [1, 3, 2]) |
155 | 114 |
|
156 | 115 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
157 | | -input_data= ["swap"] |
158 | 116 | withself.assertRaisesWithMessage(StackUnderflowError): |
159 | | -evaluate(input_data) |
| 117 | +evaluate(["swap"]) |
160 | 118 |
|
161 | 119 | deftest_errors_if_there_is_only_one_value_on_the_stack(self): |
162 | | -input_data= ["1 swap"] |
163 | 120 | withself.assertRaisesWithMessage(StackUnderflowError): |
164 | | -evaluate(input_data) |
| 121 | +evaluate(["1 swap"]) |
165 | 122 |
|
| 123 | +# over |
166 | 124 |
|
167 | | -classForthOverTest(ForthUtilities): |
168 | 125 | deftest_copies_the_second_element_if_there_are_only_two(self): |
169 | | -input_data= ["1 2 over"] |
170 | | -expected= [1, 2, 1] |
171 | | -self.assertEqual(evaluate(input_data), expected) |
| 126 | +self.assertEqual(evaluate(["1 2 over"]), [1, 2, 1]) |
172 | 127 |
|
173 | 128 | deftest_copies_the_second_element_if_there_are_more_than_two(self): |
174 | | -input_data= ["1 2 3 over"] |
175 | | -expected= [1, 2, 3, 2] |
176 | | -self.assertEqual(evaluate(input_data), expected) |
| 129 | +self.assertEqual(evaluate(["1 2 3 over"]), [1, 2, 3, 2]) |
177 | 130 |
|
178 | 131 | deftest_errors_if_there_is_nothing_on_the_stack(self): |
179 | | -input_data= ["over"] |
180 | 132 | withself.assertRaisesWithMessage(StackUnderflowError): |
181 | | -evaluate(input_data) |
| 133 | +evaluate(["over"]) |
182 | 134 |
|
183 | 135 | deftest_errors_if_there_is_only_one_value_on_the_stack(self): |
184 | | -input_data= ["1 over"] |
185 | 136 | withself.assertRaisesWithMessage(StackUnderflowError): |
186 | | -evaluate(input_data) |
| 137 | +evaluate(["1 over"]) |
187 | 138 |
|
| 139 | +# user-defined words |
188 | 140 |
|
189 | | -classForthUserDefinedWordsTest(ForthUtilities): |
190 | 141 | deftest_can_consist_of_built_in_words(self): |
191 | | -input_data= [ |
192 | | -": dup-twice dup dup ;", |
193 | | -"1 dup-twice" |
194 | | - ] |
195 | | -expected= [1, 1, 1] |
196 | | -self.assertEqual(evaluate(input_data), expected) |
| 142 | +self.assertEqual(evaluate([": dup-twice dup dup ;", "1 dup-twice"]), [1, 1, 1]) |
197 | 143 |
|
198 | 144 | deftest_execute_in_the_right_order(self): |
199 | | -input_data= [ |
200 | | -": countup 1 2 3 ;", |
201 | | -"countup" |
202 | | - ] |
203 | | -expected= [1, 2, 3] |
204 | | -self.assertEqual(evaluate(input_data), expected) |
| 145 | +self.assertEqual(evaluate([": countup 1 2 3 ;", "countup"]), [1, 2, 3]) |
205 | 146 |
|
206 | 147 | deftest_can_override_other_user_defined_words(self): |
207 | | -input_data= [ |
208 | | -": foo dup ;", |
209 | | -": foo dup dup ;", |
210 | | -"1 foo" |
211 | | - ] |
212 | | -expected= [1, 1, 1] |
213 | | -self.assertEqual(evaluate(input_data), expected) |
| 148 | +self.assertEqual( |
| 149 | +evaluate([": foo dup ;", ": foo dup dup ;", "1 foo"]), [1, 1, 1] |
| 150 | + ) |
214 | 151 |
|
215 | 152 | deftest_can_override_built_in_words(self): |
216 | | -input_data= [ |
217 | | -": swap dup ;", |
218 | | -"1 swap" |
219 | | - ] |
220 | | -expected= [1, 1] |
221 | | -self.assertEqual(evaluate(input_data), expected) |
| 153 | +self.assertEqual(evaluate([": swap dup ;", "1 swap"]), [1, 1]) |
222 | 154 |
|
223 | 155 | deftest_can_override_built_in_operators(self): |
224 | | -input_data= [ |
225 | | -": + * ;", |
226 | | -"3 4 +" |
227 | | - ] |
228 | | -expected= [12] |
229 | | -self.assertEqual(evaluate(input_data), expected) |
230 | | - |
231 | | -deftest_can_use_different_words_with_same_name(self): |
232 | | -input_data= [ |
233 | | -": foo 5 ;", |
234 | | -": bar foo ;", |
235 | | -": foo 6 ;", |
236 | | -"bar foo" |
237 | | - ] |
238 | | -expected= [5, 6] |
239 | | -self.assertEqual(evaluate(input_data), expected) |
240 | | - |
241 | | -deftest_can_define_word_that_uses_word_with_same_name(self): |
242 | | -input_data= [ |
243 | | -": foo 10 ;", |
244 | | -": foo foo 1 + ;", |
245 | | -"foo" |
246 | | - ] |
247 | | -expected= [11] |
248 | | -self.assertEqual(evaluate(input_data), expected) |
| 156 | +self.assertEqual(evaluate([": + * ;", "3 4 +"]), [12]) |
| 157 | + |
| 158 | +deftest_can_use_different_words_with_the_same_name(self): |
| 159 | +self.assertEqual( |
| 160 | +evaluate([": foo 5 ;", ": bar foo ;", ": foo 6 ;", "bar foo"]), [5, 6] |
| 161 | + ) |
| 162 | + |
| 163 | +deftest_can_define_word_that_uses_word_with_the_same_name(self): |
| 164 | +self.assertEqual(evaluate([": foo 10 ;", ": foo foo 1 + ;", "foo"]), [11]) |
249 | 165 |
|
250 | 166 | deftest_cannot_redefine_numbers(self): |
251 | | -input_data= [": 1 2 ;"] |
252 | 167 | withself.assertRaisesWithMessage(ValueError): |
253 | | -evaluate(input_data) |
| 168 | +evaluate([": 1 2 ;"]) |
254 | 169 |
|
255 | 170 | deftest_errors_if_executing_a_non_existent_word(self): |
256 | | -input_data= ["foo"] |
257 | 171 | withself.assertRaisesWithMessage(ValueError): |
258 | | -evaluate(input_data) |
| 172 | +evaluate(["foo"]) |
259 | 173 |
|
| 174 | +# case-insensitivity |
260 | 175 |
|
261 | | -classForthCaseInsensitivityTest(ForthUtilities): |
262 | 176 | deftest_dup_is_case_insensitive(self): |
263 | | -input_data= ["1 DUP Dup dup"] |
264 | | -expected= [1, 1, 1, 1] |
265 | | -self.assertEqual(evaluate(input_data), expected) |
| 177 | +self.assertEqual(evaluate(["1 DUP Dup dup"]), [1, 1, 1, 1]) |
266 | 178 |
|
267 | 179 | deftest_drop_is_case_insensitive(self): |
268 | | -input_data= ["1 2 3 4 DROP Drop drop"] |
269 | | -expected= [1] |
270 | | -self.assertEqual(evaluate(input_data), expected) |
| 180 | +self.assertEqual(evaluate(["1 2 3 4 DROP Drop drop"]), [1]) |
271 | 181 |
|
272 | 182 | deftest_swap_is_case_insensitive(self): |
273 | | -input_data= ["1 2 SWAP 3 Swap 4 swap"] |
274 | | -expected= [2, 3, 4, 1] |
275 | | -self.assertEqual(evaluate(input_data), expected) |
| 183 | +self.assertEqual(evaluate(["1 2 SWAP 3 Swap 4 swap"]), [2, 3, 4, 1]) |
276 | 184 |
|
277 | 185 | deftest_over_is_case_insensitive(self): |
278 | | -input_data= ["1 2 OVER Over over"] |
279 | | -expected= [1, 2, 1, 2, 1] |
280 | | -self.assertEqual(evaluate(input_data), expected) |
| 186 | +self.assertEqual(evaluate(["1 2 OVER Over over"]), [1, 2, 1, 2, 1]) |
281 | 187 |
|
282 | 188 | deftest_user_defined_words_are_case_insensitive(self): |
283 | | -input_data= [ |
284 | | -": foo dup ;", |
285 | | -"1 FOO Foo foo" |
286 | | - ] |
287 | | -expected= [1, 1, 1, 1] |
288 | | -self.assertEqual(evaluate(input_data), expected) |
| 189 | +self.assertEqual(evaluate([": foo dup ;", "1 FOO Foo foo"]), [1, 1, 1, 1]) |
289 | 190 |
|
290 | 191 | deftest_definitions_are_case_insensitive(self): |
291 | | -input_data= [ |
292 | | -": SWAP DUP Dup dup ;", |
293 | | -"1 swap" |
294 | | - ] |
295 | | -expected= [1, 1, 1, 1] |
296 | | -self.assertEqual(evaluate(input_data), expected) |
| 192 | +self.assertEqual(evaluate([": SWAP DUP Dup dup ;", "1 swap"]), [1, 1, 1, 1]) |
| 193 | + |
| 194 | +# Utility functions |
| 195 | +defassertRaisesWithMessage(self, exception): |
| 196 | +returnself.assertRaisesRegex(exception, r".+") |
297 | 197 |
|
298 | 198 |
|
299 | | -if__name__=='__main__': |
| 199 | +if__name__=="__main__": |
300 | 200 | unittest.main() |
0 commit comments