Set 1, challenge 3
[sandbox] / stutter / 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_identifiers_with_dashes(self):
85         expected = [stutter.Symbol('hello-world')]
86         actual = stutter.parse_all('hello-world')
87
88         self.assertEqual(expected, actual)
89
90     def test_parses_strings(self):
91         expected = ['Hello, world']
92         actual = stutter.parse_all('"Hello, world"')
93
94         self.assertEqual(expected, actual)
95
96     def test_parses_strings_with_escaped_delimiters(self):
97         expected = ['"Hello, world"']
98         actual = stutter.parse_all('"\\"Hello, world\\""')
99
100         self.assertEqual(expected, actual)
101
102     def test_parses_empty_s_expressions(self):
103         expected = [()]
104         actual = stutter.parse_all('()')
105
106         self.assertEqual(expected, actual)
107
108     def test_parses_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_nested_s_expressions(self):
115         expected = [(0, (1, (2,)))]
116         actual = stutter.parse_all('(0 (1 (2)))')
117
118         self.assertEqual(expected, actual)
119
120     def test_parses_multiple_expressions(self):
121         expected = [0, ()]
122         actual = stutter.parse_all('0 ()')
123
124         self.assertEqual(expected, actual)
125
126     def test_raises_exception_for_unclosed_parenthese(self):
127         self.assertRaises(Exception, stutter.parse_all, '(')
128
129     def test_raises_exception_for_unopened_parenthese(self):
130         self.assertRaises(Exception, stutter.parse_all, ')')
131
132 class QuoteToCTests(unittest.TestCase):
133     def test_quotes_integer_literals(self):
134         for i in range(5):
135             expected = stutter.CFunctionCallExpression(
136                 'makeObjectPointerFromInteger',
137                 [stutter.CIntegerLiteralExpression(i)],
138             )
139             
140             actual = stutter.quote_to_c(i)
141             
142             self.assertEqual(expected, actual)
143
144     def test_quotes_string_literals(self):
145         s = 'Hello, world'
146         expected = stutter.CFunctionCallExpression(
147             'makeObjectPointerFromString',
148             [stutter.CStringLiteralExpression(s)],
149         )
150
151         actual = stutter.quote_to_c(s)
152
153         self.assertEqual(expected, actual)
154
155     def test_quotes_symbols(self):
156         s = 'symbol'
157         expected = stutter.CFunctionCallExpression(
158             'getSymbol',
159             [stutter.CStringLiteralExpression(s)],
160         )
161
162         actual = stutter.quote_to_c(stutter.Symbol(s))
163
164         self.assertEqual(expected, actual)
165
166 class EvaluateApplicationArgumentsToCTests(unittest.TestCase):
167     def test_evaluates_empty_to_null(self):
168         expected = stutter.CVariableExpression('NULL')
169         actual = stutter.evaluate_application_arguments_to_c(())
170
171         self.assertEqual(expected, actual)
172
173     def test_evaluates_one_argument_to_cons(self):
174         argument = 42
175
176         sentinel = stutter.CStringLiteralExpression('1bd9707e76f8f807f3bad3e39049fea4a36d8ef2f8e2ed471ec755f7adb291d5')
177
178         def mock(argument_to_quote):
179             if argument_to_quote == argument:
180                 return sentinel
181
182         expected = stutter.CFunctionCallExpression(
183             'c_cons',
184             (sentinel, stutter.CVariableExpression('NULL')),
185         )
186
187         actual = stutter.evaluate_application_arguments_to_c(
188             (argument,),
189             quote_to_c = mock,
190         )
191
192         self.assertEqual(expected, actual)
193
194 class EvaluateApplicationToCTests(unittest.TestCase):
195     def test_evaluates_function_calls_with_no_arguments(self):
196         name = 'name'
197
198         sentinel = stutter.CVariableExpression('NULL')
199
200         def mock(arguments):
201             assert arguments == ()
202             return sentinel
203
204         result = stutter.evaluate_application_to_c(
205             (stutter.Symbol(name),),
206             evaluate_application_arguments_to_c = mock,
207         )
208
209         self.assertEqual(result.name, name)
210         self.assertEqual(len(result.arguments), 2)
211         self.assertTrue(isinstance(
212             result.arguments[0],
213             stutter.CReferenceExpression,
214         ))
215         self.assertIs(result.arguments[1], sentinel)
216
217     def test_evaluates_function_calls_with_arguments(self):
218         name = 'print'
219         argument = 42 
220
221         sentinel = stutter.CFunctionCallExpression(
222             'cons',
223             [
224                 stutter.CFunctionCallExpression(
225                     'makeObjectPointerFromInteger',
226                     [stutter.CIntegerLiteralExpression(argument)],
227                 ),
228             ],
229         )
230
231         def mock(arguments):
232             assert arguments == (argument,)
233             return sentinel
234
235         result = stutter.evaluate_application_to_c(
236             (stutter.Symbol(name), argument),
237             evaluate_application_arguments_to_c = mock,
238         )
239
240         self.assertEqual(result.name, name)
241         self.assertEqual(len(result.arguments), 2)
242         self.assertTrue(isinstance(
243             result.arguments[0],
244             stutter.CReferenceExpression,
245         ))
246         self.assertIs(result.arguments[1], sentinel)
247
248 class EvaluateToCTests(unittest.TestCase):
249     def test_evaluates_integers(self):
250         for i in range(5):
251             result = stutter.evaluate_to_c(i)
252             self.assertIsInstance(result, stutter.CIntegerLiteralExpression)
253             self.assertEqual(result.integer, i)
254
255     def test_evaluates_string_literals(self):
256         s = 'Hello, world'
257         result = stutter.evaluate_to_c(s)
258
259         self.assertIsInstance(result, stutter.CStringLiteralExpression)
260         self.assertEqual(result.string, s)
261
262     def test_calls_evaluate_application_when_given_an_application(self):
263         sentinel = object()
264         application = (stutter.Symbol('print'), 'Hello, world')
265
266         def mock(argument):
267             if argument == application:
268                 return sentinel
269
270         result = stutter.evaluate_to_c(
271             application,
272             evaluate_application_to_c = mock,
273         )
274
275         self.assertIs(result, sentinel)
276
277 class EvaluateAllToCTests(unittest.TestCase):
278     def test_returns_function_body(self):
279         result = stutter.evaluate_all_to_c([0])
280
281         self.assertIsInstance(result, stutter.CFunctionBody)
282
283     def test_main_contains_expression_statements_followed_by_return_statement(self):
284         result = stutter.evaluate_all_to_c([0,0,0])
285
286         self.assertIsInstance(result.statements[0],stutter.CDefinitionStatement)
287         self.assertIsInstance(result.statements[1],stutter.CExpressionStatement)
288         self.assertIsInstance(result.statements[2],stutter.CExpressionStatement)
289         self.assertIsInstance(result.statements[3],stutter.CReturnStatement)
290
291 class GeneratePointerTypeTests(unittest.TestCase):
292     def test_basic(self):
293         expected = 'int*'
294         actual = stutter.generate_pointer_type(stutter.CPointerType(stutter.CType('int')))
295         self.assertEqual(expected, actual)
296
297 class GenerateTypeTests(unittest.TestCase):
298     def test_basic(self):
299         expected = 'int'
300         actual = stutter.generate_type(stutter.CType('int'))
301         self.assertEqual(expected, actual)
302
303     def test_generates_pointer_types(self):
304         expected = object()
305         actual = stutter.generate_type(
306                 stutter.CPointerType(stutter.CType('int')),
307                 generate_pointer_type = lambda x : expected)
308
309         self.assertIs(expected, actual)
310
311 class GenerateArgumentDeclarationTests(unittest.TestCase):
312     def test_basic(self):
313         expected = 'int argc'
314         actual = stutter.generate_argument_declaration(
315                 stutter.CArgumentDeclaration(stutter.CType('int'), 'argc'))
316         self.assertEqual(expected, actual)
317
318 class GenerateArgumentDeclarationListTests(unittest.TestCase):
319     def test_basic(self):
320         argument_declarations = [
321                 stutter.CArgumentDeclaration(stutter.CType('int'),'argc'),
322                 stutter.CArgumentDeclaration(stutter.CPointerType(stutter.CPointerType(stutter.CType('char'))), 'argv'),
323             ]
324         expected = 'int argc, char** argv'
325         actual = stutter.generate_argument_declaration_list(argument_declarations)
326         self.assertEqual(expected, actual)
327
328 class GenerateIntegerLiteralExpressionTests(unittest.TestCase):
329     def test_basic(self):
330         expected = '0'
331         actual = stutter.generate_integer_literal_expression(
332             stutter.CIntegerLiteralExpression(0),
333         )
334         self.assertEqual(expected, actual)
335
336 class GenerateStringLiteralExpressionTests(unittest.TestCase):
337     def test_basic(self):
338         expected = '"Hello, world"'
339         actual = stutter.generate_string_literal_expression(
340             stutter.CStringLiteralExpression('Hello, world'),
341         )
342         self.assertEqual(expected, actual)
343
344     def test_escapes(self):
345         expected = r'"\\\n\"\t"'
346         actual = stutter.generate_string_literal_expression(
347             stutter.CStringLiteralExpression('\\\n"\t'),
348         )
349         self.assertEqual(expected, actual)
350
351 class GenerateVariableExpressionTests(unittest.TestCase):
352     def test_generates(self):
353         expected = 'name'
354         actual = stutter.generate_variable_expression(
355             stutter.CVariableExpression(expected),
356         )
357
358         self.assertEqual(expected, actual)
359
360 class GenerateReferenceExpressionTests(unittest.TestCase):
361     def test_generates(self):
362         expected = '&name';
363         actual = stutter.generate_reference_expression(
364             stutter.CReferenceExpression(stutter.CVariableExpression('name')),
365         )
366
367         self.assertEqual(expected, actual)
368
369 class GenerateFunctionCallExpressionTests(unittest.TestCase):
370     def test_no_arguments(self):
371         expected = 'name()'
372         actual = stutter.generate_function_call_expression(
373             stutter.CFunctionCallExpression('name', []),
374         )
375         self.assertEqual(expected, actual)
376
377     def test_one_argument(self):
378         expected = 'name(0)'
379         actual = stutter.generate_function_call_expression(
380             stutter.CFunctionCallExpression(
381                 'name',
382                 [
383                     stutter.CIntegerLiteralExpression(0),
384                 ],
385             ),
386         )
387         self.assertEqual(expected, actual)
388
389     def test_many_arguments(self):
390         expected = 'name(0, 1)'
391         actual = stutter.generate_function_call_expression(
392             stutter.CFunctionCallExpression(
393                 'name',
394                 [
395                     stutter.CIntegerLiteralExpression(0),
396                     stutter.CIntegerLiteralExpression(1),
397                 ],
398             ),
399         )
400         self.assertEqual(expected, actual)
401
402 class GenerateExpressionTests(unittest.TestCase):
403     def test_generates_integer_literal_expressions(self):
404         expected = object()
405         actual = stutter.generate_expression(
406                 stutter.CIntegerLiteralExpression(0),
407                 generate_integer_literal_expression = lambda x : expected)
408
409         self.assertIs(expected, actual)
410
411     def test_generates_string_literal_expressions(self):
412         expected = object()
413         actual = stutter.generate_expression(
414                 stutter.CStringLiteralExpression('Hello, world'),
415                 generate_string_literal_expression = lambda x : expected)
416
417         self.assertIs(expected, actual)
418
419     def test_generates_variable_expression(self):
420         expected = object()
421         actual = stutter.generate_expression(
422                 stutter.CVariableExpression('name'),
423                 generate_variable_expression = lambda x : expected)
424
425         self.assertIs(expected, actual)
426
427     def test_generates_variable_expression(self):
428         expected = object()
429         actual = stutter.generate_expression(
430                 stutter.CReferenceExpression(stutter.CVariableExpression('name')),
431                 generate_reference_expression = lambda x : expected)
432
433         self.assertIs(expected, actual)
434
435     def test_generates_function_call_expression(self):
436         expected = object()
437         actual = stutter.generate_expression(
438                 stutter.CFunctionCallExpression('name',[]),
439                 generate_function_call_expression = lambda x : expected)
440
441         self.assertIs(expected, actual)
442
443 class GenerateStatement(unittest.TestCase):
444     def test_generates_expression_statement(self):
445         return_statement = stutter.CExpressionStatement('0')
446
447         expected = object()
448         actual = stutter.generate_statement(
449             return_statement,
450             generate_expression_statement = lambda _ : expected)
451
452         self.assertIs(expected, actual)
453
454     def test_generates_return_statement(self):
455         return_statement = stutter.CReturnStatement(stutter.CIntegerLiteralExpression(0))
456
457         expected = object()
458         actual = stutter.generate_statement(
459             return_statement,
460             generate_return_statement = lambda _ : expected)
461
462         self.assertIs(expected, actual)
463
464     def test_generates_definition_statement(self):
465         definition_statement = stutter.CDefinitionStatement(
466             stutter.CType('int'),
467             'number',
468             stutter.CIntegerLiteralExpression(0),
469         )
470
471         expected = object()
472         actual = stutter.generate_statement(
473             definition_statement,
474             generate_definition_statement = lambda _ : expected)
475
476         self.assertIs(expected, actual)
477
478 class GenerateExpressionStatementTests(unittest.TestCase):
479     def test_generates_return_statement(self):
480         expression_statement = stutter.CExpressionStatement(stutter.CIntegerLiteralExpression(0))
481
482         expected = '0;'
483         actual = stutter.generate_expression_statement(expression_statement)
484
485         self.assertEqual(expected, actual)
486
487 class GenerateReturnStatementTests(unittest.TestCase):
488     def test_generates_return_statement(self):
489         return_statement = stutter.CReturnStatement(stutter.CIntegerLiteralExpression(0))
490
491         expected = 'return 0;'
492         actual = stutter.generate_return_statement(return_statement)
493
494         self.assertEqual(expected, actual)
495
496 class GenerateDefinitionStatementTests(unittest.TestCase):
497     def test_generates_definition_statement(self):
498         definition_statement = stutter.CDefinitionStatement(
499             stutter.CType('int'),
500             'number',
501             stutter.CIntegerLiteralExpression(0),
502         )
503
504         expected = 'int number = 0;'
505         actual = stutter.generate_definition_statement(definition_statement)
506
507         self.assertEqual(expected, actual)
508
509 class GenerateFunctionDeclarationTests(unittest.TestCase):
510     def test_basic(self):
511         return_type = stutter.CType('int')
512         argument_declarations = [
513                 stutter.CArgumentDeclaration(stutter.CType('int'),'argc'),
514                 stutter.CArgumentDeclaration(stutter.CPointerType(stutter.CPointerType(stutter.CType('char'))), 'argv'),
515             ]
516
517         function_declaration = stutter.CFunctionDeclaration(
518             return_type,
519             'main',
520             argument_declarations,
521             stutter.CFunctionBody(
522                 [stutter.CReturnStatement(stutter.CIntegerLiteralExpression(0))],
523             ),
524         )
525
526         expected = 'int main(int argc, char** argv)\n{\n    return 0;\n}'
527         actual = stutter.generate_function_declaration(function_declaration)
528         self.assertEqual(expected, actual)
529
530 unittest.main()