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