test_parser.py revision f2715e076435b74638acb81512c2ee014f75aea2
1import parser
2import unittest
3from test import test_support
4
5#
6#  First, we test that we can generate trees from valid source fragments,
7#  and that these valid trees are indeed allowed by the tree-loading side
8#  of the parser module.
9#
10
11class RoundtripLegalSyntaxTestCase(unittest.TestCase):
12
13    def roundtrip(self, f, s):
14        st1 = f(s)
15        t = st1.totuple()
16        try:
17            st2 = parser.sequence2st(t)
18        except parser.ParserError:
19            self.fail("could not roundtrip %r" % s)
20
21        self.assertEquals(t, st2.totuple(),
22                          "could not re-generate syntax tree")
23
24    def check_expr(self, s):
25        self.roundtrip(parser.expr, s)
26
27    def check_suite(self, s):
28        self.roundtrip(parser.suite, s)
29
30    def test_yield_statement(self):
31        self.check_suite("def f(): yield 1")
32        self.check_suite("def f(): return; yield 1")
33        self.check_suite("def f(): yield 1; return")
34        self.check_suite("def f():\n"
35                         "    for x in range(30):\n"
36                         "        yield x\n")
37
38    def test_expressions(self):
39        self.check_expr("foo(1)")
40        self.check_expr("[1, 2, 3]")
41        self.check_expr("[x**3 for x in range(20)]")
42        self.check_expr("[x**3 for x in range(20) if x % 3]")
43        self.check_expr("foo(*args)")
44        self.check_expr("foo(*args, **kw)")
45        self.check_expr("foo(**kw)")
46        self.check_expr("foo(key=value)")
47        self.check_expr("foo(key=value, *args)")
48        self.check_expr("foo(key=value, *args, **kw)")
49        self.check_expr("foo(key=value, **kw)")
50        self.check_expr("foo(a, b, c, *args)")
51        self.check_expr("foo(a, b, c, *args, **kw)")
52        self.check_expr("foo(a, b, c, **kw)")
53        self.check_expr("foo + bar")
54        self.check_expr("foo - bar")
55        self.check_expr("foo * bar")
56        self.check_expr("foo / bar")
57        self.check_expr("foo // bar")
58        self.check_expr("lambda: 0")
59        self.check_expr("lambda x: 0")
60        self.check_expr("lambda *y: 0")
61        self.check_expr("lambda *y, **z: 0")
62        self.check_expr("lambda **z: 0")
63        self.check_expr("lambda x, y: 0")
64        self.check_expr("lambda foo=bar: 0")
65        self.check_expr("lambda foo=bar, spaz=nifty+spit: 0")
66        self.check_expr("lambda foo=bar, **z: 0")
67        self.check_expr("lambda foo=bar, blaz=blat+2, **z: 0")
68        self.check_expr("lambda foo=bar, blaz=blat+2, *y, **z: 0")
69        self.check_expr("lambda x, *y, **z: 0")
70
71    def test_print(self):
72        self.check_suite("print")
73        self.check_suite("print 1")
74        self.check_suite("print 1,")
75        self.check_suite("print >>fp")
76        self.check_suite("print >>fp, 1")
77        self.check_suite("print >>fp, 1,")
78
79    def test_simple_expression(self):
80        # expr_stmt
81        self.check_suite("a")
82
83    def test_simple_assignments(self):
84        self.check_suite("a = b")
85        self.check_suite("a = b = c = d = e")
86
87    def test_simple_augmented_assignments(self):
88        self.check_suite("a += b")
89        self.check_suite("a -= b")
90        self.check_suite("a *= b")
91        self.check_suite("a /= b")
92        self.check_suite("a //= b")
93        self.check_suite("a %= b")
94        self.check_suite("a &= b")
95        self.check_suite("a |= b")
96        self.check_suite("a ^= b")
97        self.check_suite("a <<= b")
98        self.check_suite("a >>= b")
99        self.check_suite("a **= b")
100
101    def test_function_defs(self):
102        self.check_suite("def f(): pass")
103        self.check_suite("def f(*args): pass")
104        self.check_suite("def f(*args, **kw): pass")
105        self.check_suite("def f(**kw): pass")
106        self.check_suite("def f(foo=bar): pass")
107        self.check_suite("def f(foo=bar, *args): pass")
108        self.check_suite("def f(foo=bar, *args, **kw): pass")
109        self.check_suite("def f(foo=bar, **kw): pass")
110
111        self.check_suite("def f(a, b): pass")
112        self.check_suite("def f(a, b, *args): pass")
113        self.check_suite("def f(a, b, *args, **kw): pass")
114        self.check_suite("def f(a, b, **kw): pass")
115        self.check_suite("def f(a, b, foo=bar): pass")
116        self.check_suite("def f(a, b, foo=bar, *args): pass")
117        self.check_suite("def f(a, b, foo=bar, *args, **kw): pass")
118        self.check_suite("def f(a, b, foo=bar, **kw): pass")
119
120    def test_import_from_statement(self):
121        self.check_suite("from sys.path import *")
122        self.check_suite("from sys.path import dirname")
123        self.check_suite("from sys.path import dirname as my_dirname")
124        self.check_suite("from sys.path import dirname, basename")
125        self.check_suite(
126            "from sys.path import dirname as my_dirname, basename")
127        self.check_suite(
128            "from sys.path import dirname, basename as my_basename")
129
130    def test_basic_import_statement(self):
131        self.check_suite("import sys")
132        self.check_suite("import sys as system")
133        self.check_suite("import sys, math")
134        self.check_suite("import sys as system, math")
135        self.check_suite("import sys, math as my_math")
136
137    def test_pep263(self):
138        self.check_suite("# -*- coding: iso-8859-1 -*-\n"
139                         "pass\n")
140
141    def test_assert(self):
142        self.check_suite("assert alo < ahi and blo < bhi\n")
143
144#
145#  Second, we take *invalid* trees and make sure we get ParserError
146#  rejections for them.
147#
148
149class IllegalSyntaxTestCase(unittest.TestCase):
150
151    def check_bad_tree(self, tree, label):
152        try:
153            parser.sequence2st(tree)
154        except parser.ParserError:
155            pass
156        else:
157            self.fail("did not detect invalid tree for %r" % label)
158
159    def test_junk(self):
160        # not even remotely valid:
161        self.check_bad_tree((1, 2, 3), "<junk>")
162
163    def test_illegal_yield_1(self):
164        # Illegal yield statement: def f(): return 1; yield 1
165        tree = \
166        (257,
167         (264,
168          (285,
169           (259,
170            (1, 'def'),
171            (1, 'f'),
172            (260, (7, '('), (8, ')')),
173            (11, ':'),
174            (291,
175             (4, ''),
176             (5, ''),
177             (264,
178              (265,
179               (266,
180                (272,
181                 (275,
182                  (1, 'return'),
183                  (313,
184                   (292,
185                    (293,
186                     (294,
187                      (295,
188                       (297,
189                        (298,
190                         (299,
191                          (300,
192                           (301,
193                            (302, (303, (304, (305, (2, '1')))))))))))))))))),
194               (264,
195                (265,
196                 (266,
197                  (272,
198                   (276,
199                    (1, 'yield'),
200                    (313,
201                     (292,
202                      (293,
203                       (294,
204                        (295,
205                         (297,
206                          (298,
207                           (299,
208                            (300,
209                             (301,
210                              (302,
211                               (303, (304, (305, (2, '1')))))))))))))))))),
212                 (4, ''))),
213               (6, ''))))),
214           (4, ''),
215           (0, ''))))
216        self.check_bad_tree(tree, "def f():\n  return 1\n  yield 1")
217
218    def test_illegal_yield_2(self):
219        # Illegal return in generator: def f(): return 1; yield 1
220        tree = \
221        (257,
222         (264,
223          (265,
224           (266,
225            (278,
226             (1, 'from'),
227             (281, (1, '__future__')),
228             (1, 'import'),
229             (279, (1, 'generators')))),
230           (4, ''))),
231         (264,
232          (285,
233           (259,
234            (1, 'def'),
235            (1, 'f'),
236            (260, (7, '('), (8, ')')),
237            (11, ':'),
238            (291,
239             (4, ''),
240             (5, ''),
241             (264,
242              (265,
243               (266,
244                (272,
245                 (275,
246                  (1, 'return'),
247                  (313,
248                   (292,
249                    (293,
250                     (294,
251                      (295,
252                       (297,
253                        (298,
254                         (299,
255                          (300,
256                           (301,
257                            (302, (303, (304, (305, (2, '1')))))))))))))))))),
258               (264,
259                (265,
260                 (266,
261                  (272,
262                   (276,
263                    (1, 'yield'),
264                    (313,
265                     (292,
266                      (293,
267                       (294,
268                        (295,
269                         (297,
270                          (298,
271                           (299,
272                            (300,
273                             (301,
274                              (302,
275                               (303, (304, (305, (2, '1')))))))))))))))))),
276                 (4, ''))),
277               (6, ''))))),
278           (4, ''),
279           (0, ''))))
280        self.check_bad_tree(tree, "def f():\n  return 1\n  yield 1")
281
282    def test_print_chevron_comma(self):
283        # Illegal input: print >>fp,
284        tree = \
285        (257,
286         (264,
287          (265,
288           (266,
289            (268,
290             (1, 'print'),
291             (35, '>>'),
292             (290,
293              (291,
294               (292,
295                (293,
296                 (295,
297                  (296,
298                   (297,
299                    (298, (299, (300, (301, (302, (303, (1, 'fp')))))))))))))),
300             (12, ','))),
301           (4, ''))),
302         (0, ''))
303        self.check_bad_tree(tree, "print >>fp,")
304
305    def test_a_comma_comma_c(self):
306        # Illegal input: a,,c
307        tree = \
308        (258,
309         (311,
310          (290,
311           (291,
312            (292,
313             (293,
314              (295,
315               (296,
316                (297,
317                 (298, (299, (300, (301, (302, (303, (1, 'a')))))))))))))),
318          (12, ','),
319          (12, ','),
320          (290,
321           (291,
322            (292,
323             (293,
324              (295,
325               (296,
326                (297,
327                 (298, (299, (300, (301, (302, (303, (1, 'c'))))))))))))))),
328         (4, ''),
329         (0, ''))
330        self.check_bad_tree(tree, "a,,c")
331
332    def test_illegal_operator(self):
333        # Illegal input: a $= b
334        tree = \
335        (257,
336         (264,
337          (265,
338           (266,
339            (267,
340             (312,
341              (291,
342               (292,
343                (293,
344                 (294,
345                  (296,
346                   (297,
347                    (298,
348                     (299,
349                      (300, (301, (302, (303, (304, (1, 'a'))))))))))))))),
350             (268, (37, '$=')),
351             (312,
352              (291,
353               (292,
354                (293,
355                 (294,
356                  (296,
357                   (297,
358                    (298,
359                     (299,
360                      (300, (301, (302, (303, (304, (1, 'b'))))))))))))))))),
361           (4, ''))),
362         (0, ''))
363        self.check_bad_tree(tree, "a $= b")
364
365    def test_malformed_global(self):
366        #doesn't have global keyword in ast
367        tree = (257,
368                (264,
369                 (265,
370                  (266,
371                   (282, (1, 'foo'))), (4, ''))),
372                (4, ''),
373                (0, ''))
374        self.check_bad_tree(tree, "malformed global ast")
375
376def test_main():
377    loader = unittest.TestLoader()
378    suite = unittest.TestSuite()
379    suite.addTest(loader.loadTestsFromTestCase(RoundtripLegalSyntaxTestCase))
380    suite.addTest(loader.loadTestsFromTestCase(IllegalSyntaxTestCase))
381    test_support.run_suite(suite)
382
383
384if __name__ == "__main__":
385    test_main()
386