| 1 | import parser
|
|---|
| 2 | import unittest
|
|---|
| 3 | from 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 |
|
|---|
| 11 | class 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, why:
|
|---|
| 19 | self.fail("could not roundtrip %r: %s" % (s, why))
|
|---|
| 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(): yield")
|
|---|
| 33 | self.check_suite("def f(): x += yield")
|
|---|
| 34 | self.check_suite("def f(): x = yield 1")
|
|---|
| 35 | self.check_suite("def f(): x = y = yield 1")
|
|---|
| 36 | self.check_suite("def f(): x = yield")
|
|---|
| 37 | self.check_suite("def f(): x = y = yield")
|
|---|
| 38 | self.check_suite("def f(): 1 + (yield)*2")
|
|---|
| 39 | self.check_suite("def f(): (yield 1)*2")
|
|---|
| 40 | self.check_suite("def f(): return; yield 1")
|
|---|
| 41 | self.check_suite("def f(): yield 1; return")
|
|---|
| 42 | self.check_suite("def f():\n"
|
|---|
| 43 | " for x in range(30):\n"
|
|---|
| 44 | " yield x\n")
|
|---|
| 45 | self.check_suite("def f():\n"
|
|---|
| 46 | " if (yield):\n"
|
|---|
| 47 | " yield x\n")
|
|---|
| 48 |
|
|---|
| 49 | def test_expressions(self):
|
|---|
| 50 | self.check_expr("foo(1)")
|
|---|
| 51 | self.check_expr("[1, 2, 3]")
|
|---|
| 52 | self.check_expr("[x**3 for x in range(20)]")
|
|---|
| 53 | self.check_expr("[x**3 for x in range(20) if x % 3]")
|
|---|
| 54 | self.check_expr("[x**3 for x in range(20) if x % 2 if x % 3]")
|
|---|
| 55 | self.check_expr("list(x**3 for x in range(20))")
|
|---|
| 56 | self.check_expr("list(x**3 for x in range(20) if x % 3)")
|
|---|
| 57 | self.check_expr("list(x**3 for x in range(20) if x % 2 if x % 3)")
|
|---|
| 58 | self.check_expr("foo(*args)")
|
|---|
| 59 | self.check_expr("foo(*args, **kw)")
|
|---|
| 60 | self.check_expr("foo(**kw)")
|
|---|
| 61 | self.check_expr("foo(key=value)")
|
|---|
| 62 | self.check_expr("foo(key=value, *args)")
|
|---|
| 63 | self.check_expr("foo(key=value, *args, **kw)")
|
|---|
| 64 | self.check_expr("foo(key=value, **kw)")
|
|---|
| 65 | self.check_expr("foo(a, b, c, *args)")
|
|---|
| 66 | self.check_expr("foo(a, b, c, *args, **kw)")
|
|---|
| 67 | self.check_expr("foo(a, b, c, **kw)")
|
|---|
| 68 | self.check_expr("foo + bar")
|
|---|
| 69 | self.check_expr("foo - bar")
|
|---|
| 70 | self.check_expr("foo * bar")
|
|---|
| 71 | self.check_expr("foo / bar")
|
|---|
| 72 | self.check_expr("foo // bar")
|
|---|
| 73 | self.check_expr("lambda: 0")
|
|---|
| 74 | self.check_expr("lambda x: 0")
|
|---|
| 75 | self.check_expr("lambda *y: 0")
|
|---|
| 76 | self.check_expr("lambda *y, **z: 0")
|
|---|
| 77 | self.check_expr("lambda **z: 0")
|
|---|
| 78 | self.check_expr("lambda x, y: 0")
|
|---|
| 79 | self.check_expr("lambda foo=bar: 0")
|
|---|
| 80 | self.check_expr("lambda foo=bar, spaz=nifty+spit: 0")
|
|---|
| 81 | self.check_expr("lambda foo=bar, **z: 0")
|
|---|
| 82 | self.check_expr("lambda foo=bar, blaz=blat+2, **z: 0")
|
|---|
| 83 | self.check_expr("lambda foo=bar, blaz=blat+2, *y, **z: 0")
|
|---|
| 84 | self.check_expr("lambda x, *y, **z: 0")
|
|---|
| 85 | self.check_expr("(x for x in range(10))")
|
|---|
| 86 | self.check_expr("foo(x for x in range(10))")
|
|---|
| 87 |
|
|---|
| 88 | def test_print(self):
|
|---|
| 89 | self.check_suite("print")
|
|---|
| 90 | self.check_suite("print 1")
|
|---|
| 91 | self.check_suite("print 1,")
|
|---|
| 92 | self.check_suite("print >>fp")
|
|---|
| 93 | self.check_suite("print >>fp, 1")
|
|---|
| 94 | self.check_suite("print >>fp, 1,")
|
|---|
| 95 |
|
|---|
| 96 | def test_simple_expression(self):
|
|---|
| 97 | # expr_stmt
|
|---|
| 98 | self.check_suite("a")
|
|---|
| 99 |
|
|---|
| 100 | def test_simple_assignments(self):
|
|---|
| 101 | self.check_suite("a = b")
|
|---|
| 102 | self.check_suite("a = b = c = d = e")
|
|---|
| 103 |
|
|---|
| 104 | def test_simple_augmented_assignments(self):
|
|---|
| 105 | self.check_suite("a += b")
|
|---|
| 106 | self.check_suite("a -= b")
|
|---|
| 107 | self.check_suite("a *= b")
|
|---|
| 108 | self.check_suite("a /= b")
|
|---|
| 109 | self.check_suite("a //= b")
|
|---|
| 110 | self.check_suite("a %= b")
|
|---|
| 111 | self.check_suite("a &= b")
|
|---|
| 112 | self.check_suite("a |= b")
|
|---|
| 113 | self.check_suite("a ^= b")
|
|---|
| 114 | self.check_suite("a <<= b")
|
|---|
| 115 | self.check_suite("a >>= b")
|
|---|
| 116 | self.check_suite("a **= b")
|
|---|
| 117 |
|
|---|
| 118 | def test_function_defs(self):
|
|---|
| 119 | self.check_suite("def f(): pass")
|
|---|
| 120 | self.check_suite("def f(*args): pass")
|
|---|
| 121 | self.check_suite("def f(*args, **kw): pass")
|
|---|
| 122 | self.check_suite("def f(**kw): pass")
|
|---|
| 123 | self.check_suite("def f(foo=bar): pass")
|
|---|
| 124 | self.check_suite("def f(foo=bar, *args): pass")
|
|---|
| 125 | self.check_suite("def f(foo=bar, *args, **kw): pass")
|
|---|
| 126 | self.check_suite("def f(foo=bar, **kw): pass")
|
|---|
| 127 |
|
|---|
| 128 | self.check_suite("def f(a, b): pass")
|
|---|
| 129 | self.check_suite("def f(a, b, *args): pass")
|
|---|
| 130 | self.check_suite("def f(a, b, *args, **kw): pass")
|
|---|
| 131 | self.check_suite("def f(a, b, **kw): pass")
|
|---|
| 132 | self.check_suite("def f(a, b, foo=bar): pass")
|
|---|
| 133 | self.check_suite("def f(a, b, foo=bar, *args): pass")
|
|---|
| 134 | self.check_suite("def f(a, b, foo=bar, *args, **kw): pass")
|
|---|
| 135 | self.check_suite("def f(a, b, foo=bar, **kw): pass")
|
|---|
| 136 |
|
|---|
| 137 | self.check_suite("@staticmethod\n"
|
|---|
| 138 | "def f(): pass")
|
|---|
| 139 | self.check_suite("@staticmethod\n"
|
|---|
| 140 | "@funcattrs(x, y)\n"
|
|---|
| 141 | "def f(): pass")
|
|---|
| 142 | self.check_suite("@funcattrs()\n"
|
|---|
| 143 | "def f(): pass")
|
|---|
| 144 |
|
|---|
| 145 | def test_class_defs(self):
|
|---|
| 146 | self.check_suite("class foo():pass")
|
|---|
| 147 |
|
|---|
| 148 | def test_import_from_statement(self):
|
|---|
| 149 | self.check_suite("from sys.path import *")
|
|---|
| 150 | self.check_suite("from sys.path import dirname")
|
|---|
| 151 | self.check_suite("from sys.path import (dirname)")
|
|---|
| 152 | self.check_suite("from sys.path import (dirname,)")
|
|---|
| 153 | self.check_suite("from sys.path import dirname as my_dirname")
|
|---|
| 154 | self.check_suite("from sys.path import (dirname as my_dirname)")
|
|---|
| 155 | self.check_suite("from sys.path import (dirname as my_dirname,)")
|
|---|
| 156 | self.check_suite("from sys.path import dirname, basename")
|
|---|
| 157 | self.check_suite("from sys.path import (dirname, basename)")
|
|---|
| 158 | self.check_suite("from sys.path import (dirname, basename,)")
|
|---|
| 159 | self.check_suite(
|
|---|
| 160 | "from sys.path import dirname as my_dirname, basename")
|
|---|
| 161 | self.check_suite(
|
|---|
| 162 | "from sys.path import (dirname as my_dirname, basename)")
|
|---|
| 163 | self.check_suite(
|
|---|
| 164 | "from sys.path import (dirname as my_dirname, basename,)")
|
|---|
| 165 | self.check_suite(
|
|---|
| 166 | "from sys.path import dirname, basename as my_basename")
|
|---|
| 167 | self.check_suite(
|
|---|
| 168 | "from sys.path import (dirname, basename as my_basename)")
|
|---|
| 169 | self.check_suite(
|
|---|
| 170 | "from sys.path import (dirname, basename as my_basename,)")
|
|---|
| 171 |
|
|---|
| 172 | def test_basic_import_statement(self):
|
|---|
| 173 | self.check_suite("import sys")
|
|---|
| 174 | self.check_suite("import sys as system")
|
|---|
| 175 | self.check_suite("import sys, math")
|
|---|
| 176 | self.check_suite("import sys as system, math")
|
|---|
| 177 | self.check_suite("import sys, math as my_math")
|
|---|
| 178 |
|
|---|
| 179 | def test_pep263(self):
|
|---|
| 180 | self.check_suite("# -*- coding: iso-8859-1 -*-\n"
|
|---|
| 181 | "pass\n")
|
|---|
| 182 |
|
|---|
| 183 | def test_assert(self):
|
|---|
| 184 | self.check_suite("assert alo < ahi and blo < bhi\n")
|
|---|
| 185 |
|
|---|
| 186 | #
|
|---|
| 187 | # Second, we take *invalid* trees and make sure we get ParserError
|
|---|
| 188 | # rejections for them.
|
|---|
| 189 | #
|
|---|
| 190 |
|
|---|
| 191 | class IllegalSyntaxTestCase(unittest.TestCase):
|
|---|
| 192 |
|
|---|
| 193 | def check_bad_tree(self, tree, label):
|
|---|
| 194 | try:
|
|---|
| 195 | parser.sequence2st(tree)
|
|---|
| 196 | except parser.ParserError:
|
|---|
| 197 | pass
|
|---|
| 198 | else:
|
|---|
| 199 | self.fail("did not detect invalid tree for %r" % label)
|
|---|
| 200 |
|
|---|
| 201 | def test_junk(self):
|
|---|
| 202 | # not even remotely valid:
|
|---|
| 203 | self.check_bad_tree((1, 2, 3), "<junk>")
|
|---|
| 204 |
|
|---|
| 205 | def test_illegal_yield_1(self):
|
|---|
| 206 | # Illegal yield statement: def f(): return 1; yield 1
|
|---|
| 207 | tree = \
|
|---|
| 208 | (257,
|
|---|
| 209 | (264,
|
|---|
| 210 | (285,
|
|---|
| 211 | (259,
|
|---|
| 212 | (1, 'def'),
|
|---|
| 213 | (1, 'f'),
|
|---|
| 214 | (260, (7, '('), (8, ')')),
|
|---|
| 215 | (11, ':'),
|
|---|
| 216 | (291,
|
|---|
| 217 | (4, ''),
|
|---|
| 218 | (5, ''),
|
|---|
| 219 | (264,
|
|---|
| 220 | (265,
|
|---|
| 221 | (266,
|
|---|
| 222 | (272,
|
|---|
| 223 | (275,
|
|---|
| 224 | (1, 'return'),
|
|---|
| 225 | (313,
|
|---|
| 226 | (292,
|
|---|
| 227 | (293,
|
|---|
| 228 | (294,
|
|---|
| 229 | (295,
|
|---|
| 230 | (297,
|
|---|
| 231 | (298,
|
|---|
| 232 | (299,
|
|---|
| 233 | (300,
|
|---|
| 234 | (301,
|
|---|
| 235 | (302, (303, (304, (305, (2, '1')))))))))))))))))),
|
|---|
| 236 | (264,
|
|---|
| 237 | (265,
|
|---|
| 238 | (266,
|
|---|
| 239 | (272,
|
|---|
| 240 | (276,
|
|---|
| 241 | (1, 'yield'),
|
|---|
| 242 | (313,
|
|---|
| 243 | (292,
|
|---|
| 244 | (293,
|
|---|
| 245 | (294,
|
|---|
| 246 | (295,
|
|---|
| 247 | (297,
|
|---|
| 248 | (298,
|
|---|
| 249 | (299,
|
|---|
| 250 | (300,
|
|---|
| 251 | (301,
|
|---|
| 252 | (302,
|
|---|
| 253 | (303, (304, (305, (2, '1')))))))))))))))))),
|
|---|
| 254 | (4, ''))),
|
|---|
| 255 | (6, ''))))),
|
|---|
| 256 | (4, ''),
|
|---|
| 257 | (0, ''))))
|
|---|
| 258 | self.check_bad_tree(tree, "def f():\n return 1\n yield 1")
|
|---|
| 259 |
|
|---|
| 260 | def test_illegal_yield_2(self):
|
|---|
| 261 | # Illegal return in generator: def f(): return 1; yield 1
|
|---|
| 262 | tree = \
|
|---|
| 263 | (257,
|
|---|
| 264 | (264,
|
|---|
| 265 | (265,
|
|---|
| 266 | (266,
|
|---|
| 267 | (278,
|
|---|
| 268 | (1, 'from'),
|
|---|
| 269 | (281, (1, '__future__')),
|
|---|
| 270 | (1, 'import'),
|
|---|
| 271 | (279, (1, 'generators')))),
|
|---|
| 272 | (4, ''))),
|
|---|
| 273 | (264,
|
|---|
| 274 | (285,
|
|---|
| 275 | (259,
|
|---|
| 276 | (1, 'def'),
|
|---|
| 277 | (1, 'f'),
|
|---|
| 278 | (260, (7, '('), (8, ')')),
|
|---|
| 279 | (11, ':'),
|
|---|
| 280 | (291,
|
|---|
| 281 | (4, ''),
|
|---|
| 282 | (5, ''),
|
|---|
| 283 | (264,
|
|---|
| 284 | (265,
|
|---|
| 285 | (266,
|
|---|
| 286 | (272,
|
|---|
| 287 | (275,
|
|---|
| 288 | (1, 'return'),
|
|---|
| 289 | (313,
|
|---|
| 290 | (292,
|
|---|
| 291 | (293,
|
|---|
| 292 | (294,
|
|---|
| 293 | (295,
|
|---|
| 294 | (297,
|
|---|
| 295 | (298,
|
|---|
| 296 | (299,
|
|---|
| 297 | (300,
|
|---|
| 298 | (301,
|
|---|
| 299 | (302, (303, (304, (305, (2, '1')))))))))))))))))),
|
|---|
| 300 | (264,
|
|---|
| 301 | (265,
|
|---|
| 302 | (266,
|
|---|
| 303 | (272,
|
|---|
| 304 | (276,
|
|---|
| 305 | (1, 'yield'),
|
|---|
| 306 | (313,
|
|---|
| 307 | (292,
|
|---|
| 308 | (293,
|
|---|
| 309 | (294,
|
|---|
| 310 | (295,
|
|---|
| 311 | (297,
|
|---|
| 312 | (298,
|
|---|
| 313 | (299,
|
|---|
| 314 | (300,
|
|---|
| 315 | (301,
|
|---|
| 316 | (302,
|
|---|
| 317 | (303, (304, (305, (2, '1')))))))))))))))))),
|
|---|
| 318 | (4, ''))),
|
|---|
| 319 | (6, ''))))),
|
|---|
| 320 | (4, ''),
|
|---|
| 321 | (0, ''))))
|
|---|
| 322 | self.check_bad_tree(tree, "def f():\n return 1\n yield 1")
|
|---|
| 323 |
|
|---|
| 324 | def test_print_chevron_comma(self):
|
|---|
| 325 | # Illegal input: print >>fp,
|
|---|
| 326 | tree = \
|
|---|
| 327 | (257,
|
|---|
| 328 | (264,
|
|---|
| 329 | (265,
|
|---|
| 330 | (266,
|
|---|
| 331 | (268,
|
|---|
| 332 | (1, 'print'),
|
|---|
| 333 | (35, '>>'),
|
|---|
| 334 | (290,
|
|---|
| 335 | (291,
|
|---|
| 336 | (292,
|
|---|
| 337 | (293,
|
|---|
| 338 | (295,
|
|---|
| 339 | (296,
|
|---|
| 340 | (297,
|
|---|
| 341 | (298, (299, (300, (301, (302, (303, (1, 'fp')))))))))))))),
|
|---|
| 342 | (12, ','))),
|
|---|
| 343 | (4, ''))),
|
|---|
| 344 | (0, ''))
|
|---|
| 345 | self.check_bad_tree(tree, "print >>fp,")
|
|---|
| 346 |
|
|---|
| 347 | def test_a_comma_comma_c(self):
|
|---|
| 348 | # Illegal input: a,,c
|
|---|
| 349 | tree = \
|
|---|
| 350 | (258,
|
|---|
| 351 | (311,
|
|---|
| 352 | (290,
|
|---|
| 353 | (291,
|
|---|
| 354 | (292,
|
|---|
| 355 | (293,
|
|---|
| 356 | (295,
|
|---|
| 357 | (296,
|
|---|
| 358 | (297,
|
|---|
| 359 | (298, (299, (300, (301, (302, (303, (1, 'a')))))))))))))),
|
|---|
| 360 | (12, ','),
|
|---|
| 361 | (12, ','),
|
|---|
| 362 | (290,
|
|---|
| 363 | (291,
|
|---|
| 364 | (292,
|
|---|
| 365 | (293,
|
|---|
| 366 | (295,
|
|---|
| 367 | (296,
|
|---|
| 368 | (297,
|
|---|
| 369 | (298, (299, (300, (301, (302, (303, (1, 'c'))))))))))))))),
|
|---|
| 370 | (4, ''),
|
|---|
| 371 | (0, ''))
|
|---|
| 372 | self.check_bad_tree(tree, "a,,c")
|
|---|
| 373 |
|
|---|
| 374 | def test_illegal_operator(self):
|
|---|
| 375 | # Illegal input: a $= b
|
|---|
| 376 | tree = \
|
|---|
| 377 | (257,
|
|---|
| 378 | (264,
|
|---|
| 379 | (265,
|
|---|
| 380 | (266,
|
|---|
| 381 | (267,
|
|---|
| 382 | (312,
|
|---|
| 383 | (291,
|
|---|
| 384 | (292,
|
|---|
| 385 | (293,
|
|---|
| 386 | (294,
|
|---|
| 387 | (296,
|
|---|
| 388 | (297,
|
|---|
| 389 | (298,
|
|---|
| 390 | (299,
|
|---|
| 391 | (300, (301, (302, (303, (304, (1, 'a'))))))))))))))),
|
|---|
| 392 | (268, (37, '$=')),
|
|---|
| 393 | (312,
|
|---|
| 394 | (291,
|
|---|
| 395 | (292,
|
|---|
| 396 | (293,
|
|---|
| 397 | (294,
|
|---|
| 398 | (296,
|
|---|
| 399 | (297,
|
|---|
| 400 | (298,
|
|---|
| 401 | (299,
|
|---|
| 402 | (300, (301, (302, (303, (304, (1, 'b'))))))))))))))))),
|
|---|
| 403 | (4, ''))),
|
|---|
| 404 | (0, ''))
|
|---|
| 405 | self.check_bad_tree(tree, "a $= b")
|
|---|
| 406 |
|
|---|
| 407 | def test_malformed_global(self):
|
|---|
| 408 | #doesn't have global keyword in ast
|
|---|
| 409 | tree = (257,
|
|---|
| 410 | (264,
|
|---|
| 411 | (265,
|
|---|
| 412 | (266,
|
|---|
| 413 | (282, (1, 'foo'))), (4, ''))),
|
|---|
| 414 | (4, ''),
|
|---|
| 415 | (0, ''))
|
|---|
| 416 | self.check_bad_tree(tree, "malformed global ast")
|
|---|
| 417 |
|
|---|
| 418 |
|
|---|
| 419 | class CompileTestCase(unittest.TestCase):
|
|---|
| 420 |
|
|---|
| 421 | # These tests are very minimal. :-(
|
|---|
| 422 |
|
|---|
| 423 | def test_compile_expr(self):
|
|---|
| 424 | st = parser.expr('2 + 3')
|
|---|
| 425 | code = parser.compilest(st)
|
|---|
| 426 | self.assertEquals(eval(code), 5)
|
|---|
| 427 |
|
|---|
| 428 | def test_compile_suite(self):
|
|---|
| 429 | st = parser.suite('x = 2; y = x + 3')
|
|---|
| 430 | code = parser.compilest(st)
|
|---|
| 431 | globs = {}
|
|---|
| 432 | exec code in globs
|
|---|
| 433 | self.assertEquals(globs['y'], 5)
|
|---|
| 434 |
|
|---|
| 435 | def test_compile_error(self):
|
|---|
| 436 | st = parser.suite('1 = 3 + 4')
|
|---|
| 437 | self.assertRaises(SyntaxError, parser.compilest, st)
|
|---|
| 438 |
|
|---|
| 439 | def test_main():
|
|---|
| 440 | test_support.run_unittest(
|
|---|
| 441 | RoundtripLegalSyntaxTestCase,
|
|---|
| 442 | IllegalSyntaxTestCase,
|
|---|
| 443 | CompileTestCase,
|
|---|
| 444 | )
|
|---|
| 445 |
|
|---|
| 446 |
|
|---|
| 447 | if __name__ == "__main__":
|
|---|
| 448 | test_main()
|
|---|