blob: c879fdd8307ad12dc841dc59d6ba6e06fbc424e5 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test import support
14from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
17from shutil import (_make_tarball, _make_zipfile, make_archive,
18 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
21 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000022import tarfile
23import warnings
24
25from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030026from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Antoine Pitrou7fff0962009-05-01 21:09:44 +000034TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000035
Tarek Ziadé396fad72010-02-23 05:30:31 +000036try:
37 import grp
38 import pwd
39 UID_GID_SUPPORT = True
40except ImportError:
41 UID_GID_SUPPORT = False
42
43try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 import zipfile
45 ZIP_SUPPORT = True
46except ImportError:
47 ZIP_SUPPORT = find_executable('zip')
48
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040049def _fake_rename(*args, **kwargs):
50 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010051 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052
53def mock_rename(func):
54 @functools.wraps(func)
55 def wrap(*args, **kwargs):
56 try:
57 builtin_rename = os.rename
58 os.rename = _fake_rename
59 return func(*args, **kwargs)
60 finally:
61 os.rename = builtin_rename
62 return wrap
63
Éric Araujoa7e33a12011-08-12 19:51:35 +020064def write_file(path, content, binary=False):
65 """Write *content* to a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'wb' if binary else 'w') as fp:
74 fp.write(content)
75
76def read_file(path, binary=False):
77 """Return contents from a file located at *path*.
78
79 If *path* is a tuple instead of a string, os.path.join will be used to
80 make a path. If *binary* is true, the file will be opened in binary
81 mode.
82 """
83 if isinstance(path, tuple):
84 path = os.path.join(*path)
85 with open(path, 'rb' if binary else 'r') as fp:
86 return fp.read()
87
88
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000111 def test_rmtree_errors(self):
112 # filename is guaranteed not to exist
113 filename = tempfile.mktemp()
114 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000115
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000116 # See bug #1071513 for why we don't run this on cygwin
117 # and bug #1076467 for why we don't run this as root.
118 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000119 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000120 def test_on_error(self):
121 self.errorState = 0
122 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200123 self.addCleanup(shutil.rmtree, TESTFN)
124
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200125 self.child_file_path = os.path.join(TESTFN, 'a')
126 self.child_dir_path = os.path.join(TESTFN, 'b')
127 support.create_empty_file(self.child_file_path)
128 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000129 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200130 old_child_file_mode = os.stat(self.child_file_path).st_mode
131 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000132 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200133 new_mode = stat.S_IREAD|stat.S_IEXEC
134 os.chmod(self.child_file_path, new_mode)
135 os.chmod(self.child_dir_path, new_mode)
136 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000137
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200138 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
139 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
140 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
141
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000142 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000143 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200144 self.assertEqual(self.errorState, 3,
145 "Expected call to onerror function did not "
146 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000147
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000148 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000149 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200150 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000151 # This function is run when shutil.rmtree fails.
152 # 99.9% of the time it initially fails to remove
153 # a file in the directory, so the first time through
154 # func is os.remove.
155 # However, some Linux machines running ZFS on
156 # FUSE experienced a failure earlier in the process
157 # at os.listdir. The first failure may legally
158 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200159 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200160 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200161 self.assertEqual(arg, self.child_file_path)
162 elif func is os.rmdir:
163 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000164 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200165 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200166 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000167 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200168 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000169 else:
170 self.assertEqual(func, os.rmdir)
171 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000172 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200173 self.errorState = 3
174
175 def test_rmtree_does_not_choke_on_failing_lstat(self):
176 try:
177 orig_lstat = os.lstat
178 def raiser(fn):
179 if fn != TESTFN:
180 raise OSError()
181 else:
182 return orig_lstat(fn)
183 os.lstat = raiser
184
185 os.mkdir(TESTFN)
186 write_file((TESTFN, 'foo'), 'foo')
187 shutil.rmtree(TESTFN)
188 finally:
189 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000190
Antoine Pitrou78091e62011-12-29 18:54:15 +0100191 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
192 @support.skip_unless_symlink
193 def test_copymode_follow_symlinks(self):
194 tmp_dir = self.mkdtemp()
195 src = os.path.join(tmp_dir, 'foo')
196 dst = os.path.join(tmp_dir, 'bar')
197 src_link = os.path.join(tmp_dir, 'baz')
198 dst_link = os.path.join(tmp_dir, 'quux')
199 write_file(src, 'foo')
200 write_file(dst, 'foo')
201 os.symlink(src, src_link)
202 os.symlink(dst, dst_link)
203 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
204 # file to file
205 os.chmod(dst, stat.S_IRWXO)
206 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
207 shutil.copymode(src, dst)
208 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
209 # follow src link
210 os.chmod(dst, stat.S_IRWXO)
211 shutil.copymode(src_link, dst)
212 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
213 # follow dst link
214 os.chmod(dst, stat.S_IRWXO)
215 shutil.copymode(src, dst_link)
216 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
217 # follow both links
218 os.chmod(dst, stat.S_IRWXO)
219 shutil.copymode(src_link, dst)
220 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
221
222 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
223 @support.skip_unless_symlink
224 def test_copymode_symlink_to_symlink(self):
225 tmp_dir = self.mkdtemp()
226 src = os.path.join(tmp_dir, 'foo')
227 dst = os.path.join(tmp_dir, 'bar')
228 src_link = os.path.join(tmp_dir, 'baz')
229 dst_link = os.path.join(tmp_dir, 'quux')
230 write_file(src, 'foo')
231 write_file(dst, 'foo')
232 os.symlink(src, src_link)
233 os.symlink(dst, dst_link)
234 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
235 os.chmod(dst, stat.S_IRWXU)
236 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
237 # link to link
238 os.lchmod(dst_link, stat.S_IRWXO)
239 shutil.copymode(src_link, dst_link, symlinks=True)
240 self.assertEqual(os.lstat(src_link).st_mode,
241 os.lstat(dst_link).st_mode)
242 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
243 # src link - use chmod
244 os.lchmod(dst_link, stat.S_IRWXO)
245 shutil.copymode(src_link, dst, symlinks=True)
246 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
247 # dst link - use chmod
248 os.lchmod(dst_link, stat.S_IRWXO)
249 shutil.copymode(src, dst_link, symlinks=True)
250 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
251
252 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
253 @support.skip_unless_symlink
254 def test_copymode_symlink_to_symlink_wo_lchmod(self):
255 tmp_dir = self.mkdtemp()
256 src = os.path.join(tmp_dir, 'foo')
257 dst = os.path.join(tmp_dir, 'bar')
258 src_link = os.path.join(tmp_dir, 'baz')
259 dst_link = os.path.join(tmp_dir, 'quux')
260 write_file(src, 'foo')
261 write_file(dst, 'foo')
262 os.symlink(src, src_link)
263 os.symlink(dst, dst_link)
264 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
265
266 @support.skip_unless_symlink
267 def test_copystat_symlinks(self):
268 tmp_dir = self.mkdtemp()
269 src = os.path.join(tmp_dir, 'foo')
270 dst = os.path.join(tmp_dir, 'bar')
271 src_link = os.path.join(tmp_dir, 'baz')
272 dst_link = os.path.join(tmp_dir, 'qux')
273 write_file(src, 'foo')
274 src_stat = os.stat(src)
275 os.utime(src, (src_stat.st_atime,
276 src_stat.st_mtime - 42.0)) # ensure different mtimes
277 write_file(dst, 'bar')
278 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
279 os.symlink(src, src_link)
280 os.symlink(dst, dst_link)
281 if hasattr(os, 'lchmod'):
282 os.lchmod(src_link, stat.S_IRWXO)
283 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
284 os.lchflags(src_link, stat.UF_NODUMP)
285 src_link_stat = os.lstat(src_link)
286 # follow
287 if hasattr(os, 'lchmod'):
288 shutil.copystat(src_link, dst_link, symlinks=False)
289 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
290 # don't follow
291 shutil.copystat(src_link, dst_link, symlinks=True)
292 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700293 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100294 for attr in 'st_atime', 'st_mtime':
295 # The modification times may be truncated in the new file.
296 self.assertLessEqual(getattr(src_link_stat, attr),
297 getattr(dst_link_stat, attr) + 1)
298 if hasattr(os, 'lchmod'):
299 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
300 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
301 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
302 # tell to follow but dst is not a link
303 shutil.copystat(src_link, dst, symlinks=True)
304 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
305 00000.1)
306
Ned Deilybaf75712012-05-10 17:05:19 -0700307 @unittest.skipUnless(hasattr(os, 'chflags') and
308 hasattr(errno, 'EOPNOTSUPP') and
309 hasattr(errno, 'ENOTSUP'),
310 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
311 def test_copystat_handles_harmless_chflags_errors(self):
312 tmpdir = self.mkdtemp()
313 file1 = os.path.join(tmpdir, 'file1')
314 file2 = os.path.join(tmpdir, 'file2')
315 write_file(file1, 'xxx')
316 write_file(file2, 'xxx')
317
318 def make_chflags_raiser(err):
319 ex = OSError()
320
Larry Hastings90867a52012-06-22 17:01:41 -0700321 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700322 ex.errno = err
323 raise ex
324 return _chflags_raiser
325 old_chflags = os.chflags
326 try:
327 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
328 os.chflags = make_chflags_raiser(err)
329 shutil.copystat(file1, file2)
330 # assert others errors break it
331 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
332 self.assertRaises(OSError, shutil.copystat, file1, file2)
333 finally:
334 os.chflags = old_chflags
335
Antoine Pitrou424246f2012-05-12 19:02:01 +0200336 @support.skip_unless_xattr
337 def test_copyxattr(self):
338 tmp_dir = self.mkdtemp()
339 src = os.path.join(tmp_dir, 'foo')
340 write_file(src, 'foo')
341 dst = os.path.join(tmp_dir, 'bar')
342 write_file(dst, 'bar')
343
344 # no xattr == no problem
345 shutil._copyxattr(src, dst)
346 # common case
347 os.setxattr(src, 'user.foo', b'42')
348 os.setxattr(src, 'user.bar', b'43')
349 shutil._copyxattr(src, dst)
350 self.assertEqual(os.listxattr(src), os.listxattr(dst))
351 self.assertEqual(
352 os.getxattr(src, 'user.foo'),
353 os.getxattr(dst, 'user.foo'))
354 # check errors don't affect other attrs
355 os.remove(dst)
356 write_file(dst, 'bar')
357 os_error = OSError(errno.EPERM, 'EPERM')
358
Larry Hastings9cf065c2012-06-22 16:30:09 -0700359 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200360 if attr == 'user.foo':
361 raise os_error
362 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700363 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200364 try:
365 orig_setxattr = os.setxattr
366 os.setxattr = _raise_on_user_foo
367 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200368 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200369 finally:
370 os.setxattr = orig_setxattr
371
372 @support.skip_unless_symlink
373 @support.skip_unless_xattr
374 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
375 'root privileges required')
376 def test_copyxattr_symlinks(self):
377 # On Linux, it's only possible to access non-user xattr for symlinks;
378 # which in turn require root privileges. This test should be expanded
379 # as soon as other platforms gain support for extended attributes.
380 tmp_dir = self.mkdtemp()
381 src = os.path.join(tmp_dir, 'foo')
382 src_link = os.path.join(tmp_dir, 'baz')
383 write_file(src, 'foo')
384 os.symlink(src, src_link)
385 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700386 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200387 dst = os.path.join(tmp_dir, 'bar')
388 dst_link = os.path.join(tmp_dir, 'qux')
389 write_file(dst, 'bar')
390 os.symlink(dst, dst_link)
391 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700392 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200393 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
394 shutil._copyxattr(src_link, dst, symlinks=True)
395 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
396
Antoine Pitrou78091e62011-12-29 18:54:15 +0100397 @support.skip_unless_symlink
398 def test_copy_symlinks(self):
399 tmp_dir = self.mkdtemp()
400 src = os.path.join(tmp_dir, 'foo')
401 dst = os.path.join(tmp_dir, 'bar')
402 src_link = os.path.join(tmp_dir, 'baz')
403 write_file(src, 'foo')
404 os.symlink(src, src_link)
405 if hasattr(os, 'lchmod'):
406 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
407 # don't follow
408 shutil.copy(src_link, dst, symlinks=False)
409 self.assertFalse(os.path.islink(dst))
410 self.assertEqual(read_file(src), read_file(dst))
411 os.remove(dst)
412 # follow
413 shutil.copy(src_link, dst, symlinks=True)
414 self.assertTrue(os.path.islink(dst))
415 self.assertEqual(os.readlink(dst), os.readlink(src_link))
416 if hasattr(os, 'lchmod'):
417 self.assertEqual(os.lstat(src_link).st_mode,
418 os.lstat(dst).st_mode)
419
420 @support.skip_unless_symlink
421 def test_copy2_symlinks(self):
422 tmp_dir = self.mkdtemp()
423 src = os.path.join(tmp_dir, 'foo')
424 dst = os.path.join(tmp_dir, 'bar')
425 src_link = os.path.join(tmp_dir, 'baz')
426 write_file(src, 'foo')
427 os.symlink(src, src_link)
428 if hasattr(os, 'lchmod'):
429 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
430 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
431 os.lchflags(src_link, stat.UF_NODUMP)
432 src_stat = os.stat(src)
433 src_link_stat = os.lstat(src_link)
434 # follow
435 shutil.copy2(src_link, dst, symlinks=False)
436 self.assertFalse(os.path.islink(dst))
437 self.assertEqual(read_file(src), read_file(dst))
438 os.remove(dst)
439 # don't follow
440 shutil.copy2(src_link, dst, symlinks=True)
441 self.assertTrue(os.path.islink(dst))
442 self.assertEqual(os.readlink(dst), os.readlink(src_link))
443 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700444 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100445 for attr in 'st_atime', 'st_mtime':
446 # The modification times may be truncated in the new file.
447 self.assertLessEqual(getattr(src_link_stat, attr),
448 getattr(dst_stat, attr) + 1)
449 if hasattr(os, 'lchmod'):
450 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
451 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
452 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
453 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
454
Antoine Pitrou424246f2012-05-12 19:02:01 +0200455 @support.skip_unless_xattr
456 def test_copy2_xattr(self):
457 tmp_dir = self.mkdtemp()
458 src = os.path.join(tmp_dir, 'foo')
459 dst = os.path.join(tmp_dir, 'bar')
460 write_file(src, 'foo')
461 os.setxattr(src, 'user.foo', b'42')
462 shutil.copy2(src, dst)
463 self.assertEqual(
464 os.getxattr(src, 'user.foo'),
465 os.getxattr(dst, 'user.foo'))
466 os.remove(dst)
467
Antoine Pitrou78091e62011-12-29 18:54:15 +0100468 @support.skip_unless_symlink
469 def test_copyfile_symlinks(self):
470 tmp_dir = self.mkdtemp()
471 src = os.path.join(tmp_dir, 'src')
472 dst = os.path.join(tmp_dir, 'dst')
473 dst_link = os.path.join(tmp_dir, 'dst_link')
474 link = os.path.join(tmp_dir, 'link')
475 write_file(src, 'foo')
476 os.symlink(src, link)
477 # don't follow
478 shutil.copyfile(link, dst_link, symlinks=True)
479 self.assertTrue(os.path.islink(dst_link))
480 self.assertEqual(os.readlink(link), os.readlink(dst_link))
481 # follow
482 shutil.copyfile(link, dst)
483 self.assertFalse(os.path.islink(dst))
484
Hynek Schlawack2100b422012-06-23 20:28:32 +0200485 def test_rmtree_uses_safe_fd_version_if_available(self):
486 if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd:
487 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000488 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200489 tmp_dir = self.mkdtemp()
490 d = os.path.join(tmp_dir, 'a')
491 os.mkdir(d)
492 try:
493 real_rmtree = shutil._rmtree_safe_fd
494 class Called(Exception): pass
495 def _raiser(*args, **kwargs):
496 raise Called
497 shutil._rmtree_safe_fd = _raiser
498 self.assertRaises(Called, shutil.rmtree, d)
499 finally:
500 shutil._rmtree_safe_fd = real_rmtree
501 else:
502 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000503 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200504
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000505 def test_rmtree_dont_delete_file(self):
506 # When called on a file instead of a directory, don't delete it.
507 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200508 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200509 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000510 os.remove(path)
511
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000512 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000513 src_dir = tempfile.mkdtemp()
514 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200515 self.addCleanup(shutil.rmtree, src_dir)
516 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
517 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000518 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200519 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000520
Éric Araujoa7e33a12011-08-12 19:51:35 +0200521 shutil.copytree(src_dir, dst_dir)
522 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
523 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
524 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
525 'test.txt')))
526 actual = read_file((dst_dir, 'test.txt'))
527 self.assertEqual(actual, '123')
528 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
529 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000530
Antoine Pitrou78091e62011-12-29 18:54:15 +0100531 @support.skip_unless_symlink
532 def test_copytree_symlinks(self):
533 tmp_dir = self.mkdtemp()
534 src_dir = os.path.join(tmp_dir, 'src')
535 dst_dir = os.path.join(tmp_dir, 'dst')
536 sub_dir = os.path.join(src_dir, 'sub')
537 os.mkdir(src_dir)
538 os.mkdir(sub_dir)
539 write_file((src_dir, 'file.txt'), 'foo')
540 src_link = os.path.join(sub_dir, 'link')
541 dst_link = os.path.join(dst_dir, 'sub/link')
542 os.symlink(os.path.join(src_dir, 'file.txt'),
543 src_link)
544 if hasattr(os, 'lchmod'):
545 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
546 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
547 os.lchflags(src_link, stat.UF_NODUMP)
548 src_stat = os.lstat(src_link)
549 shutil.copytree(src_dir, dst_dir, symlinks=True)
550 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
551 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
552 os.path.join(src_dir, 'file.txt'))
553 dst_stat = os.lstat(dst_link)
554 if hasattr(os, 'lchmod'):
555 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
556 if hasattr(os, 'lchflags'):
557 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
558
Georg Brandl2ee470f2008-07-16 12:55:28 +0000559 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000560 # creating data
561 join = os.path.join
562 exists = os.path.exists
563 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000564 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000565 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200566 write_file((src_dir, 'test.txt'), '123')
567 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000568 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200569 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000570 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200571 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000572 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
573 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200574 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
575 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000576
577 # testing glob-like patterns
578 try:
579 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
580 shutil.copytree(src_dir, dst_dir, ignore=patterns)
581 # checking the result: some elements should not be copied
582 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200583 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
584 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000585 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200586 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000587 try:
588 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
589 shutil.copytree(src_dir, dst_dir, ignore=patterns)
590 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200591 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
592 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
593 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000594 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200595 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000596
597 # testing callable-style
598 try:
599 def _filter(src, names):
600 res = []
601 for name in names:
602 path = os.path.join(src, name)
603
604 if (os.path.isdir(path) and
605 path.split()[-1] == 'subdir'):
606 res.append(name)
607 elif os.path.splitext(path)[-1] in ('.py'):
608 res.append(name)
609 return res
610
611 shutil.copytree(src_dir, dst_dir, ignore=_filter)
612
613 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200614 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
615 'test.py')))
616 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000617
618 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200619 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000620 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000621 shutil.rmtree(src_dir)
622 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000623
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000624 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000625 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000626 # Temporarily disable test on Windows.
627 if os.name == 'nt':
628 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000629 # bug 851123.
630 os.mkdir(TESTFN)
631 src = os.path.join(TESTFN, 'cheese')
632 dst = os.path.join(TESTFN, 'shop')
633 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000634 with open(src, 'w') as f:
635 f.write('cheddar')
636 os.link(src, dst)
637 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
638 with open(src, 'r') as f:
639 self.assertEqual(f.read(), 'cheddar')
640 os.remove(dst)
641 finally:
642 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000643
Brian Curtin3b4499c2010-12-28 14:31:47 +0000644 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000645 def test_dont_copy_file_onto_symlink_to_itself(self):
646 # bug 851123.
647 os.mkdir(TESTFN)
648 src = os.path.join(TESTFN, 'cheese')
649 dst = os.path.join(TESTFN, 'shop')
650 try:
651 with open(src, 'w') as f:
652 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000653 # Using `src` here would mean we end up with a symlink pointing
654 # to TESTFN/TESTFN/cheese, while it should point at
655 # TESTFN/cheese.
656 os.symlink('cheese', dst)
657 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000658 with open(src, 'r') as f:
659 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000660 os.remove(dst)
661 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000662 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000663
Brian Curtin3b4499c2010-12-28 14:31:47 +0000664 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000665 def test_rmtree_on_symlink(self):
666 # bug 1669.
667 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000668 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000669 src = os.path.join(TESTFN, 'cheese')
670 dst = os.path.join(TESTFN, 'shop')
671 os.mkdir(src)
672 os.symlink(src, dst)
673 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200674 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000675 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000676 shutil.rmtree(TESTFN, ignore_errors=True)
677
678 if hasattr(os, "mkfifo"):
679 # Issue #3002: copyfile and copytree block indefinitely on named pipes
680 def test_copyfile_named_pipe(self):
681 os.mkfifo(TESTFN)
682 try:
683 self.assertRaises(shutil.SpecialFileError,
684 shutil.copyfile, TESTFN, TESTFN2)
685 self.assertRaises(shutil.SpecialFileError,
686 shutil.copyfile, __file__, TESTFN)
687 finally:
688 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000689
Brian Curtin3b4499c2010-12-28 14:31:47 +0000690 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000691 def test_copytree_named_pipe(self):
692 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000693 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000694 subdir = os.path.join(TESTFN, "subdir")
695 os.mkdir(subdir)
696 pipe = os.path.join(subdir, "mypipe")
697 os.mkfifo(pipe)
698 try:
699 shutil.copytree(TESTFN, TESTFN2)
700 except shutil.Error as e:
701 errors = e.args[0]
702 self.assertEqual(len(errors), 1)
703 src, dst, error_msg = errors[0]
704 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
705 else:
706 self.fail("shutil.Error should have been raised")
707 finally:
708 shutil.rmtree(TESTFN, ignore_errors=True)
709 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000710
Tarek Ziadé5340db32010-04-19 22:30:51 +0000711 def test_copytree_special_func(self):
712
713 src_dir = self.mkdtemp()
714 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200715 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000716 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200717 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000718
719 copied = []
720 def _copy(src, dst):
721 copied.append((src, dst))
722
723 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000724 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000725
Brian Curtin3b4499c2010-12-28 14:31:47 +0000726 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000727 def test_copytree_dangling_symlinks(self):
728
729 # a dangling symlink raises an error at the end
730 src_dir = self.mkdtemp()
731 dst_dir = os.path.join(self.mkdtemp(), 'destination')
732 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
733 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200734 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000735 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
736
737 # a dangling symlink is ignored with the proper flag
738 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
739 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
740 self.assertNotIn('test.txt', os.listdir(dst_dir))
741
742 # a dangling symlink is copied if symlinks=True
743 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
744 shutil.copytree(src_dir, dst_dir, symlinks=True)
745 self.assertIn('test.txt', os.listdir(dst_dir))
746
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400747 def _copy_file(self, method):
748 fname = 'test.txt'
749 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200750 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400751 file1 = os.path.join(tmpdir, fname)
752 tmpdir2 = self.mkdtemp()
753 method(file1, tmpdir2)
754 file2 = os.path.join(tmpdir2, fname)
755 return (file1, file2)
756
757 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
758 def test_copy(self):
759 # Ensure that the copied file exists and has the same mode bits.
760 file1, file2 = self._copy_file(shutil.copy)
761 self.assertTrue(os.path.exists(file2))
762 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
763
764 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700765 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400766 def test_copy2(self):
767 # Ensure that the copied file exists and has the same mode and
768 # modification time bits.
769 file1, file2 = self._copy_file(shutil.copy2)
770 self.assertTrue(os.path.exists(file2))
771 file1_stat = os.stat(file1)
772 file2_stat = os.stat(file2)
773 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
774 for attr in 'st_atime', 'st_mtime':
775 # The modification times may be truncated in the new file.
776 self.assertLessEqual(getattr(file1_stat, attr),
777 getattr(file2_stat, attr) + 1)
778 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
779 self.assertEqual(getattr(file1_stat, 'st_flags'),
780 getattr(file2_stat, 'st_flags'))
781
Ezio Melotti975077a2011-05-19 22:03:22 +0300782 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000783 def test_make_tarball(self):
784 # creating something to tar
785 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200786 write_file((tmpdir, 'file1'), 'xxx')
787 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000788 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200789 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000790
791 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400792 # force shutil to create the directory
793 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000794 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
795 "source and target should be on same drive")
796
797 base_name = os.path.join(tmpdir2, 'archive')
798
799 # working with relative paths to avoid tar warnings
800 old_dir = os.getcwd()
801 os.chdir(tmpdir)
802 try:
803 _make_tarball(splitdrive(base_name)[1], '.')
804 finally:
805 os.chdir(old_dir)
806
807 # check if the compressed tarball was created
808 tarball = base_name + '.tar.gz'
809 self.assertTrue(os.path.exists(tarball))
810
811 # trying an uncompressed one
812 base_name = os.path.join(tmpdir2, 'archive')
813 old_dir = os.getcwd()
814 os.chdir(tmpdir)
815 try:
816 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
817 finally:
818 os.chdir(old_dir)
819 tarball = base_name + '.tar'
820 self.assertTrue(os.path.exists(tarball))
821
822 def _tarinfo(self, path):
823 tar = tarfile.open(path)
824 try:
825 names = tar.getnames()
826 names.sort()
827 return tuple(names)
828 finally:
829 tar.close()
830
831 def _create_files(self):
832 # creating something to tar
833 tmpdir = self.mkdtemp()
834 dist = os.path.join(tmpdir, 'dist')
835 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200836 write_file((dist, 'file1'), 'xxx')
837 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000838 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200839 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000840 os.mkdir(os.path.join(dist, 'sub2'))
841 tmpdir2 = self.mkdtemp()
842 base_name = os.path.join(tmpdir2, 'archive')
843 return tmpdir, tmpdir2, base_name
844
Ezio Melotti975077a2011-05-19 22:03:22 +0300845 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000846 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
847 'Need the tar command to run')
848 def test_tarfile_vs_tar(self):
849 tmpdir, tmpdir2, base_name = self._create_files()
850 old_dir = os.getcwd()
851 os.chdir(tmpdir)
852 try:
853 _make_tarball(base_name, 'dist')
854 finally:
855 os.chdir(old_dir)
856
857 # check if the compressed tarball was created
858 tarball = base_name + '.tar.gz'
859 self.assertTrue(os.path.exists(tarball))
860
861 # now create another tarball using `tar`
862 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
863 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
864 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
865 old_dir = os.getcwd()
866 os.chdir(tmpdir)
867 try:
868 with captured_stdout() as s:
869 spawn(tar_cmd)
870 spawn(gzip_cmd)
871 finally:
872 os.chdir(old_dir)
873
874 self.assertTrue(os.path.exists(tarball2))
875 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000876 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000877
878 # trying an uncompressed one
879 base_name = os.path.join(tmpdir2, 'archive')
880 old_dir = os.getcwd()
881 os.chdir(tmpdir)
882 try:
883 _make_tarball(base_name, 'dist', compress=None)
884 finally:
885 os.chdir(old_dir)
886 tarball = base_name + '.tar'
887 self.assertTrue(os.path.exists(tarball))
888
889 # now for a dry_run
890 base_name = os.path.join(tmpdir2, 'archive')
891 old_dir = os.getcwd()
892 os.chdir(tmpdir)
893 try:
894 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
895 finally:
896 os.chdir(old_dir)
897 tarball = base_name + '.tar'
898 self.assertTrue(os.path.exists(tarball))
899
Ezio Melotti975077a2011-05-19 22:03:22 +0300900 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000901 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
902 def test_make_zipfile(self):
903 # creating something to tar
904 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200905 write_file((tmpdir, 'file1'), 'xxx')
906 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000907
908 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400909 # force shutil to create the directory
910 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000911 base_name = os.path.join(tmpdir2, 'archive')
912 _make_zipfile(base_name, tmpdir)
913
914 # check if the compressed tarball was created
915 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000916 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000917
918
919 def test_make_archive(self):
920 tmpdir = self.mkdtemp()
921 base_name = os.path.join(tmpdir, 'archive')
922 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
923
Ezio Melotti975077a2011-05-19 22:03:22 +0300924 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000925 def test_make_archive_owner_group(self):
926 # testing make_archive with owner and group, with various combinations
927 # this works even if there's not gid/uid support
928 if UID_GID_SUPPORT:
929 group = grp.getgrgid(0)[0]
930 owner = pwd.getpwuid(0)[0]
931 else:
932 group = owner = 'root'
933
934 base_dir, root_dir, base_name = self._create_files()
935 base_name = os.path.join(self.mkdtemp() , 'archive')
936 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
937 group=group)
938 self.assertTrue(os.path.exists(res))
939
940 res = make_archive(base_name, 'zip', root_dir, base_dir)
941 self.assertTrue(os.path.exists(res))
942
943 res = make_archive(base_name, 'tar', root_dir, base_dir,
944 owner=owner, group=group)
945 self.assertTrue(os.path.exists(res))
946
947 res = make_archive(base_name, 'tar', root_dir, base_dir,
948 owner='kjhkjhkjg', group='oihohoh')
949 self.assertTrue(os.path.exists(res))
950
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000951
Ezio Melotti975077a2011-05-19 22:03:22 +0300952 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000953 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
954 def test_tarfile_root_owner(self):
955 tmpdir, tmpdir2, base_name = self._create_files()
956 old_dir = os.getcwd()
957 os.chdir(tmpdir)
958 group = grp.getgrgid(0)[0]
959 owner = pwd.getpwuid(0)[0]
960 try:
961 archive_name = _make_tarball(base_name, 'dist', compress=None,
962 owner=owner, group=group)
963 finally:
964 os.chdir(old_dir)
965
966 # check if the compressed tarball was created
967 self.assertTrue(os.path.exists(archive_name))
968
969 # now checks the rights
970 archive = tarfile.open(archive_name)
971 try:
972 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000973 self.assertEqual(member.uid, 0)
974 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000975 finally:
976 archive.close()
977
978 def test_make_archive_cwd(self):
979 current_dir = os.getcwd()
980 def _breaks(*args, **kw):
981 raise RuntimeError()
982
983 register_archive_format('xxx', _breaks, [], 'xxx file')
984 try:
985 try:
986 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
987 except Exception:
988 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000989 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000990 finally:
991 unregister_archive_format('xxx')
992
993 def test_register_archive_format(self):
994
995 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
996 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
997 1)
998 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
999 [(1, 2), (1, 2, 3)])
1000
1001 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1002 formats = [name for name, params in get_archive_formats()]
1003 self.assertIn('xxx', formats)
1004
1005 unregister_archive_format('xxx')
1006 formats = [name for name, params in get_archive_formats()]
1007 self.assertNotIn('xxx', formats)
1008
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001009 def _compare_dirs(self, dir1, dir2):
1010 # check that dir1 and dir2 are equivalent,
1011 # return the diff
1012 diff = []
1013 for root, dirs, files in os.walk(dir1):
1014 for file_ in files:
1015 path = os.path.join(root, file_)
1016 target_path = os.path.join(dir2, os.path.split(path)[-1])
1017 if not os.path.exists(target_path):
1018 diff.append(file_)
1019 return diff
1020
Ezio Melotti975077a2011-05-19 22:03:22 +03001021 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001022 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001023 formats = ['tar', 'gztar', 'zip']
1024 if BZ2_SUPPORTED:
1025 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001026
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001027 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001028 tmpdir = self.mkdtemp()
1029 base_dir, root_dir, base_name = self._create_files()
1030 tmpdir2 = self.mkdtemp()
1031 filename = make_archive(base_name, format, root_dir, base_dir)
1032
1033 # let's try to unpack it now
1034 unpack_archive(filename, tmpdir2)
1035 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001036 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001037
Nick Coghlanabf202d2011-03-16 13:52:20 -04001038 # and again, this time with the format specified
1039 tmpdir3 = self.mkdtemp()
1040 unpack_archive(filename, tmpdir3, format=format)
1041 diff = self._compare_dirs(tmpdir, tmpdir3)
1042 self.assertEqual(diff, [])
1043 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1044 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1045
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001046 def test_unpack_registery(self):
1047
1048 formats = get_unpack_formats()
1049
1050 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001051 self.assertEqual(extra, 1)
1052 self.assertEqual(filename, 'stuff.boo')
1053 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001054
1055 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1056 unpack_archive('stuff.boo', 'xx')
1057
1058 # trying to register a .boo unpacker again
1059 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1060 ['.boo'], _boo)
1061
1062 # should work now
1063 unregister_unpack_format('Boo')
1064 register_unpack_format('Boo2', ['.boo'], _boo)
1065 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1066 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1067
1068 # let's leave a clean state
1069 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001070 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001071
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001072 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1073 "disk_usage not available on this platform")
1074 def test_disk_usage(self):
1075 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001076 self.assertGreater(usage.total, 0)
1077 self.assertGreater(usage.used, 0)
1078 self.assertGreaterEqual(usage.free, 0)
1079 self.assertGreaterEqual(usage.total, usage.used)
1080 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001081
Sandro Tosid902a142011-08-22 23:28:27 +02001082 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1083 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1084 def test_chown(self):
1085
1086 # cleaned-up automatically by TestShutil.tearDown method
1087 dirname = self.mkdtemp()
1088 filename = tempfile.mktemp(dir=dirname)
1089 write_file(filename, 'testing chown function')
1090
1091 with self.assertRaises(ValueError):
1092 shutil.chown(filename)
1093
1094 with self.assertRaises(LookupError):
1095 shutil.chown(filename, user='non-exising username')
1096
1097 with self.assertRaises(LookupError):
1098 shutil.chown(filename, group='non-exising groupname')
1099
1100 with self.assertRaises(TypeError):
1101 shutil.chown(filename, b'spam')
1102
1103 with self.assertRaises(TypeError):
1104 shutil.chown(filename, 3.14)
1105
1106 uid = os.getuid()
1107 gid = os.getgid()
1108
1109 def check_chown(path, uid=None, gid=None):
1110 s = os.stat(filename)
1111 if uid is not None:
1112 self.assertEqual(uid, s.st_uid)
1113 if gid is not None:
1114 self.assertEqual(gid, s.st_gid)
1115
1116 shutil.chown(filename, uid, gid)
1117 check_chown(filename, uid, gid)
1118 shutil.chown(filename, uid)
1119 check_chown(filename, uid)
1120 shutil.chown(filename, user=uid)
1121 check_chown(filename, uid)
1122 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001123 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001124
1125 shutil.chown(dirname, uid, gid)
1126 check_chown(dirname, uid, gid)
1127 shutil.chown(dirname, uid)
1128 check_chown(dirname, uid)
1129 shutil.chown(dirname, user=uid)
1130 check_chown(dirname, uid)
1131 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001132 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001133
1134 user = pwd.getpwuid(uid)[0]
1135 group = grp.getgrgid(gid)[0]
1136 shutil.chown(filename, user, group)
1137 check_chown(filename, uid, gid)
1138 shutil.chown(dirname, user, group)
1139 check_chown(dirname, uid, gid)
1140
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001141 def test_copy_return_value(self):
1142 # copy and copy2 both return their destination path.
1143 for fn in (shutil.copy, shutil.copy2):
1144 src_dir = self.mkdtemp()
1145 dst_dir = self.mkdtemp()
1146 src = os.path.join(src_dir, 'foo')
1147 write_file(src, 'foo')
1148 rv = fn(src, dst_dir)
1149 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1150 rv = fn(src, os.path.join(dst_dir, 'bar'))
1151 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1152
1153 def test_copyfile_return_value(self):
1154 # copytree returns its destination path.
1155 src_dir = self.mkdtemp()
1156 dst_dir = self.mkdtemp()
1157 dst_file = os.path.join(dst_dir, 'bar')
1158 src_file = os.path.join(src_dir, 'foo')
1159 write_file(src_file, 'foo')
1160 rv = shutil.copyfile(src_file, dst_file)
1161 self.assertTrue(os.path.exists(rv))
1162 self.assertEqual(read_file(src_file), read_file(dst_file))
1163
1164 def test_copytree_return_value(self):
1165 # copytree returns its destination path.
1166 src_dir = self.mkdtemp()
1167 dst_dir = src_dir + "dest"
1168 src = os.path.join(src_dir, 'foo')
1169 write_file(src, 'foo')
1170 rv = shutil.copytree(src_dir, dst_dir)
1171 self.assertEqual(['foo'], os.listdir(rv))
1172
Christian Heimes9bd667a2008-01-20 15:14:11 +00001173
Brian Curtinc57a3452012-06-22 16:00:30 -05001174class TestWhich(unittest.TestCase):
1175
1176 def setUp(self):
1177 self.temp_dir = tempfile.mkdtemp()
1178 # Give the temp_file an ".exe" suffix for all.
1179 # It's needed on Windows and not harmful on other platforms.
1180 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1181 suffix=".exe")
1182 os.chmod(self.temp_file.name, stat.S_IXUSR)
1183 self.addCleanup(self.temp_file.close)
1184 self.dir, self.file = os.path.split(self.temp_file.name)
1185
1186 def test_basic(self):
1187 # Given an EXE in a directory, it should be returned.
1188 rv = shutil.which(self.file, path=self.dir)
1189 self.assertEqual(rv, self.temp_file.name)
1190
1191 def test_full_path_short_circuit(self):
1192 # When given the fully qualified path to an executable that exists,
1193 # it should be returned.
1194 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1195 self.assertEqual(self.temp_file.name, rv)
1196
1197 def test_non_matching_mode(self):
1198 # Set the file read-only and ask for writeable files.
1199 os.chmod(self.temp_file.name, stat.S_IREAD)
1200 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1201 self.assertIsNone(rv)
1202
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001203 def test_relative(self):
1204 old_cwd = os.getcwd()
1205 base_dir, tail_dir = os.path.split(self.dir)
1206 os.chdir(base_dir)
1207 try:
1208 rv = shutil.which(self.file, path=tail_dir)
1209 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1210 finally:
1211 os.chdir(old_cwd)
1212
Brian Curtinc57a3452012-06-22 16:00:30 -05001213 def test_nonexistent_file(self):
1214 # Return None when no matching executable file is found on the path.
1215 rv = shutil.which("foo.exe", path=self.dir)
1216 self.assertIsNone(rv)
1217
1218 @unittest.skipUnless(sys.platform == "win32",
1219 "pathext check is Windows-only")
1220 def test_pathext_checking(self):
1221 # Ask for the file without the ".exe" extension, then ensure that
1222 # it gets found properly with the extension.
1223 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1224 self.assertEqual(self.temp_file.name, rv)
1225
1226
Christian Heimesada8c3b2008-03-18 18:26:33 +00001227class TestMove(unittest.TestCase):
1228
1229 def setUp(self):
1230 filename = "foo"
1231 self.src_dir = tempfile.mkdtemp()
1232 self.dst_dir = tempfile.mkdtemp()
1233 self.src_file = os.path.join(self.src_dir, filename)
1234 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001235 with open(self.src_file, "wb") as f:
1236 f.write(b"spam")
1237
1238 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001239 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001240 try:
1241 if d:
1242 shutil.rmtree(d)
1243 except:
1244 pass
1245
1246 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001247 with open(src, "rb") as f:
1248 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001249 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001250 with open(real_dst, "rb") as f:
1251 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001252 self.assertFalse(os.path.exists(src))
1253
1254 def _check_move_dir(self, src, dst, real_dst):
1255 contents = sorted(os.listdir(src))
1256 shutil.move(src, dst)
1257 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1258 self.assertFalse(os.path.exists(src))
1259
1260 def test_move_file(self):
1261 # Move a file to another location on the same filesystem.
1262 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1263
1264 def test_move_file_to_dir(self):
1265 # Move a file inside an existing dir on the same filesystem.
1266 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1267
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001268 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001269 def test_move_file_other_fs(self):
1270 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001271 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001272
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001273 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001274 def test_move_file_to_dir_other_fs(self):
1275 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001276 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001277
1278 def test_move_dir(self):
1279 # Move a dir to another location on the same filesystem.
1280 dst_dir = tempfile.mktemp()
1281 try:
1282 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1283 finally:
1284 try:
1285 shutil.rmtree(dst_dir)
1286 except:
1287 pass
1288
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001289 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001290 def test_move_dir_other_fs(self):
1291 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001292 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001293
1294 def test_move_dir_to_dir(self):
1295 # Move a dir inside an existing dir on the same filesystem.
1296 self._check_move_dir(self.src_dir, self.dst_dir,
1297 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1298
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001299 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001300 def test_move_dir_to_dir_other_fs(self):
1301 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001302 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001303
1304 def test_existing_file_inside_dest_dir(self):
1305 # A file with the same name inside the destination dir already exists.
1306 with open(self.dst_file, "wb"):
1307 pass
1308 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1309
1310 def test_dont_move_dir_in_itself(self):
1311 # Moving a dir inside itself raises an Error.
1312 dst = os.path.join(self.src_dir, "bar")
1313 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1314
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001315 def test_destinsrc_false_negative(self):
1316 os.mkdir(TESTFN)
1317 try:
1318 for src, dst in [('srcdir', 'srcdir/dest')]:
1319 src = os.path.join(TESTFN, src)
1320 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001321 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001322 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001323 'dst (%s) is not in src (%s)' % (dst, src))
1324 finally:
1325 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001326
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001327 def test_destinsrc_false_positive(self):
1328 os.mkdir(TESTFN)
1329 try:
1330 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1331 src = os.path.join(TESTFN, src)
1332 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001333 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001334 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001335 'dst (%s) is in src (%s)' % (dst, src))
1336 finally:
1337 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001338
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001339 @support.skip_unless_symlink
1340 @mock_rename
1341 def test_move_file_symlink(self):
1342 dst = os.path.join(self.src_dir, 'bar')
1343 os.symlink(self.src_file, dst)
1344 shutil.move(dst, self.dst_file)
1345 self.assertTrue(os.path.islink(self.dst_file))
1346 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1347
1348 @support.skip_unless_symlink
1349 @mock_rename
1350 def test_move_file_symlink_to_dir(self):
1351 filename = "bar"
1352 dst = os.path.join(self.src_dir, filename)
1353 os.symlink(self.src_file, dst)
1354 shutil.move(dst, self.dst_dir)
1355 final_link = os.path.join(self.dst_dir, filename)
1356 self.assertTrue(os.path.islink(final_link))
1357 self.assertTrue(os.path.samefile(self.src_file, final_link))
1358
1359 @support.skip_unless_symlink
1360 @mock_rename
1361 def test_move_dangling_symlink(self):
1362 src = os.path.join(self.src_dir, 'baz')
1363 dst = os.path.join(self.src_dir, 'bar')
1364 os.symlink(src, dst)
1365 dst_link = os.path.join(self.dst_dir, 'quux')
1366 shutil.move(dst, dst_link)
1367 self.assertTrue(os.path.islink(dst_link))
1368 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1369
1370 @support.skip_unless_symlink
1371 @mock_rename
1372 def test_move_dir_symlink(self):
1373 src = os.path.join(self.src_dir, 'baz')
1374 dst = os.path.join(self.src_dir, 'bar')
1375 os.mkdir(src)
1376 os.symlink(src, dst)
1377 dst_link = os.path.join(self.dst_dir, 'quux')
1378 shutil.move(dst, dst_link)
1379 self.assertTrue(os.path.islink(dst_link))
1380 self.assertTrue(os.path.samefile(src, dst_link))
1381
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001382 def test_move_return_value(self):
1383 rv = shutil.move(self.src_file, self.dst_dir)
1384 self.assertEqual(rv,
1385 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1386
1387 def test_move_as_rename_return_value(self):
1388 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1389 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1390
Tarek Ziadé5340db32010-04-19 22:30:51 +00001391
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001392class TestCopyFile(unittest.TestCase):
1393
1394 _delete = False
1395
1396 class Faux(object):
1397 _entered = False
1398 _exited_with = None
1399 _raised = False
1400 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1401 self._raise_in_exit = raise_in_exit
1402 self._suppress_at_exit = suppress_at_exit
1403 def read(self, *args):
1404 return ''
1405 def __enter__(self):
1406 self._entered = True
1407 def __exit__(self, exc_type, exc_val, exc_tb):
1408 self._exited_with = exc_type, exc_val, exc_tb
1409 if self._raise_in_exit:
1410 self._raised = True
1411 raise IOError("Cannot close")
1412 return self._suppress_at_exit
1413
1414 def tearDown(self):
1415 if self._delete:
1416 del shutil.open
1417
1418 def _set_shutil_open(self, func):
1419 shutil.open = func
1420 self._delete = True
1421
1422 def test_w_source_open_fails(self):
1423 def _open(filename, mode='r'):
1424 if filename == 'srcfile':
1425 raise IOError('Cannot open "srcfile"')
1426 assert 0 # shouldn't reach here.
1427
1428 self._set_shutil_open(_open)
1429
1430 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1431
1432 def test_w_dest_open_fails(self):
1433
1434 srcfile = self.Faux()
1435
1436 def _open(filename, mode='r'):
1437 if filename == 'srcfile':
1438 return srcfile
1439 if filename == 'destfile':
1440 raise IOError('Cannot open "destfile"')
1441 assert 0 # shouldn't reach here.
1442
1443 self._set_shutil_open(_open)
1444
1445 shutil.copyfile('srcfile', 'destfile')
1446 self.assertTrue(srcfile._entered)
1447 self.assertTrue(srcfile._exited_with[0] is IOError)
1448 self.assertEqual(srcfile._exited_with[1].args,
1449 ('Cannot open "destfile"',))
1450
1451 def test_w_dest_close_fails(self):
1452
1453 srcfile = self.Faux()
1454 destfile = self.Faux(True)
1455
1456 def _open(filename, mode='r'):
1457 if filename == 'srcfile':
1458 return srcfile
1459 if filename == 'destfile':
1460 return destfile
1461 assert 0 # shouldn't reach here.
1462
1463 self._set_shutil_open(_open)
1464
1465 shutil.copyfile('srcfile', 'destfile')
1466 self.assertTrue(srcfile._entered)
1467 self.assertTrue(destfile._entered)
1468 self.assertTrue(destfile._raised)
1469 self.assertTrue(srcfile._exited_with[0] is IOError)
1470 self.assertEqual(srcfile._exited_with[1].args,
1471 ('Cannot close',))
1472
1473 def test_w_source_close_fails(self):
1474
1475 srcfile = self.Faux(True)
1476 destfile = self.Faux()
1477
1478 def _open(filename, mode='r'):
1479 if filename == 'srcfile':
1480 return srcfile
1481 if filename == 'destfile':
1482 return destfile
1483 assert 0 # shouldn't reach here.
1484
1485 self._set_shutil_open(_open)
1486
1487 self.assertRaises(IOError,
1488 shutil.copyfile, 'srcfile', 'destfile')
1489 self.assertTrue(srcfile._entered)
1490 self.assertTrue(destfile._entered)
1491 self.assertFalse(destfile._raised)
1492 self.assertTrue(srcfile._exited_with[0] is None)
1493 self.assertTrue(srcfile._raised)
1494
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001495 def test_move_dir_caseinsensitive(self):
1496 # Renames a folder to the same name
1497 # but a different case.
1498
1499 self.src_dir = tempfile.mkdtemp()
1500 dst_dir = os.path.join(
1501 os.path.dirname(self.src_dir),
1502 os.path.basename(self.src_dir).upper())
1503 self.assertNotEqual(self.src_dir, dst_dir)
1504
1505 try:
1506 shutil.move(self.src_dir, dst_dir)
1507 self.assertTrue(os.path.isdir(dst_dir))
1508 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001509 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001510
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001511class TermsizeTests(unittest.TestCase):
1512 def test_does_not_crash(self):
1513 """Check if get_terminal_size() returns a meaningful value.
1514
1515 There's no easy portable way to actually check the size of the
1516 terminal, so let's check if it returns something sensible instead.
1517 """
1518 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001519 self.assertGreaterEqual(size.columns, 0)
1520 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001521
1522 def test_os_environ_first(self):
1523 "Check if environment variables have precedence"
1524
1525 with support.EnvironmentVarGuard() as env:
1526 env['COLUMNS'] = '777'
1527 size = shutil.get_terminal_size()
1528 self.assertEqual(size.columns, 777)
1529
1530 with support.EnvironmentVarGuard() as env:
1531 env['LINES'] = '888'
1532 size = shutil.get_terminal_size()
1533 self.assertEqual(size.lines, 888)
1534
1535 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1536 def test_stty_match(self):
1537 """Check if stty returns the same results ignoring env
1538
1539 This test will fail if stdin and stdout are connected to
1540 different terminals with different sizes. Nevertheless, such
1541 situations should be pretty rare.
1542 """
1543 try:
1544 size = subprocess.check_output(['stty', 'size']).decode().split()
1545 except (FileNotFoundError, subprocess.CalledProcessError):
1546 self.skipTest("stty invocation failed")
1547 expected = (int(size[1]), int(size[0])) # reversed order
1548
1549 with support.EnvironmentVarGuard() as env:
1550 del env['LINES']
1551 del env['COLUMNS']
1552 actual = shutil.get_terminal_size()
1553
1554 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001555
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001556
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001557def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001558 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001559 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001560
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001561if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001562 test_main()