xref: /aosp_15_r20/external/yapf/yapftests/file_resources_test.py (revision 7249d1a64f4850ccf838e62a46276f891f72998e)
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