17db96d56Sopenharmony_ci""" 27db96d56Sopenharmony_ciUnit tests for refactor.py. 37db96d56Sopenharmony_ci""" 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ciimport sys 67db96d56Sopenharmony_ciimport os 77db96d56Sopenharmony_ciimport codecs 87db96d56Sopenharmony_ciimport io 97db96d56Sopenharmony_ciimport re 107db96d56Sopenharmony_ciimport tempfile 117db96d56Sopenharmony_ciimport shutil 127db96d56Sopenharmony_ciimport unittest 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_cifrom lib2to3 import refactor, pygram, fixer_base 157db96d56Sopenharmony_cifrom lib2to3.pgen2 import token 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ciTEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") 197db96d56Sopenharmony_ciFIXER_DIR = os.path.join(TEST_DATA_DIR, "fixers") 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_cisys.path.append(FIXER_DIR) 227db96d56Sopenharmony_citry: 237db96d56Sopenharmony_ci _DEFAULT_FIXERS = refactor.get_fixers_from_package("myfixes") 247db96d56Sopenharmony_cifinally: 257db96d56Sopenharmony_ci sys.path.pop() 267db96d56Sopenharmony_ci 277db96d56Sopenharmony_ci_2TO3_FIXERS = refactor.get_fixers_from_package("lib2to3.fixes") 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ciclass TestRefactoringTool(unittest.TestCase): 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci def setUp(self): 327db96d56Sopenharmony_ci sys.path.append(FIXER_DIR) 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci def tearDown(self): 357db96d56Sopenharmony_ci sys.path.pop() 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci def check_instances(self, instances, classes): 387db96d56Sopenharmony_ci for inst, cls in zip(instances, classes): 397db96d56Sopenharmony_ci if not isinstance(inst, cls): 407db96d56Sopenharmony_ci self.fail("%s are not instances of %s" % instances, classes) 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci def rt(self, options=None, fixers=_DEFAULT_FIXERS, explicit=None): 437db96d56Sopenharmony_ci return refactor.RefactoringTool(fixers, options, explicit) 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ci def test_print_function_option(self): 467db96d56Sopenharmony_ci rt = self.rt({"print_function" : True}) 477db96d56Sopenharmony_ci self.assertNotIn("print", rt.grammar.keywords) 487db96d56Sopenharmony_ci self.assertNotIn("print", rt.driver.grammar.keywords) 497db96d56Sopenharmony_ci 507db96d56Sopenharmony_ci def test_exec_function_option(self): 517db96d56Sopenharmony_ci rt = self.rt({"exec_function" : True}) 527db96d56Sopenharmony_ci self.assertNotIn("exec", rt.grammar.keywords) 537db96d56Sopenharmony_ci self.assertNotIn("exec", rt.driver.grammar.keywords) 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci def test_write_unchanged_files_option(self): 567db96d56Sopenharmony_ci rt = self.rt() 577db96d56Sopenharmony_ci self.assertFalse(rt.write_unchanged_files) 587db96d56Sopenharmony_ci rt = self.rt({"write_unchanged_files" : True}) 597db96d56Sopenharmony_ci self.assertTrue(rt.write_unchanged_files) 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci def test_fixer_loading_helpers(self): 627db96d56Sopenharmony_ci contents = ["explicit", "first", "last", "parrot", "preorder"] 637db96d56Sopenharmony_ci non_prefixed = refactor.get_all_fix_names("myfixes") 647db96d56Sopenharmony_ci prefixed = refactor.get_all_fix_names("myfixes", False) 657db96d56Sopenharmony_ci full_names = refactor.get_fixers_from_package("myfixes") 667db96d56Sopenharmony_ci self.assertEqual(prefixed, ["fix_" + name for name in contents]) 677db96d56Sopenharmony_ci self.assertEqual(non_prefixed, contents) 687db96d56Sopenharmony_ci self.assertEqual(full_names, 697db96d56Sopenharmony_ci ["myfixes.fix_" + name for name in contents]) 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci def test_detect_future_features(self): 727db96d56Sopenharmony_ci run = refactor._detect_future_features 737db96d56Sopenharmony_ci fs = frozenset 747db96d56Sopenharmony_ci empty = fs() 757db96d56Sopenharmony_ci self.assertEqual(run(""), empty) 767db96d56Sopenharmony_ci self.assertEqual(run("from __future__ import print_function"), 777db96d56Sopenharmony_ci fs(("print_function",))) 787db96d56Sopenharmony_ci self.assertEqual(run("from __future__ import generators"), 797db96d56Sopenharmony_ci fs(("generators",))) 807db96d56Sopenharmony_ci self.assertEqual(run("from __future__ import generators, feature"), 817db96d56Sopenharmony_ci fs(("generators", "feature"))) 827db96d56Sopenharmony_ci inp = "from __future__ import generators, print_function" 837db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("generators", "print_function"))) 847db96d56Sopenharmony_ci inp ="from __future__ import print_function, generators" 857db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("print_function", "generators"))) 867db96d56Sopenharmony_ci inp = "from __future__ import (print_function,)" 877db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("print_function",))) 887db96d56Sopenharmony_ci inp = "from __future__ import (generators, print_function)" 897db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("generators", "print_function"))) 907db96d56Sopenharmony_ci inp = "from __future__ import (generators, nested_scopes)" 917db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("generators", "nested_scopes"))) 927db96d56Sopenharmony_ci inp = """from __future__ import generators 937db96d56Sopenharmony_cifrom __future__ import print_function""" 947db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("generators", "print_function"))) 957db96d56Sopenharmony_ci invalid = ("from", 967db96d56Sopenharmony_ci "from 4", 977db96d56Sopenharmony_ci "from x", 987db96d56Sopenharmony_ci "from x 5", 997db96d56Sopenharmony_ci "from x im", 1007db96d56Sopenharmony_ci "from x import", 1017db96d56Sopenharmony_ci "from x import 4", 1027db96d56Sopenharmony_ci ) 1037db96d56Sopenharmony_ci for inp in invalid: 1047db96d56Sopenharmony_ci self.assertEqual(run(inp), empty) 1057db96d56Sopenharmony_ci inp = "'docstring'\nfrom __future__ import print_function" 1067db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("print_function",))) 1077db96d56Sopenharmony_ci inp = "'docstring'\n'somng'\nfrom __future__ import print_function" 1087db96d56Sopenharmony_ci self.assertEqual(run(inp), empty) 1097db96d56Sopenharmony_ci inp = "# comment\nfrom __future__ import print_function" 1107db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("print_function",))) 1117db96d56Sopenharmony_ci inp = "# comment\n'doc'\nfrom __future__ import print_function" 1127db96d56Sopenharmony_ci self.assertEqual(run(inp), fs(("print_function",))) 1137db96d56Sopenharmony_ci inp = "class x: pass\nfrom __future__ import print_function" 1147db96d56Sopenharmony_ci self.assertEqual(run(inp), empty) 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci def test_get_headnode_dict(self): 1177db96d56Sopenharmony_ci class NoneFix(fixer_base.BaseFix): 1187db96d56Sopenharmony_ci pass 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ci class FileInputFix(fixer_base.BaseFix): 1217db96d56Sopenharmony_ci PATTERN = "file_input< any * >" 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci class SimpleFix(fixer_base.BaseFix): 1247db96d56Sopenharmony_ci PATTERN = "'name'" 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci no_head = NoneFix({}, []) 1277db96d56Sopenharmony_ci with_head = FileInputFix({}, []) 1287db96d56Sopenharmony_ci simple = SimpleFix({}, []) 1297db96d56Sopenharmony_ci d = refactor._get_headnode_dict([no_head, with_head, simple]) 1307db96d56Sopenharmony_ci top_fixes = d.pop(pygram.python_symbols.file_input) 1317db96d56Sopenharmony_ci self.assertEqual(top_fixes, [with_head, no_head]) 1327db96d56Sopenharmony_ci name_fixes = d.pop(token.NAME) 1337db96d56Sopenharmony_ci self.assertEqual(name_fixes, [simple, no_head]) 1347db96d56Sopenharmony_ci for fixes in d.values(): 1357db96d56Sopenharmony_ci self.assertEqual(fixes, [no_head]) 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci def test_fixer_loading(self): 1387db96d56Sopenharmony_ci from myfixes.fix_first import FixFirst 1397db96d56Sopenharmony_ci from myfixes.fix_last import FixLast 1407db96d56Sopenharmony_ci from myfixes.fix_parrot import FixParrot 1417db96d56Sopenharmony_ci from myfixes.fix_preorder import FixPreorder 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci rt = self.rt() 1447db96d56Sopenharmony_ci pre, post = rt.get_fixers() 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci self.check_instances(pre, [FixPreorder]) 1477db96d56Sopenharmony_ci self.check_instances(post, [FixFirst, FixParrot, FixLast]) 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci def test_naughty_fixers(self): 1507db96d56Sopenharmony_ci self.assertRaises(ImportError, self.rt, fixers=["not_here"]) 1517db96d56Sopenharmony_ci self.assertRaises(refactor.FixerError, self.rt, fixers=["no_fixer_cls"]) 1527db96d56Sopenharmony_ci self.assertRaises(refactor.FixerError, self.rt, fixers=["bad_order"]) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci def test_refactor_string(self): 1557db96d56Sopenharmony_ci rt = self.rt() 1567db96d56Sopenharmony_ci input = "def parrot(): pass\n\n" 1577db96d56Sopenharmony_ci tree = rt.refactor_string(input, "<test>") 1587db96d56Sopenharmony_ci self.assertNotEqual(str(tree), input) 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci input = "def f(): pass\n\n" 1617db96d56Sopenharmony_ci tree = rt.refactor_string(input, "<test>") 1627db96d56Sopenharmony_ci self.assertEqual(str(tree), input) 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci def test_refactor_stdin(self): 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci class MyRT(refactor.RefactoringTool): 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci def print_output(self, old_text, new_text, filename, equal): 1697db96d56Sopenharmony_ci results.extend([old_text, new_text, filename, equal]) 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci results = [] 1727db96d56Sopenharmony_ci rt = MyRT(_DEFAULT_FIXERS) 1737db96d56Sopenharmony_ci save = sys.stdin 1747db96d56Sopenharmony_ci sys.stdin = io.StringIO("def parrot(): pass\n\n") 1757db96d56Sopenharmony_ci try: 1767db96d56Sopenharmony_ci rt.refactor_stdin() 1777db96d56Sopenharmony_ci finally: 1787db96d56Sopenharmony_ci sys.stdin = save 1797db96d56Sopenharmony_ci expected = ["def parrot(): pass\n\n", 1807db96d56Sopenharmony_ci "def cheese(): pass\n\n", 1817db96d56Sopenharmony_ci "<stdin>", False] 1827db96d56Sopenharmony_ci self.assertEqual(results, expected) 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ci def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS, 1857db96d56Sopenharmony_ci options=None, mock_log_debug=None, 1867db96d56Sopenharmony_ci actually_write=True): 1877db96d56Sopenharmony_ci test_file = self.init_test_file(test_file) 1887db96d56Sopenharmony_ci old_contents = self.read_file(test_file) 1897db96d56Sopenharmony_ci rt = self.rt(fixers=fixers, options=options) 1907db96d56Sopenharmony_ci if mock_log_debug: 1917db96d56Sopenharmony_ci rt.log_debug = mock_log_debug 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ci rt.refactor_file(test_file) 1947db96d56Sopenharmony_ci self.assertEqual(old_contents, self.read_file(test_file)) 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci if not actually_write: 1977db96d56Sopenharmony_ci return 1987db96d56Sopenharmony_ci rt.refactor_file(test_file, True) 1997db96d56Sopenharmony_ci new_contents = self.read_file(test_file) 2007db96d56Sopenharmony_ci self.assertNotEqual(old_contents, new_contents) 2017db96d56Sopenharmony_ci return new_contents 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci def init_test_file(self, test_file): 2047db96d56Sopenharmony_ci tmpdir = tempfile.mkdtemp(prefix="2to3-test_refactor") 2057db96d56Sopenharmony_ci self.addCleanup(shutil.rmtree, tmpdir) 2067db96d56Sopenharmony_ci shutil.copy(test_file, tmpdir) 2077db96d56Sopenharmony_ci test_file = os.path.join(tmpdir, os.path.basename(test_file)) 2087db96d56Sopenharmony_ci os.chmod(test_file, 0o644) 2097db96d56Sopenharmony_ci return test_file 2107db96d56Sopenharmony_ci 2117db96d56Sopenharmony_ci def read_file(self, test_file): 2127db96d56Sopenharmony_ci with open(test_file, "rb") as fp: 2137db96d56Sopenharmony_ci return fp.read() 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci def refactor_file(self, test_file, fixers=_2TO3_FIXERS): 2167db96d56Sopenharmony_ci test_file = self.init_test_file(test_file) 2177db96d56Sopenharmony_ci old_contents = self.read_file(test_file) 2187db96d56Sopenharmony_ci rt = self.rt(fixers=fixers) 2197db96d56Sopenharmony_ci rt.refactor_file(test_file, True) 2207db96d56Sopenharmony_ci new_contents = self.read_file(test_file) 2217db96d56Sopenharmony_ci return old_contents, new_contents 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci def test_refactor_file(self): 2247db96d56Sopenharmony_ci test_file = os.path.join(FIXER_DIR, "parrot_example.py") 2257db96d56Sopenharmony_ci self.check_file_refactoring(test_file, _DEFAULT_FIXERS) 2267db96d56Sopenharmony_ci 2277db96d56Sopenharmony_ci def test_refactor_file_write_unchanged_file(self): 2287db96d56Sopenharmony_ci test_file = os.path.join(FIXER_DIR, "parrot_example.py") 2297db96d56Sopenharmony_ci debug_messages = [] 2307db96d56Sopenharmony_ci def recording_log_debug(msg, *args): 2317db96d56Sopenharmony_ci debug_messages.append(msg % args) 2327db96d56Sopenharmony_ci self.check_file_refactoring(test_file, fixers=(), 2337db96d56Sopenharmony_ci options={"write_unchanged_files": True}, 2347db96d56Sopenharmony_ci mock_log_debug=recording_log_debug, 2357db96d56Sopenharmony_ci actually_write=False) 2367db96d56Sopenharmony_ci # Testing that it logged this message when write=False was passed is 2377db96d56Sopenharmony_ci # sufficient to see that it did not bail early after "No changes". 2387db96d56Sopenharmony_ci message_regex = r"Not writing changes to .*%s" % \ 2397db96d56Sopenharmony_ci re.escape(os.sep + os.path.basename(test_file)) 2407db96d56Sopenharmony_ci for message in debug_messages: 2417db96d56Sopenharmony_ci if "Not writing changes" in message: 2427db96d56Sopenharmony_ci self.assertRegex(message, message_regex) 2437db96d56Sopenharmony_ci break 2447db96d56Sopenharmony_ci else: 2457db96d56Sopenharmony_ci self.fail("%r not matched in %r" % (message_regex, debug_messages)) 2467db96d56Sopenharmony_ci 2477db96d56Sopenharmony_ci def test_refactor_dir(self): 2487db96d56Sopenharmony_ci def check(structure, expected): 2497db96d56Sopenharmony_ci def mock_refactor_file(self, f, *args): 2507db96d56Sopenharmony_ci got.append(f) 2517db96d56Sopenharmony_ci save_func = refactor.RefactoringTool.refactor_file 2527db96d56Sopenharmony_ci refactor.RefactoringTool.refactor_file = mock_refactor_file 2537db96d56Sopenharmony_ci rt = self.rt() 2547db96d56Sopenharmony_ci got = [] 2557db96d56Sopenharmony_ci dir = tempfile.mkdtemp(prefix="2to3-test_refactor") 2567db96d56Sopenharmony_ci try: 2577db96d56Sopenharmony_ci os.mkdir(os.path.join(dir, "a_dir")) 2587db96d56Sopenharmony_ci for fn in structure: 2597db96d56Sopenharmony_ci open(os.path.join(dir, fn), "wb").close() 2607db96d56Sopenharmony_ci rt.refactor_dir(dir) 2617db96d56Sopenharmony_ci finally: 2627db96d56Sopenharmony_ci refactor.RefactoringTool.refactor_file = save_func 2637db96d56Sopenharmony_ci shutil.rmtree(dir) 2647db96d56Sopenharmony_ci self.assertEqual(got, 2657db96d56Sopenharmony_ci [os.path.join(dir, path) for path in expected]) 2667db96d56Sopenharmony_ci check([], []) 2677db96d56Sopenharmony_ci tree = ["nothing", 2687db96d56Sopenharmony_ci "hi.py", 2697db96d56Sopenharmony_ci ".dumb", 2707db96d56Sopenharmony_ci ".after.py", 2717db96d56Sopenharmony_ci "notpy.npy", 2727db96d56Sopenharmony_ci "sappy"] 2737db96d56Sopenharmony_ci expected = ["hi.py"] 2747db96d56Sopenharmony_ci check(tree, expected) 2757db96d56Sopenharmony_ci tree = ["hi.py", 2767db96d56Sopenharmony_ci os.path.join("a_dir", "stuff.py")] 2777db96d56Sopenharmony_ci check(tree, tree) 2787db96d56Sopenharmony_ci 2797db96d56Sopenharmony_ci def test_file_encoding(self): 2807db96d56Sopenharmony_ci fn = os.path.join(TEST_DATA_DIR, "different_encoding.py") 2817db96d56Sopenharmony_ci self.check_file_refactoring(fn) 2827db96d56Sopenharmony_ci 2837db96d56Sopenharmony_ci def test_false_file_encoding(self): 2847db96d56Sopenharmony_ci fn = os.path.join(TEST_DATA_DIR, "false_encoding.py") 2857db96d56Sopenharmony_ci data = self.check_file_refactoring(fn) 2867db96d56Sopenharmony_ci 2877db96d56Sopenharmony_ci def test_bom(self): 2887db96d56Sopenharmony_ci fn = os.path.join(TEST_DATA_DIR, "bom.py") 2897db96d56Sopenharmony_ci data = self.check_file_refactoring(fn) 2907db96d56Sopenharmony_ci self.assertTrue(data.startswith(codecs.BOM_UTF8)) 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci def test_crlf_newlines(self): 2937db96d56Sopenharmony_ci old_sep = os.linesep 2947db96d56Sopenharmony_ci os.linesep = "\r\n" 2957db96d56Sopenharmony_ci try: 2967db96d56Sopenharmony_ci fn = os.path.join(TEST_DATA_DIR, "crlf.py") 2977db96d56Sopenharmony_ci fixes = refactor.get_fixers_from_package("lib2to3.fixes") 2987db96d56Sopenharmony_ci self.check_file_refactoring(fn, fixes) 2997db96d56Sopenharmony_ci finally: 3007db96d56Sopenharmony_ci os.linesep = old_sep 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci def test_crlf_unchanged(self): 3037db96d56Sopenharmony_ci fn = os.path.join(TEST_DATA_DIR, "crlf.py") 3047db96d56Sopenharmony_ci old, new = self.refactor_file(fn) 3057db96d56Sopenharmony_ci self.assertIn(b"\r\n", old) 3067db96d56Sopenharmony_ci self.assertIn(b"\r\n", new) 3077db96d56Sopenharmony_ci self.assertNotIn(b"\r\r\n", new) 3087db96d56Sopenharmony_ci 3097db96d56Sopenharmony_ci def test_refactor_docstring(self): 3107db96d56Sopenharmony_ci rt = self.rt() 3117db96d56Sopenharmony_ci 3127db96d56Sopenharmony_ci doc = """ 3137db96d56Sopenharmony_ci>>> example() 3147db96d56Sopenharmony_ci42 3157db96d56Sopenharmony_ci""" 3167db96d56Sopenharmony_ci out = rt.refactor_docstring(doc, "<test>") 3177db96d56Sopenharmony_ci self.assertEqual(out, doc) 3187db96d56Sopenharmony_ci 3197db96d56Sopenharmony_ci doc = """ 3207db96d56Sopenharmony_ci>>> def parrot(): 3217db96d56Sopenharmony_ci... return 43 3227db96d56Sopenharmony_ci""" 3237db96d56Sopenharmony_ci out = rt.refactor_docstring(doc, "<test>") 3247db96d56Sopenharmony_ci self.assertNotEqual(out, doc) 3257db96d56Sopenharmony_ci 3267db96d56Sopenharmony_ci def test_explicit(self): 3277db96d56Sopenharmony_ci from myfixes.fix_explicit import FixExplicit 3287db96d56Sopenharmony_ci 3297db96d56Sopenharmony_ci rt = self.rt(fixers=["myfixes.fix_explicit"]) 3307db96d56Sopenharmony_ci self.assertEqual(len(rt.post_order), 0) 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ci rt = self.rt(explicit=["myfixes.fix_explicit"]) 3337db96d56Sopenharmony_ci for fix in rt.post_order: 3347db96d56Sopenharmony_ci if isinstance(fix, FixExplicit): 3357db96d56Sopenharmony_ci break 3367db96d56Sopenharmony_ci else: 3377db96d56Sopenharmony_ci self.fail("explicit fixer not loaded") 338