| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 |
- # -*- coding: utf-8 -*-
- # Copyright 2015 Google Inc. All Rights Reserved.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """Tests for yapf.file_resources."""
- import codecs
- import contextlib
- import os
- import shutil
- import tempfile
- import unittest
- from io import BytesIO
- from yapf.yapflib import errors
- from yapf.yapflib import file_resources
- from yapftests import utils
- @contextlib.contextmanager
- def _restore_working_dir():
- curdir = os.getcwd()
- try:
- yield
- finally:
- os.chdir(curdir)
- @contextlib.contextmanager
- def _exists_mocked_in_module(module, mock_implementation):
- unmocked_exists = getattr(module, 'exists')
- setattr(module, 'exists', mock_implementation)
- try:
- yield
- finally:
- setattr(module, 'exists', unmocked_exists)
- class GetExcludePatternsForDir(unittest.TestCase):
- def setUp(self): # pylint: disable=g-missing-super-call
- self.test_tmpdir = tempfile.mkdtemp()
- def tearDown(self): # pylint: disable=g-missing-super-call
- shutil.rmtree(self.test_tmpdir)
- def test_get_exclude_file_patterns_from_yapfignore(self):
- local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore')
- ignore_patterns = ['temp/**/*.py', 'temp2/*.py']
- with open(local_ignore_file, 'w') as f:
- f.writelines('\n'.join(ignore_patterns))
- self.assertEqual(
- sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)),
- sorted(ignore_patterns))
- def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self):
- local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore')
- ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py']
- with open(local_ignore_file, 'w') as f:
- f.writelines('\n'.join(ignore_patterns))
- with self.assertRaises(errors.YapfError):
- file_resources.GetExcludePatternsForDir(self.test_tmpdir)
- def test_get_exclude_file_patterns_from_pyproject(self):
- try:
- import tomli
- except ImportError:
- return
- local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml')
- ignore_patterns = ['temp/**/*.py', 'temp2/*.py']
- with open(local_ignore_file, 'w') as f:
- f.write('[tool.yapfignore]\n')
- f.write('ignore_patterns=[')
- f.writelines('\n,'.join(['"{}"'.format(p) for p in ignore_patterns]))
- f.write(']')
- self.assertEqual(
- sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)),
- sorted(ignore_patterns))
- def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self):
- try:
- import tomli
- except ImportError:
- return
- local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml')
- ignore_patterns = []
- open(local_ignore_file, 'w').close()
- self.assertEqual(
- sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)),
- sorted(ignore_patterns))
- def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty(self):
- try:
- import tomli
- except ImportError:
- return
- local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml')
- ignore_patterns = []
- with open(local_ignore_file, 'w') as f:
- f.write('[tool.yapfignore]\n')
- self.assertEqual(
- sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)),
- sorted(ignore_patterns))
- def test_get_exclude_file_patterns_with_no_config_files(self):
- ignore_patterns = []
- self.assertEqual(
- sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)),
- sorted(ignore_patterns))
- class GetDefaultStyleForDirTest(unittest.TestCase):
- def setUp(self): # pylint: disable=g-missing-super-call
- self.test_tmpdir = tempfile.mkdtemp()
- def tearDown(self): # pylint: disable=g-missing-super-call
- shutil.rmtree(self.test_tmpdir)
- def test_no_local_style(self):
- test_file = os.path.join(self.test_tmpdir, 'file.py')
- style_name = file_resources.GetDefaultStyleForDir(test_file)
- self.assertEqual(style_name, 'pep8')
- def test_no_local_style_custom_default(self):
- test_file = os.path.join(self.test_tmpdir, 'file.py')
- style_name = file_resources.GetDefaultStyleForDir(
- test_file, default_style='custom-default')
- self.assertEqual(style_name, 'custom-default')
- def test_with_local_style(self):
- # Create an empty .style.yapf file in test_tmpdir
- style_file = os.path.join(self.test_tmpdir, '.style.yapf')
- open(style_file, 'w').close()
- test_filename = os.path.join(self.test_tmpdir, 'file.py')
- self.assertEqual(style_file,
- file_resources.GetDefaultStyleForDir(test_filename))
- test_filename = os.path.join(self.test_tmpdir, 'dir1', 'file.py')
- self.assertEqual(style_file,
- file_resources.GetDefaultStyleForDir(test_filename))
- def test_setup_config(self):
- # An empty setup.cfg file should not be used
- setup_config = os.path.join(self.test_tmpdir, 'setup.cfg')
- open(setup_config, 'w').close()
- test_dir = os.path.join(self.test_tmpdir, 'dir1')
- style_name = file_resources.GetDefaultStyleForDir(test_dir)
- self.assertEqual(style_name, 'pep8')
- # One with a '[yapf]' section should be used
- with open(setup_config, 'w') as f:
- f.write('[yapf]\n')
- self.assertEqual(setup_config,
- file_resources.GetDefaultStyleForDir(test_dir))
- def test_pyproject_toml(self):
- # An empty pyproject.toml file should not be used
- try:
- import tomli
- except ImportError:
- return
- pyproject_toml = os.path.join(self.test_tmpdir, 'pyproject.toml')
- open(pyproject_toml, 'w').close()
- test_dir = os.path.join(self.test_tmpdir, 'dir1')
- style_name = file_resources.GetDefaultStyleForDir(test_dir)
- self.assertEqual(style_name, 'pep8')
- # One with a '[tool.yapf]' section should be used
- with open(pyproject_toml, 'w') as f:
- f.write('[tool.yapf]\n')
- self.assertEqual(pyproject_toml,
- file_resources.GetDefaultStyleForDir(test_dir))
- def test_local_style_at_root(self):
- # Test behavior of files located on the root, and under root.
- rootdir = os.path.abspath(os.path.sep)
- test_dir_at_root = os.path.join(rootdir, 'dir1')
- test_dir_under_root = os.path.join(rootdir, 'dir1', 'dir2')
- # Fake placing only a style file at the root by mocking `os.path.exists`.
- style_file = os.path.join(rootdir, '.style.yapf')
- def mock_exists_implementation(path):
- return path == style_file
- with _exists_mocked_in_module(file_resources.os.path,
- mock_exists_implementation):
- # Both files should find the style file at the root.
- default_style_at_root = file_resources.GetDefaultStyleForDir(
- test_dir_at_root)
- self.assertEqual(style_file, default_style_at_root)
- default_style_under_root = file_resources.GetDefaultStyleForDir(
- test_dir_under_root)
- self.assertEqual(style_file, default_style_under_root)
- def _touch_files(filenames):
- for name in filenames:
- open(name, 'a').close()
- class GetCommandLineFilesTest(unittest.TestCase):
- def setUp(self): # pylint: disable=g-missing-super-call
- self.test_tmpdir = tempfile.mkdtemp()
- self.old_dir = os.getcwd()
- def tearDown(self): # pylint: disable=g-missing-super-call
- os.chdir(self.old_dir)
- shutil.rmtree(self.test_tmpdir)
- def _make_test_dir(self, name):
- fullpath = os.path.normpath(os.path.join(self.test_tmpdir, name))
- os.makedirs(fullpath)
- return fullpath
- def test_find_files_not_dirs(self):
- tdir1 = self._make_test_dir('test1')
- tdir2 = self._make_test_dir('test2')
- file1 = os.path.join(tdir1, 'testfile1.py')
- file2 = os.path.join(tdir2, 'testfile2.py')
- _touch_files([file1, file2])
- self.assertEqual(
- file_resources.GetCommandLineFiles([file1, file2],
- recursive=False,
- exclude=None), [file1, file2])
- self.assertEqual(
- file_resources.GetCommandLineFiles([file1, file2],
- recursive=True,
- exclude=None), [file1, file2])
- def test_nonrecursive_find_in_dir(self):
- tdir1 = self._make_test_dir('test1')
- tdir2 = self._make_test_dir('test1/foo')
- file1 = os.path.join(tdir1, 'testfile1.py')
- file2 = os.path.join(tdir2, 'testfile2.py')
- _touch_files([file1, file2])
- self.assertRaises(
- errors.YapfError,
- file_resources.GetCommandLineFiles,
- command_line_file_list=[tdir1],
- recursive=False,
- exclude=None)
- def test_recursive_find_in_dir(self):
- tdir1 = self._make_test_dir('test1')
- tdir2 = self._make_test_dir('test2/testinner/')
- tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx')
- files = [
- os.path.join(tdir1, 'testfile1.py'),
- os.path.join(tdir2, 'testfile2.py'),
- os.path.join(tdir3, 'testfile3.py'),
- ]
- _touch_files(files)
- self.assertEqual(
- sorted(
- file_resources.GetCommandLineFiles([self.test_tmpdir],
- recursive=True,
- exclude=None)), sorted(files))
- def test_recursive_find_in_dir_with_exclude(self):
- tdir1 = self._make_test_dir('test1')
- tdir2 = self._make_test_dir('test2/testinner/')
- tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx')
- files = [
- os.path.join(tdir1, 'testfile1.py'),
- os.path.join(tdir2, 'testfile2.py'),
- os.path.join(tdir3, 'testfile3.py'),
- ]
- _touch_files(files)
- self.assertEqual(
- sorted(
- file_resources.GetCommandLineFiles([self.test_tmpdir],
- recursive=True,
- exclude=['*test*3.py'])),
- sorted([
- os.path.join(tdir1, 'testfile1.py'),
- os.path.join(tdir2, 'testfile2.py'),
- ]))
- def test_find_with_excluded_hidden_dirs(self):
- tdir1 = self._make_test_dir('.test1')
- tdir2 = self._make_test_dir('test_2')
- tdir3 = self._make_test_dir('test.3')
- files = [
- os.path.join(tdir1, 'testfile1.py'),
- os.path.join(tdir2, 'testfile2.py'),
- os.path.join(tdir3, 'testfile3.py'),
- ]
- _touch_files(files)
- actual = file_resources.GetCommandLineFiles([self.test_tmpdir],
- recursive=True,
- exclude=['*.test1*'])
- self.assertEqual(
- sorted(actual),
- sorted([
- os.path.join(tdir2, 'testfile2.py'),
- os.path.join(tdir3, 'testfile3.py'),
- ]))
- def test_find_with_excluded_hidden_dirs_relative(self):
- """Test find with excluded hidden dirs.
- A regression test against a specific case where a hidden directory (one
- beginning with a period) is being excluded, but it is also an immediate
- child of the current directory which has been specified in a relative
- manner.
- At its core, the bug has to do with overzealous stripping of "./foo" so that
- it removes too much from "./.foo" .
- """
- tdir1 = self._make_test_dir('.test1')
- tdir2 = self._make_test_dir('test_2')
- tdir3 = self._make_test_dir('test.3')
- files = [
- os.path.join(tdir1, 'testfile1.py'),
- os.path.join(tdir2, 'testfile2.py'),
- os.path.join(tdir3, 'testfile3.py'),
- ]
- _touch_files(files)
- # We must temporarily change the current directory, so that we test against
- # patterns like ./.test1/file instead of /tmp/foo/.test1/file
- with _restore_working_dir():
- os.chdir(self.test_tmpdir)
- actual = file_resources.GetCommandLineFiles(
- [os.path.relpath(self.test_tmpdir)],
- recursive=True,
- exclude=['*.test1*'])
- self.assertEqual(
- sorted(actual),
- sorted([
- os.path.join(
- os.path.relpath(self.test_tmpdir), os.path.basename(tdir2),
- 'testfile2.py'),
- os.path.join(
- os.path.relpath(self.test_tmpdir), os.path.basename(tdir3),
- 'testfile3.py'),
- ]))
- def test_find_with_excluded_dirs(self):
- tdir1 = self._make_test_dir('test1')
- tdir2 = self._make_test_dir('test2/testinner/')
- tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx')
- files = [
- os.path.join(tdir1, 'testfile1.py'),
- os.path.join(tdir2, 'testfile2.py'),
- os.path.join(tdir3, 'testfile3.py'),
- ]
- _touch_files(files)
- os.chdir(self.test_tmpdir)
- found = sorted(
- file_resources.GetCommandLineFiles(['test1', 'test2', 'test3'],
- recursive=True,
- exclude=[
- 'test1',
- 'test2/testinner/',
- ]))
- self.assertEqual(
- found, ['test3/foo/bar/bas/xxx/testfile3.py'.replace('/', os.path.sep)])
- found = sorted(
- file_resources.GetCommandLineFiles(['.'],
- recursive=True,
- exclude=[
- 'test1',
- 'test3',
- ]))
- self.assertEqual(
- found, ['./test2/testinner/testfile2.py'.replace('/', os.path.sep)])
- def test_find_with_excluded_current_dir(self):
- with self.assertRaises(errors.YapfError):
- file_resources.GetCommandLineFiles([], False, exclude=['./z'])
- class IsPythonFileTest(unittest.TestCase):
- def setUp(self): # pylint: disable=g-missing-super-call
- self.test_tmpdir = tempfile.mkdtemp()
- def tearDown(self): # pylint: disable=g-missing-super-call
- shutil.rmtree(self.test_tmpdir)
- def test_with_py_extension(self):
- file1 = os.path.join(self.test_tmpdir, 'testfile1.py')
- self.assertTrue(file_resources.IsPythonFile(file1))
- def test_empty_without_py_extension(self):
- file1 = os.path.join(self.test_tmpdir, 'testfile1')
- self.assertFalse(file_resources.IsPythonFile(file1))
- file2 = os.path.join(self.test_tmpdir, 'testfile1.rb')
- self.assertFalse(file_resources.IsPythonFile(file2))
- def test_python_shebang(self):
- file1 = os.path.join(self.test_tmpdir, 'testfile1')
- with open(file1, 'w') as f:
- f.write('#!/usr/bin/python\n')
- self.assertTrue(file_resources.IsPythonFile(file1))
- file2 = os.path.join(self.test_tmpdir, 'testfile2.run')
- with open(file2, 'w') as f:
- f.write('#! /bin/python2\n')
- self.assertTrue(file_resources.IsPythonFile(file1))
- def test_with_latin_encoding(self):
- file1 = os.path.join(self.test_tmpdir, 'testfile1')
- with codecs.open(file1, mode='w', encoding='latin-1') as f:
- f.write('#! /bin/python2\n')
- self.assertTrue(file_resources.IsPythonFile(file1))
- def test_with_invalid_encoding(self):
- file1 = os.path.join(self.test_tmpdir, 'testfile1')
- with open(file1, 'w') as f:
- f.write('#! /bin/python2\n')
- f.write('# -*- coding: iso-3-14159 -*-\n')
- self.assertFalse(file_resources.IsPythonFile(file1))
- class IsIgnoredTest(unittest.TestCase):
- def test_root_path(self):
- self.assertTrue(file_resources.IsIgnored('media', ['media']))
- self.assertFalse(file_resources.IsIgnored('media', ['media/*']))
- def test_sub_path(self):
- self.assertTrue(file_resources.IsIgnored('media/a', ['*/a']))
- self.assertTrue(file_resources.IsIgnored('media/b', ['media/*']))
- self.assertTrue(file_resources.IsIgnored('media/b/c', ['*/*/c']))
- def test_trailing_slash(self):
- self.assertTrue(file_resources.IsIgnored('z', ['z']))
- self.assertTrue(file_resources.IsIgnored('z', ['z' + os.path.sep]))
- class BufferedByteStream(object):
- def __init__(self):
- self.stream = BytesIO()
- def getvalue(self): # pylint: disable=invalid-name
- return self.stream.getvalue().decode('utf-8')
- @property
- def buffer(self):
- return self.stream
- class WriteReformattedCodeTest(unittest.TestCase):
- @classmethod
- def setUpClass(cls): # pylint: disable=g-missing-super-call
- cls.test_tmpdir = tempfile.mkdtemp()
- @classmethod
- def tearDownClass(cls): # pylint: disable=g-missing-super-call
- shutil.rmtree(cls.test_tmpdir)
- def test_write_to_file(self):
- s = 'foobar\n'
- with utils.NamedTempFile(dirname=self.test_tmpdir) as (f, fname):
- file_resources.WriteReformattedCode(
- fname, s, in_place=True, encoding='utf-8')
- f.flush()
- with open(fname) as f2:
- self.assertEqual(f2.read(), s)
- def test_write_to_stdout(self):
- s = 'foobar'
- stream = BufferedByteStream()
- with utils.stdout_redirector(stream):
- file_resources.WriteReformattedCode(
- None, s, in_place=False, encoding='utf-8')
- self.assertEqual(stream.getvalue(), s)
- def test_write_encoded_to_stdout(self):
- s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa
- stream = BufferedByteStream()
- with utils.stdout_redirector(stream):
- file_resources.WriteReformattedCode(
- None, s, in_place=False, encoding='utf-8')
- self.assertEqual(stream.getvalue(), s)
- class LineEndingTest(unittest.TestCase):
- def test_line_ending_linefeed(self):
- lines = ['spam\n', 'spam\n']
- actual = file_resources.LineEnding(lines)
- self.assertEqual(actual, '\n')
- def test_line_ending_carriage_return(self):
- lines = ['spam\r', 'spam\r']
- actual = file_resources.LineEnding(lines)
- self.assertEqual(actual, '\r')
- def test_line_ending_combo(self):
- lines = ['spam\r\n', 'spam\r\n']
- actual = file_resources.LineEnding(lines)
- self.assertEqual(actual, '\r\n')
- def test_line_ending_weighted(self):
- lines = [
- 'spam\n',
- 'spam\n',
- 'spam\r',
- 'spam\r\n',
- ]
- actual = file_resources.LineEnding(lines)
- self.assertEqual(actual, '\n')
- def test_line_ending_empty(self):
- lines = []
- actual = file_resources.LineEnding(lines)
- self.assertEqual(actual, '\n')
- def test_line_ending_no_newline(self):
- lines = ['spam']
- actual = file_resources.LineEnding(lines)
- self.assertEqual(actual, '\n')
- def test_line_ending_tie(self):
- lines = [
- 'spam\n',
- 'spam\n',
- 'spam\r\n',
- 'spam\r\n',
- ]
- actual = file_resources.LineEnding(lines)
- self.assertEqual(actual, '\n')
- if __name__ == '__main__':
- unittest.main()
|