1 """Tests for scripts in the Tools directory. 2 3 This file contains regression tests for some of the scripts found in the 4 Tools directory of a Python checkout or tarball, such as reindent.py. 5 """ 6 7 import os 8 import runpy 9 import sys 10 import unittest 11 import shutil 12 from cStringIO import StringIO 13 import subprocess 14 import sysconfig 15 import tempfile 16 import textwrap 17 from test import test_support 18 from test.script_helper import assert_python_ok, temp_dir 19 20 if not sysconfig.is_python_build(): 21 # XXX some installers do contain the tools, should we detect that 22 # and run the tests in that case too? 23 raise unittest.SkipTest('test irrelevant for an installed Python') 24 25 basepath = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 26 'Tools') 27 scriptsdir = os.path.join(basepath, 'scripts') 28 29 30 class ReindentTests(unittest.TestCase): 31 script = os.path.join(scriptsdir, 'reindent.py') 32 33 def test_noargs(self): 34 assert_python_ok(self.script) 35 36 def test_help(self): 37 rc, out, err = assert_python_ok(self.script, '-h') 38 self.assertEqual(out, b'') 39 self.assertGreater(err, b'') 40 41 42 class PindentTests(unittest.TestCase): 43 script = os.path.join(scriptsdir, 'pindent.py') 44 45 def assertFileEqual(self, fn1, fn2): 46 with open(fn1) as f1, open(fn2) as f2: 47 self.assertEqual(f1.readlines(), f2.readlines()) 48 49 def pindent(self, source, *args): 50 proc = subprocess.Popen( 51 (sys.executable, self.script) + args, 52 stdin=subprocess.PIPE, stdout=subprocess.PIPE, 53 universal_newlines=True) 54 out, err = proc.communicate(source) 55 self.assertIsNone(err) 56 return out 57 58 def lstriplines(self, data): 59 return '\n'.join(line.lstrip() for line in data.splitlines()) + '\n' 60 61 def test_selftest(self): 62 self.maxDiff = None 63 with temp_dir() as directory: 64 data_path = os.path.join(directory, '_test.py') 65 with open(self.script) as f: 66 closed = f.read() 67 with open(data_path, 'w') as f: 68 f.write(closed) 69 70 rc, out, err = assert_python_ok(self.script, '-d', data_path) 71 self.assertEqual(out, b'') 72 self.assertEqual(err, b'') 73 backup = data_path + '~' 74 self.assertTrue(os.path.exists(backup)) 75 with open(backup) as f: 76 self.assertEqual(f.read(), closed) 77 with open(data_path) as f: 78 clean = f.read() 79 compile(clean, '_test.py', 'exec') 80 self.assertEqual(self.pindent(clean, '-c'), closed) 81 self.assertEqual(self.pindent(closed, '-d'), clean) 82 83 rc, out, err = assert_python_ok(self.script, '-c', data_path) 84 self.assertEqual(out, b'') 85 self.assertEqual(err, b'') 86 with open(backup) as f: 87 self.assertEqual(f.read(), clean) 88 with open(data_path) as f: 89 self.assertEqual(f.read(), closed) 90 91 broken = self.lstriplines(closed) 92 with open(data_path, 'w') as f: 93 f.write(broken) 94 rc, out, err = assert_python_ok(self.script, '-r', data_path) 95 self.assertEqual(out, b'') 96 self.assertEqual(err, b'') 97 with open(backup) as f: 98 self.assertEqual(f.read(), broken) 99 with open(data_path) as f: 100 indented = f.read() 101 compile(indented, '_test.py', 'exec') 102 self.assertEqual(self.pindent(broken, '-r'), indented) 103 104 def pindent_test(self, clean, closed): 105 self.assertEqual(self.pindent(clean, '-c'), closed) 106 self.assertEqual(self.pindent(closed, '-d'), clean) 107 broken = self.lstriplines(closed) 108 self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '4'), closed) 109 110 def test_statements(self): 111 clean = textwrap.dedent("""\ 112 if a: 113 pass 114 115 if a: 116 pass 117 else: 118 pass 119 120 if a: 121 pass 122 elif: 123 pass 124 else: 125 pass 126 127 while a: 128 break 129 130 while a: 131 break 132 else: 133 pass 134 135 for i in a: 136 break 137 138 for i in a: 139 break 140 else: 141 pass 142 143 try: 144 pass 145 finally: 146 pass 147 148 try: 149 pass 150 except TypeError: 151 pass 152 except ValueError: 153 pass 154 else: 155 pass 156 157 try: 158 pass 159 except TypeError: 160 pass 161 except ValueError: 162 pass 163 finally: 164 pass 165 166 with a: 167 pass 168 169 class A: 170 pass 171 172 def f(): 173 pass 174 """) 175 176 closed = textwrap.dedent("""\ 177 if a: 178 pass 179 # end if 180 181 if a: 182 pass 183 else: 184 pass 185 # end if 186 187 if a: 188 pass 189 elif: 190 pass 191 else: 192 pass 193 # end if 194 195 while a: 196 break 197 # end while 198 199 while a: 200 break 201 else: 202 pass 203 # end while 204 205 for i in a: 206 break 207 # end for 208 209 for i in a: 210 break 211 else: 212 pass 213 # end for 214 215 try: 216 pass 217 finally: 218 pass 219 # end try 220 221 try: 222 pass 223 except TypeError: 224 pass 225 except ValueError: 226 pass 227 else: 228 pass 229 # end try 230 231 try: 232 pass 233 except TypeError: 234 pass 235 except ValueError: 236 pass 237 finally: 238 pass 239 # end try 240 241 with a: 242 pass 243 # end with 244 245 class A: 246 pass 247 # end class A 248 249 def f(): 250 pass 251 # end def f 252 """) 253 self.pindent_test(clean, closed) 254 255 def test_multilevel(self): 256 clean = textwrap.dedent("""\ 257 def foobar(a, b): 258 if a == b: 259 a = a+1 260 elif a < b: 261 b = b-1 262 if b > a: a = a-1 263 else: 264 print 'oops!' 265 """) 266 closed = textwrap.dedent("""\ 267 def foobar(a, b): 268 if a == b: 269 a = a+1 270 elif a < b: 271 b = b-1 272 if b > a: a = a-1 273 # end if 274 else: 275 print 'oops!' 276 # end if 277 # end def foobar 278 """) 279 self.pindent_test(clean, closed) 280 281 def test_preserve_indents(self): 282 clean = textwrap.dedent("""\ 283 if a: 284 if b: 285 pass 286 """) 287 closed = textwrap.dedent("""\ 288 if a: 289 if b: 290 pass 291 # end if 292 # end if 293 """) 294 self.assertEqual(self.pindent(clean, '-c'), closed) 295 self.assertEqual(self.pindent(closed, '-d'), clean) 296 broken = self.lstriplines(closed) 297 self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '9'), closed) 298 clean = textwrap.dedent("""\ 299 if a: 300 \tif b: 301 \t\tpass 302 """) 303 closed = textwrap.dedent("""\ 304 if a: 305 \tif b: 306 \t\tpass 307 \t# end if 308 # end if 309 """) 310 self.assertEqual(self.pindent(clean, '-c'), closed) 311 self.assertEqual(self.pindent(closed, '-d'), clean) 312 broken = self.lstriplines(closed) 313 self.assertEqual(self.pindent(broken, '-r'), closed) 314 315 def test_escaped_newline(self): 316 clean = textwrap.dedent("""\ 317 class\\ 318 \\ 319 A: 320 def\ 321 \\ 322 f: 323 pass 324 """) 325 closed = textwrap.dedent("""\ 326 class\\ 327 \\ 328 A: 329 def\ 330 \\ 331 f: 332 pass 333 # end def f 334 # end class A 335 """) 336 self.assertEqual(self.pindent(clean, '-c'), closed) 337 self.assertEqual(self.pindent(closed, '-d'), clean) 338 339 def test_empty_line(self): 340 clean = textwrap.dedent("""\ 341 if a: 342 343 pass 344 """) 345 closed = textwrap.dedent("""\ 346 if a: 347 348 pass 349 # end if 350 """) 351 self.pindent_test(clean, closed) 352 353 def test_oneline(self): 354 clean = textwrap.dedent("""\ 355 if a: pass 356 """) 357 closed = textwrap.dedent("""\ 358 if a: pass 359 # end if 360 """) 361 self.pindent_test(clean, closed) 362 363 364 class FixcidTests(unittest.TestCase): 365 def test_parse_strings(self): 366 old1 = 'int xx = "xx\\"xx"[xx];\n' 367 old2 = "int xx = 'x\\'xx' + xx;\n" 368 output = self.run_script(old1 + old2) 369 new1 = 'int yy = "xx\\"xx"[yy];\n' 370 new2 = "int yy = 'x\\'xx' + yy;\n" 371 self.assertMultiLineEqual(output, 372 "1\n" 373 "< {old1}" 374 "> {new1}" 375 "{new1}" 376 "2\n" 377 "< {old2}" 378 "> {new2}" 379 "{new2}".format(old1=old1, old2=old2, new1=new1, new2=new2) 380 ) 381 382 def test_alter_comments(self): 383 output = self.run_script( 384 substfile= 385 "xx yy\n" 386 "*aa bb\n", 387 args=("-c", "-",), 388 input= 389 "/* xx altered */\n" 390 "int xx;\n" 391 "/* aa unaltered */\n" 392 "int aa;\n", 393 ) 394 self.assertMultiLineEqual(output, 395 "1\n" 396 "< /* xx altered */\n" 397 "> /* yy altered */\n" 398 "/* yy altered */\n" 399 "2\n" 400 "< int xx;\n" 401 "> int yy;\n" 402 "int yy;\n" 403 "/* aa unaltered */\n" 404 "4\n" 405 "< int aa;\n" 406 "> int bb;\n" 407 "int bb;\n" 408 ) 409 410 def test_directory(self): 411 os.mkdir(test_support.TESTFN) 412 self.addCleanup(test_support.rmtree, test_support.TESTFN) 413 c_filename = os.path.join(test_support.TESTFN, "file.c") 414 with open(c_filename, "w") as file: 415 file.write("int xx;\n") 416 with open(os.path.join(test_support.TESTFN, "file.py"), "w") as file: 417 file.write("xx = 'unaltered'\n") 418 script = os.path.join(scriptsdir, "fixcid.py") 419 output = self.run_script(args=(test_support.TESTFN,)) 420 self.assertMultiLineEqual(output, 421 "{}:\n" 422 "1\n" 423 '< int xx;\n' 424 '> int yy;\n'.format(c_filename) 425 ) 426 427 def run_script(self, input="", args=("-",), substfile="xx yy\n"): 428 substfilename = test_support.TESTFN + ".subst" 429 with open(substfilename, "w") as file: 430 file.write(substfile) 431 self.addCleanup(test_support.unlink, substfilename) 432 433 argv = ["fixcid.py", "-s", substfilename] + list(args) 434 script = os.path.join(scriptsdir, "fixcid.py") 435 with test_support.swap_attr(sys, "argv", argv), \ 436 test_support.swap_attr(sys, "stdin", StringIO(input)), \ 437 test_support.captured_stdout() as output: 438 try: 439 runpy.run_path(script, run_name="__main__") 440 except SystemExit as exit: 441 self.assertEqual(exit.code, 0) 442 return output.getvalue() 443 444 445 def test_main(): 446 test_support.run_unittest(*[obj for obj in globals().values() 447 if isinstance(obj, type)]) 448 449 450 if __name__ == '__main__': 451 unittest.main() 452