-
Notifications
You must be signed in to change notification settings - Fork 11
/
tests.py
180 lines (153 loc) · 7.77 KB
/
tests.py
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
175
176
177
178
179
180
import unittest
from kimi import *
class TestTokenize(unittest.TestCase):
def test_numbers(self):
# Valid number literals
self.assertEqual(tokenize("3"), [('literal', 3)])
self.assertEqual(tokenize("+3"), [('literal', 3)])
self.assertEqual(tokenize("-4"), [('literal', -4)])
# Not valid (considered symbols)
self.assertEqual(tokenize("2.5"), [('symbol', '2.5')])
self.assertEqual(tokenize("-2-4"), [('symbol', '-2-4')])
def test_strings(self):
# Valid string literals
self.assertEqual(tokenize('"some string"'), [('literal', 'some string')])
self.assertEqual(tokenize('"some (string)"'), [('literal', 'some (string)')])
self.assertEqual(tokenize('''"some 'string'"'''), [('literal', "some 'string'")])
# Not valid
self.assertEqual(tokenize('"some \"string\""'), [('literal', 'some '), ('symbol', 'string'), ('literal', '')])
def test_symbols(self):
# Valid symbols
self.assertEqual(tokenize("x"), [('symbol', 'x')])
self.assertEqual(tokenize("123abc123"), [('symbol', '123abc123')])
self.assertEqual(tokenize("--thing--"), [('symbol', '--thing--')])
# Not valid
self.assertEqual(tokenize("x y"), [('symbol', 'x'), ('symbol', 'y')])
self.assertEqual(tokenize("z(x)"), [('symbol', 'z'), ('opening', None), ('symbol', 'x'), ('closing', None)])
def test_apply(self):
self.assertEqual(tokenize("(- 1 2)"), [('opening', None), ('symbol', '-'), ('literal', 1), ('literal', 2), ('closing', None)])
self.assertEqual(tokenize("(define square (lambda x (* x x)))"),
[('opening', None), ('symbol', 'define'), ('symbol', 'square'),
('opening', None), ('symbol', 'lambda'), ('symbol', 'x'),
('opening', None), ('symbol', '*'), ('symbol', 'x'), ('symbol', 'x'),
('closing', None), ('closing', None), ('closing', None)])
def test_syntax_errors(self):
self.assertRaises(SystemExit, tokenize, ("( + 1 2 )"))
self.assertRaises(SystemExit, tokenize, ("(((+ 1 2)))"))
self.assertRaises(SystemExit, tokenize, (")+ 1 2("))
self.assertRaises(SystemExit, tokenize, ("+ 1 2()"))
# self.assertEqual(tokenize("(+ 1 2) (+ 3 4)"),
# [('opening', None), ('symbol', '+'), ('literal', 1), ('literal', 2), ('closing', None),
# ('opening', None), ('symbol', '+'), ('literal', 3), ('literal', 4), ('closing', None)] )
class TestParse(unittest.TestCase):
def test_parse(self):
self.assertEqual(parse(tokenize("(+ 1 2)")),
{'type': 'apply',
'operator': {'type': 'symbol', 'value': '+'},
'arguments': ({'type': 'literal', 'value': 1},
{'type': 'literal', 'value': 2})})
self.assertEqual(parse(tokenize("(define square (lambda x (* x x)))")),
{'type': 'apply',
'operator': {'type': 'symbol', 'value': 'define'},
'arguments': ({'type': 'symbol', 'value': 'square'},
{'type': 'apply',
'operator': {'type': 'symbol', 'value': 'lambda'},
'arguments': ({'type': 'symbol', 'value': 'x'},
{'type': 'apply',
'operator': {'type': 'symbol', 'value': '*'},
'arguments': ({'type': 'symbol', 'value': 'x'},
{'type': 'symbol', 'value': 'x'})})})})
class TestExecute(unittest.TestCase):
def test_atoms(self):
self.assertEqual(execute("-10"), -10)
self.assertEqual(execute("true"), True)
self.assertEqual(execute('"string"'), "string")
def test_nesting(self):
self.assertEqual(execute("(| (& true false) (! true))"), False)
self.assertEqual(execute("(+ (* 2 3) (- 4 2))"), 8)
@unittest.expectedFailure
def test_bad_program(self):
self.assertRaises(SystemExit, execute, ("(+ (1) (2))"))
self.assertEqual(execute("(+ 1 2) (+ 3 4)"), 7) #or throw error
class TestBuiltins(unittest.TestCase):
def test_arithmetic(self):
# Addition
self.assertEqual(execute("(+ 1 2)"), 3)
self.assertEqual(execute("(+ -1 2)"), 1)
# Subtraction
self.assertEqual(execute("(- 2 1)"), 1)
self.assertEqual(execute("(- 1 -2)"), 3)
# Multiplication
self.assertEqual(execute("(* 2 4)"), 8)
self.assertEqual(execute("(* 3 -2)"), -6)
# Floor division
self.assertEqual(execute("(/ 6 2)"), 3)
self.assertEqual(execute("(/ 7 2)"), 3)
self.assertEqual(execute("(/ 1 2)"), 0)
self.assertEqual(execute("(/ 6 -2)"), -3)
self.assertEqual(execute("(/ -3 -2)"), 1)
# Modulo
self.assertEqual(execute("(% 7 2)"), 1)
self.assertEqual(execute("(% 6 -4)"), -2)
self.assertEqual(execute("(% 2 3)"), 2)
def test_logic(self):
# And
self.assertEqual(execute("(& true true)"), True)
self.assertEqual(execute("(& true false)"), False)
self.assertEqual(execute("(& false true)"), False)
self.assertEqual(execute("(& false false)"), False)
# Or
self.assertEqual(execute("(| true true)"), True)
self.assertEqual(execute("(| true false)"), True)
self.assertEqual(execute("(| false true)"), True)
self.assertEqual(execute("(| false false)"), False)
# Not
self.assertEqual(execute("(! true)"), False)
self.assertEqual(execute("(! false)"), True)
def test_equality(self):
self.assertEqual(execute("(= 1 1)"), True)
self.assertEqual(execute("(= 1 2)"), False)
self.assertEqual(execute('(= "yes" "yes")'), True)
self.assertEqual(execute('(= "yes" "no")'), False)
self.assertEqual(execute("(= false false)"), True)
self.assertEqual(execute("(= true false)"), False)
def test_comparison(self):
# Greater than
self.assertEqual(execute("(> 2 1)"), True)
self.assertEqual(execute("(> 2 2)"), False)
self.assertEqual(execute("(> 1 2)"), False)
# Less than
self.assertEqual(execute("(< 2 1)"), False)
self.assertEqual(execute("(< 2 2)"), False)
self.assertEqual(execute("(< 1 2)"), True)
# Greater or equal
self.assertEqual(execute("(>= 2 1)"), True)
self.assertEqual(execute("(>= 2 2)"), True)
self.assertEqual(execute("(>= 1 2)"), False)
# Less or equal
self.assertEqual(execute("(<= 2 1)"), False)
self.assertEqual(execute("(<= 2 2)"), True)
self.assertEqual(execute("(<= 1 2)"), True)
def test_lists(self):
self.assertEqual(execute("(prepend 1 (prepend 2 nil))"), (1, (2, None)))
self.assertEqual(execute("(list 1 2)"), (1, (2, None)))
self.assertEqual(execute("(first (list 1 2))"), 1)
self.assertEqual(execute("(rest (list 1 2))"), (2, None))
class TestSpecialForms(unittest.TestCase):
def test_do(self):
self.assertEqual(execute("(do (> 4 3))"), True)
self.assertEqual(execute("(do (+ 1 2) (+ 3 4))"), 7)
def test_lambda(self):
self.assertTrue(callable(execute("(lambda x (* x x))")))
self.assertEqual(execute("((lambda x (* x x)) 2)"), 4)
self.assertEqual(execute("((lambda a b (! (& a b))) true false)"), True)
self.assertEqual(execute("((lambda a ((lambda y (- a y)) 3)) 7)"), 4)
#
def test_define(self):
self.assertEqual(execute("(do (define x 1) (+ x x))"), 2)
def test_if(self):
self.assertEqual(execute("(if true 1 2)"), 1)
self.assertEqual(execute("(if false 1 2)"), 2)
self.assertRaises(SystemExit, execute, "(if 1 2 3)")
if __name__ == '__main__':
unittest.main()