1*7249d1a6SKrzysztof Kosiński# -*- coding: utf-8 -*- 2*7249d1a6SKrzysztof Kosiński# Copyright 2015 Google Inc. All Rights Reserved. 3*7249d1a6SKrzysztof Kosiński# 4*7249d1a6SKrzysztof Kosiński# Licensed under the Apache License, Version 2.0 (the "License"); 5*7249d1a6SKrzysztof Kosiński# you may not use this file except in compliance with the License. 6*7249d1a6SKrzysztof Kosiński# You may obtain a copy of the License at 7*7249d1a6SKrzysztof Kosiński# 8*7249d1a6SKrzysztof Kosiński# http://www.apache.org/licenses/LICENSE-2.0 9*7249d1a6SKrzysztof Kosiński# 10*7249d1a6SKrzysztof Kosiński# Unless required by applicable law or agreed to in writing, software 11*7249d1a6SKrzysztof Kosiński# distributed under the License is distributed on an "AS IS" BASIS, 12*7249d1a6SKrzysztof Kosiński# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*7249d1a6SKrzysztof Kosiński# See the License for the specific language governing permissions and 14*7249d1a6SKrzysztof Kosiński# limitations under the License. 15*7249d1a6SKrzysztof Kosiński"""Tests for yapf.file_resources.""" 16*7249d1a6SKrzysztof Kosiński 17*7249d1a6SKrzysztof Kosińskiimport contextlib 18*7249d1a6SKrzysztof Kosińskiimport os 19*7249d1a6SKrzysztof Kosińskiimport shutil 20*7249d1a6SKrzysztof Kosińskiimport tempfile 21*7249d1a6SKrzysztof Kosińskiimport unittest 22*7249d1a6SKrzysztof Kosiński 23*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import errors 24*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import file_resources 25*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import py3compat 26*7249d1a6SKrzysztof Kosiński 27*7249d1a6SKrzysztof Kosińskifrom yapftests import utils 28*7249d1a6SKrzysztof Kosiński 29*7249d1a6SKrzysztof Kosiński 30*7249d1a6SKrzysztof Kosiński@contextlib.contextmanager 31*7249d1a6SKrzysztof Kosińskidef _restore_working_dir(): 32*7249d1a6SKrzysztof Kosiński curdir = os.getcwd() 33*7249d1a6SKrzysztof Kosiński try: 34*7249d1a6SKrzysztof Kosiński yield 35*7249d1a6SKrzysztof Kosiński finally: 36*7249d1a6SKrzysztof Kosiński os.chdir(curdir) 37*7249d1a6SKrzysztof Kosiński 38*7249d1a6SKrzysztof Kosiński 39*7249d1a6SKrzysztof Kosiński@contextlib.contextmanager 40*7249d1a6SKrzysztof Kosińskidef _exists_mocked_in_module(module, mock_implementation): 41*7249d1a6SKrzysztof Kosiński unmocked_exists = getattr(module, 'exists') 42*7249d1a6SKrzysztof Kosiński setattr(module, 'exists', mock_implementation) 43*7249d1a6SKrzysztof Kosiński try: 44*7249d1a6SKrzysztof Kosiński yield 45*7249d1a6SKrzysztof Kosiński finally: 46*7249d1a6SKrzysztof Kosiński setattr(module, 'exists', unmocked_exists) 47*7249d1a6SKrzysztof Kosiński 48*7249d1a6SKrzysztof Kosiński 49*7249d1a6SKrzysztof Kosińskiclass GetExcludePatternsForDir(unittest.TestCase): 50*7249d1a6SKrzysztof Kosiński 51*7249d1a6SKrzysztof Kosiński def setUp(self): # pylint: disable=g-missing-super-call 52*7249d1a6SKrzysztof Kosiński self.test_tmpdir = tempfile.mkdtemp() 53*7249d1a6SKrzysztof Kosiński 54*7249d1a6SKrzysztof Kosiński def tearDown(self): # pylint: disable=g-missing-super-call 55*7249d1a6SKrzysztof Kosiński shutil.rmtree(self.test_tmpdir) 56*7249d1a6SKrzysztof Kosiński 57*7249d1a6SKrzysztof Kosiński def test_get_exclude_file_patterns_from_yapfignore(self): 58*7249d1a6SKrzysztof Kosiński local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') 59*7249d1a6SKrzysztof Kosiński ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] 60*7249d1a6SKrzysztof Kosiński with open(local_ignore_file, 'w') as f: 61*7249d1a6SKrzysztof Kosiński f.writelines('\n'.join(ignore_patterns)) 62*7249d1a6SKrzysztof Kosiński 63*7249d1a6SKrzysztof Kosiński self.assertEqual( 64*7249d1a6SKrzysztof Kosiński sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), 65*7249d1a6SKrzysztof Kosiński sorted(ignore_patterns)) 66*7249d1a6SKrzysztof Kosiński 67*7249d1a6SKrzysztof Kosiński def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self): 68*7249d1a6SKrzysztof Kosiński local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') 69*7249d1a6SKrzysztof Kosiński ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] 70*7249d1a6SKrzysztof Kosiński with open(local_ignore_file, 'w') as f: 71*7249d1a6SKrzysztof Kosiński f.writelines('\n'.join(ignore_patterns)) 72*7249d1a6SKrzysztof Kosiński 73*7249d1a6SKrzysztof Kosiński with self.assertRaises(errors.YapfError): 74*7249d1a6SKrzysztof Kosiński file_resources.GetExcludePatternsForDir(self.test_tmpdir) 75*7249d1a6SKrzysztof Kosiński 76*7249d1a6SKrzysztof Kosiński def test_get_exclude_file_patterns_from_pyproject(self): 77*7249d1a6SKrzysztof Kosiński try: 78*7249d1a6SKrzysztof Kosiński import toml 79*7249d1a6SKrzysztof Kosiński except ImportError: 80*7249d1a6SKrzysztof Kosiński return 81*7249d1a6SKrzysztof Kosiński local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') 82*7249d1a6SKrzysztof Kosiński ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] 83*7249d1a6SKrzysztof Kosiński with open(local_ignore_file, 'w') as f: 84*7249d1a6SKrzysztof Kosiński f.write('[tool.yapfignore]\n') 85*7249d1a6SKrzysztof Kosiński f.write('ignore_patterns=[') 86*7249d1a6SKrzysztof Kosiński f.writelines('\n,'.join(['"{}"'.format(p) for p in ignore_patterns])) 87*7249d1a6SKrzysztof Kosiński f.write(']') 88*7249d1a6SKrzysztof Kosiński 89*7249d1a6SKrzysztof Kosiński self.assertEqual( 90*7249d1a6SKrzysztof Kosiński sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), 91*7249d1a6SKrzysztof Kosiński sorted(ignore_patterns)) 92*7249d1a6SKrzysztof Kosiński 93*7249d1a6SKrzysztof Kosiński @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') 94*7249d1a6SKrzysztof Kosiński def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): 95*7249d1a6SKrzysztof Kosiński try: 96*7249d1a6SKrzysztof Kosiński import toml 97*7249d1a6SKrzysztof Kosiński except ImportError: 98*7249d1a6SKrzysztof Kosiński return 99*7249d1a6SKrzysztof Kosiński local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') 100*7249d1a6SKrzysztof Kosiński ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] 101*7249d1a6SKrzysztof Kosiński with open(local_ignore_file, 'w') as f: 102*7249d1a6SKrzysztof Kosiński f.write('[tool.yapfignore]\n') 103*7249d1a6SKrzysztof Kosiński f.write('ignore_patterns=[') 104*7249d1a6SKrzysztof Kosiński f.writelines('\n,'.join(['"{}"'.format(p) for p in ignore_patterns])) 105*7249d1a6SKrzysztof Kosiński f.write(']') 106*7249d1a6SKrzysztof Kosiński 107*7249d1a6SKrzysztof Kosiński with self.assertRaises(errors.YapfError): 108*7249d1a6SKrzysztof Kosiński file_resources.GetExcludePatternsForDir(self.test_tmpdir) 109*7249d1a6SKrzysztof Kosiński 110*7249d1a6SKrzysztof Kosiński def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): 111*7249d1a6SKrzysztof Kosiński try: 112*7249d1a6SKrzysztof Kosiński import toml 113*7249d1a6SKrzysztof Kosiński except ImportError: 114*7249d1a6SKrzysztof Kosiński return 115*7249d1a6SKrzysztof Kosiński local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') 116*7249d1a6SKrzysztof Kosiński ignore_patterns = [] 117*7249d1a6SKrzysztof Kosiński open(local_ignore_file, 'w').close() 118*7249d1a6SKrzysztof Kosiński 119*7249d1a6SKrzysztof Kosiński self.assertEqual( 120*7249d1a6SKrzysztof Kosiński sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), 121*7249d1a6SKrzysztof Kosiński sorted(ignore_patterns)) 122*7249d1a6SKrzysztof Kosiński 123*7249d1a6SKrzysztof Kosiński def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty(self): 124*7249d1a6SKrzysztof Kosiński try: 125*7249d1a6SKrzysztof Kosiński import toml 126*7249d1a6SKrzysztof Kosiński except ImportError: 127*7249d1a6SKrzysztof Kosiński return 128*7249d1a6SKrzysztof Kosiński local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') 129*7249d1a6SKrzysztof Kosiński ignore_patterns = [] 130*7249d1a6SKrzysztof Kosiński with open(local_ignore_file, 'w') as f: 131*7249d1a6SKrzysztof Kosiński f.write('[tool.yapfignore]\n') 132*7249d1a6SKrzysztof Kosiński 133*7249d1a6SKrzysztof Kosiński self.assertEqual( 134*7249d1a6SKrzysztof Kosiński sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), 135*7249d1a6SKrzysztof Kosiński sorted(ignore_patterns)) 136*7249d1a6SKrzysztof Kosiński 137*7249d1a6SKrzysztof Kosiński def test_get_exclude_file_patterns_with_no_config_files(self): 138*7249d1a6SKrzysztof Kosiński ignore_patterns = [] 139*7249d1a6SKrzysztof Kosiński 140*7249d1a6SKrzysztof Kosiński self.assertEqual( 141*7249d1a6SKrzysztof Kosiński sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), 142*7249d1a6SKrzysztof Kosiński sorted(ignore_patterns)) 143*7249d1a6SKrzysztof Kosiński 144*7249d1a6SKrzysztof Kosiński 145*7249d1a6SKrzysztof Kosińskiclass GetDefaultStyleForDirTest(unittest.TestCase): 146*7249d1a6SKrzysztof Kosiński 147*7249d1a6SKrzysztof Kosiński def setUp(self): # pylint: disable=g-missing-super-call 148*7249d1a6SKrzysztof Kosiński self.test_tmpdir = tempfile.mkdtemp() 149*7249d1a6SKrzysztof Kosiński 150*7249d1a6SKrzysztof Kosiński def tearDown(self): # pylint: disable=g-missing-super-call 151*7249d1a6SKrzysztof Kosiński shutil.rmtree(self.test_tmpdir) 152*7249d1a6SKrzysztof Kosiński 153*7249d1a6SKrzysztof Kosiński def test_no_local_style(self): 154*7249d1a6SKrzysztof Kosiński test_file = os.path.join(self.test_tmpdir, 'file.py') 155*7249d1a6SKrzysztof Kosiński style_name = file_resources.GetDefaultStyleForDir(test_file) 156*7249d1a6SKrzysztof Kosiński self.assertEqual(style_name, 'pep8') 157*7249d1a6SKrzysztof Kosiński 158*7249d1a6SKrzysztof Kosiński def test_no_local_style_custom_default(self): 159*7249d1a6SKrzysztof Kosiński test_file = os.path.join(self.test_tmpdir, 'file.py') 160*7249d1a6SKrzysztof Kosiński style_name = file_resources.GetDefaultStyleForDir( 161*7249d1a6SKrzysztof Kosiński test_file, default_style='custom-default') 162*7249d1a6SKrzysztof Kosiński self.assertEqual(style_name, 'custom-default') 163*7249d1a6SKrzysztof Kosiński 164*7249d1a6SKrzysztof Kosiński def test_with_local_style(self): 165*7249d1a6SKrzysztof Kosiński # Create an empty .style.yapf file in test_tmpdir 166*7249d1a6SKrzysztof Kosiński style_file = os.path.join(self.test_tmpdir, '.style.yapf') 167*7249d1a6SKrzysztof Kosiński open(style_file, 'w').close() 168*7249d1a6SKrzysztof Kosiński 169*7249d1a6SKrzysztof Kosiński test_filename = os.path.join(self.test_tmpdir, 'file.py') 170*7249d1a6SKrzysztof Kosiński self.assertEqual(style_file, 171*7249d1a6SKrzysztof Kosiński file_resources.GetDefaultStyleForDir(test_filename)) 172*7249d1a6SKrzysztof Kosiński 173*7249d1a6SKrzysztof Kosiński test_filename = os.path.join(self.test_tmpdir, 'dir1', 'file.py') 174*7249d1a6SKrzysztof Kosiński self.assertEqual(style_file, 175*7249d1a6SKrzysztof Kosiński file_resources.GetDefaultStyleForDir(test_filename)) 176*7249d1a6SKrzysztof Kosiński 177*7249d1a6SKrzysztof Kosiński def test_setup_config(self): 178*7249d1a6SKrzysztof Kosiński # An empty setup.cfg file should not be used 179*7249d1a6SKrzysztof Kosiński setup_config = os.path.join(self.test_tmpdir, 'setup.cfg') 180*7249d1a6SKrzysztof Kosiński open(setup_config, 'w').close() 181*7249d1a6SKrzysztof Kosiński 182*7249d1a6SKrzysztof Kosiński test_dir = os.path.join(self.test_tmpdir, 'dir1') 183*7249d1a6SKrzysztof Kosiński style_name = file_resources.GetDefaultStyleForDir(test_dir) 184*7249d1a6SKrzysztof Kosiński self.assertEqual(style_name, 'pep8') 185*7249d1a6SKrzysztof Kosiński 186*7249d1a6SKrzysztof Kosiński # One with a '[yapf]' section should be used 187*7249d1a6SKrzysztof Kosiński with open(setup_config, 'w') as f: 188*7249d1a6SKrzysztof Kosiński f.write('[yapf]\n') 189*7249d1a6SKrzysztof Kosiński self.assertEqual(setup_config, 190*7249d1a6SKrzysztof Kosiński file_resources.GetDefaultStyleForDir(test_dir)) 191*7249d1a6SKrzysztof Kosiński 192*7249d1a6SKrzysztof Kosiński def test_pyproject_toml(self): 193*7249d1a6SKrzysztof Kosiński # An empty pyproject.toml file should not be used 194*7249d1a6SKrzysztof Kosiński try: 195*7249d1a6SKrzysztof Kosiński import toml 196*7249d1a6SKrzysztof Kosiński except ImportError: 197*7249d1a6SKrzysztof Kosiński return 198*7249d1a6SKrzysztof Kosiński 199*7249d1a6SKrzysztof Kosiński pyproject_toml = os.path.join(self.test_tmpdir, 'pyproject.toml') 200*7249d1a6SKrzysztof Kosiński open(pyproject_toml, 'w').close() 201*7249d1a6SKrzysztof Kosiński 202*7249d1a6SKrzysztof Kosiński test_dir = os.path.join(self.test_tmpdir, 'dir1') 203*7249d1a6SKrzysztof Kosiński style_name = file_resources.GetDefaultStyleForDir(test_dir) 204*7249d1a6SKrzysztof Kosiński self.assertEqual(style_name, 'pep8') 205*7249d1a6SKrzysztof Kosiński 206*7249d1a6SKrzysztof Kosiński # One with a '[tool.yapf]' section should be used 207*7249d1a6SKrzysztof Kosiński with open(pyproject_toml, 'w') as f: 208*7249d1a6SKrzysztof Kosiński f.write('[tool.yapf]\n') 209*7249d1a6SKrzysztof Kosiński self.assertEqual(pyproject_toml, 210*7249d1a6SKrzysztof Kosiński file_resources.GetDefaultStyleForDir(test_dir)) 211*7249d1a6SKrzysztof Kosiński 212*7249d1a6SKrzysztof Kosiński def test_local_style_at_root(self): 213*7249d1a6SKrzysztof Kosiński # Test behavior of files located on the root, and under root. 214*7249d1a6SKrzysztof Kosiński rootdir = os.path.abspath(os.path.sep) 215*7249d1a6SKrzysztof Kosiński test_dir_at_root = os.path.join(rootdir, 'dir1') 216*7249d1a6SKrzysztof Kosiński test_dir_under_root = os.path.join(rootdir, 'dir1', 'dir2') 217*7249d1a6SKrzysztof Kosiński 218*7249d1a6SKrzysztof Kosiński # Fake placing only a style file at the root by mocking `os.path.exists`. 219*7249d1a6SKrzysztof Kosiński style_file = os.path.join(rootdir, '.style.yapf') 220*7249d1a6SKrzysztof Kosiński 221*7249d1a6SKrzysztof Kosiński def mock_exists_implementation(path): 222*7249d1a6SKrzysztof Kosiński return path == style_file 223*7249d1a6SKrzysztof Kosiński 224*7249d1a6SKrzysztof Kosiński with _exists_mocked_in_module(file_resources.os.path, 225*7249d1a6SKrzysztof Kosiński mock_exists_implementation): 226*7249d1a6SKrzysztof Kosiński # Both files should find the style file at the root. 227*7249d1a6SKrzysztof Kosiński default_style_at_root = file_resources.GetDefaultStyleForDir( 228*7249d1a6SKrzysztof Kosiński test_dir_at_root) 229*7249d1a6SKrzysztof Kosiński self.assertEqual(style_file, default_style_at_root) 230*7249d1a6SKrzysztof Kosiński default_style_under_root = file_resources.GetDefaultStyleForDir( 231*7249d1a6SKrzysztof Kosiński test_dir_under_root) 232*7249d1a6SKrzysztof Kosiński self.assertEqual(style_file, default_style_under_root) 233*7249d1a6SKrzysztof Kosiński 234*7249d1a6SKrzysztof Kosiński 235*7249d1a6SKrzysztof Kosińskidef _touch_files(filenames): 236*7249d1a6SKrzysztof Kosiński for name in filenames: 237*7249d1a6SKrzysztof Kosiński open(name, 'a').close() 238*7249d1a6SKrzysztof Kosiński 239*7249d1a6SKrzysztof Kosiński 240*7249d1a6SKrzysztof Kosińskiclass GetCommandLineFilesTest(unittest.TestCase): 241*7249d1a6SKrzysztof Kosiński 242*7249d1a6SKrzysztof Kosiński def setUp(self): # pylint: disable=g-missing-super-call 243*7249d1a6SKrzysztof Kosiński self.test_tmpdir = tempfile.mkdtemp() 244*7249d1a6SKrzysztof Kosiński self.old_dir = os.getcwd() 245*7249d1a6SKrzysztof Kosiński 246*7249d1a6SKrzysztof Kosiński def tearDown(self): # pylint: disable=g-missing-super-call 247*7249d1a6SKrzysztof Kosiński os.chdir(self.old_dir) 248*7249d1a6SKrzysztof Kosiński shutil.rmtree(self.test_tmpdir) 249*7249d1a6SKrzysztof Kosiński 250*7249d1a6SKrzysztof Kosiński def _make_test_dir(self, name): 251*7249d1a6SKrzysztof Kosiński fullpath = os.path.normpath(os.path.join(self.test_tmpdir, name)) 252*7249d1a6SKrzysztof Kosiński os.makedirs(fullpath) 253*7249d1a6SKrzysztof Kosiński return fullpath 254*7249d1a6SKrzysztof Kosiński 255*7249d1a6SKrzysztof Kosiński def test_find_files_not_dirs(self): 256*7249d1a6SKrzysztof Kosiński tdir1 = self._make_test_dir('test1') 257*7249d1a6SKrzysztof Kosiński tdir2 = self._make_test_dir('test2') 258*7249d1a6SKrzysztof Kosiński file1 = os.path.join(tdir1, 'testfile1.py') 259*7249d1a6SKrzysztof Kosiński file2 = os.path.join(tdir2, 'testfile2.py') 260*7249d1a6SKrzysztof Kosiński _touch_files([file1, file2]) 261*7249d1a6SKrzysztof Kosiński 262*7249d1a6SKrzysztof Kosiński self.assertEqual( 263*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles([file1, file2], 264*7249d1a6SKrzysztof Kosiński recursive=False, 265*7249d1a6SKrzysztof Kosiński exclude=None), [file1, file2]) 266*7249d1a6SKrzysztof Kosiński self.assertEqual( 267*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles([file1, file2], 268*7249d1a6SKrzysztof Kosiński recursive=True, 269*7249d1a6SKrzysztof Kosiński exclude=None), [file1, file2]) 270*7249d1a6SKrzysztof Kosiński 271*7249d1a6SKrzysztof Kosiński def test_nonrecursive_find_in_dir(self): 272*7249d1a6SKrzysztof Kosiński tdir1 = self._make_test_dir('test1') 273*7249d1a6SKrzysztof Kosiński tdir2 = self._make_test_dir('test1/foo') 274*7249d1a6SKrzysztof Kosiński file1 = os.path.join(tdir1, 'testfile1.py') 275*7249d1a6SKrzysztof Kosiński file2 = os.path.join(tdir2, 'testfile2.py') 276*7249d1a6SKrzysztof Kosiński _touch_files([file1, file2]) 277*7249d1a6SKrzysztof Kosiński 278*7249d1a6SKrzysztof Kosiński self.assertRaises( 279*7249d1a6SKrzysztof Kosiński errors.YapfError, 280*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles, 281*7249d1a6SKrzysztof Kosiński command_line_file_list=[tdir1], 282*7249d1a6SKrzysztof Kosiński recursive=False, 283*7249d1a6SKrzysztof Kosiński exclude=None) 284*7249d1a6SKrzysztof Kosiński 285*7249d1a6SKrzysztof Kosiński def test_recursive_find_in_dir(self): 286*7249d1a6SKrzysztof Kosiński tdir1 = self._make_test_dir('test1') 287*7249d1a6SKrzysztof Kosiński tdir2 = self._make_test_dir('test2/testinner/') 288*7249d1a6SKrzysztof Kosiński tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') 289*7249d1a6SKrzysztof Kosiński files = [ 290*7249d1a6SKrzysztof Kosiński os.path.join(tdir1, 'testfile1.py'), 291*7249d1a6SKrzysztof Kosiński os.path.join(tdir2, 'testfile2.py'), 292*7249d1a6SKrzysztof Kosiński os.path.join(tdir3, 'testfile3.py'), 293*7249d1a6SKrzysztof Kosiński ] 294*7249d1a6SKrzysztof Kosiński _touch_files(files) 295*7249d1a6SKrzysztof Kosiński 296*7249d1a6SKrzysztof Kosiński self.assertEqual( 297*7249d1a6SKrzysztof Kosiński sorted( 298*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles([self.test_tmpdir], 299*7249d1a6SKrzysztof Kosiński recursive=True, 300*7249d1a6SKrzysztof Kosiński exclude=None)), sorted(files)) 301*7249d1a6SKrzysztof Kosiński 302*7249d1a6SKrzysztof Kosiński def test_recursive_find_in_dir_with_exclude(self): 303*7249d1a6SKrzysztof Kosiński tdir1 = self._make_test_dir('test1') 304*7249d1a6SKrzysztof Kosiński tdir2 = self._make_test_dir('test2/testinner/') 305*7249d1a6SKrzysztof Kosiński tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') 306*7249d1a6SKrzysztof Kosiński files = [ 307*7249d1a6SKrzysztof Kosiński os.path.join(tdir1, 'testfile1.py'), 308*7249d1a6SKrzysztof Kosiński os.path.join(tdir2, 'testfile2.py'), 309*7249d1a6SKrzysztof Kosiński os.path.join(tdir3, 'testfile3.py'), 310*7249d1a6SKrzysztof Kosiński ] 311*7249d1a6SKrzysztof Kosiński _touch_files(files) 312*7249d1a6SKrzysztof Kosiński 313*7249d1a6SKrzysztof Kosiński self.assertEqual( 314*7249d1a6SKrzysztof Kosiński sorted( 315*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles([self.test_tmpdir], 316*7249d1a6SKrzysztof Kosiński recursive=True, 317*7249d1a6SKrzysztof Kosiński exclude=['*test*3.py'])), 318*7249d1a6SKrzysztof Kosiński sorted([ 319*7249d1a6SKrzysztof Kosiński os.path.join(tdir1, 'testfile1.py'), 320*7249d1a6SKrzysztof Kosiński os.path.join(tdir2, 'testfile2.py'), 321*7249d1a6SKrzysztof Kosiński ])) 322*7249d1a6SKrzysztof Kosiński 323*7249d1a6SKrzysztof Kosiński def test_find_with_excluded_hidden_dirs(self): 324*7249d1a6SKrzysztof Kosiński tdir1 = self._make_test_dir('.test1') 325*7249d1a6SKrzysztof Kosiński tdir2 = self._make_test_dir('test_2') 326*7249d1a6SKrzysztof Kosiński tdir3 = self._make_test_dir('test.3') 327*7249d1a6SKrzysztof Kosiński files = [ 328*7249d1a6SKrzysztof Kosiński os.path.join(tdir1, 'testfile1.py'), 329*7249d1a6SKrzysztof Kosiński os.path.join(tdir2, 'testfile2.py'), 330*7249d1a6SKrzysztof Kosiński os.path.join(tdir3, 'testfile3.py'), 331*7249d1a6SKrzysztof Kosiński ] 332*7249d1a6SKrzysztof Kosiński _touch_files(files) 333*7249d1a6SKrzysztof Kosiński 334*7249d1a6SKrzysztof Kosiński actual = file_resources.GetCommandLineFiles([self.test_tmpdir], 335*7249d1a6SKrzysztof Kosiński recursive=True, 336*7249d1a6SKrzysztof Kosiński exclude=['*.test1*']) 337*7249d1a6SKrzysztof Kosiński 338*7249d1a6SKrzysztof Kosiński self.assertEqual( 339*7249d1a6SKrzysztof Kosiński sorted(actual), 340*7249d1a6SKrzysztof Kosiński sorted([ 341*7249d1a6SKrzysztof Kosiński os.path.join(tdir2, 'testfile2.py'), 342*7249d1a6SKrzysztof Kosiński os.path.join(tdir3, 'testfile3.py'), 343*7249d1a6SKrzysztof Kosiński ])) 344*7249d1a6SKrzysztof Kosiński 345*7249d1a6SKrzysztof Kosiński def test_find_with_excluded_hidden_dirs_relative(self): 346*7249d1a6SKrzysztof Kosiński """Test find with excluded hidden dirs. 347*7249d1a6SKrzysztof Kosiński 348*7249d1a6SKrzysztof Kosiński A regression test against a specific case where a hidden directory (one 349*7249d1a6SKrzysztof Kosiński beginning with a period) is being excluded, but it is also an immediate 350*7249d1a6SKrzysztof Kosiński child of the current directory which has been specified in a relative 351*7249d1a6SKrzysztof Kosiński manner. 352*7249d1a6SKrzysztof Kosiński 353*7249d1a6SKrzysztof Kosiński At its core, the bug has to do with overzelous stripping of "./foo" so that 354*7249d1a6SKrzysztof Kosiński it removes too much from "./.foo" . 355*7249d1a6SKrzysztof Kosiński """ 356*7249d1a6SKrzysztof Kosiński tdir1 = self._make_test_dir('.test1') 357*7249d1a6SKrzysztof Kosiński tdir2 = self._make_test_dir('test_2') 358*7249d1a6SKrzysztof Kosiński tdir3 = self._make_test_dir('test.3') 359*7249d1a6SKrzysztof Kosiński files = [ 360*7249d1a6SKrzysztof Kosiński os.path.join(tdir1, 'testfile1.py'), 361*7249d1a6SKrzysztof Kosiński os.path.join(tdir2, 'testfile2.py'), 362*7249d1a6SKrzysztof Kosiński os.path.join(tdir3, 'testfile3.py'), 363*7249d1a6SKrzysztof Kosiński ] 364*7249d1a6SKrzysztof Kosiński _touch_files(files) 365*7249d1a6SKrzysztof Kosiński 366*7249d1a6SKrzysztof Kosiński # We must temporarily change the current directory, so that we test against 367*7249d1a6SKrzysztof Kosiński # patterns like ./.test1/file instead of /tmp/foo/.test1/file 368*7249d1a6SKrzysztof Kosiński with _restore_working_dir(): 369*7249d1a6SKrzysztof Kosiński 370*7249d1a6SKrzysztof Kosiński os.chdir(self.test_tmpdir) 371*7249d1a6SKrzysztof Kosiński actual = file_resources.GetCommandLineFiles( 372*7249d1a6SKrzysztof Kosiński [os.path.relpath(self.test_tmpdir)], 373*7249d1a6SKrzysztof Kosiński recursive=True, 374*7249d1a6SKrzysztof Kosiński exclude=['*.test1*']) 375*7249d1a6SKrzysztof Kosiński 376*7249d1a6SKrzysztof Kosiński self.assertEqual( 377*7249d1a6SKrzysztof Kosiński sorted(actual), 378*7249d1a6SKrzysztof Kosiński sorted([ 379*7249d1a6SKrzysztof Kosiński os.path.join( 380*7249d1a6SKrzysztof Kosiński os.path.relpath(self.test_tmpdir), os.path.basename(tdir2), 381*7249d1a6SKrzysztof Kosiński 'testfile2.py'), 382*7249d1a6SKrzysztof Kosiński os.path.join( 383*7249d1a6SKrzysztof Kosiński os.path.relpath(self.test_tmpdir), os.path.basename(tdir3), 384*7249d1a6SKrzysztof Kosiński 'testfile3.py'), 385*7249d1a6SKrzysztof Kosiński ])) 386*7249d1a6SKrzysztof Kosiński 387*7249d1a6SKrzysztof Kosiński def test_find_with_excluded_dirs(self): 388*7249d1a6SKrzysztof Kosiński tdir1 = self._make_test_dir('test1') 389*7249d1a6SKrzysztof Kosiński tdir2 = self._make_test_dir('test2/testinner/') 390*7249d1a6SKrzysztof Kosiński tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') 391*7249d1a6SKrzysztof Kosiński files = [ 392*7249d1a6SKrzysztof Kosiński os.path.join(tdir1, 'testfile1.py'), 393*7249d1a6SKrzysztof Kosiński os.path.join(tdir2, 'testfile2.py'), 394*7249d1a6SKrzysztof Kosiński os.path.join(tdir3, 'testfile3.py'), 395*7249d1a6SKrzysztof Kosiński ] 396*7249d1a6SKrzysztof Kosiński _touch_files(files) 397*7249d1a6SKrzysztof Kosiński 398*7249d1a6SKrzysztof Kosiński os.chdir(self.test_tmpdir) 399*7249d1a6SKrzysztof Kosiński 400*7249d1a6SKrzysztof Kosiński found = sorted( 401*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles(['test1', 'test2', 'test3'], 402*7249d1a6SKrzysztof Kosiński recursive=True, 403*7249d1a6SKrzysztof Kosiński exclude=[ 404*7249d1a6SKrzysztof Kosiński 'test1', 405*7249d1a6SKrzysztof Kosiński 'test2/testinner/', 406*7249d1a6SKrzysztof Kosiński ])) 407*7249d1a6SKrzysztof Kosiński 408*7249d1a6SKrzysztof Kosiński self.assertEqual( 409*7249d1a6SKrzysztof Kosiński found, ['test3/foo/bar/bas/xxx/testfile3.py'.replace("/", os.path.sep)]) 410*7249d1a6SKrzysztof Kosiński 411*7249d1a6SKrzysztof Kosiński found = sorted( 412*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles(['.'], 413*7249d1a6SKrzysztof Kosiński recursive=True, 414*7249d1a6SKrzysztof Kosiński exclude=[ 415*7249d1a6SKrzysztof Kosiński 'test1', 416*7249d1a6SKrzysztof Kosiński 'test3', 417*7249d1a6SKrzysztof Kosiński ])) 418*7249d1a6SKrzysztof Kosiński 419*7249d1a6SKrzysztof Kosiński self.assertEqual( 420*7249d1a6SKrzysztof Kosiński found, ['./test2/testinner/testfile2.py'.replace("/", os.path.sep)]) 421*7249d1a6SKrzysztof Kosiński 422*7249d1a6SKrzysztof Kosiński def test_find_with_excluded_current_dir(self): 423*7249d1a6SKrzysztof Kosiński with self.assertRaises(errors.YapfError): 424*7249d1a6SKrzysztof Kosiński file_resources.GetCommandLineFiles([], False, exclude=['./z']) 425*7249d1a6SKrzysztof Kosiński 426*7249d1a6SKrzysztof Kosiński 427*7249d1a6SKrzysztof Kosińskiclass IsPythonFileTest(unittest.TestCase): 428*7249d1a6SKrzysztof Kosiński 429*7249d1a6SKrzysztof Kosiński def setUp(self): # pylint: disable=g-missing-super-call 430*7249d1a6SKrzysztof Kosiński self.test_tmpdir = tempfile.mkdtemp() 431*7249d1a6SKrzysztof Kosiński 432*7249d1a6SKrzysztof Kosiński def tearDown(self): # pylint: disable=g-missing-super-call 433*7249d1a6SKrzysztof Kosiński shutil.rmtree(self.test_tmpdir) 434*7249d1a6SKrzysztof Kosiński 435*7249d1a6SKrzysztof Kosiński def test_with_py_extension(self): 436*7249d1a6SKrzysztof Kosiński file1 = os.path.join(self.test_tmpdir, 'testfile1.py') 437*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsPythonFile(file1)) 438*7249d1a6SKrzysztof Kosiński 439*7249d1a6SKrzysztof Kosiński def test_empty_without_py_extension(self): 440*7249d1a6SKrzysztof Kosiński file1 = os.path.join(self.test_tmpdir, 'testfile1') 441*7249d1a6SKrzysztof Kosiński self.assertFalse(file_resources.IsPythonFile(file1)) 442*7249d1a6SKrzysztof Kosiński file2 = os.path.join(self.test_tmpdir, 'testfile1.rb') 443*7249d1a6SKrzysztof Kosiński self.assertFalse(file_resources.IsPythonFile(file2)) 444*7249d1a6SKrzysztof Kosiński 445*7249d1a6SKrzysztof Kosiński def test_python_shebang(self): 446*7249d1a6SKrzysztof Kosiński file1 = os.path.join(self.test_tmpdir, 'testfile1') 447*7249d1a6SKrzysztof Kosiński with open(file1, 'w') as f: 448*7249d1a6SKrzysztof Kosiński f.write(u'#!/usr/bin/python\n') 449*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsPythonFile(file1)) 450*7249d1a6SKrzysztof Kosiński 451*7249d1a6SKrzysztof Kosiński file2 = os.path.join(self.test_tmpdir, 'testfile2.run') 452*7249d1a6SKrzysztof Kosiński with open(file2, 'w') as f: 453*7249d1a6SKrzysztof Kosiński f.write(u'#! /bin/python2\n') 454*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsPythonFile(file1)) 455*7249d1a6SKrzysztof Kosiński 456*7249d1a6SKrzysztof Kosiński def test_with_latin_encoding(self): 457*7249d1a6SKrzysztof Kosiński file1 = os.path.join(self.test_tmpdir, 'testfile1') 458*7249d1a6SKrzysztof Kosiński with py3compat.open_with_encoding(file1, mode='w', encoding='latin-1') as f: 459*7249d1a6SKrzysztof Kosiński f.write(u'#! /bin/python2\n') 460*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsPythonFile(file1)) 461*7249d1a6SKrzysztof Kosiński 462*7249d1a6SKrzysztof Kosiński def test_with_invalid_encoding(self): 463*7249d1a6SKrzysztof Kosiński file1 = os.path.join(self.test_tmpdir, 'testfile1') 464*7249d1a6SKrzysztof Kosiński with open(file1, 'w') as f: 465*7249d1a6SKrzysztof Kosiński f.write(u'#! /bin/python2\n') 466*7249d1a6SKrzysztof Kosiński f.write(u'# -*- coding: iso-3-14159 -*-\n') 467*7249d1a6SKrzysztof Kosiński self.assertFalse(file_resources.IsPythonFile(file1)) 468*7249d1a6SKrzysztof Kosiński 469*7249d1a6SKrzysztof Kosiński 470*7249d1a6SKrzysztof Kosińskiclass IsIgnoredTest(unittest.TestCase): 471*7249d1a6SKrzysztof Kosiński 472*7249d1a6SKrzysztof Kosiński def test_root_path(self): 473*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsIgnored('media', ['media'])) 474*7249d1a6SKrzysztof Kosiński self.assertFalse(file_resources.IsIgnored('media', ['media/*'])) 475*7249d1a6SKrzysztof Kosiński 476*7249d1a6SKrzysztof Kosiński def test_sub_path(self): 477*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsIgnored('media/a', ['*/a'])) 478*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsIgnored('media/b', ['media/*'])) 479*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsIgnored('media/b/c', ['*/*/c'])) 480*7249d1a6SKrzysztof Kosiński 481*7249d1a6SKrzysztof Kosiński def test_trailing_slash(self): 482*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsIgnored('z', ['z'])) 483*7249d1a6SKrzysztof Kosiński self.assertTrue(file_resources.IsIgnored('z', ['z' + os.path.sep])) 484*7249d1a6SKrzysztof Kosiński 485*7249d1a6SKrzysztof Kosiński 486*7249d1a6SKrzysztof Kosińskiclass BufferedByteStream(object): 487*7249d1a6SKrzysztof Kosiński 488*7249d1a6SKrzysztof Kosiński def __init__(self): 489*7249d1a6SKrzysztof Kosiński self.stream = py3compat.BytesIO() 490*7249d1a6SKrzysztof Kosiński 491*7249d1a6SKrzysztof Kosiński def getvalue(self): # pylint: disable=invalid-name 492*7249d1a6SKrzysztof Kosiński return self.stream.getvalue().decode('utf-8') 493*7249d1a6SKrzysztof Kosiński 494*7249d1a6SKrzysztof Kosiński @property 495*7249d1a6SKrzysztof Kosiński def buffer(self): 496*7249d1a6SKrzysztof Kosiński return self.stream 497*7249d1a6SKrzysztof Kosiński 498*7249d1a6SKrzysztof Kosiński 499*7249d1a6SKrzysztof Kosińskiclass WriteReformattedCodeTest(unittest.TestCase): 500*7249d1a6SKrzysztof Kosiński 501*7249d1a6SKrzysztof Kosiński @classmethod 502*7249d1a6SKrzysztof Kosiński def setUpClass(cls): # pylint: disable=g-missing-super-call 503*7249d1a6SKrzysztof Kosiński cls.test_tmpdir = tempfile.mkdtemp() 504*7249d1a6SKrzysztof Kosiński 505*7249d1a6SKrzysztof Kosiński @classmethod 506*7249d1a6SKrzysztof Kosiński def tearDownClass(cls): # pylint: disable=g-missing-super-call 507*7249d1a6SKrzysztof Kosiński shutil.rmtree(cls.test_tmpdir) 508*7249d1a6SKrzysztof Kosiński 509*7249d1a6SKrzysztof Kosiński def test_write_to_file(self): 510*7249d1a6SKrzysztof Kosiński s = u'foobar\n' 511*7249d1a6SKrzysztof Kosiński with utils.NamedTempFile(dirname=self.test_tmpdir) as (f, fname): 512*7249d1a6SKrzysztof Kosiński file_resources.WriteReformattedCode( 513*7249d1a6SKrzysztof Kosiński fname, s, in_place=True, encoding='utf-8') 514*7249d1a6SKrzysztof Kosiński f.flush() 515*7249d1a6SKrzysztof Kosiński 516*7249d1a6SKrzysztof Kosiński with open(fname) as f2: 517*7249d1a6SKrzysztof Kosiński self.assertEqual(f2.read(), s) 518*7249d1a6SKrzysztof Kosiński 519*7249d1a6SKrzysztof Kosiński def test_write_to_stdout(self): 520*7249d1a6SKrzysztof Kosiński s = u'foobar' 521*7249d1a6SKrzysztof Kosiński stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() 522*7249d1a6SKrzysztof Kosiński with utils.stdout_redirector(stream): 523*7249d1a6SKrzysztof Kosiński file_resources.WriteReformattedCode( 524*7249d1a6SKrzysztof Kosiński None, s, in_place=False, encoding='utf-8') 525*7249d1a6SKrzysztof Kosiński self.assertEqual(stream.getvalue(), s) 526*7249d1a6SKrzysztof Kosiński 527*7249d1a6SKrzysztof Kosiński def test_write_encoded_to_stdout(self): 528*7249d1a6SKrzysztof Kosiński s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa 529*7249d1a6SKrzysztof Kosiński stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() 530*7249d1a6SKrzysztof Kosiński with utils.stdout_redirector(stream): 531*7249d1a6SKrzysztof Kosiński file_resources.WriteReformattedCode( 532*7249d1a6SKrzysztof Kosiński None, s, in_place=False, encoding='utf-8') 533*7249d1a6SKrzysztof Kosiński self.assertEqual(stream.getvalue(), s) 534*7249d1a6SKrzysztof Kosiński 535*7249d1a6SKrzysztof Kosiński 536*7249d1a6SKrzysztof Kosińskiclass LineEndingTest(unittest.TestCase): 537*7249d1a6SKrzysztof Kosiński 538*7249d1a6SKrzysztof Kosiński def test_line_ending_linefeed(self): 539*7249d1a6SKrzysztof Kosiński lines = ['spam\n', 'spam\n'] 540*7249d1a6SKrzysztof Kosiński actual = file_resources.LineEnding(lines) 541*7249d1a6SKrzysztof Kosiński self.assertEqual(actual, '\n') 542*7249d1a6SKrzysztof Kosiński 543*7249d1a6SKrzysztof Kosiński def test_line_ending_carriage_return(self): 544*7249d1a6SKrzysztof Kosiński lines = ['spam\r', 'spam\r'] 545*7249d1a6SKrzysztof Kosiński actual = file_resources.LineEnding(lines) 546*7249d1a6SKrzysztof Kosiński self.assertEqual(actual, '\r') 547*7249d1a6SKrzysztof Kosiński 548*7249d1a6SKrzysztof Kosiński def test_line_ending_combo(self): 549*7249d1a6SKrzysztof Kosiński lines = ['spam\r\n', 'spam\r\n'] 550*7249d1a6SKrzysztof Kosiński actual = file_resources.LineEnding(lines) 551*7249d1a6SKrzysztof Kosiński self.assertEqual(actual, '\r\n') 552*7249d1a6SKrzysztof Kosiński 553*7249d1a6SKrzysztof Kosiński def test_line_ending_weighted(self): 554*7249d1a6SKrzysztof Kosiński lines = [ 555*7249d1a6SKrzysztof Kosiński 'spam\n', 556*7249d1a6SKrzysztof Kosiński 'spam\n', 557*7249d1a6SKrzysztof Kosiński 'spam\r', 558*7249d1a6SKrzysztof Kosiński 'spam\r\n', 559*7249d1a6SKrzysztof Kosiński ] 560*7249d1a6SKrzysztof Kosiński actual = file_resources.LineEnding(lines) 561*7249d1a6SKrzysztof Kosiński self.assertEqual(actual, '\n') 562*7249d1a6SKrzysztof Kosiński 563*7249d1a6SKrzysztof Kosiński 564*7249d1a6SKrzysztof Kosińskiif __name__ == '__main__': 565*7249d1a6SKrzysztof Kosiński unittest.main() 566