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_maybe_make_directory__success(self): 187 fs = FileSystem() 188 189 with fs.mkdtemp(prefix='filesystem_unittest_') as base_path: 190 sub_path = os.path.join(base_path, "newdir") 191 self.assertFalse(os.path.exists(sub_path)) 192 self.assertFalse(fs.isdir(sub_path)) 193 194 fs.maybe_make_directory(sub_path) 195 self.assertTrue(os.path.exists(sub_path)) 196 self.assertTrue(fs.isdir(sub_path)) 197 198 # Make sure we can re-create it. 199 fs.maybe_make_directory(sub_path) 200 self.assertTrue(os.path.exists(sub_path)) 201 self.assertTrue(fs.isdir(sub_path)) 202 203 # Clean up. 204 os.rmdir(sub_path) 205 206 self.assertFalse(os.path.exists(base_path)) 207 self.assertFalse(fs.isdir(base_path)) 208 209 def test_maybe_make_directory__failure(self): 210 # FIXME: os.chmod() doesn't work on Windows to set directories 211 # as readonly, so we skip this test for now. 212 if sys.platform in ('win32', 'cygwin'): 213 return 214 215 fs = FileSystem() 216 with fs.mkdtemp(prefix='filesystem_unittest_') as d: 217 # Remove write permissions on the parent directory. 218 os.chmod(d, stat.S_IRUSR) 219 220 # Now try to create a sub directory - should fail. 221 sub_dir = fs.join(d, 'subdir') 222 self.assertRaises(OSError, fs.maybe_make_directory, sub_dir) 223 224 # Clean up in case the test failed and we did create the 225 # directory. 226 if os.path.exists(sub_dir): 227 os.rmdir(sub_dir) 228 229 def test_read_and_write_text_file(self): 230 fs = FileSystem() 231 text_path = None 232 233 unicode_text_string = u'\u016An\u012Dc\u014Dde\u033D' 234 hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD' 235 try: 236 text_path = tempfile.mktemp(prefix='tree_unittest_') 237 file = fs.open_text_file_for_writing(text_path) 238 file.write(unicode_text_string) 239 file.close() 240 241 file = fs.open_text_file_for_reading(text_path) 242 read_text = file.read() 243 file.close() 244 245 self.assertEqual(read_text, unicode_text_string) 246 finally: 247 if text_path and fs.isfile(text_path): 248 os.remove(text_path) 249 250 def test_read_and_write_file(self): 251 fs = FileSystem() 252 text_path = None 253 binary_path = None 254 255 unicode_text_string = u'\u016An\u012Dc\u014Dde\u033D' 256 hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD' 257 try: 258 text_path = tempfile.mktemp(prefix='tree_unittest_') 259 binary_path = tempfile.mktemp(prefix='tree_unittest_') 260 fs.write_text_file(text_path, unicode_text_string) 261 contents = fs.read_binary_file(text_path) 262 self.assertEqual(contents, hex_equivalent) 263 264 fs.write_binary_file(binary_path, hex_equivalent) 265 text_contents = fs.read_text_file(binary_path) 266 self.assertEqual(text_contents, unicode_text_string) 267 finally: 268 if text_path and fs.isfile(text_path): 269 os.remove(text_path) 270 if binary_path and fs.isfile(binary_path): 271 os.remove(binary_path) 272 273 def test_read_binary_file__missing(self): 274 fs = FileSystem() 275 self.assertRaises(IOError, fs.read_binary_file, self._missing_file) 276 277 def test_read_text_file__missing(self): 278 fs = FileSystem() 279 self.assertRaises(IOError, fs.read_text_file, self._missing_file) 280 281 def test_remove_file_with_retry(self): 282 RealFileSystemTest._remove_failures = 2 283 284 def remove_with_exception(filename): 285 RealFileSystemTest._remove_failures -= 1 286 if RealFileSystemTest._remove_failures >= 0: 287 try: 288 raise WindowsError 289 except NameError: 290 raise FileSystem._WindowsError 291 292 fs = FileSystem() 293 self.assertTrue(fs.remove('filename', remove_with_exception)) 294 self.assertEqual(-1, RealFileSystemTest._remove_failures) 295 296 def test_sep(self): 297 fs = FileSystem() 298 299 self.assertEqual(fs.sep, os.sep) 300 self.assertEqual(fs.join("foo", "bar"), 301 os.path.join("foo", "bar")) 302