|
1
|
|
|
from copy import deepcopy |
|
2
|
|
|
|
|
3
|
|
|
from interpreter.trifle_types import ( |
|
4
|
|
|
List, Bytestring, String, Character, |
|
5
|
|
|
TrifleExceptionInstance, |
|
6
|
|
|
Integer, TRUE, FALSE, NULL) |
|
7
|
|
|
from interpreter.trifle_parser import parse_one, parse |
|
8
|
|
|
from interpreter.lexer import lex |
|
9
|
|
|
from interpreter.errors import ( |
|
10
|
|
|
error, value_error, wrong_type, wrong_argument_number) |
|
11
|
|
|
from interpreter.evaluator import evaluate, is_thrown_exception |
|
12
|
|
|
from interpreter.environment import Environment, Scope |
|
13
|
|
|
from main import env_with_prelude |
|
14
|
|
|
|
|
15
|
|
|
from test_utils import ( |
|
16
|
|
|
evaluate_with_prelude, mock_stdout_fd |
|
17
|
|
|
) |
|
18
|
|
|
from built_in_tests import BuiltInTestCase |
|
19
|
|
|
|
|
20
|
|
|
|
|
21
|
|
|
"""Unit tests for functions and macros in the prelude. It's easier to |
|
22
|
|
|
test in Python than in Trifle, since Trifle code uses many parts of |
|
23
|
|
|
the prelude very often. |
|
24
|
|
|
|
|
25
|
|
|
""" |
|
26
|
|
|
|
|
27
|
|
|
# TODO: we should shell out to the RPython-compiled binary instead of |
|
28
|
|
|
# assuming CPython behaves the same. |
|
29
|
|
|
class PreludeTestCase(BuiltInTestCase): |
|
30
|
|
|
env = env_with_prelude() |
|
31
|
|
|
|
|
32
|
|
|
def eval(self, program): |
|
33
|
|
|
"""Evaluate this program in a fresh environment with the prelude |
|
34
|
|
|
already included. Returns the result of the last expression. |
|
35
|
|
|
|
|
36
|
|
|
""" |
|
37
|
|
|
# Fresh copy of the environment so tests don't interfere with one another. |
|
38
|
|
|
env = Environment([Scope({})]) |
|
39
|
|
|
global_scope = self.env.scopes[0] |
|
40
|
|
|
for key, value in global_scope.bindings.iteritems(): |
|
41
|
|
|
# We do a deep copy of mutable values. |
|
42
|
|
|
if isinstance(value, List): |
|
43
|
|
|
env.set(key, deepcopy(value)) |
|
44
|
|
|
elif isinstance(value, String): |
|
45
|
|
|
env.set(key, deepcopy(value)) |
|
46
|
|
|
elif isinstance(value, Bytestring): |
|
47
|
|
|
env.set(key, deepcopy(value)) |
|
48
|
|
|
else: |
|
49
|
|
|
env.set(key, value) |
|
50
|
|
|
|
|
51
|
|
|
parse_tree = parse(lex(program)) |
|
52
|
|
|
if isinstance(parse_tree, TrifleExceptionInstance): |
|
53
|
|
|
self.fail("Parse error on: %r" % program) |
|
54
|
|
|
|
|
55
|
|
|
result = NULL |
|
56
|
|
|
for expression in parse_tree.values: |
|
57
|
|
|
result = evaluate(expression, env) |
|
58
|
|
|
|
|
59
|
|
|
if is_thrown_exception(result, error): |
|
60
|
|
|
return result |
|
61
|
|
|
|
|
62
|
|
|
return result |
|
63
|
|
|
|
|
64
|
|
|
def assertEvalsTo(self, program, expected_result): |
|
65
|
|
|
result = self.eval(program) |
|
66
|
|
|
self.assertEqual(result, expected_result) |
|
67
|
|
|
|
|
68
|
|
|
def test_exceptions_equal(self): |
|
69
|
|
|
"""Regression test: Ensure we aren't actually creating copies of |
|
70
|
|
|
exception types and breaking equality in tests. |
|
71
|
|
|
|
|
72
|
|
|
""" |
|
73
|
|
|
self.assertEqual(self.eval(u'error'), error) |
|
74
|
|
|
|
|
75
|
|
|
|
|
76
|
|
|
class SetTest(PreludeTestCase): |
|
77
|
|
|
def test_set(self): |
|
78
|
|
|
self.assertEvalsTo(u"(set! x 1) x", Integer.fromint(1)) |
|
79
|
|
|
|
|
80
|
|
|
def test_set_returns_null(self): |
|
81
|
|
|
self.assertEvalsTo(u"(set! x 1)", NULL) |
|
82
|
|
|
|
|
83
|
|
|
def test_set_not_symbol(self): |
|
84
|
|
|
result = self.eval(u"(set! 1 2)") |
|
85
|
|
|
|
|
86
|
|
|
self.assertTrifleError(result, wrong_type) |
|
87
|
|
|
|
|
88
|
|
|
# Our exception message should talk about set!, not set-symbol!. |
|
89
|
|
|
self.assertIn("set!", result.message) |
|
90
|
|
|
|
|
91
|
|
|
|
|
92
|
|
|
class FunctionTest(PreludeTestCase): |
|
93
|
|
|
def test_function(self): |
|
94
|
|
|
self.assertEvalsTo(u"(function x () 1) (x)", Integer.fromint(1)) |
|
95
|
|
|
|
|
96
|
|
|
def test_function_returns_null(self): |
|
97
|
|
|
self.assertEvalsTo(u"(function x () 1)", NULL) |
|
98
|
|
|
|
|
99
|
|
|
# TODO: it would be nice to assert that these errors happen |
|
100
|
|
|
# at macro expansion, not during evaluation due to lambda being |
|
101
|
|
|
# robust. |
|
102
|
|
|
def test_function_not_symbol(self): |
|
103
|
|
|
result = self.eval(u"(function 1 () 1)") |
|
104
|
|
|
self.assertTrifleError(result, wrong_type) |
|
105
|
|
|
|
|
106
|
|
|
def test_function_params_not_list(self): |
|
107
|
|
|
result = self.eval(u"(function x y 1)") |
|
108
|
|
|
self.assertTrifleError(result, wrong_type) |
|
109
|
|
|
|
|
110
|
|
|
|
|
111
|
|
|
class DoTest(PreludeTestCase): |
|
112
|
|
|
def test_do(self): |
|
113
|
|
|
self.assertEvalsTo(u"(do 1 2)", Integer.fromint(2)) |
|
114
|
|
|
|
|
115
|
|
|
def test_do_no_args(self): |
|
116
|
|
|
self.assertEvalsTo(u"(do)", NULL) |
|
117
|
|
|
|
|
118
|
|
|
|
|
119
|
|
|
class IdentityTest(PreludeTestCase): |
|
120
|
|
|
def test_identity(self): |
|
121
|
|
|
self.assertEvalsTo(u"(identity 123)", Integer.fromint(123)) |
|
122
|
|
|
|
|
123
|
|
|
|
|
124
|
|
|
class IncTest(PreludeTestCase): |
|
125
|
|
|
def test_inc(self): |
|
126
|
|
|
self.assertEvalsTo(u"(inc 5)", Integer.fromint(6)) |
|
127
|
|
|
|
|
128
|
|
|
def test_inc_macro(self): |
|
129
|
|
|
self.assertEvalsTo(u"(set! x 2) (inc! x) x", Integer.fromint(3)) |
|
130
|
|
|
|
|
131
|
|
|
|
|
132
|
|
|
class ZeroPredicateTest(PreludeTestCase): |
|
133
|
|
|
def test_not_zero(self): |
|
134
|
|
|
self.assertEvalsTo(u"(zero? 5)", FALSE) |
|
135
|
|
|
|
|
136
|
|
|
self.assertEvalsTo(u"(zero? -3)", FALSE) |
|
137
|
|
|
|
|
138
|
|
|
self.assertEvalsTo(u"(zero? #null)", FALSE) |
|
139
|
|
|
|
|
140
|
|
|
def test_zero(self): |
|
141
|
|
|
self.assertEvalsTo(u"(zero? 0)", TRUE) |
|
142
|
|
|
|
|
143
|
|
|
self.assertEvalsTo(u"(zero? 0.0)", TRUE) |
|
144
|
|
|
|
|
145
|
|
|
self.assertEvalsTo(u"(zero? -0.0)", TRUE) |
|
146
|
|
|
|
|
147
|
|
|
|
|
148
|
|
|
class DecTest(PreludeTestCase): |
|
149
|
|
|
def test_dec(self): |
|
150
|
|
|
self.assertEvalsTo(u"(dec 5)", Integer.fromint(4)) |
|
151
|
|
|
|
|
152
|
|
|
def test_dec_macro(self): |
|
153
|
|
|
self.assertEvalsTo(u"(set! x 2) (dec! x) x", Integer.fromint(1)) |
|
154
|
|
|
|
|
155
|
|
|
|
|
156
|
|
|
class ForEachTest(PreludeTestCase): |
|
157
|
|
|
def test_for_each(self): |
|
158
|
|
|
self.assertEqual( |
|
159
|
|
|
evaluate_with_prelude(parse_one(lex(u"""(let (total 0 numbers (list 1 2 3 4)) |
|
160
|
|
|
(for-each number numbers (set! total (+ total number))) |
|
161
|
|
|
total)"""))), |
|
162
|
|
|
Integer.fromint(10)) |
|
163
|
|
|
|
|
164
|
|
|
def test_for_each_eval_list_once(self): |
|
165
|
|
|
self.assertEqual( |
|
166
|
|
|
self.eval( |
|
167
|
|
|
u"(set! x 0)" |
|
168
|
|
|
u"(for-each y (do (inc! x) (list 1 2)) y)" |
|
169
|
|
|
u"x" |
|
170
|
|
|
), |
|
171
|
|
|
Integer.fromint(1)) |
|
172
|
|
|
|
|
173
|
|
|
|
|
174
|
|
|
class LoopTest(PreludeTestCase): |
|
175
|
|
|
def test_loop(self): |
|
176
|
|
|
self.assertEqual( |
|
177
|
|
|
self.eval( |
|
178
|
|
|
u"(set! x 0)" |
|
179
|
|
|
u"(try" |
|
180
|
|
|
u' (loop (if (< x 5) (inc! x) (throw error "done!")))' |
|
181
|
|
|
u" :catch error e" |
|
182
|
|
|
u" x" |
|
183
|
|
|
u")" |
|
184
|
|
|
), |
|
185
|
|
|
Integer.fromint(5)) |
|
186
|
|
|
|
|
187
|
|
|
|
|
188
|
|
|
class ListTest(PreludeTestCase): |
|
189
|
|
|
def test_list(self): |
|
190
|
|
|
expected = List([Integer.fromint(1), Integer.fromint(2), Integer.fromint(3)]) |
|
191
|
|
|
self.assertEvalsTo(u"(list 1 2 3)", expected) |
|
192
|
|
|
|
|
193
|
|
|
|
|
194
|
|
|
class MapTest(PreludeTestCase): |
|
195
|
|
|
def test_map(self): |
|
196
|
|
|
expected = List([Integer.fromint(2), Integer.fromint(3), Integer.fromint(4)]) |
|
197
|
|
|
self.assertEvalsTo(u"(map (lambda (x) (+ x 1)) (list 1 2 3))", expected) |
|
198
|
|
|
|
|
199
|
|
|
def test_map_bytestring(self): |
|
200
|
|
|
self.assertEqual( |
|
201
|
|
|
evaluate_with_prelude(parse_one(lex(u'(map (lambda (x) (+ x 1)) #bytes("abc"))'))), |
|
202
|
|
|
Bytestring([ord(c) for c in "bcd"])) |
|
203
|
|
|
|
|
204
|
|
|
def test_map_string(self): |
|
205
|
|
|
self.assertEqual( |
|
206
|
|
|
evaluate_with_prelude(parse_one(lex(u'(map (lambda (x) \'z\') "abc")'))), |
|
207
|
|
|
String(list(u"zzz"))) |
|
208
|
|
|
|
|
209
|
|
|
|
|
210
|
|
|
class FilterTest(PreludeTestCase): |
|
211
|
|
|
def test_filter(self): |
|
212
|
|
|
self.assertEvalsTo(u"(filter (lambda (x) (equal? x 2)) (list 1 2 3))", |
|
213
|
|
|
List([Integer.fromint(2)])) |
|
214
|
|
|
|
|
215
|
|
|
def test_map_bytestring(self): |
|
216
|
|
|
self.assertEqual( |
|
217
|
|
|
evaluate_with_prelude(parse_one(lex(u'(filter (lambda (x) (equal? x 98)) #bytes("abc"))'))), |
|
218
|
|
|
Bytestring([ord("b")])) |
|
219
|
|
|
|
|
220
|
|
|
def test_map_string(self): |
|
221
|
|
|
self.assertEqual( |
|
222
|
|
|
evaluate_with_prelude(parse_one(lex(u'(filter (lambda (x) (equal? x \'b\')) "abc")'))), |
|
223
|
|
|
String(list(u"b"))) |
|
224
|
|
|
|
|
225
|
|
|
|
|
226
|
|
|
class NthItemTest(PreludeTestCase): |
|
227
|
|
|
def test_first(self): |
|
228
|
|
|
self.assertEvalsTo(u"(first (list 1 2 3 4 5))", Integer.fromint(1)) |
|
229
|
|
|
|
|
230
|
|
|
def test_first_bytestring(self): |
|
231
|
|
|
self.assertEqual( |
|
232
|
|
|
evaluate_with_prelude(parse_one(lex(u'(first #bytes("abc"))'))), |
|
233
|
|
|
Integer.fromint(97)) |
|
234
|
|
|
|
|
235
|
|
|
def test_first_string(self): |
|
236
|
|
|
self.assertEqual( |
|
237
|
|
|
evaluate_with_prelude(parse_one(lex(u'(first "abc")'))), |
|
238
|
|
|
Character(u'a')) |
|
239
|
|
|
|
|
240
|
|
|
def test_second(self): |
|
241
|
|
|
self.assertEvalsTo(u"(second (list 1 2 3 4 5))", Integer.fromint(2)) |
|
242
|
|
|
|
|
243
|
|
|
def test_second_bytestring(self): |
|
244
|
|
|
self.assertEqual( |
|
245
|
|
|
evaluate_with_prelude(parse_one(lex(u'(second #bytes("abc"))'))), |
|
246
|
|
|
Integer.fromint(98)) |
|
247
|
|
|
|
|
248
|
|
|
def test_second_string(self): |
|
249
|
|
|
self.assertEqual( |
|
250
|
|
|
evaluate_with_prelude(parse_one(lex(u'(second "abc")'))), |
|
251
|
|
|
Character(u'b')) |
|
252
|
|
|
|
|
253
|
|
|
def test_third(self): |
|
254
|
|
|
self.assertEvalsTo(u"(third (list 1 2 3 4 5))", Integer.fromint(3)) |
|
255
|
|
|
|
|
256
|
|
|
def test_third_bytestring(self): |
|
257
|
|
|
self.assertEqual( |
|
258
|
|
|
evaluate_with_prelude(parse_one(lex(u'(third #bytes("abc"))'))), |
|
259
|
|
|
Integer.fromint(99)) |
|
260
|
|
|
|
|
261
|
|
|
def test_third_string(self): |
|
262
|
|
|
self.assertEqual( |
|
263
|
|
|
evaluate_with_prelude(parse_one(lex(u'(third "abc")'))), |
|
264
|
|
|
Character(u'c')) |
|
265
|
|
|
|
|
266
|
|
|
def test_fourth(self): |
|
267
|
|
|
self.assertEvalsTo(u"(fourth (list 1 2 3 4 5))", Integer.fromint(4)) |
|
268
|
|
|
|
|
269
|
|
|
def test_fourth_bytestring(self): |
|
270
|
|
|
self.assertEqual( |
|
271
|
|
|
evaluate_with_prelude(parse_one(lex(u'(fourth #bytes("abcd"))'))), |
|
272
|
|
|
Integer.fromint(100)) |
|
273
|
|
|
|
|
274
|
|
|
def test_fourth_string(self): |
|
275
|
|
|
self.assertEqual( |
|
276
|
|
|
evaluate_with_prelude(parse_one(lex(u'(fourth "abcd")'))), |
|
277
|
|
|
Character(u'd')) |
|
278
|
|
|
|
|
279
|
|
|
def test_fifth(self): |
|
280
|
|
|
self.assertEvalsTo(u"(fifth (list 1 2 3 4 5))", Integer.fromint(5)) |
|
281
|
|
|
|
|
282
|
|
|
def test_fifth_bytestring(self): |
|
283
|
|
|
self.assertEqual( |
|
284
|
|
|
evaluate_with_prelude(parse_one(lex(u'(fifth #bytes("abcde"))'))), |
|
285
|
|
|
Integer.fromint(101)) |
|
286
|
|
|
|
|
287
|
|
|
def test_fifth_string(self): |
|
288
|
|
|
self.assertEqual( |
|
289
|
|
|
evaluate_with_prelude(parse_one(lex(u'(fifth "abcde")'))), |
|
290
|
|
|
Character(u'e')) |
|
291
|
|
|
|
|
292
|
|
|
|
|
293
|
|
|
class LastTest(PreludeTestCase): |
|
294
|
|
|
def test_last(self): |
|
295
|
|
|
self.assertEvalsTo(u"(last (list 1 2 3 4 5))", Integer.fromint(5)) |
|
296
|
|
|
|
|
297
|
|
|
def test_last_bytestring(self): |
|
298
|
|
|
self.assertEqual( |
|
299
|
|
|
evaluate_with_prelude(parse_one(lex(u'(last #bytes("abc"))'))), |
|
300
|
|
|
Integer.fromint(99)) |
|
301
|
|
|
|
|
302
|
|
|
def test_last_string(self): |
|
303
|
|
|
self.assertEqual( |
|
304
|
|
|
evaluate_with_prelude(parse_one(lex(u'(last "abc")'))), |
|
305
|
|
|
Character(u'c')) |
|
306
|
|
|
|
|
307
|
|
|
def test_last_empty_list(self): |
|
308
|
|
|
# TODO: we need a separate index error |
|
309
|
|
|
self.assertEvalError( |
|
310
|
|
|
u"(last (list))", value_error) |
|
311
|
|
|
|
|
312
|
|
|
|
|
313
|
|
View Code Duplication |
class AppendTest(PreludeTestCase): |
|
|
|
|
|
|
314
|
|
|
def test_append(self): |
|
315
|
|
|
expected = List([Integer.fromint(1), Integer.fromint(2)]) |
|
316
|
|
|
|
|
317
|
|
|
self.assertEvalsTo( |
|
318
|
|
|
u"(set-symbol! (quote x) (quote (1))) (append! x 2) x", |
|
319
|
|
|
expected) |
|
320
|
|
|
|
|
321
|
|
|
def test_append_bytestring(self): |
|
322
|
|
|
self.assertEvalsTo( |
|
323
|
|
|
u'(set-symbol! (quote x) #bytes("a")) (append! x 98) x', |
|
324
|
|
|
Bytestring([ord(c) for c in "ab"])) |
|
325
|
|
|
|
|
326
|
|
|
def test_append_string(self): |
|
327
|
|
|
self.assertEvalsTo( |
|
328
|
|
|
u'(set-symbol! (quote x) "a") (append! x \'b\') x', |
|
329
|
|
|
String(list(u"ab"))) |
|
330
|
|
|
|
|
331
|
|
|
def test_append_returns_null(self): |
|
332
|
|
|
self.assertEvalsTo( |
|
333
|
|
|
u"(append! (quote ()) 1)", |
|
334
|
|
|
NULL) |
|
335
|
|
|
|
|
336
|
|
|
def test_append_arg_number(self): |
|
337
|
|
|
self.assertEvalError( |
|
338
|
|
|
u"(append! (quote ()))", wrong_argument_number) |
|
339
|
|
|
|
|
340
|
|
|
self.assertEvalError( |
|
341
|
|
|
u"(append! (quote ()) 0 1)", wrong_argument_number) |
|
342
|
|
|
|
|
343
|
|
|
def test_append_typeerror(self): |
|
344
|
|
|
# first argument must be a list |
|
345
|
|
|
self.assertEvalError( |
|
346
|
|
|
u"(append! #null 0)", wrong_type) |
|
347
|
|
|
|
|
348
|
|
|
|
|
349
|
|
View Code Duplication |
class PushTest(PreludeTestCase): |
|
|
|
|
|
|
350
|
|
|
def test_push_list(self): |
|
351
|
|
|
expected = List([Integer.fromint(1)]) |
|
352
|
|
|
self.assertEvalsTo(u"(set-symbol! (quote x) (quote ())) (push! x 1) x", expected) |
|
353
|
|
|
|
|
354
|
|
|
def test_push_bytestring(self): |
|
355
|
|
|
self.assertEvalsTo( |
|
356
|
|
|
u'(set-symbol! (quote x) #bytes("bc")) (push! x 97) x', |
|
357
|
|
|
Bytestring([ord(c) for c in b"abc"])) |
|
358
|
|
|
|
|
359
|
|
|
def test_push_string(self): |
|
360
|
|
|
self.assertEvalsTo( |
|
361
|
|
|
u'(set-symbol! (quote x) "bc") (push! x \'a\') x', |
|
362
|
|
|
String(list(u"abc"))) |
|
363
|
|
|
|
|
364
|
|
|
def test_push_returns_null(self): |
|
365
|
|
|
self.assertEqual( |
|
366
|
|
|
evaluate_with_prelude(parse_one(lex( |
|
367
|
|
|
u"(push! (quote ()) 1)"))), |
|
368
|
|
|
NULL) |
|
369
|
|
|
|
|
370
|
|
|
def test_push_arg_number(self): |
|
371
|
|
|
self.assertEvalError( |
|
372
|
|
|
u"(push! (quote ()))", wrong_argument_number) |
|
373
|
|
|
|
|
374
|
|
|
self.assertEvalError( |
|
375
|
|
|
u"(push! (quote ()) 0 1)", wrong_argument_number) |
|
376
|
|
|
|
|
377
|
|
|
def test_push_typeerror(self): |
|
378
|
|
|
# first argument must be a list |
|
379
|
|
|
self.assertEvalError( |
|
380
|
|
|
u"(push! #null 0)", wrong_type) |
|
381
|
|
|
|
|
382
|
|
|
|
|
383
|
|
|
class NotTest(PreludeTestCase): |
|
384
|
|
|
def test_not_booleans(self): |
|
385
|
|
|
self.assertEvalsTo(u"(not #true)", FALSE) |
|
386
|
|
|
|
|
387
|
|
|
self.assertEvalsTo(u"(not #false)", TRUE) |
|
388
|
|
|
|
|
389
|
|
|
|
|
390
|
|
|
class AndTest(PreludeTestCase): |
|
391
|
|
|
def test_and(self): |
|
392
|
|
|
self.assertEvalsTo(u"(and #true #true)", TRUE) |
|
393
|
|
|
self.assertEvalsTo(u"(and #true #false)", FALSE) |
|
394
|
|
|
self.assertEvalsTo(u"(and #false #true)", FALSE) |
|
395
|
|
|
self.assertEvalsTo(u"(and #false #false)", FALSE) |
|
396
|
|
|
|
|
397
|
|
|
def test_and_arity(self): |
|
398
|
|
|
self.assertEvalsTo(u"(and)", TRUE) |
|
399
|
|
|
|
|
400
|
|
|
self.assertEvalsTo(u"(and #true #true #true)", TRUE) |
|
401
|
|
|
|
|
402
|
|
|
def test_and_evaluation(self): |
|
403
|
|
|
"""Statements should not be evaluated more than once.""" |
|
404
|
|
|
self.assertEvalsTo( |
|
405
|
|
|
(u"(set! x 0)" |
|
406
|
|
|
u"(and (do (inc! x) #true))" |
|
407
|
|
|
u"x"), |
|
408
|
|
|
Integer.fromint(1)) |
|
409
|
|
|
|
|
410
|
|
|
|
|
411
|
|
|
class OrTest(PreludeTestCase): |
|
412
|
|
|
def test_or(self): |
|
413
|
|
|
self.assertEvalsTo(u"(or #true #true)", TRUE) |
|
414
|
|
|
self.assertEvalsTo(u"(or #true #false)", TRUE) |
|
415
|
|
|
self.assertEvalsTo(u"(or #false #true)", TRUE) |
|
416
|
|
|
self.assertEvalsTo(u"(or #false #false)", FALSE) |
|
417
|
|
|
|
|
418
|
|
|
def test_or_arity(self): |
|
419
|
|
|
self.assertEvalsTo(u"(or)", FALSE) |
|
420
|
|
|
|
|
421
|
|
|
self.assertEvalsTo(u"(or #true #true #true)", TRUE) |
|
422
|
|
|
|
|
423
|
|
|
def test_or_evaluation(self): |
|
424
|
|
|
"""Statements should not be evaluated more than once.""" |
|
425
|
|
|
self.assertEvalsTo( |
|
426
|
|
|
(u"(set! x 0)" |
|
427
|
|
|
u"(or (do (inc! x) #true))" |
|
428
|
|
|
u"x"), |
|
429
|
|
|
Integer.fromint(1)) |
|
430
|
|
|
|
|
431
|
|
|
|
|
432
|
|
|
class RestTest(PreludeTestCase): |
|
433
|
|
|
def test_rest(self): |
|
434
|
|
|
self.assertEvalsTo(u"(rest (list 1 2 3))", List([Integer.fromint(2), Integer.fromint(3)])) |
|
435
|
|
|
|
|
436
|
|
|
def test_rest_bytestring(self): |
|
437
|
|
|
self.assertEqual( |
|
438
|
|
|
evaluate_with_prelude(parse_one(lex(u'(rest #bytes("abc"))'))), |
|
439
|
|
|
Bytestring([ord(c) for c in b"bc"])) |
|
440
|
|
|
|
|
441
|
|
|
def test_rest_string(self): |
|
442
|
|
|
self.assertEqual( |
|
443
|
|
|
evaluate_with_prelude(parse_one(lex(u'(rest "abc")'))), |
|
444
|
|
|
String(list(u"bc"))) |
|
445
|
|
|
|
|
446
|
|
|
def test_rest_empty_list(self): |
|
447
|
|
|
self.assertEvalsTo(u"(rest (list))", List()) |
|
448
|
|
|
|
|
449
|
|
|
def test_rest_fresh_copy(self): |
|
450
|
|
|
self.assertEvalsTo(u"(append! (rest (quote (1))) 2) (rest (quote (3)))", List()) |
|
451
|
|
|
|
|
452
|
|
|
self.assertEvalsTo( |
|
453
|
|
|
u"(append! (rest \"a\") 'b') (rest \"c\")", |
|
454
|
|
|
String(list())) |
|
455
|
|
|
|
|
456
|
|
|
self.assertEvalsTo( |
|
457
|
|
|
u"(append! (rest #bytes(\"a\")) 65) (rest #bytes(\"c\"))", |
|
458
|
|
|
Bytestring([])) |
|
459
|
|
|
|
|
460
|
|
|
|
|
461
|
|
|
class WhenTest(PreludeTestCase): |
|
462
|
|
|
def test_when_true(self): |
|
463
|
|
|
self.assertEvalsTo(u"(when #true 1)", Integer.fromint(1)) |
|
464
|
|
|
|
|
465
|
|
|
def test_when_false(self): |
|
466
|
|
|
self.assertEvalsTo(u"(when #false 1 2)", NULL) |
|
467
|
|
|
|
|
468
|
|
|
|
|
469
|
|
|
class WhenNotTest(PreludeTestCase): |
|
470
|
|
|
def test_when_not_true(self): |
|
471
|
|
|
self.assertEvalsTo(u"(when-not #true 1)", NULL) |
|
472
|
|
|
|
|
473
|
|
|
def test_when_not_false(self): |
|
474
|
|
|
self.assertEvalsTo(u"(when-not #false 1 2)", Integer.fromint(2)) |
|
475
|
|
|
|
|
476
|
|
|
|
|
477
|
|
|
class CaseTest(PreludeTestCase): |
|
478
|
|
|
def test_case_true(self): |
|
479
|
|
|
self.assertEvalsTo(u"(case (#true 1))", Integer.fromint(1)) |
|
480
|
|
|
|
|
481
|
|
|
def test_case_first_match(self): |
|
482
|
|
|
self.assertEvalsTo(u"(case (#true 1) (#true 2))", Integer.fromint(1)) |
|
483
|
|
|
|
|
484
|
|
|
def test_case_second_match(self): |
|
485
|
|
|
self.assertEvalsTo(u"(case (#false 1) (#true 2))", Integer.fromint(2)) |
|
486
|
|
|
|
|
487
|
|
|
def test_clause_body_in_correct_scope(self): |
|
488
|
|
|
self.assertEvalsTo(u"(let (x 2) (case (#false 1) (#true x)))", Integer.fromint(2)) |
|
489
|
|
|
|
|
490
|
|
|
|
|
491
|
|
|
class RangeTest(PreludeTestCase): |
|
492
|
|
|
def test_range(self): |
|
493
|
|
|
self.assertEvalsTo(u"(range 5)", self.eval(u"(list 0 1 2 3 4)")) |
|
494
|
|
|
|
|
495
|
|
|
def test_range_(self): |
|
496
|
|
|
self.assertTrifleError( |
|
497
|
|
|
self.eval(u"(range -1)"), |
|
498
|
|
|
value_error) |
|
499
|
|
|
|
|
500
|
|
|
|
|
501
|
|
|
class InequalityTest(PreludeTestCase): |
|
502
|
|
|
def test_greater_than(self): |
|
503
|
|
|
self.assertEvalsTo(u"(> 2 1)", TRUE) |
|
504
|
|
|
self.assertEvalsTo(u"(> 2 2)", FALSE) |
|
505
|
|
|
self.assertEvalsTo(u"(> 2 3)", FALSE) |
|
506
|
|
|
|
|
507
|
|
|
def test_greater_or_equal(self): |
|
508
|
|
|
self.assertEvalsTo(u"(>= 2 1)", TRUE) |
|
509
|
|
|
self.assertEvalsTo(u"(>= 2 2)", TRUE) |
|
510
|
|
|
self.assertEvalsTo(u"(>= 2 3)", FALSE) |
|
511
|
|
|
|
|
512
|
|
|
def test_less_or_equal(self): |
|
513
|
|
|
self.assertEvalsTo(u"(<= 2 1)", FALSE) |
|
514
|
|
|
self.assertEvalsTo(u"(<= 2 2)", TRUE) |
|
515
|
|
|
self.assertEvalsTo(u"(<= 2 3)", TRUE) |
|
516
|
|
|
|
|
517
|
|
|
def test_incomparable_types(self): |
|
518
|
|
|
self.assertEvalError( |
|
519
|
|
|
u"(> 1 #null)", wrong_type) |
|
520
|
|
|
|
|
521
|
|
|
self.assertEvalError( |
|
522
|
|
|
u"(>= 1 #null)", wrong_type) |
|
523
|
|
|
|
|
524
|
|
|
self.assertEvalError( |
|
525
|
|
|
u"(<= 1 #null)", wrong_type) |
|
526
|
|
|
|
|
527
|
|
|
|
|
528
|
|
|
class SortTest(PreludeTestCase): |
|
529
|
|
|
def test_sort_empty(self): |
|
530
|
|
|
self.assertEvalsTo(u"(sort (list))", List()) |
|
531
|
|
|
|
|
532
|
|
|
def test_sort_list(self): |
|
533
|
|
|
self.assertEvalsTo(u"(sort (list 5 4 3 2 1))", |
|
534
|
|
|
List([Integer.fromint(1), Integer.fromint(2), Integer.fromint(3), Integer.fromint(4), Integer.fromint(5)]) |
|
535
|
|
|
) |
|
536
|
|
|
|
|
537
|
|
|
|
|
538
|
|
|
class EmptyTest(PreludeTestCase): |
|
539
|
|
|
def test_empty_list(self): |
|
540
|
|
|
self.assertEvalsTo(u"(empty (list))", List()) |
|
541
|
|
|
self.assertEvalsTo(u"(empty (list 1 2 3))", List()) |
|
542
|
|
|
|
|
543
|
|
|
def test_empty_bytestring(self): |
|
544
|
|
|
self.assertEvalsTo(u'(empty #bytes("abc"))', Bytestring([])) |
|
545
|
|
|
self.assertEvalsTo(u'(empty #bytes(""))', Bytestring([])) |
|
546
|
|
|
|
|
547
|
|
|
def test_empty_string(self): |
|
548
|
|
|
self.assertEvalsTo(u'(empty "abc")', String([])) |
|
549
|
|
|
self.assertEvalsTo(u'(empty "")', String([])) |
|
550
|
|
|
|
|
551
|
|
|
def test_result_is_copy(self): |
|
552
|
|
|
self.assertEvalsTo(u'(set! x "") (same? x (empty x))', FALSE) |
|
553
|
|
|
|
|
554
|
|
|
def test_result_is_fresh(self): |
|
555
|
|
|
# Regression test. |
|
556
|
|
|
self.assertEvalsTo(u'(same? (empty "a") (empty "b"))', FALSE) |
|
557
|
|
|
|
|
558
|
|
|
self.assertEvalsTo(u'(same? (empty (quote (1))) (empty (quote (2))))', FALSE) |
|
559
|
|
|
|
|
560
|
|
|
self.assertEvalsTo(u'(same? (empty #bytes("a")) (empty #bytes("b")))', FALSE) |
|
561
|
|
|
|
|
562
|
|
|
|
|
563
|
|
|
class EmptyPredicateTest(PreludeTestCase): |
|
564
|
|
|
def test_empty(self): |
|
565
|
|
|
self.assertEvalsTo(u'(empty? "")', TRUE) |
|
566
|
|
|
self.assertEvalsTo(u'(empty? (list))', TRUE) |
|
567
|
|
|
|
|
568
|
|
|
def test_not_empty(self): |
|
569
|
|
|
self.assertEvalsTo(u'(empty? #bytes("a"))', FALSE) |
|
570
|
|
|
self.assertEvalsTo(u'(empty? (list 1 2))', FALSE) |
|
571
|
|
|
|
|
572
|
|
|
|
|
573
|
|
|
class CopyTest(PreludeTestCase): |
|
574
|
|
|
def test_copy_equal(self): |
|
575
|
|
|
self.assertEvalsTo(u"(copy (list 1 2))", List([Integer.fromint(1), Integer.fromint(2)])) |
|
576
|
|
|
|
|
577
|
|
|
def test_copy_not_sequence_error(self): |
|
578
|
|
|
self.assertTrifleError( |
|
579
|
|
|
self.eval(u"(copy #null)"), wrong_type) |
|
580
|
|
|
|
|
581
|
|
|
def test_copy_not_same(self): |
|
582
|
|
|
self.assertEvalsTo(u"(set! x (list)) (same? x (copy x))", FALSE) |
|
583
|
|
|
|
|
584
|
|
|
|
|
585
|
|
|
class JoinMutateTest(PreludeTestCase): |
|
586
|
|
|
def test_join(self): |
|
587
|
|
|
self.assertEvalsTo( |
|
588
|
|
|
u"(set! x (list 1)) (join! x (list 2)) x", |
|
589
|
|
|
List([Integer.fromint(1), Integer.fromint(2)])) |
|
590
|
|
|
|
|
591
|
|
|
|
|
592
|
|
|
class JoinTest(PreludeTestCase): |
|
593
|
|
|
def test_join(self): |
|
594
|
|
|
self.assertEvalsTo( |
|
595
|
|
|
u"(join (list 1) (list) (list 2 3))", |
|
596
|
|
|
List([Integer.fromint(1), Integer.fromint(2), Integer.fromint(3)])) |
|
597
|
|
|
|
|
598
|
|
|
def test_join_string(self): |
|
599
|
|
|
self.assertEvalsTo( |
|
600
|
|
|
u'(join "foo" "bar")', |
|
601
|
|
|
String(list(u"foobar"))) |
|
602
|
|
|
|
|
603
|
|
|
|
|
604
|
|
|
class PrintTest(PreludeTestCase): |
|
605
|
|
|
def test_print_returns_null(self): |
|
606
|
|
|
self.assertEqual( |
|
607
|
|
|
self.eval(u'(print! "foo")'), |
|
608
|
|
|
NULL) |
|
609
|
|
|
|
|
610
|
|
|
def test_print_writes_to_stdout(self): |
|
611
|
|
|
with mock_stdout_fd() as stdout: |
|
612
|
|
|
self.eval(u'(print! "foo")') |
|
613
|
|
|
|
|
614
|
|
|
self.assertEqual(stdout.call_args[0][1], "foo\n") |
|
615
|
|
|
|
|
616
|
|
|
def test_print_handles_numbers(self): |
|
617
|
|
|
with mock_stdout_fd() as stdout: |
|
618
|
|
|
self.eval(u'(print! 1)') |
|
619
|
|
|
|
|
620
|
|
|
self.assertEqual(stdout.call_args[0][1], "1\n") |
|
621
|
|
|
|
|
622
|
|
|
def test_print_wrong_arg_number(self): |
|
623
|
|
|
self.assertEvalError( |
|
624
|
|
|
u"(print! 1 2)", wrong_argument_number) |
|
625
|
|
|
|
|
626
|
|
|
|
|
627
|
|
|
class SequencePredicateTest(PreludeTestCase): |
|
628
|
|
|
def test_sequence(self): |
|
629
|
|
|
self.assertEvalsTo(u"(sequence? (list))", TRUE) |
|
630
|
|
|
self.assertEvalsTo(u'(sequence? "")', TRUE) |
|
631
|
|
|
self.assertEvalsTo(u'(sequence? #bytes(""))', TRUE) |
|
632
|
|
|
self.assertEvalsTo(u"(sequence? #false)", FALSE) |
|
633
|
|
|
self.assertEvalsTo(u"(sequence? #null)", FALSE) |
|
634
|
|
|
|
|
635
|
|
|
def test_sequence_arity(self): |
|
636
|
|
|
self.assertTrifleError( |
|
637
|
|
|
self.eval(u"(sequence?)"), wrong_argument_number) |
|
638
|
|
|
self.assertTrifleError( |
|
639
|
|
|
self.eval(u"(sequence? 0 0)"), wrong_argument_number) |
|
640
|
|
|
|