blob: 9f67b49f3a6b2b35cec0c9335593a72671b9c3ad [file] [log] [blame]
Zachary Ware2b0a6102014-07-16 14:26:09 -05001"""Tests for the unparse.py script in the Tools/parser directory."""
2
Mark Dickinsonae100052010-06-28 19:44:20 +00003import unittest
4import test.support
Pablo Galindo27fc3b62019-11-24 23:02:40 +00005import pathlib
Mark Dickinsonbe4fb692012-06-23 09:27:47 +01006import random
Mark Dickinsond751c2e2010-06-29 14:08:23 +00007import tokenize
Mark Dickinsonbe4fb692012-06-23 09:27:47 +01008import ast
Mark Dickinsonae100052010-06-28 19:44:20 +00009
Zachary Ware2b0a6102014-07-16 14:26:09 -050010
Mark Dickinsond751c2e2010-06-29 14:08:23 +000011def read_pyfile(filename):
12 """Read and return the contents of a Python source file (as a
13 string), taking into account the file encoding."""
Hakan Çelik6a5bf152020-04-16 13:11:55 +030014 with tokenize.open(filename) as stream:
15 return stream.read()
Mark Dickinsond751c2e2010-06-29 14:08:23 +000016
Pablo Galindo27fc3b62019-11-24 23:02:40 +000017
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +000018for_else = """\
Mark Dickinsonae100052010-06-28 19:44:20 +000019def f():
20 for x in range(10):
21 break
22 else:
23 y = 2
24 z = 3
25"""
26
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +000027while_else = """\
Mark Dickinsonae100052010-06-28 19:44:20 +000028def g():
29 while True:
30 break
31 else:
32 y = 2
33 z = 3
34"""
35
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +000036relative_import = """\
37from . import fred
38from .. import barney
39from .australia import shrimp as prawns
40"""
41
42nonlocal_ex = """\
43def f():
44 x = 1
45 def g():
46 nonlocal x
47 x = 2
48 y = 7
49 def h():
50 nonlocal x, y
51"""
52
53# also acts as test for 'except ... as ...'
54raise_from = """\
55try:
56 1 / 0
57except ZeroDivisionError as e:
58 raise ArithmeticError from e
59"""
60
61class_decorator = """\
62@f1(arg)
63@f2
64class Foo: pass
65"""
66
Mark Dickinson8d6d7602010-06-30 08:32:11 +000067elif1 = """\
68if cond1:
69 suite1
70elif cond2:
71 suite2
72else:
73 suite3
74"""
75
76elif2 = """\
77if cond1:
78 suite1
79elif cond2:
80 suite2
81"""
82
Mark Dickinson81ad8cc2010-06-30 08:46:53 +000083try_except_finally = """\
84try:
85 suite1
86except ex1:
87 suite2
88except ex2:
89 suite3
90else:
91 suite4
92finally:
93 suite5
94"""
Mark Dickinson8d6d7602010-06-30 08:32:11 +000095
Mark Dickinsonfe8440a2012-05-06 17:35:19 +010096with_simple = """\
97with f():
98 suite1
99"""
100
101with_as = """\
102with f() as x:
103 suite1
104"""
105
106with_two_items = """\
107with f() as x, g() as y:
108 suite1
109"""
110
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300111docstring_prefixes = (
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300112 "",
Batuhan Taskaya25160cd2020-05-17 00:53:25 +0300113 "class foo:\n ",
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300114 "def foo():\n ",
115 "async def foo():\n ",
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300116)
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000117
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000118class ASTTestCase(unittest.TestCase):
119 def assertASTEqual(self, ast1, ast2):
120 self.assertEqual(ast.dump(ast1), ast.dump(ast2))
Mark Dickinsonae100052010-06-28 19:44:20 +0000121
Batuhan Taşkaya5b66ec12020-03-15 22:56:57 +0300122 def check_ast_roundtrip(self, code1, **kwargs):
Pablo Galindo6341fc72020-05-17 03:53:57 +0100123 with self.subTest(code1=code1, ast_parse_kwargs=kwargs):
124 ast1 = ast.parse(code1, **kwargs)
125 code2 = ast.unparse(ast1)
126 ast2 = ast.parse(code2, **kwargs)
127 self.assertASTEqual(ast1, ast2)
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000128
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000129 def check_invalid(self, node, raises=ValueError):
Pablo Galindo6341fc72020-05-17 03:53:57 +0100130 with self.subTest(node=node):
131 self.assertRaises(raises, ast.unparse, node)
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000132
Batuhan Taskaya493bf1c2020-05-03 20:11:51 +0300133 def get_source(self, code1, code2=None):
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300134 code2 = code2 or code1
135 code1 = ast.unparse(ast.parse(code1))
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300136 return code1, code2
137
Batuhan Taskaya493bf1c2020-05-03 20:11:51 +0300138 def check_src_roundtrip(self, code1, code2=None):
139 code1, code2 = self.get_source(code1, code2)
Pablo Galindo6341fc72020-05-17 03:53:57 +0100140 with self.subTest(code1=code1, code2=code2):
141 self.assertEqual(code2, code1)
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300142
Batuhan Taskaya493bf1c2020-05-03 20:11:51 +0300143 def check_src_dont_roundtrip(self, code1, code2=None):
144 code1, code2 = self.get_source(code1, code2)
Pablo Galindo6341fc72020-05-17 03:53:57 +0100145 with self.subTest(code1=code1, code2=code2):
146 self.assertNotEqual(code2, code1)
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000147
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000148class UnparseTestCase(ASTTestCase):
149 # Tests for specific bugs found in earlier versions of unparse
Mark Dickinsonae100052010-06-28 19:44:20 +0000150
Eric V. Smith608adf92015-09-20 15:09:15 -0400151 def test_fstrings(self):
152 # See issue 25180
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300153 self.check_ast_roundtrip(r"""f'{f"{0}"*3}'""")
154 self.check_ast_roundtrip(r"""f'{f"{y}"*3}'""")
Shantanua993e902020-11-20 13:16:42 -0800155 self.check_ast_roundtrip("""f''""")
156 self.check_ast_roundtrip('''f"""'end' "quote\\""""''')
157
158 def test_fstrings_complicated(self):
159 # See issue 28002
160 self.check_ast_roundtrip("""f'''{"'"}'''""")
161 self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
162 self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-'single quote\\'\'\'\'''')
163 self.check_ast_roundtrip('f"""{\'\'\'\n\'\'\'}"""')
164 self.check_ast_roundtrip('f"""{g(\'\'\'\n\'\'\')}"""')
165 self.check_ast_roundtrip('''f"a\\r\\nb"''')
166 self.check_ast_roundtrip('''f"\\u2028{'x'}"''')
Eric V. Smith608adf92015-09-20 15:09:15 -0400167
Chih-Hsuan Yenaaf47ca2019-05-27 01:08:20 +0800168 def test_strings(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300169 self.check_ast_roundtrip("u'foo'")
170 self.check_ast_roundtrip("r'foo'")
171 self.check_ast_roundtrip("b'foo'")
Chih-Hsuan Yenaaf47ca2019-05-27 01:08:20 +0800172
Mark Dickinsonae100052010-06-28 19:44:20 +0000173 def test_del_statement(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300174 self.check_ast_roundtrip("del x, y, z")
Mark Dickinsonae100052010-06-28 19:44:20 +0000175
176 def test_shifts(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300177 self.check_ast_roundtrip("45 << 2")
178 self.check_ast_roundtrip("13 >> 7")
Mark Dickinsonae100052010-06-28 19:44:20 +0000179
180 def test_for_else(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300181 self.check_ast_roundtrip(for_else)
Mark Dickinsonae100052010-06-28 19:44:20 +0000182
183 def test_while_else(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300184 self.check_ast_roundtrip(while_else)
Mark Dickinsonae100052010-06-28 19:44:20 +0000185
186 def test_unary_parens(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300187 self.check_ast_roundtrip("(-1)**7")
188 self.check_ast_roundtrip("(-1.)**8")
189 self.check_ast_roundtrip("(-1j)**6")
190 self.check_ast_roundtrip("not True or False")
191 self.check_ast_roundtrip("True or not False")
Mark Dickinsonae100052010-06-28 19:44:20 +0000192
Mark Dickinson3eb02902010-06-29 08:52:36 +0000193 def test_integer_parens(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300194 self.check_ast_roundtrip("3 .__abs__()")
Mark Dickinson3eb02902010-06-29 08:52:36 +0000195
Mark Dickinson8042e282010-06-29 10:01:48 +0000196 def test_huge_float(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300197 self.check_ast_roundtrip("1e1000")
198 self.check_ast_roundtrip("-1e1000")
199 self.check_ast_roundtrip("1e1000j")
200 self.check_ast_roundtrip("-1e1000j")
Mark Dickinsoncba8c102010-06-30 11:45:53 +0000201
Kodi Arfer08ff4362021-03-18 13:36:06 -0400202 def test_nan(self):
203 self.assertASTEqual(
204 ast.parse(ast.unparse(ast.Constant(value=float('nan')))),
205 ast.parse('1e1000 - 1e1000')
206 )
207
Mark Dickinsoncba8c102010-06-30 11:45:53 +0000208 def test_min_int(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300209 self.check_ast_roundtrip(str(-(2 ** 31)))
210 self.check_ast_roundtrip(str(-(2 ** 63)))
Mark Dickinsoncba8c102010-06-30 11:45:53 +0000211
212 def test_imaginary_literals(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300213 self.check_ast_roundtrip("7j")
214 self.check_ast_roundtrip("-7j")
215 self.check_ast_roundtrip("0j")
216 self.check_ast_roundtrip("-0j")
Mark Dickinson8042e282010-06-29 10:01:48 +0000217
218 def test_lambda_parentheses(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300219 self.check_ast_roundtrip("(lambda: int)()")
Mark Dickinson8042e282010-06-29 10:01:48 +0000220
Mark Dickinsonf5451e52010-06-28 20:09:18 +0000221 def test_chained_comparisons(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300222 self.check_ast_roundtrip("1 < 4 <= 5")
223 self.check_ast_roundtrip("a is b is c is not d")
Mark Dickinsonf5451e52010-06-28 20:09:18 +0000224
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000225 def test_function_arguments(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300226 self.check_ast_roundtrip("def f(): pass")
227 self.check_ast_roundtrip("def f(a): pass")
228 self.check_ast_roundtrip("def f(b = 2): pass")
229 self.check_ast_roundtrip("def f(a, b): pass")
230 self.check_ast_roundtrip("def f(a, b = 2): pass")
231 self.check_ast_roundtrip("def f(a = 5, b = 2): pass")
232 self.check_ast_roundtrip("def f(*, a = 1, b = 2): pass")
233 self.check_ast_roundtrip("def f(*, a = 1, b): pass")
234 self.check_ast_roundtrip("def f(*, a, b = 2): pass")
235 self.check_ast_roundtrip("def f(a, b = None, *, c, **kwds): pass")
236 self.check_ast_roundtrip("def f(a=2, *args, c=5, d, **kwds): pass")
237 self.check_ast_roundtrip("def f(*args, **kwargs): pass")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000238
239 def test_relative_import(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300240 self.check_ast_roundtrip(relative_import)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000241
242 def test_nonlocal(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300243 self.check_ast_roundtrip(nonlocal_ex)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000244
245 def test_raise_from(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300246 self.check_ast_roundtrip(raise_from)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000247
248 def test_bytes(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300249 self.check_ast_roundtrip("b'123'")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000250
251 def test_annotations(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300252 self.check_ast_roundtrip("def f(a : int): pass")
253 self.check_ast_roundtrip("def f(a: int = 5): pass")
254 self.check_ast_roundtrip("def f(*args: [int]): pass")
255 self.check_ast_roundtrip("def f(**kwargs: dict): pass")
256 self.check_ast_roundtrip("def f() -> None: pass")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000257
258 def test_set_literal(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300259 self.check_ast_roundtrip("{'a', 'b', 'c'}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000260
Kodi Arfer08ff4362021-03-18 13:36:06 -0400261 def test_empty_set(self):
262 self.assertASTEqual(
263 ast.parse(ast.unparse(ast.Set(elts=[]))),
264 ast.parse('{*()}')
265 )
266
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000267 def test_set_comprehension(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300268 self.check_ast_roundtrip("{x for x in range(5)}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000269
270 def test_dict_comprehension(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300271 self.check_ast_roundtrip("{x: x*x for x in range(10)}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000272
273 def test_class_decorators(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300274 self.check_ast_roundtrip(class_decorator)
Mark Dickinsonae100052010-06-28 19:44:20 +0000275
Mark Dickinson578aa562010-06-29 18:38:59 +0000276 def test_class_definition(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300277 self.check_ast_roundtrip("class A(metaclass=type, *[], **{}): pass")
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000278
Mark Dickinson8d6d7602010-06-30 08:32:11 +0000279 def test_elifs(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300280 self.check_ast_roundtrip(elif1)
281 self.check_ast_roundtrip(elif2)
Mark Dickinson8d6d7602010-06-30 08:32:11 +0000282
Mark Dickinson81ad8cc2010-06-30 08:46:53 +0000283 def test_try_except_finally(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300284 self.check_ast_roundtrip(try_except_finally)
Mark Dickinson81ad8cc2010-06-30 08:46:53 +0000285
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100286 def test_starred_assignment(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300287 self.check_ast_roundtrip("a, *b, c = seq")
288 self.check_ast_roundtrip("a, (*b, c) = seq")
289 self.check_ast_roundtrip("a, *b[0], c = seq")
290 self.check_ast_roundtrip("a, *(b, c) = seq")
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100291
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100292 def test_with_simple(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300293 self.check_ast_roundtrip(with_simple)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100294
295 def test_with_as(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300296 self.check_ast_roundtrip(with_as)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100297
298 def test_with_two_items(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300299 self.check_ast_roundtrip(with_two_items)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100300
Berker Peksagd66dd5c2016-03-06 16:50:15 +0200301 def test_dict_unpacking_in_dict(self):
302 # See issue 26489
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300303 self.check_ast_roundtrip(r"""{**{'y': 2}, 'x': 1}""")
304 self.check_ast_roundtrip(r"""{**{'y': 2}, **{'x': 1}}""")
Berker Peksagd66dd5c2016-03-06 16:50:15 +0200305
Batuhan Taskayac102a142020-05-18 23:48:49 +0300306 def test_slices(self):
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300307 self.check_ast_roundtrip("a[i]")
308 self.check_ast_roundtrip("a[i,]")
309 self.check_ast_roundtrip("a[i, j]")
Batuhan Taskayac102a142020-05-18 23:48:49 +0300310 self.check_ast_roundtrip("a[(*a,)]")
311 self.check_ast_roundtrip("a[(a:=b)]")
312 self.check_ast_roundtrip("a[(a:=b,c)]")
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300313 self.check_ast_roundtrip("a[()]")
314 self.check_ast_roundtrip("a[i:j]")
315 self.check_ast_roundtrip("a[:j]")
316 self.check_ast_roundtrip("a[i:]")
317 self.check_ast_roundtrip("a[i:j:k]")
318 self.check_ast_roundtrip("a[:j:k]")
319 self.check_ast_roundtrip("a[i::k]")
320 self.check_ast_roundtrip("a[i:j,]")
321 self.check_ast_roundtrip("a[i:j, k]")
322
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000323 def test_invalid_raise(self):
324 self.check_invalid(ast.Raise(exc=None, cause=ast.Name(id="X")))
325
326 def test_invalid_fstring_constant(self):
327 self.check_invalid(ast.JoinedStr(values=[ast.Constant(value=100)]))
328
329 def test_invalid_fstring_conversion(self):
330 self.check_invalid(
331 ast.FormattedValue(
332 value=ast.Constant(value="a", kind=None),
333 conversion=ord("Y"), # random character
334 format_spec=None,
335 )
336 )
337
Shantanua993e902020-11-20 13:16:42 -0800338 def test_invalid_fstring_backslash(self):
339 self.check_invalid(ast.FormattedValue(value=ast.Constant(value="\\\\")))
340
Batuhan Taşkaya7b35bef2020-01-02 21:20:04 +0300341 def test_invalid_yield_from(self):
342 self.check_invalid(ast.YieldFrom(value=None))
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100343
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300344 def test_docstrings(self):
345 docstrings = (
346 'this ends with double quote"',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300347 'this includes a """triple quote"""',
348 '\r',
349 '\\r',
350 '\t',
351 '\\t',
352 '\n',
353 '\\n',
CyberSaxosTiGERd71a6492020-05-18 21:41:35 +0300354 '\r\\r\t\\t\n\\n',
355 '""">>> content = \"\"\"blabla\"\"\" <<<"""',
356 r'foo\n\x00',
Shantanua993e902020-11-20 13:16:42 -0800357 "' \\'\\'\\'\"\"\" \"\"\\'\\' \\'",
358 '🐍⛎𩸽üéş^\\\\X\\\\BB\N{LONG RIGHTWARDS SQUIGGLE ARROW}'
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300359 )
360 for docstring in docstrings:
361 # check as Module docstrings for easy testing
Batuhan Taskayae966af72020-05-17 01:49:07 +0300362 self.check_ast_roundtrip(f"'''{docstring}'''")
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300363
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300364 def test_constant_tuples(self):
365 self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
366 self.check_src_roundtrip(
367 ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
368 )
369
Batuhan Taşkaya5b66ec12020-03-15 22:56:57 +0300370 def test_function_type(self):
371 for function_type in (
372 "() -> int",
373 "(int, int) -> int",
374 "(Callable[complex], More[Complex(call.to_typevar())]) -> None"
375 ):
376 self.check_ast_roundtrip(function_type, mode="func_type")
377
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300378 def test_type_comments(self):
379 for statement in (
380 "a = 5 # type:",
381 "a = 5 # type: int",
382 "a = 5 # type: int and more",
383 "def x(): # type: () -> None\n\tpass",
384 "def x(y): # type: (int) -> None and more\n\tpass",
385 "async def x(): # type: () -> None\n\tpass",
386 "async def x(y): # type: (int) -> None and more\n\tpass",
387 "for x in y: # type: int\n\tpass",
388 "async for x in y: # type: int\n\tpass",
389 "with x(): # type: int\n\tpass",
390 "async with x(): # type: int\n\tpass"
391 ):
392 self.check_ast_roundtrip(statement, type_comments=True)
393
394 def test_type_ignore(self):
395 for statement in (
396 "a = 5 # type: ignore",
397 "a = 5 # type: ignore and more",
398 "def x(): # type: ignore\n\tpass",
399 "def x(y): # type: ignore and more\n\tpass",
400 "async def x(): # type: ignore\n\tpass",
401 "async def x(y): # type: ignore and more\n\tpass",
402 "for x in y: # type: ignore\n\tpass",
403 "async for x in y: # type: ignore\n\tpass",
404 "with x(): # type: ignore\n\tpass",
405 "async with x(): # type: ignore\n\tpass"
406 ):
407 self.check_ast_roundtrip(statement, type_comments=True)
408
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300409
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300410class CosmeticTestCase(ASTTestCase):
411 """Test if there are cosmetic issues caused by unnecesary additions"""
412
413 def test_simple_expressions_parens(self):
414 self.check_src_roundtrip("(a := b)")
415 self.check_src_roundtrip("await x")
416 self.check_src_roundtrip("x if x else y")
417 self.check_src_roundtrip("lambda x: x")
418 self.check_src_roundtrip("1 + 1")
419 self.check_src_roundtrip("1 + 2 / 3")
420 self.check_src_roundtrip("(1 + 2) / 3")
421 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2)")
422 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2) ** 2")
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300423 self.check_src_roundtrip("~x")
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300424 self.check_src_roundtrip("x and y")
425 self.check_src_roundtrip("x and y and z")
426 self.check_src_roundtrip("x and (y and x)")
427 self.check_src_roundtrip("(x and y) and z")
428 self.check_src_roundtrip("(x ** y) ** z ** q")
429 self.check_src_roundtrip("x >> y")
430 self.check_src_roundtrip("x << y")
431 self.check_src_roundtrip("x >> y and x >> z")
432 self.check_src_roundtrip("x + y - z * q ^ t ** k")
433 self.check_src_roundtrip("P * V if P and V else n * R * T")
434 self.check_src_roundtrip("lambda P, V, n: P * V == n * R * T")
435 self.check_src_roundtrip("flag & (other | foo)")
436 self.check_src_roundtrip("not x == y")
437 self.check_src_roundtrip("x == (not y)")
438 self.check_src_roundtrip("yield x")
439 self.check_src_roundtrip("yield from x")
440 self.check_src_roundtrip("call((yield x))")
441 self.check_src_roundtrip("return x + (yield x)")
442
Batuhan Taskaya25160cd2020-05-17 00:53:25 +0300443 def test_class_bases_and_keywords(self):
444 self.check_src_roundtrip("class X:\n pass")
445 self.check_src_roundtrip("class X(A):\n pass")
446 self.check_src_roundtrip("class X(A, B, C, D):\n pass")
447 self.check_src_roundtrip("class X(x=y):\n pass")
448 self.check_src_roundtrip("class X(metaclass=z):\n pass")
449 self.check_src_roundtrip("class X(x=y, z=d):\n pass")
450 self.check_src_roundtrip("class X(A, x=y):\n pass")
451 self.check_src_roundtrip("class X(A, **kw):\n pass")
452 self.check_src_roundtrip("class X(*args):\n pass")
453 self.check_src_roundtrip("class X(*args, **kwargs):\n pass")
454
Shantanua993e902020-11-20 13:16:42 -0800455 def test_fstrings(self):
456 self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
457 self.check_src_roundtrip('''f"\\u2028{'x'}"''')
458 self.check_src_roundtrip(r"f'{x}\n'")
459 self.check_src_roundtrip('''f''\'{"""\n"""}\\n''\'''')
460 self.check_src_roundtrip('''f''\'{f"""{x}\n"""}\\n''\'''')
461
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300462 def test_docstrings(self):
463 docstrings = (
464 '"""simple doc string"""',
465 '''"""A more complex one
466 with some newlines"""''',
467 '''"""Foo bar baz
468
469 empty newline"""''',
470 '"""With some \t"""',
471 '"""Foo "bar" baz """',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300472 '"""\\r"""',
473 '""""""',
474 '"""\'\'\'"""',
475 '"""\'\'\'\'\'\'"""',
Shantanua993e902020-11-20 13:16:42 -0800476 '"""🐍⛎𩸽üéş^\\\\X\\\\BB⟿"""',
477 '"""end in single \'quote\'"""',
478 "'''end in double \"quote\"'''",
479 '"""almost end in double "quote"."""',
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300480 )
481
482 for prefix in docstring_prefixes:
483 for docstring in docstrings:
484 self.check_src_roundtrip(f"{prefix}{docstring}")
485
486 def test_docstrings_negative_cases(self):
487 # Test some cases that involve strings in the children of the
488 # first node but aren't docstrings to make sure we don't have
489 # False positives.
490 docstrings_negative = (
491 'a = """false"""',
492 '"""false""" + """unless its optimized"""',
493 '1 + 1\n"""false"""',
494 'f"""no, top level but f-fstring"""'
495 )
496 for prefix in docstring_prefixes:
497 for negative in docstrings_negative:
498 # this cases should be result with single quote
499 # rather then triple quoted docstring
500 src = f"{prefix}{negative}"
501 self.check_ast_roundtrip(src)
502 self.check_src_dont_roundtrip(src)
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300503
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300504 def test_unary_op_factor(self):
505 for prefix in ("+", "-", "~"):
506 self.check_src_roundtrip(f"{prefix}1")
507 for prefix in ("not",):
508 self.check_src_roundtrip(f"{prefix} 1")
509
Batuhan Taskayac102a142020-05-18 23:48:49 +0300510 def test_slices(self):
511 self.check_src_roundtrip("a[1]")
512 self.check_src_roundtrip("a[1, 2]")
513 self.check_src_roundtrip("a[(1, *a)]")
514
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000515class DirectoryTestCase(ASTTestCase):
516 """Test roundtrip behaviour on all files in Lib and Lib/test."""
517
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000518 lib_dir = pathlib.Path(__file__).parent / ".."
519 test_directories = (lib_dir, lib_dir / "test")
Pablo Galindo23a226b2019-12-29 19:20:55 +0000520 run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
Nick Coghlan1e7b8582021-04-29 15:58:44 +1000521 "test_ast.py", "test_asdl_parser.py", "test_fstring.py",
522 "test_patma.py"}
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000523
Pablo Galindoac229112019-12-09 17:57:50 +0000524 _files_to_test = None
525
526 @classmethod
527 def files_to_test(cls):
528
529 if cls._files_to_test is not None:
530 return cls._files_to_test
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000531
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000532 items = [
533 item.resolve()
Pablo Galindoac229112019-12-09 17:57:50 +0000534 for directory in cls.test_directories
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000535 for item in directory.glob("*.py")
536 if not item.name.startswith("bad")
537 ]
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000538
Mark Dickinsonbe4fb692012-06-23 09:27:47 +0100539 # Test limited subset of files unless the 'cpu' resource is specified.
540 if not test.support.is_resource_enabled("cpu"):
Pablo Galindobe287c32019-12-29 20:18:36 +0000541
542 tests_to_run_always = {item for item in items if
543 item.name in cls.run_always_files}
544
Pablo Galindo23a226b2019-12-29 19:20:55 +0000545 items = set(random.sample(items, 10))
546
Pablo Galindobe287c32019-12-29 20:18:36 +0000547 # Make sure that at least tests that heavily use grammar features are
548 # always considered in order to reduce the chance of missing something.
549 items = list(items | tests_to_run_always)
Pablo Galindoac229112019-12-09 17:57:50 +0000550
551 # bpo-31174: Store the names sample to always test the same files.
552 # It prevents false alarms when hunting reference leaks.
553 cls._files_to_test = items
554
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000555 return items
Victor Stinner8e482be2017-10-24 03:33:36 -0700556
557 def test_files(self):
Pablo Galindoac229112019-12-09 17:57:50 +0000558 for item in self.files_to_test():
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000559 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000560 print(f"Testing {item.absolute()}")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400561
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000562 with self.subTest(filename=item):
563 source = read_pyfile(item)
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300564 self.check_ast_roundtrip(source)
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000565
566
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000567if __name__ == "__main__":
Zachary Ware2b0a6102014-07-16 14:26:09 -0500568 unittest.main()