Home | History | Annotate | Download | only in system
      1 # vim: set fileencoding=utf-8 :
      2 # Copyright (C) 2010 Google Inc. All rights reserved.
      3 #
      4 # Redistribution and use in source and binary forms, with or without
      5 # modification, are permitted provided that the following conditions are
      6 # met:
      7 #
      8 #    * Redistributions of source code must retain the above copyright
      9 # notice, this list of conditions and the following disclaimer.
     10 #    * Redistributions in binary form must reproduce the above
     11 # copyright notice, this list of conditions and the following disclaimer
     12 # in the documentation and/or other materials provided with the
     13 # distribution.
     14 #    * Neither the name of Google Inc. nor the names of its
     15 # contributors may be used to endorse or promote products derived from
     16 # this software without specific prior written permission.
     17 #
     18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 # NOTE: The fileencoding comment on the first line of the file is
     31 # important; without it, Python will choke while trying to parse the file,
     32 # since it includes non-ASCII characters.
     33 
     34 import os
     35 import stat
     36 import sys
     37 import tempfile
     38 import webkitpy.thirdparty.unittest2 as unittest
     39 
     40 from webkitpy.common.system.filesystem import FileSystem
     41 
     42 
     43 class GenericFileSystemTests(object):
     44     """Tests that should pass on either a real or mock filesystem."""
     45     # pylint gets confused about this being a mixin: pylint: disable=E1101
     46     def setup_generic_test_dir(self):
     47         fs = self.fs
     48         self.generic_test_dir = str(self.fs.mkdtemp())
     49         self.orig_cwd = fs.getcwd()
     50         fs.chdir(self.generic_test_dir)
     51         fs.write_text_file('foo.txt', 'foo')
     52         fs.write_text_file('foobar', 'foobar')
     53         fs.maybe_make_directory('foodir')
     54         fs.write_text_file(fs.join('foodir', 'baz'), 'baz')
     55         fs.chdir(self.orig_cwd)
     56 
     57     def teardown_generic_test_dir(self):
     58         self.fs.rmtree(self.generic_test_dir)
     59         self.fs.chdir(self.orig_cwd)
     60         self.generic_test_dir = None
     61 
     62     def test_glob__trailing_asterisk(self):
     63         self.fs.chdir(self.generic_test_dir)
     64         self.assertEqual(set(self.fs.glob('fo*')), set(['foo.txt', 'foobar', 'foodir']))
     65 
     66     def test_glob__leading_asterisk(self):
     67         self.fs.chdir(self.generic_test_dir)
     68         self.assertEqual(set(self.fs.glob('*xt')), set(['foo.txt']))
     69 
     70     def test_glob__middle_asterisk(self):
     71         self.fs.chdir(self.generic_test_dir)
     72         self.assertEqual(set(self.fs.glob('f*r')), set(['foobar', 'foodir']))
     73 
     74     def test_glob__period_is_escaped(self):
     75         self.fs.chdir(self.generic_test_dir)
     76         self.assertEqual(set(self.fs.glob('foo.*')), set(['foo.txt']))
     77 
     78     def test_relpath_unix(self):
     79         if sys.platform == 'win32':
     80             return
     81         self.assertEqual(self.fs.relpath('aaa/bbb'), 'aaa/bbb')
     82         self.assertEqual(self.fs.relpath('aaa/bbb/'), 'aaa/bbb')
     83         self.assertEqual(self.fs.relpath('aaa/bbb/.'), 'aaa/bbb')
     84         self.assertEqual(self.fs.relpath('aaa/./bbb'), 'aaa/bbb')
     85         self.assertEqual(self.fs.relpath('aaa/../bbb/'), 'bbb')
     86         self.assertEqual(self.fs.relpath('aaa/bbb', 'aaa/bbb'), '.')
     87         self.assertEqual(self.fs.relpath('aaa/bbb/ccc', 'aaa/bbb'), 'ccc')
     88         self.assertEqual(self.fs.relpath('aaa/./ccc', 'aaa/bbb'), '../ccc')
     89         self.assertEqual(self.fs.relpath('aaa/../ccc', 'aaa/bbb'), '../../ccc')
     90         self.assertEqual(self.fs.relpath('aaa/bbb', 'aaa/ccc'), '../bbb')
     91         self.assertEqual(self.fs.relpath('aaa/bbb', 'ccc/ddd'), '../../aaa/bbb')
     92         self.assertEqual(self.fs.relpath('aaa/bbb', 'aaa/b'), '../bbb')
     93         self.assertEqual(self.fs.relpath('aaa/bbb', 'a/bbb'), '../../aaa/bbb')
     94 
     95     def test_relpath_win32(self):
     96         if sys.platform != 'win32':
     97             return
     98         self.assertEqual(self.fs.relpath('aaa\\bbb'), 'aaa\\bbb')
     99         self.assertEqual(self.fs.relpath('aaa\\bbb\\'), 'aaa\\bbb')
    100         self.assertEqual(self.fs.relpath('aaa\\bbb\\.'), 'aaa\\bbb')
    101         self.assertEqual(self.fs.relpath('aaa\\.\\bbb'), 'aaa\\bbb')
    102         self.assertEqual(self.fs.relpath('aaa\\..\\bbb\\'), 'bbb')
    103         self.assertEqual(self.fs.relpath('aaa\\bbb', 'aaa\\bbb'), '.')
    104         self.assertEqual(self.fs.relpath('aaa\\bbb\\ccc', 'aaa\\bbb'), 'ccc')
    105         self.assertEqual(self.fs.relpath('aaa\\.\\ccc', 'aaa\\bbb'), '..\\ccc')
    106         self.assertEqual(self.fs.relpath('aaa\\..\\ccc', 'aaa\\bbb'), '..\\..\\ccc')
    107         self.assertEqual(self.fs.relpath('aaa\\bbb', 'aaa\\ccc'), '..\\bbb')
    108         self.assertEqual(self.fs.relpath('aaa\\bbb', 'ccc\\ddd'), '..\\..\\aaa\\bbb')
    109         self.assertEqual(self.fs.relpath('aaa\\bbb', 'aaa\\b'), '..\\bbb')
    110         self.assertEqual(self.fs.relpath('aaa\\bbb', 'a\\bbb'), '..\\..\\aaa\\bbb')
    111 
    112     def test_rmtree(self):
    113         self.fs.chdir(self.generic_test_dir)
    114         self.fs.rmtree('foo')
    115         self.assertTrue(self.fs.exists('foodir'))
    116         self.assertTrue(self.fs.exists(self.fs.join('foodir', 'baz')))
    117         self.fs.rmtree('foodir')
    118         self.assertFalse(self.fs.exists('foodir'))
    119         self.assertFalse(self.fs.exists(self.fs.join('foodir', 'baz')))
    120 
    121 
    122 class RealFileSystemTest(unittest.TestCase, GenericFileSystemTests):
    123     def setUp(self):
    124         self.fs = FileSystem()
    125         self.setup_generic_test_dir()
    126 
    127         self._this_dir = os.path.dirname(os.path.abspath(__file__))
    128         self._missing_file = os.path.join(self._this_dir, 'missing_file.py')
    129         self._this_file = os.path.join(self._this_dir, 'filesystem_unittest.py')
    130 
    131     def tearDown(self):
    132         self.teardown_generic_test_dir()
    133         self.fs = None
    134 
    135     def test_chdir(self):
    136         fs = FileSystem()
    137         cwd = fs.getcwd()
    138         newdir = '/'
    139         if sys.platform == 'win32':
    140             newdir = 'c:\\'
    141         fs.chdir(newdir)
    142         self.assertEqual(fs.getcwd(), newdir)
    143         fs.chdir(cwd)
    144 
    145     def test_chdir__notexists(self):
    146         fs = FileSystem()
    147         newdir = '/dirdoesnotexist'
    148         if sys.platform == 'win32':
    149             newdir = 'c:\\dirdoesnotexist'
    150         self.assertRaises(OSError, fs.chdir, newdir)
    151 
    152     def test_exists__true(self):
    153         fs = FileSystem()
    154         self.assertTrue(fs.exists(self._this_file))
    155 
    156     def test_exists__false(self):
    157         fs = FileSystem()
    158         self.assertFalse(fs.exists(self._missing_file))
    159 
    160     def test_getcwd(self):
    161         fs = FileSystem()
    162         self.assertTrue(fs.exists(fs.getcwd()))
    163 
    164     def test_isdir__true(self):
    165         fs = FileSystem()
    166         self.assertTrue(fs.isdir(self._this_dir))
    167 
    168     def test_isdir__false(self):
    169         fs = FileSystem()
    170         self.assertFalse(fs.isdir(self._this_file))
    171 
    172     def test_join(self):
    173         fs = FileSystem()
    174         self.assertEqual(fs.join('foo', 'bar'),
    175                          os.path.join('foo', 'bar'))
    176 
    177     def test_listdir(self):
    178         fs = FileSystem()
    179         with fs.mkdtemp(prefix='filesystem_unittest_') as d:
    180             self.assertEqual(fs.listdir(d), [])
    181             new_file = os.path.join(d, 'foo')
    182             fs.write_text_file(new_file, u'foo')
    183             self.assertEqual(fs.listdir(d), ['foo'])
    184             os.remove(new_file)
    185 
    186     def test_walk(self):
    187         fs = FileSystem()
    188         with fs.mkdtemp(prefix='filesystem_unittest_') as d:
    189             self.assertEqual(list(fs.walk(d)), [(d, [], [])])
    190             new_file = os.path.join(d, 'foo')
    191             fs.write_text_file(new_file, u'foo')
    192             self.assertEqual(list(fs.walk(d)), [(d, [], ['foo'])])
    193             os.remove(new_file)
    194 
    195     def test_maybe_make_directory__success(self):
    196         fs = FileSystem()
    197 
    198         with fs.mkdtemp(prefix='filesystem_unittest_') as base_path:
    199             sub_path = os.path.join(base_path, "newdir")
    200             self.assertFalse(os.path.exists(sub_path))
    201             self.assertFalse(fs.isdir(sub_path))
    202 
    203             fs.maybe_make_directory(sub_path)
    204             self.assertTrue(os.path.exists(sub_path))
    205             self.assertTrue(fs.isdir(sub_path))
    206 
    207             # Make sure we can re-create it.
    208             fs.maybe_make_directory(sub_path)
    209             self.assertTrue(os.path.exists(sub_path))
    210             self.assertTrue(fs.isdir(sub_path))
    211 
    212             # Clean up.
    213             os.rmdir(sub_path)
    214 
    215         self.assertFalse(os.path.exists(base_path))
    216         self.assertFalse(fs.isdir(base_path))
    217 
    218     def test_maybe_make_directory__failure(self):
    219         # FIXME: os.chmod() doesn't work on Windows to set directories
    220         # as readonly, so we skip this test for now.
    221         if sys.platform in ('win32', 'cygwin'):
    222             return
    223 
    224         fs = FileSystem()
    225         with fs.mkdtemp(prefix='filesystem_unittest_') as d:
    226             # Remove write permissions on the parent directory.
    227             os.chmod(d, stat.S_IRUSR)
    228 
    229             # Now try to create a sub directory - should fail.
    230             sub_dir = fs.join(d, 'subdir')
    231             self.assertRaises(OSError, fs.maybe_make_directory, sub_dir)
    232 
    233             # Clean up in case the test failed and we did create the
    234             # directory.
    235             if os.path.exists(sub_dir):
    236                 os.rmdir(sub_dir)
    237 
    238     def test_read_and_write_text_file(self):
    239         fs = FileSystem()
    240         text_path = None
    241 
    242         unicode_text_string = u'\u016An\u012Dc\u014Dde\u033D'
    243         hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD'
    244         try:
    245             text_path = tempfile.mktemp(prefix='tree_unittest_')
    246             file = fs.open_text_file_for_writing(text_path)
    247             file.write(unicode_text_string)
    248             file.close()
    249 
    250             file = fs.open_text_file_for_reading(text_path)
    251             read_text = file.read()
    252             file.close()
    253 
    254             self.assertEqual(read_text, unicode_text_string)
    255         finally:
    256             if text_path and fs.isfile(text_path):
    257                 os.remove(text_path)
    258 
    259     def test_read_and_write_file(self):
    260         fs = FileSystem()
    261         text_path = None
    262         binary_path = None
    263 
    264         unicode_text_string = u'\u016An\u012Dc\u014Dde\u033D'
    265         hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD'
    266         try:
    267             text_path = tempfile.mktemp(prefix='tree_unittest_')
    268             binary_path = tempfile.mktemp(prefix='tree_unittest_')
    269             fs.write_text_file(text_path, unicode_text_string)
    270             contents = fs.read_binary_file(text_path)
    271             self.assertEqual(contents, hex_equivalent)
    272 
    273             fs.write_binary_file(binary_path, hex_equivalent)
    274             text_contents = fs.read_text_file(binary_path)
    275             self.assertEqual(text_contents, unicode_text_string)
    276         finally:
    277             if text_path and fs.isfile(text_path):
    278                 os.remove(text_path)
    279             if binary_path and fs.isfile(binary_path):
    280                 os.remove(binary_path)
    281 
    282     def test_read_binary_file__missing(self):
    283         fs = FileSystem()
    284         self.assertRaises(IOError, fs.read_binary_file, self._missing_file)
    285 
    286     def test_read_text_file__missing(self):
    287         fs = FileSystem()
    288         self.assertRaises(IOError, fs.read_text_file, self._missing_file)
    289 
    290     def test_remove_file_with_retry(self):
    291         RealFileSystemTest._remove_failures = 2
    292 
    293         def remove_with_exception(filename):
    294             RealFileSystemTest._remove_failures -= 1
    295             if RealFileSystemTest._remove_failures >= 0:
    296                 try:
    297                     raise WindowsError
    298                 except NameError:
    299                     raise FileSystem._WindowsError
    300 
    301         fs = FileSystem()
    302         self.assertTrue(fs.remove('filename', remove_with_exception))
    303         self.assertEqual(-1, RealFileSystemTest._remove_failures)
    304 
    305     def test_sep(self):
    306         fs = FileSystem()
    307 
    308         self.assertEqual(fs.sep, os.sep)
    309         self.assertEqual(fs.join("foo", "bar"),
    310                           os.path.join("foo", "bar"))
    311