d9504328b95eb0f9252671c97bcfa188915817e4
[sandbox] / stutter_test.py
1 #!/usr/bin/env python
2
3 import stutter
4 import unittest
5
6 class IsIntegerTests(unittest.TestCase):
7     def test_returns_true_for_integers(self):
8         for i in range(10):
9             self.assertTrue(stutter.is_integer(i))
10
11     def test_returns_false_for_booleans(self):
12         self.assertFalse(stutter.is_integer(True))
13         self.assertFalse(stutter.is_integer(False))
14
15     def test_returns_false_for_other_types(self):
16         for o in [object(), '', 0.1, [], (), {}, set()]:
17             self.assertFalse(stutter.is_integer(o))
18
19 class UndelimitStringTests(unittest.TestCase):
20     def test_returns_empty_strings(self):
21         expected = ''
22         actual = stutter.undelimit_string('""')
23         
24         self.assertEqual(expected, actual)
25
26     def test_returns_strings_without_escapes(self):
27         expected = 'Hello, world'
28         actual = stutter.undelimit_string('"Hello, world"')
29         
30         self.assertEqual(expected, actual)
31
32     def test_returns_strings_with_newlines(self):
33         expected = 'Hello, world\nGoodbye, cruel world'
34         actual = stutter.undelimit_string('"Hello, world\\nGoodbye, cruel world"')
35         
36         self.assertEqual(expected, actual)
37
38     def test_returns_strings_with_escaped_delimiters(self):
39         expected = '"Hello, world"'
40         actual = stutter.undelimit_string('"\\"Hello, world\\""')
41         
42         self.assertEqual(expected, actual)
43
44     def test_returns_strings_with_escaped_escape_characters(self):
45         expected = '\\no'
46         actual = stutter.undelimit_string('"\\\\no"')
47         
48         self.assertEqual(expected, actual)
49
50 class IndentTests(unittest.TestCase):
51     def test_indents_single_line(self):
52         expected = '    Hello, world'
53         actual = stutter.indent('Hello, world')
54         self.assertEqual(expected, actual)
55
56     def test_indents_multiple_lines(self):
57         expected = '    Hello, world\n    Goodbye, cruel world'
58         actual = stutter.indent('Hello, world\nGoodbye, cruel world')
59         self.assertEqual(expected, actual)
60
61     def test_leaves_empty_lines_empty(self):
62         expected = '    Hello, world\n\n    Goodbye, cruel world'
63         actual = stutter.indent('Hello, world\n \nGoodbye, cruel world')
64         self.assertEqual(expected, actual)
65
66     def test_indents_already_indented_lines(self):
67         expected = '        Hello, world\n\n        Goodbye, cruel world'
68         actual = stutter.indent('    Hello, world\n\n    Goodbye, cruel world')
69         self.assertEqual(expected, actual)
70
71 class ParseAllTests(unittest.TestCase):
72     def test_parses_integers(self):
73         expected = [0]
74         actual = stutter.parse_all('0')
75
76         self.assertEqual(expected, actual)
77
78     def test_parses_identifiers(self):
79         expected = [stutter.Symbol('print')]
80         actual = stutter.parse_all('print')
81
82         self.assertEqual(expected, actual)
83
84     def test_parses_strings(self):
85         expected = ['Hello, world']
86         actual = stutter.parse_all('"Hello, world"')
87
88         self.assertEqual(expected, actual)
89
90     def test_parses_strings_with_escaped_delimiters(self):
91         expected = ['"Hello, world"']
92         actual = stutter.parse_all('"\\"Hello, world\\""')
93
94         self.assertEqual(expected, actual)
95
96     def test_parses_empty_s_expressions(self):
97         expected = [()]
98         actual = stutter.parse_all('()')
99
100         self.assertEqual(expected, actual)
101
102     def test_parses_s_expressions(self):
103         expected = [(0, 1, 2)]
104         actual = stutter.parse_all('(0 1 2)')
105
106         self.assertEqual(expected, actual)
107
108     def test_parses_nested_s_expressions(self):
109         expected = [(0, (1, (2,)))]
110         actual = stutter.parse_all('(0 (1 (2)))')
111
112         self.assertEqual(expected, actual)
113
114     def test_parses_multiple_expressions(self):
115         expected = [0, ()]
116         actual = stutter.parse_all('0 ()')
117
118         self.assertEqual(expected, actual)
119
120     def test_raises_exception_for_unclosed_parenthese(self):
121         self.assertRaises(Exception, stutter.parse_all, '(')
122
123     def test_raises_exception_for_unopened_parenthese(self):
124         self.assertRaises(Exception, stutter.parse_all, ')')
125
126 class QuoteToCTests(unittest.TestCase):
127     def test_quotes_integer_literals(self):
128         for i in range(5):
129             expected = stutter.CFunctionCallExpression(
130                 'makeObjectPointerFromInteger',
131                 [stutter.CIntegerLiteralExpression(i)],
132             )
133             
134             actual = stutter.quote_to_c(i)
135             
136             self.assertEqual(expected, actual)
137
138     def test_quotes_string_literals(self):
139         s = 'Hello, world'
140         expected = stutter.CFunctionCallExpression(
141             'makeObjectPointerFromString',
142             [stutter.CStringLiteralExpression(s)],
143         )
144
145         actual = stutter.quote_to_c(s)
146
147         self.assertEqual(expected, actual)
148
149 class EvaluateApplicationArgumentsToCTests(unittest.TestCase):
150     def test_evaluates_empty_to_null(self):
151         expected = stutter.CVariableExpression('NULL')
152         actual = stutter.evaluate_application_arguments_to_c(())
153
154         self.assertEqual(expected, actual)
155
156     def test_evaluates_one_argument_to_cons(self):
157         argument = 42
158
159         sentinel = stutter.CStringLiteralExpression('1bd9707e76f8f807f3bad3e39049fea4a36d8ef2f8e2ed471ec755f7adb291d5')
160
161         def mock(argument_to_quote):
162             if argument_to_quote == argument:
163                 return sentinel
164
165         expected = stutter.CFunctionCallExpression(
166             'c_cons',
167             (sentinel, stutter.CVariableExpression('NULL')),
168         )
169
170         actual = stutter.evaluate_application_arguments_to_c(
171             (argument,),
172             quote_to_c = mock,
173         )
174
175         self.assertEqual(expected, actual)
176
177 class EvaluateApplicationToCTests(unittest.TestCase):
178     def test_evaluates_function_calls_with_no_arguments(self):
179         name = 'name'
180
181         sentinel = stutter.CVariableExpression('NULL')
182
183         def mock(arguments):
184             assert arguments == ()
185             return sentinel
186
187         result = stutter.evaluate_application_to_c(
188             (stutter.Symbol(name),),
189             evaluate_application_arguments_to_c = mock,
190         )
191
192         self.assertEqual(result.name, name)
193         self.assertEqual(len(result.arguments), 1)
194         self.assertIs(result.arguments[0], sentinel)
195
196     def test_evaluates_function_calls_with_arguments(self):
197         name = 'print'
198         argument = 42 
199
200         sentinel = stutter.CFunctionCallExpression(
201             'cons',
202             [
203                 stutter.CFunctionCallExpression(
204                     'makeObjectPointerFromInteger',
205                     [stutter.CIntegerLiteralExpression(argument)],
206                 ),
207             ],
208         )
209
210         def mock(arguments):
211             assert arguments == (argument,)
212             return sentinel
213
214         result = stutter.evaluate_application_to_c(
215             (stutter.Symbol(name), argument),
216             evaluate_application_arguments_to_c = mock,
217         )
218
219         self.assertEqual(result.name, name)
220         self.assertEqual(len(result.arguments), 1)
221         self.assertIs(result.arguments[0], sentinel)
222
223 class EvaluateToCTests(unittest.TestCase):
224     def test_evaluates_integers(self):
225         for i in range(5):
226             result = stutter.evaluate_to_c(i)
227             self.assertIsInstance(result, stutter.CIntegerLiteralExpression)
228             self.assertEqual(result.integer, i)
229
230     def test_evaluates_string_literals(self):
231         s = 'Hello, world'
232         result = stutter.evaluate_to_c(s)
233
234         self.assertIsInstance(result, stutter.CStringLiteralExpression)
235         self.assertEqual(result.string, s)
236
237     def test_calls_evaluate_application_when_given_an_application(self):
238         sentinel = object()
239         application = (stutter.Symbol('print'), 'Hello, world')
240
241         def mock(argument):
242             if argument == application:
243                 return sentinel
244
245         result = stutter.evaluate_to_c(
246             application,
247             evaluate_application_to_c = mock,
248         )
249
250         self.assertIs(result, sentinel)
251
252 class EvaluateAllToCTests(unittest.TestCase):
253     def test_returns_function_body(self):
254         result = stutter.evaluate_all_to_c([0])
255
256         self.assertIsInstance(result, stutter.CFunctionBody)
257
258     def test_main_contains_expression_statements_followed_by_return_statement(self):
259         result = stutter.evaluate_all_to_c([0,0,0])
260
261         self.assertIsInstance(result.statements[0],stutter.CExpressionStatement)
262         self.assertIsInstance(result.statements[1],stutter.CExpressionStatement)
263         self.assertIsInstance(result.statements[2],stutter.CReturnStatement)
264
265 class GeneratePointerTypeTests(unittest.TestCase):
266     def test_basic(self):
267         expected = 'int*'
268         actual = stutter.generate_pointer_type(stutter.CPointerType(stutter.CType('int')))
269         self.assertEqual(expected, actual)
270
271 class GenerateTypeTests(unittest.TestCase):
272     def test_basic(self):
273         expected = 'int'
274         actual = stutter.generate_type(stutter.CType('int'))
275         self.assertEqual(expected, actual)
276
277     def test_generates_pointer_types(self):
278         expected = object()
279         actual = stutter.generate_type(
280                 stutter.CPointerType(stutter.CType('int')),
281                 generate_pointer_type = lambda x : expected)
282
283         self.assertIs(expected, actual)
284
285 class GenerateArgumentDeclarationTests(unittest.TestCase):
286     def test_basic(self):
287         expected = 'int argc'
288         actual = stutter.generate_argument_declaration(
289                 stutter.CArgumentDeclaration(stutter.CType('int'), 'argc'))
290         self.assertEqual(expected, actual)
291
292 class GenerateArgumentDeclarationListTests(unittest.TestCase):
293     def test_basic(self):
294         argument_declarations = [
295                 stutter.CArgumentDeclaration(stutter.CType('int'),'argc'),
296                 stutter.CArgumentDeclaration(stutter.CPointerType(stutter.CPointerType(stutter.CType('char'))), 'argv'),
297             ]
298         expected = 'int argc, char** argv'
299         actual = stutter.generate_argument_declaration_list(argument_declarations)
300         self.assertEqual(expected, actual)
301
302 class GenerateIntegerLiteralExpressionTests(unittest.TestCase):
303     def test_basic(self):
304         expected = '0'
305         actual = stutter.generate_integer_literal_expression(
306             stutter.CIntegerLiteralExpression(0),
307         )
308         self.assertEqual(expected, actual)
309
310 class GenerateStringLiteralExpressionTests(unittest.TestCase):
311     def test_basic(self):
312         expected = '"Hello, world"'
313         actual = stutter.generate_string_literal_expression(
314             stutter.CStringLiteralExpression('Hello, world'),
315         )
316         self.assertEqual(expected, actual)
317
318     def test_escapes(self):
319         expected = r'"\\\n\"\t"'
320         actual = stutter.generate_string_literal_expression(
321             stutter.CStringLiteralExpression('\\\n"\t'),
322         )
323         self.assertEqual(expected, actual)
324
325 class GenerateVariableExpressionTests(unittest.TestCase):
326     def test_generates(self):
327         expected = 'name'
328         actual = stutter.generate_variable_expression(
329             stutter.CVariableExpression(expected),
330         )
331
332         self.assertEqual(expected, actual)
333
334 class GenerateFunctionCallExpressionTests(unittest.TestCase):
335     def test_no_arguments(self):
336         expected = 'name()'
337         actual = stutter.generate_function_call_expression(
338             stutter.CFunctionCallExpression('name', []),
339         )
340         self.assertEqual(expected, actual)
341
342     def test_one_argument(self):
343         expected = 'name(0)'
344         actual = stutter.generate_function_call_expression(
345             stutter.CFunctionCallExpression(
346                 'name',
347                 [
348                     stutter.CIntegerLiteralExpression(0),
349                 ],
350             ),
351         )
352         self.assertEqual(expected, actual)
353
354     def test_many_arguments(self):
355         expected = 'name(0, 1)'
356         actual = stutter.generate_function_call_expression(
357             stutter.CFunctionCallExpression(
358                 'name',
359                 [
360                     stutter.CIntegerLiteralExpression(0),
361                     stutter.CIntegerLiteralExpression(1),
362                 ],
363             ),
364         )
365         self.assertEqual(expected, actual)
366
367 class GenerateExpressionTests(unittest.TestCase):
368     def test_generates_integer_literal_expressions(self):
369         expected = object()
370         actual = stutter.generate_expression(
371                 stutter.CIntegerLiteralExpression(0),
372                 generate_integer_literal_expression = lambda x : expected)
373
374         self.assertIs(expected, actual)
375
376     def test_generates_string_literal_expressions(self):
377         expected = object()
378         actual = stutter.generate_expression(
379                 stutter.CStringLiteralExpression('Hello, world'),
380                 generate_string_literal_expression = lambda x : expected)
381
382         self.assertIs(expected, actual)
383
384     def test_generates_variable_expression(self):
385         expected = object()
386         actual = stutter.generate_expression(
387                 stutter.CVariableExpression('name'),
388                 generate_variable_expression = lambda x : expected)
389
390         self.assertIs(expected, actual)
391
392     def test_generates_function_call_expression(self):
393         expected = object()
394         actual = stutter.generate_expression(
395                 stutter.CFunctionCallExpression('name',[]),
396                 generate_function_call_expression = lambda x : expected)
397
398         self.assertIs(expected, actual)
399
400 class GenerateStatement(unittest.TestCase):
401     def test_generates_expression_statement(self):
402         return_statement = stutter.CExpressionStatement('0')
403
404         expected = object()
405         actual = stutter.generate_statement(
406             return_statement,
407             generate_expression_statement = lambda _ : expected)
408
409         self.assertIs(expected, actual)
410
411     def test_generates_return_statement(self):
412         return_statement = stutter.CReturnStatement(stutter.CIntegerLiteralExpression(0))
413
414         expected = object()
415         actual = stutter.generate_statement(
416             return_statement,
417             generate_return_statement = lambda _ : expected)
418
419         self.assertIs(expected, actual)
420
421 class GenerateExpressionStatementTests(unittest.TestCase):
422     def test_generates_return_statement(self):
423         expression_statement = stutter.CExpressionStatement(stutter.CIntegerLiteralExpression(0))
424
425         expected = '0;'
426         actual = stutter.generate_expression_statement(expression_statement)
427
428         self.assertEqual(expected, actual)
429
430 class GenerateReturnStatementTests(unittest.TestCase):
431     def test_generates_return_statement(self):
432         return_statement = stutter.CReturnStatement(stutter.CIntegerLiteralExpression(0))
433
434         expected = 'return 0;'
435         actual = stutter.generate_return_statement(return_statement)
436
437         self.assertEqual(expected, actual)
438
439 class GenerateFunctionDeclarationTests(unittest.TestCase):
440     def test_basic(self):
441         return_type = stutter.CType('int')
442         argument_declarations = [
443                 stutter.CArgumentDeclaration(stutter.CType('int'),'argc'),
444                 stutter.CArgumentDeclaration(stutter.CPointerType(stutter.CPointerType(stutter.CType('char'))), 'argv'),
445             ]
446
447         function_declaration = stutter.CFunctionDeclaration(
448             return_type,
449             'main',
450             argument_declarations,
451             stutter.CFunctionBody(
452                 [stutter.CReturnStatement(stutter.CIntegerLiteralExpression(0))],
453             ),
454         )
455
456         expected = 'int main(int argc, char** argv)\n{\n    return 0;\n}'
457         actual = stutter.generate_function_declaration(function_declaration)
458         self.assertEqual(expected, actual)
459
460 unittest.main()