blob: d23deee62496ab29e520958e4854bda00d981a59 [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
Hynek Schlawack3b527782012-06-25 13:27:31 +0200111 def test_rmtree_works_on_bytes(self):
112 tmp = self.mkdtemp()
113 victim = os.path.join(tmp, 'killme')
114 os.mkdir(victim)
115 write_file(os.path.join(victim, 'somefile'), 'foo')
116 victim = os.fsencode(victim)
117 self.assertIsInstance(victim, bytes)
118 shutil.rmtree(victim)
119
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000120 def test_rmtree_errors(self):
121 # filename is guaranteed not to exist
122 filename = tempfile.mktemp()
123 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000124
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000125 # See bug #1071513 for why we don't run this on cygwin
126 # and bug #1076467 for why we don't run this as root.
127 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000128 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000129 def test_on_error(self):
130 self.errorState = 0
131 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200132 self.addCleanup(shutil.rmtree, TESTFN)
133
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200134 self.child_file_path = os.path.join(TESTFN, 'a')
135 self.child_dir_path = os.path.join(TESTFN, 'b')
136 support.create_empty_file(self.child_file_path)
137 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000138 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200139 old_child_file_mode = os.stat(self.child_file_path).st_mode
140 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000141 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200142 new_mode = stat.S_IREAD|stat.S_IEXEC
143 os.chmod(self.child_file_path, new_mode)
144 os.chmod(self.child_dir_path, new_mode)
145 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000146
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200147 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
148 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
149 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
150
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000151 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000152 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200153 self.assertEqual(self.errorState, 3,
154 "Expected call to onerror function did not "
155 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000156
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000157 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000158 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200159 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000160 # This function is run when shutil.rmtree fails.
161 # 99.9% of the time it initially fails to remove
162 # a file in the directory, so the first time through
163 # func is os.remove.
164 # However, some Linux machines running ZFS on
165 # FUSE experienced a failure earlier in the process
166 # at os.listdir. The first failure may legally
167 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200168 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200169 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200170 self.assertEqual(arg, self.child_file_path)
171 elif func is os.rmdir:
172 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000173 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200174 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200175 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000176 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200177 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000178 else:
179 self.assertEqual(func, os.rmdir)
180 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000181 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200182 self.errorState = 3
183
184 def test_rmtree_does_not_choke_on_failing_lstat(self):
185 try:
186 orig_lstat = os.lstat
187 def raiser(fn):
188 if fn != TESTFN:
189 raise OSError()
190 else:
191 return orig_lstat(fn)
192 os.lstat = raiser
193
194 os.mkdir(TESTFN)
195 write_file((TESTFN, 'foo'), 'foo')
196 shutil.rmtree(TESTFN)
197 finally:
198 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000199
Antoine Pitrou78091e62011-12-29 18:54:15 +0100200 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
201 @support.skip_unless_symlink
202 def test_copymode_follow_symlinks(self):
203 tmp_dir = self.mkdtemp()
204 src = os.path.join(tmp_dir, 'foo')
205 dst = os.path.join(tmp_dir, 'bar')
206 src_link = os.path.join(tmp_dir, 'baz')
207 dst_link = os.path.join(tmp_dir, 'quux')
208 write_file(src, 'foo')
209 write_file(dst, 'foo')
210 os.symlink(src, src_link)
211 os.symlink(dst, dst_link)
212 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
213 # file to file
214 os.chmod(dst, stat.S_IRWXO)
215 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
216 shutil.copymode(src, dst)
217 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
218 # follow src link
219 os.chmod(dst, stat.S_IRWXO)
220 shutil.copymode(src_link, dst)
221 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
222 # follow dst link
223 os.chmod(dst, stat.S_IRWXO)
224 shutil.copymode(src, dst_link)
225 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
226 # follow both links
227 os.chmod(dst, stat.S_IRWXO)
228 shutil.copymode(src_link, dst)
229 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
230
231 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
232 @support.skip_unless_symlink
233 def test_copymode_symlink_to_symlink(self):
234 tmp_dir = self.mkdtemp()
235 src = os.path.join(tmp_dir, 'foo')
236 dst = os.path.join(tmp_dir, 'bar')
237 src_link = os.path.join(tmp_dir, 'baz')
238 dst_link = os.path.join(tmp_dir, 'quux')
239 write_file(src, 'foo')
240 write_file(dst, 'foo')
241 os.symlink(src, src_link)
242 os.symlink(dst, dst_link)
243 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
244 os.chmod(dst, stat.S_IRWXU)
245 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
246 # link to link
247 os.lchmod(dst_link, stat.S_IRWXO)
248 shutil.copymode(src_link, dst_link, symlinks=True)
249 self.assertEqual(os.lstat(src_link).st_mode,
250 os.lstat(dst_link).st_mode)
251 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
252 # src link - use chmod
253 os.lchmod(dst_link, stat.S_IRWXO)
254 shutil.copymode(src_link, dst, symlinks=True)
255 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
256 # dst link - use chmod
257 os.lchmod(dst_link, stat.S_IRWXO)
258 shutil.copymode(src, dst_link, symlinks=True)
259 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
260
261 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
262 @support.skip_unless_symlink
263 def test_copymode_symlink_to_symlink_wo_lchmod(self):
264 tmp_dir = self.mkdtemp()
265 src = os.path.join(tmp_dir, 'foo')
266 dst = os.path.join(tmp_dir, 'bar')
267 src_link = os.path.join(tmp_dir, 'baz')
268 dst_link = os.path.join(tmp_dir, 'quux')
269 write_file(src, 'foo')
270 write_file(dst, 'foo')
271 os.symlink(src, src_link)
272 os.symlink(dst, dst_link)
273 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
274
275 @support.skip_unless_symlink
276 def test_copystat_symlinks(self):
277 tmp_dir = self.mkdtemp()
278 src = os.path.join(tmp_dir, 'foo')
279 dst = os.path.join(tmp_dir, 'bar')
280 src_link = os.path.join(tmp_dir, 'baz')
281 dst_link = os.path.join(tmp_dir, 'qux')
282 write_file(src, 'foo')
283 src_stat = os.stat(src)
284 os.utime(src, (src_stat.st_atime,
285 src_stat.st_mtime - 42.0)) # ensure different mtimes
286 write_file(dst, 'bar')
287 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
288 os.symlink(src, src_link)
289 os.symlink(dst, dst_link)
290 if hasattr(os, 'lchmod'):
291 os.lchmod(src_link, stat.S_IRWXO)
292 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
293 os.lchflags(src_link, stat.UF_NODUMP)
294 src_link_stat = os.lstat(src_link)
295 # follow
296 if hasattr(os, 'lchmod'):
297 shutil.copystat(src_link, dst_link, symlinks=False)
298 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
299 # don't follow
300 shutil.copystat(src_link, dst_link, symlinks=True)
301 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700302 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100303 for attr in 'st_atime', 'st_mtime':
304 # The modification times may be truncated in the new file.
305 self.assertLessEqual(getattr(src_link_stat, attr),
306 getattr(dst_link_stat, attr) + 1)
307 if hasattr(os, 'lchmod'):
308 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
309 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
310 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
311 # tell to follow but dst is not a link
312 shutil.copystat(src_link, dst, symlinks=True)
313 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
314 00000.1)
315
Ned Deilybaf75712012-05-10 17:05:19 -0700316 @unittest.skipUnless(hasattr(os, 'chflags') and
317 hasattr(errno, 'EOPNOTSUPP') and
318 hasattr(errno, 'ENOTSUP'),
319 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
320 def test_copystat_handles_harmless_chflags_errors(self):
321 tmpdir = self.mkdtemp()
322 file1 = os.path.join(tmpdir, 'file1')
323 file2 = os.path.join(tmpdir, 'file2')
324 write_file(file1, 'xxx')
325 write_file(file2, 'xxx')
326
327 def make_chflags_raiser(err):
328 ex = OSError()
329
Larry Hastings90867a52012-06-22 17:01:41 -0700330 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700331 ex.errno = err
332 raise ex
333 return _chflags_raiser
334 old_chflags = os.chflags
335 try:
336 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
337 os.chflags = make_chflags_raiser(err)
338 shutil.copystat(file1, file2)
339 # assert others errors break it
340 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
341 self.assertRaises(OSError, shutil.copystat, file1, file2)
342 finally:
343 os.chflags = old_chflags
344
Antoine Pitrou424246f2012-05-12 19:02:01 +0200345 @support.skip_unless_xattr
346 def test_copyxattr(self):
347 tmp_dir = self.mkdtemp()
348 src = os.path.join(tmp_dir, 'foo')
349 write_file(src, 'foo')
350 dst = os.path.join(tmp_dir, 'bar')
351 write_file(dst, 'bar')
352
353 # no xattr == no problem
354 shutil._copyxattr(src, dst)
355 # common case
356 os.setxattr(src, 'user.foo', b'42')
357 os.setxattr(src, 'user.bar', b'43')
358 shutil._copyxattr(src, dst)
359 self.assertEqual(os.listxattr(src), os.listxattr(dst))
360 self.assertEqual(
361 os.getxattr(src, 'user.foo'),
362 os.getxattr(dst, 'user.foo'))
363 # check errors don't affect other attrs
364 os.remove(dst)
365 write_file(dst, 'bar')
366 os_error = OSError(errno.EPERM, 'EPERM')
367
Larry Hastings9cf065c2012-06-22 16:30:09 -0700368 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200369 if attr == 'user.foo':
370 raise os_error
371 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700372 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200373 try:
374 orig_setxattr = os.setxattr
375 os.setxattr = _raise_on_user_foo
376 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200377 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200378 finally:
379 os.setxattr = orig_setxattr
380
381 @support.skip_unless_symlink
382 @support.skip_unless_xattr
383 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
384 'root privileges required')
385 def test_copyxattr_symlinks(self):
386 # On Linux, it's only possible to access non-user xattr for symlinks;
387 # which in turn require root privileges. This test should be expanded
388 # as soon as other platforms gain support for extended attributes.
389 tmp_dir = self.mkdtemp()
390 src = os.path.join(tmp_dir, 'foo')
391 src_link = os.path.join(tmp_dir, 'baz')
392 write_file(src, 'foo')
393 os.symlink(src, src_link)
394 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700395 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200396 dst = os.path.join(tmp_dir, 'bar')
397 dst_link = os.path.join(tmp_dir, 'qux')
398 write_file(dst, 'bar')
399 os.symlink(dst, dst_link)
400 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700401 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200402 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
403 shutil._copyxattr(src_link, dst, symlinks=True)
404 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
405
Antoine Pitrou78091e62011-12-29 18:54:15 +0100406 @support.skip_unless_symlink
407 def test_copy_symlinks(self):
408 tmp_dir = self.mkdtemp()
409 src = os.path.join(tmp_dir, 'foo')
410 dst = os.path.join(tmp_dir, 'bar')
411 src_link = os.path.join(tmp_dir, 'baz')
412 write_file(src, 'foo')
413 os.symlink(src, src_link)
414 if hasattr(os, 'lchmod'):
415 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
416 # don't follow
417 shutil.copy(src_link, dst, symlinks=False)
418 self.assertFalse(os.path.islink(dst))
419 self.assertEqual(read_file(src), read_file(dst))
420 os.remove(dst)
421 # follow
422 shutil.copy(src_link, dst, symlinks=True)
423 self.assertTrue(os.path.islink(dst))
424 self.assertEqual(os.readlink(dst), os.readlink(src_link))
425 if hasattr(os, 'lchmod'):
426 self.assertEqual(os.lstat(src_link).st_mode,
427 os.lstat(dst).st_mode)
428
429 @support.skip_unless_symlink
430 def test_copy2_symlinks(self):
431 tmp_dir = self.mkdtemp()
432 src = os.path.join(tmp_dir, 'foo')
433 dst = os.path.join(tmp_dir, 'bar')
434 src_link = os.path.join(tmp_dir, 'baz')
435 write_file(src, 'foo')
436 os.symlink(src, src_link)
437 if hasattr(os, 'lchmod'):
438 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
439 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
440 os.lchflags(src_link, stat.UF_NODUMP)
441 src_stat = os.stat(src)
442 src_link_stat = os.lstat(src_link)
443 # follow
444 shutil.copy2(src_link, dst, symlinks=False)
445 self.assertFalse(os.path.islink(dst))
446 self.assertEqual(read_file(src), read_file(dst))
447 os.remove(dst)
448 # don't follow
449 shutil.copy2(src_link, dst, symlinks=True)
450 self.assertTrue(os.path.islink(dst))
451 self.assertEqual(os.readlink(dst), os.readlink(src_link))
452 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700453 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100454 for attr in 'st_atime', 'st_mtime':
455 # The modification times may be truncated in the new file.
456 self.assertLessEqual(getattr(src_link_stat, attr),
457 getattr(dst_stat, attr) + 1)
458 if hasattr(os, 'lchmod'):
459 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
460 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
461 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
462 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
463
Antoine Pitrou424246f2012-05-12 19:02:01 +0200464 @support.skip_unless_xattr
465 def test_copy2_xattr(self):
466 tmp_dir = self.mkdtemp()
467 src = os.path.join(tmp_dir, 'foo')
468 dst = os.path.join(tmp_dir, 'bar')
469 write_file(src, 'foo')
470 os.setxattr(src, 'user.foo', b'42')
471 shutil.copy2(src, dst)
472 self.assertEqual(
473 os.getxattr(src, 'user.foo'),
474 os.getxattr(dst, 'user.foo'))
475 os.remove(dst)
476
Antoine Pitrou78091e62011-12-29 18:54:15 +0100477 @support.skip_unless_symlink
478 def test_copyfile_symlinks(self):
479 tmp_dir = self.mkdtemp()
480 src = os.path.join(tmp_dir, 'src')
481 dst = os.path.join(tmp_dir, 'dst')
482 dst_link = os.path.join(tmp_dir, 'dst_link')
483 link = os.path.join(tmp_dir, 'link')
484 write_file(src, 'foo')
485 os.symlink(src, link)
486 # don't follow
487 shutil.copyfile(link, dst_link, symlinks=True)
488 self.assertTrue(os.path.islink(dst_link))
489 self.assertEqual(os.readlink(link), os.readlink(dst_link))
490 # follow
491 shutil.copyfile(link, dst)
492 self.assertFalse(os.path.islink(dst))
493
Hynek Schlawack2100b422012-06-23 20:28:32 +0200494 def test_rmtree_uses_safe_fd_version_if_available(self):
495 if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd:
496 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000497 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200498 tmp_dir = self.mkdtemp()
499 d = os.path.join(tmp_dir, 'a')
500 os.mkdir(d)
501 try:
502 real_rmtree = shutil._rmtree_safe_fd
503 class Called(Exception): pass
504 def _raiser(*args, **kwargs):
505 raise Called
506 shutil._rmtree_safe_fd = _raiser
507 self.assertRaises(Called, shutil.rmtree, d)
508 finally:
509 shutil._rmtree_safe_fd = real_rmtree
510 else:
511 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000512 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200513
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000514 def test_rmtree_dont_delete_file(self):
515 # When called on a file instead of a directory, don't delete it.
516 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200517 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200518 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000519 os.remove(path)
520
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000521 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000522 src_dir = tempfile.mkdtemp()
523 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200524 self.addCleanup(shutil.rmtree, src_dir)
525 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
526 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000527 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200528 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000529
Éric Araujoa7e33a12011-08-12 19:51:35 +0200530 shutil.copytree(src_dir, dst_dir)
531 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
532 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
533 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
534 'test.txt')))
535 actual = read_file((dst_dir, 'test.txt'))
536 self.assertEqual(actual, '123')
537 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
538 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000539
Antoine Pitrou78091e62011-12-29 18:54:15 +0100540 @support.skip_unless_symlink
541 def test_copytree_symlinks(self):
542 tmp_dir = self.mkdtemp()
543 src_dir = os.path.join(tmp_dir, 'src')
544 dst_dir = os.path.join(tmp_dir, 'dst')
545 sub_dir = os.path.join(src_dir, 'sub')
546 os.mkdir(src_dir)
547 os.mkdir(sub_dir)
548 write_file((src_dir, 'file.txt'), 'foo')
549 src_link = os.path.join(sub_dir, 'link')
550 dst_link = os.path.join(dst_dir, 'sub/link')
551 os.symlink(os.path.join(src_dir, 'file.txt'),
552 src_link)
553 if hasattr(os, 'lchmod'):
554 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
555 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
556 os.lchflags(src_link, stat.UF_NODUMP)
557 src_stat = os.lstat(src_link)
558 shutil.copytree(src_dir, dst_dir, symlinks=True)
559 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
560 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
561 os.path.join(src_dir, 'file.txt'))
562 dst_stat = os.lstat(dst_link)
563 if hasattr(os, 'lchmod'):
564 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
565 if hasattr(os, 'lchflags'):
566 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
567
Georg Brandl2ee470f2008-07-16 12:55:28 +0000568 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000569 # creating data
570 join = os.path.join
571 exists = os.path.exists
572 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000573 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000574 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200575 write_file((src_dir, 'test.txt'), '123')
576 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000577 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200578 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000579 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200580 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000581 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
582 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200583 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
584 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000585
586 # testing glob-like patterns
587 try:
588 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
589 shutil.copytree(src_dir, dst_dir, ignore=patterns)
590 # checking the result: some elements should not be copied
591 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200592 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
593 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
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 try:
597 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
598 shutil.copytree(src_dir, dst_dir, ignore=patterns)
599 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200600 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
601 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
602 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000603 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200604 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000605
606 # testing callable-style
607 try:
608 def _filter(src, names):
609 res = []
610 for name in names:
611 path = os.path.join(src, name)
612
613 if (os.path.isdir(path) and
614 path.split()[-1] == 'subdir'):
615 res.append(name)
616 elif os.path.splitext(path)[-1] in ('.py'):
617 res.append(name)
618 return res
619
620 shutil.copytree(src_dir, dst_dir, ignore=_filter)
621
622 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200623 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
624 'test.py')))
625 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000626
627 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200628 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000629 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000630 shutil.rmtree(src_dir)
631 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000632
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000633 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000634 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000635 # Temporarily disable test on Windows.
636 if os.name == 'nt':
637 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000638 # bug 851123.
639 os.mkdir(TESTFN)
640 src = os.path.join(TESTFN, 'cheese')
641 dst = os.path.join(TESTFN, 'shop')
642 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000643 with open(src, 'w') as f:
644 f.write('cheddar')
645 os.link(src, dst)
646 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
647 with open(src, 'r') as f:
648 self.assertEqual(f.read(), 'cheddar')
649 os.remove(dst)
650 finally:
651 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000652
Brian Curtin3b4499c2010-12-28 14:31:47 +0000653 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000654 def test_dont_copy_file_onto_symlink_to_itself(self):
655 # bug 851123.
656 os.mkdir(TESTFN)
657 src = os.path.join(TESTFN, 'cheese')
658 dst = os.path.join(TESTFN, 'shop')
659 try:
660 with open(src, 'w') as f:
661 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000662 # Using `src` here would mean we end up with a symlink pointing
663 # to TESTFN/TESTFN/cheese, while it should point at
664 # TESTFN/cheese.
665 os.symlink('cheese', dst)
666 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000667 with open(src, 'r') as f:
668 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000669 os.remove(dst)
670 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000671 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000672
Brian Curtin3b4499c2010-12-28 14:31:47 +0000673 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000674 def test_rmtree_on_symlink(self):
675 # bug 1669.
676 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000677 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000678 src = os.path.join(TESTFN, 'cheese')
679 dst = os.path.join(TESTFN, 'shop')
680 os.mkdir(src)
681 os.symlink(src, dst)
682 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200683 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000684 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000685 shutil.rmtree(TESTFN, ignore_errors=True)
686
687 if hasattr(os, "mkfifo"):
688 # Issue #3002: copyfile and copytree block indefinitely on named pipes
689 def test_copyfile_named_pipe(self):
690 os.mkfifo(TESTFN)
691 try:
692 self.assertRaises(shutil.SpecialFileError,
693 shutil.copyfile, TESTFN, TESTFN2)
694 self.assertRaises(shutil.SpecialFileError,
695 shutil.copyfile, __file__, TESTFN)
696 finally:
697 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000698
Brian Curtin3b4499c2010-12-28 14:31:47 +0000699 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000700 def test_copytree_named_pipe(self):
701 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000702 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000703 subdir = os.path.join(TESTFN, "subdir")
704 os.mkdir(subdir)
705 pipe = os.path.join(subdir, "mypipe")
706 os.mkfifo(pipe)
707 try:
708 shutil.copytree(TESTFN, TESTFN2)
709 except shutil.Error as e:
710 errors = e.args[0]
711 self.assertEqual(len(errors), 1)
712 src, dst, error_msg = errors[0]
713 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
714 else:
715 self.fail("shutil.Error should have been raised")
716 finally:
717 shutil.rmtree(TESTFN, ignore_errors=True)
718 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000719
Tarek Ziadé5340db32010-04-19 22:30:51 +0000720 def test_copytree_special_func(self):
721
722 src_dir = self.mkdtemp()
723 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200724 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000725 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200726 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000727
728 copied = []
729 def _copy(src, dst):
730 copied.append((src, dst))
731
732 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000733 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000734
Brian Curtin3b4499c2010-12-28 14:31:47 +0000735 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000736 def test_copytree_dangling_symlinks(self):
737
738 # a dangling symlink raises an error at the end
739 src_dir = self.mkdtemp()
740 dst_dir = os.path.join(self.mkdtemp(), 'destination')
741 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
742 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200743 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000744 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
745
746 # a dangling symlink is ignored with the proper flag
747 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
748 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
749 self.assertNotIn('test.txt', os.listdir(dst_dir))
750
751 # a dangling symlink is copied if symlinks=True
752 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
753 shutil.copytree(src_dir, dst_dir, symlinks=True)
754 self.assertIn('test.txt', os.listdir(dst_dir))
755
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400756 def _copy_file(self, method):
757 fname = 'test.txt'
758 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200759 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400760 file1 = os.path.join(tmpdir, fname)
761 tmpdir2 = self.mkdtemp()
762 method(file1, tmpdir2)
763 file2 = os.path.join(tmpdir2, fname)
764 return (file1, file2)
765
766 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
767 def test_copy(self):
768 # Ensure that the copied file exists and has the same mode bits.
769 file1, file2 = self._copy_file(shutil.copy)
770 self.assertTrue(os.path.exists(file2))
771 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
772
773 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700774 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400775 def test_copy2(self):
776 # Ensure that the copied file exists and has the same mode and
777 # modification time bits.
778 file1, file2 = self._copy_file(shutil.copy2)
779 self.assertTrue(os.path.exists(file2))
780 file1_stat = os.stat(file1)
781 file2_stat = os.stat(file2)
782 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
783 for attr in 'st_atime', 'st_mtime':
784 # The modification times may be truncated in the new file.
785 self.assertLessEqual(getattr(file1_stat, attr),
786 getattr(file2_stat, attr) + 1)
787 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
788 self.assertEqual(getattr(file1_stat, 'st_flags'),
789 getattr(file2_stat, 'st_flags'))
790
Ezio Melotti975077a2011-05-19 22:03:22 +0300791 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000792 def test_make_tarball(self):
793 # creating something to tar
794 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200795 write_file((tmpdir, 'file1'), 'xxx')
796 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000797 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200798 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000799
800 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400801 # force shutil to create the directory
802 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000803 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
804 "source and target should be on same drive")
805
806 base_name = os.path.join(tmpdir2, 'archive')
807
808 # working with relative paths to avoid tar warnings
809 old_dir = os.getcwd()
810 os.chdir(tmpdir)
811 try:
812 _make_tarball(splitdrive(base_name)[1], '.')
813 finally:
814 os.chdir(old_dir)
815
816 # check if the compressed tarball was created
817 tarball = base_name + '.tar.gz'
818 self.assertTrue(os.path.exists(tarball))
819
820 # trying an uncompressed one
821 base_name = os.path.join(tmpdir2, 'archive')
822 old_dir = os.getcwd()
823 os.chdir(tmpdir)
824 try:
825 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
826 finally:
827 os.chdir(old_dir)
828 tarball = base_name + '.tar'
829 self.assertTrue(os.path.exists(tarball))
830
831 def _tarinfo(self, path):
832 tar = tarfile.open(path)
833 try:
834 names = tar.getnames()
835 names.sort()
836 return tuple(names)
837 finally:
838 tar.close()
839
840 def _create_files(self):
841 # creating something to tar
842 tmpdir = self.mkdtemp()
843 dist = os.path.join(tmpdir, 'dist')
844 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200845 write_file((dist, 'file1'), 'xxx')
846 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000847 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200848 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000849 os.mkdir(os.path.join(dist, 'sub2'))
850 tmpdir2 = self.mkdtemp()
851 base_name = os.path.join(tmpdir2, 'archive')
852 return tmpdir, tmpdir2, base_name
853
Ezio Melotti975077a2011-05-19 22:03:22 +0300854 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000855 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
856 'Need the tar command to run')
857 def test_tarfile_vs_tar(self):
858 tmpdir, tmpdir2, base_name = self._create_files()
859 old_dir = os.getcwd()
860 os.chdir(tmpdir)
861 try:
862 _make_tarball(base_name, 'dist')
863 finally:
864 os.chdir(old_dir)
865
866 # check if the compressed tarball was created
867 tarball = base_name + '.tar.gz'
868 self.assertTrue(os.path.exists(tarball))
869
870 # now create another tarball using `tar`
871 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
872 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
873 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
874 old_dir = os.getcwd()
875 os.chdir(tmpdir)
876 try:
877 with captured_stdout() as s:
878 spawn(tar_cmd)
879 spawn(gzip_cmd)
880 finally:
881 os.chdir(old_dir)
882
883 self.assertTrue(os.path.exists(tarball2))
884 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000885 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000886
887 # trying an uncompressed one
888 base_name = os.path.join(tmpdir2, 'archive')
889 old_dir = os.getcwd()
890 os.chdir(tmpdir)
891 try:
892 _make_tarball(base_name, 'dist', compress=None)
893 finally:
894 os.chdir(old_dir)
895 tarball = base_name + '.tar'
896 self.assertTrue(os.path.exists(tarball))
897
898 # now for a dry_run
899 base_name = os.path.join(tmpdir2, 'archive')
900 old_dir = os.getcwd()
901 os.chdir(tmpdir)
902 try:
903 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
904 finally:
905 os.chdir(old_dir)
906 tarball = base_name + '.tar'
907 self.assertTrue(os.path.exists(tarball))
908
Ezio Melotti975077a2011-05-19 22:03:22 +0300909 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
911 def test_make_zipfile(self):
912 # creating something to tar
913 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200914 write_file((tmpdir, 'file1'), 'xxx')
915 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000916
917 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400918 # force shutil to create the directory
919 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000920 base_name = os.path.join(tmpdir2, 'archive')
921 _make_zipfile(base_name, tmpdir)
922
923 # check if the compressed tarball was created
924 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000925 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000926
927
928 def test_make_archive(self):
929 tmpdir = self.mkdtemp()
930 base_name = os.path.join(tmpdir, 'archive')
931 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
932
Ezio Melotti975077a2011-05-19 22:03:22 +0300933 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000934 def test_make_archive_owner_group(self):
935 # testing make_archive with owner and group, with various combinations
936 # this works even if there's not gid/uid support
937 if UID_GID_SUPPORT:
938 group = grp.getgrgid(0)[0]
939 owner = pwd.getpwuid(0)[0]
940 else:
941 group = owner = 'root'
942
943 base_dir, root_dir, base_name = self._create_files()
944 base_name = os.path.join(self.mkdtemp() , 'archive')
945 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
946 group=group)
947 self.assertTrue(os.path.exists(res))
948
949 res = make_archive(base_name, 'zip', root_dir, base_dir)
950 self.assertTrue(os.path.exists(res))
951
952 res = make_archive(base_name, 'tar', root_dir, base_dir,
953 owner=owner, group=group)
954 self.assertTrue(os.path.exists(res))
955
956 res = make_archive(base_name, 'tar', root_dir, base_dir,
957 owner='kjhkjhkjg', group='oihohoh')
958 self.assertTrue(os.path.exists(res))
959
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000960
Ezio Melotti975077a2011-05-19 22:03:22 +0300961 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000962 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
963 def test_tarfile_root_owner(self):
964 tmpdir, tmpdir2, base_name = self._create_files()
965 old_dir = os.getcwd()
966 os.chdir(tmpdir)
967 group = grp.getgrgid(0)[0]
968 owner = pwd.getpwuid(0)[0]
969 try:
970 archive_name = _make_tarball(base_name, 'dist', compress=None,
971 owner=owner, group=group)
972 finally:
973 os.chdir(old_dir)
974
975 # check if the compressed tarball was created
976 self.assertTrue(os.path.exists(archive_name))
977
978 # now checks the rights
979 archive = tarfile.open(archive_name)
980 try:
981 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000982 self.assertEqual(member.uid, 0)
983 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000984 finally:
985 archive.close()
986
987 def test_make_archive_cwd(self):
988 current_dir = os.getcwd()
989 def _breaks(*args, **kw):
990 raise RuntimeError()
991
992 register_archive_format('xxx', _breaks, [], 'xxx file')
993 try:
994 try:
995 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
996 except Exception:
997 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000998 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000999 finally:
1000 unregister_archive_format('xxx')
1001
1002 def test_register_archive_format(self):
1003
1004 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1005 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1006 1)
1007 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1008 [(1, 2), (1, 2, 3)])
1009
1010 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1011 formats = [name for name, params in get_archive_formats()]
1012 self.assertIn('xxx', formats)
1013
1014 unregister_archive_format('xxx')
1015 formats = [name for name, params in get_archive_formats()]
1016 self.assertNotIn('xxx', formats)
1017
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001018 def _compare_dirs(self, dir1, dir2):
1019 # check that dir1 and dir2 are equivalent,
1020 # return the diff
1021 diff = []
1022 for root, dirs, files in os.walk(dir1):
1023 for file_ in files:
1024 path = os.path.join(root, file_)
1025 target_path = os.path.join(dir2, os.path.split(path)[-1])
1026 if not os.path.exists(target_path):
1027 diff.append(file_)
1028 return diff
1029
Ezio Melotti975077a2011-05-19 22:03:22 +03001030 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001031 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001032 formats = ['tar', 'gztar', 'zip']
1033 if BZ2_SUPPORTED:
1034 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001035
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001036 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001037 tmpdir = self.mkdtemp()
1038 base_dir, root_dir, base_name = self._create_files()
1039 tmpdir2 = self.mkdtemp()
1040 filename = make_archive(base_name, format, root_dir, base_dir)
1041
1042 # let's try to unpack it now
1043 unpack_archive(filename, tmpdir2)
1044 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001045 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001046
Nick Coghlanabf202d2011-03-16 13:52:20 -04001047 # and again, this time with the format specified
1048 tmpdir3 = self.mkdtemp()
1049 unpack_archive(filename, tmpdir3, format=format)
1050 diff = self._compare_dirs(tmpdir, tmpdir3)
1051 self.assertEqual(diff, [])
1052 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1053 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1054
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001055 def test_unpack_registery(self):
1056
1057 formats = get_unpack_formats()
1058
1059 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001060 self.assertEqual(extra, 1)
1061 self.assertEqual(filename, 'stuff.boo')
1062 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001063
1064 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1065 unpack_archive('stuff.boo', 'xx')
1066
1067 # trying to register a .boo unpacker again
1068 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1069 ['.boo'], _boo)
1070
1071 # should work now
1072 unregister_unpack_format('Boo')
1073 register_unpack_format('Boo2', ['.boo'], _boo)
1074 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1075 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1076
1077 # let's leave a clean state
1078 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001079 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001080
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001081 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1082 "disk_usage not available on this platform")
1083 def test_disk_usage(self):
1084 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001085 self.assertGreater(usage.total, 0)
1086 self.assertGreater(usage.used, 0)
1087 self.assertGreaterEqual(usage.free, 0)
1088 self.assertGreaterEqual(usage.total, usage.used)
1089 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001090
Sandro Tosid902a142011-08-22 23:28:27 +02001091 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1092 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1093 def test_chown(self):
1094
1095 # cleaned-up automatically by TestShutil.tearDown method
1096 dirname = self.mkdtemp()
1097 filename = tempfile.mktemp(dir=dirname)
1098 write_file(filename, 'testing chown function')
1099
1100 with self.assertRaises(ValueError):
1101 shutil.chown(filename)
1102
1103 with self.assertRaises(LookupError):
1104 shutil.chown(filename, user='non-exising username')
1105
1106 with self.assertRaises(LookupError):
1107 shutil.chown(filename, group='non-exising groupname')
1108
1109 with self.assertRaises(TypeError):
1110 shutil.chown(filename, b'spam')
1111
1112 with self.assertRaises(TypeError):
1113 shutil.chown(filename, 3.14)
1114
1115 uid = os.getuid()
1116 gid = os.getgid()
1117
1118 def check_chown(path, uid=None, gid=None):
1119 s = os.stat(filename)
1120 if uid is not None:
1121 self.assertEqual(uid, s.st_uid)
1122 if gid is not None:
1123 self.assertEqual(gid, s.st_gid)
1124
1125 shutil.chown(filename, uid, gid)
1126 check_chown(filename, uid, gid)
1127 shutil.chown(filename, uid)
1128 check_chown(filename, uid)
1129 shutil.chown(filename, user=uid)
1130 check_chown(filename, uid)
1131 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001132 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001133
1134 shutil.chown(dirname, uid, gid)
1135 check_chown(dirname, uid, gid)
1136 shutil.chown(dirname, uid)
1137 check_chown(dirname, uid)
1138 shutil.chown(dirname, user=uid)
1139 check_chown(dirname, uid)
1140 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001141 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001142
1143 user = pwd.getpwuid(uid)[0]
1144 group = grp.getgrgid(gid)[0]
1145 shutil.chown(filename, user, group)
1146 check_chown(filename, uid, gid)
1147 shutil.chown(dirname, user, group)
1148 check_chown(dirname, uid, gid)
1149
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001150 def test_copy_return_value(self):
1151 # copy and copy2 both return their destination path.
1152 for fn in (shutil.copy, shutil.copy2):
1153 src_dir = self.mkdtemp()
1154 dst_dir = self.mkdtemp()
1155 src = os.path.join(src_dir, 'foo')
1156 write_file(src, 'foo')
1157 rv = fn(src, dst_dir)
1158 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1159 rv = fn(src, os.path.join(dst_dir, 'bar'))
1160 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1161
1162 def test_copyfile_return_value(self):
1163 # copytree returns its destination path.
1164 src_dir = self.mkdtemp()
1165 dst_dir = self.mkdtemp()
1166 dst_file = os.path.join(dst_dir, 'bar')
1167 src_file = os.path.join(src_dir, 'foo')
1168 write_file(src_file, 'foo')
1169 rv = shutil.copyfile(src_file, dst_file)
1170 self.assertTrue(os.path.exists(rv))
1171 self.assertEqual(read_file(src_file), read_file(dst_file))
1172
1173 def test_copytree_return_value(self):
1174 # copytree returns its destination path.
1175 src_dir = self.mkdtemp()
1176 dst_dir = src_dir + "dest"
1177 src = os.path.join(src_dir, 'foo')
1178 write_file(src, 'foo')
1179 rv = shutil.copytree(src_dir, dst_dir)
1180 self.assertEqual(['foo'], os.listdir(rv))
1181
Christian Heimes9bd667a2008-01-20 15:14:11 +00001182
Brian Curtinc57a3452012-06-22 16:00:30 -05001183class TestWhich(unittest.TestCase):
1184
1185 def setUp(self):
1186 self.temp_dir = tempfile.mkdtemp()
1187 # Give the temp_file an ".exe" suffix for all.
1188 # It's needed on Windows and not harmful on other platforms.
1189 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1190 suffix=".exe")
1191 os.chmod(self.temp_file.name, stat.S_IXUSR)
1192 self.addCleanup(self.temp_file.close)
1193 self.dir, self.file = os.path.split(self.temp_file.name)
1194
1195 def test_basic(self):
1196 # Given an EXE in a directory, it should be returned.
1197 rv = shutil.which(self.file, path=self.dir)
1198 self.assertEqual(rv, self.temp_file.name)
1199
1200 def test_full_path_short_circuit(self):
1201 # When given the fully qualified path to an executable that exists,
1202 # it should be returned.
1203 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1204 self.assertEqual(self.temp_file.name, rv)
1205
1206 def test_non_matching_mode(self):
1207 # Set the file read-only and ask for writeable files.
1208 os.chmod(self.temp_file.name, stat.S_IREAD)
1209 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1210 self.assertIsNone(rv)
1211
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001212 def test_relative(self):
1213 old_cwd = os.getcwd()
1214 base_dir, tail_dir = os.path.split(self.dir)
1215 os.chdir(base_dir)
1216 try:
1217 rv = shutil.which(self.file, path=tail_dir)
1218 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1219 finally:
1220 os.chdir(old_cwd)
1221
Brian Curtinc57a3452012-06-22 16:00:30 -05001222 def test_nonexistent_file(self):
1223 # Return None when no matching executable file is found on the path.
1224 rv = shutil.which("foo.exe", path=self.dir)
1225 self.assertIsNone(rv)
1226
1227 @unittest.skipUnless(sys.platform == "win32",
1228 "pathext check is Windows-only")
1229 def test_pathext_checking(self):
1230 # Ask for the file without the ".exe" extension, then ensure that
1231 # it gets found properly with the extension.
1232 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1233 self.assertEqual(self.temp_file.name, rv)
1234
1235
Christian Heimesada8c3b2008-03-18 18:26:33 +00001236class TestMove(unittest.TestCase):
1237
1238 def setUp(self):
1239 filename = "foo"
1240 self.src_dir = tempfile.mkdtemp()
1241 self.dst_dir = tempfile.mkdtemp()
1242 self.src_file = os.path.join(self.src_dir, filename)
1243 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001244 with open(self.src_file, "wb") as f:
1245 f.write(b"spam")
1246
1247 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001248 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001249 try:
1250 if d:
1251 shutil.rmtree(d)
1252 except:
1253 pass
1254
1255 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001256 with open(src, "rb") as f:
1257 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001258 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001259 with open(real_dst, "rb") as f:
1260 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001261 self.assertFalse(os.path.exists(src))
1262
1263 def _check_move_dir(self, src, dst, real_dst):
1264 contents = sorted(os.listdir(src))
1265 shutil.move(src, dst)
1266 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1267 self.assertFalse(os.path.exists(src))
1268
1269 def test_move_file(self):
1270 # Move a file to another location on the same filesystem.
1271 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1272
1273 def test_move_file_to_dir(self):
1274 # Move a file inside an existing dir on the same filesystem.
1275 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1276
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001277 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001278 def test_move_file_other_fs(self):
1279 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001280 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001281
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001282 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001283 def test_move_file_to_dir_other_fs(self):
1284 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001285 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001286
1287 def test_move_dir(self):
1288 # Move a dir to another location on the same filesystem.
1289 dst_dir = tempfile.mktemp()
1290 try:
1291 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1292 finally:
1293 try:
1294 shutil.rmtree(dst_dir)
1295 except:
1296 pass
1297
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001298 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001299 def test_move_dir_other_fs(self):
1300 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001301 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001302
1303 def test_move_dir_to_dir(self):
1304 # Move a dir inside an existing dir on the same filesystem.
1305 self._check_move_dir(self.src_dir, self.dst_dir,
1306 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1307
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001308 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001309 def test_move_dir_to_dir_other_fs(self):
1310 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001311 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001312
1313 def test_existing_file_inside_dest_dir(self):
1314 # A file with the same name inside the destination dir already exists.
1315 with open(self.dst_file, "wb"):
1316 pass
1317 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1318
1319 def test_dont_move_dir_in_itself(self):
1320 # Moving a dir inside itself raises an Error.
1321 dst = os.path.join(self.src_dir, "bar")
1322 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1323
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001324 def test_destinsrc_false_negative(self):
1325 os.mkdir(TESTFN)
1326 try:
1327 for src, dst in [('srcdir', 'srcdir/dest')]:
1328 src = os.path.join(TESTFN, src)
1329 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001330 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001331 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001332 'dst (%s) is not in src (%s)' % (dst, src))
1333 finally:
1334 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001335
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001336 def test_destinsrc_false_positive(self):
1337 os.mkdir(TESTFN)
1338 try:
1339 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1340 src = os.path.join(TESTFN, src)
1341 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001342 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001343 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001344 'dst (%s) is in src (%s)' % (dst, src))
1345 finally:
1346 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001347
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001348 @support.skip_unless_symlink
1349 @mock_rename
1350 def test_move_file_symlink(self):
1351 dst = os.path.join(self.src_dir, 'bar')
1352 os.symlink(self.src_file, dst)
1353 shutil.move(dst, self.dst_file)
1354 self.assertTrue(os.path.islink(self.dst_file))
1355 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1356
1357 @support.skip_unless_symlink
1358 @mock_rename
1359 def test_move_file_symlink_to_dir(self):
1360 filename = "bar"
1361 dst = os.path.join(self.src_dir, filename)
1362 os.symlink(self.src_file, dst)
1363 shutil.move(dst, self.dst_dir)
1364 final_link = os.path.join(self.dst_dir, filename)
1365 self.assertTrue(os.path.islink(final_link))
1366 self.assertTrue(os.path.samefile(self.src_file, final_link))
1367
1368 @support.skip_unless_symlink
1369 @mock_rename
1370 def test_move_dangling_symlink(self):
1371 src = os.path.join(self.src_dir, 'baz')
1372 dst = os.path.join(self.src_dir, 'bar')
1373 os.symlink(src, dst)
1374 dst_link = os.path.join(self.dst_dir, 'quux')
1375 shutil.move(dst, dst_link)
1376 self.assertTrue(os.path.islink(dst_link))
1377 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1378
1379 @support.skip_unless_symlink
1380 @mock_rename
1381 def test_move_dir_symlink(self):
1382 src = os.path.join(self.src_dir, 'baz')
1383 dst = os.path.join(self.src_dir, 'bar')
1384 os.mkdir(src)
1385 os.symlink(src, dst)
1386 dst_link = os.path.join(self.dst_dir, 'quux')
1387 shutil.move(dst, dst_link)
1388 self.assertTrue(os.path.islink(dst_link))
1389 self.assertTrue(os.path.samefile(src, dst_link))
1390
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001391 def test_move_return_value(self):
1392 rv = shutil.move(self.src_file, self.dst_dir)
1393 self.assertEqual(rv,
1394 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1395
1396 def test_move_as_rename_return_value(self):
1397 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1398 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1399
Tarek Ziadé5340db32010-04-19 22:30:51 +00001400
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001401class TestCopyFile(unittest.TestCase):
1402
1403 _delete = False
1404
1405 class Faux(object):
1406 _entered = False
1407 _exited_with = None
1408 _raised = False
1409 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1410 self._raise_in_exit = raise_in_exit
1411 self._suppress_at_exit = suppress_at_exit
1412 def read(self, *args):
1413 return ''
1414 def __enter__(self):
1415 self._entered = True
1416 def __exit__(self, exc_type, exc_val, exc_tb):
1417 self._exited_with = exc_type, exc_val, exc_tb
1418 if self._raise_in_exit:
1419 self._raised = True
1420 raise IOError("Cannot close")
1421 return self._suppress_at_exit
1422
1423 def tearDown(self):
1424 if self._delete:
1425 del shutil.open
1426
1427 def _set_shutil_open(self, func):
1428 shutil.open = func
1429 self._delete = True
1430
1431 def test_w_source_open_fails(self):
1432 def _open(filename, mode='r'):
1433 if filename == 'srcfile':
1434 raise IOError('Cannot open "srcfile"')
1435 assert 0 # shouldn't reach here.
1436
1437 self._set_shutil_open(_open)
1438
1439 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1440
1441 def test_w_dest_open_fails(self):
1442
1443 srcfile = self.Faux()
1444
1445 def _open(filename, mode='r'):
1446 if filename == 'srcfile':
1447 return srcfile
1448 if filename == 'destfile':
1449 raise IOError('Cannot open "destfile"')
1450 assert 0 # shouldn't reach here.
1451
1452 self._set_shutil_open(_open)
1453
1454 shutil.copyfile('srcfile', 'destfile')
1455 self.assertTrue(srcfile._entered)
1456 self.assertTrue(srcfile._exited_with[0] is IOError)
1457 self.assertEqual(srcfile._exited_with[1].args,
1458 ('Cannot open "destfile"',))
1459
1460 def test_w_dest_close_fails(self):
1461
1462 srcfile = self.Faux()
1463 destfile = self.Faux(True)
1464
1465 def _open(filename, mode='r'):
1466 if filename == 'srcfile':
1467 return srcfile
1468 if filename == 'destfile':
1469 return destfile
1470 assert 0 # shouldn't reach here.
1471
1472 self._set_shutil_open(_open)
1473
1474 shutil.copyfile('srcfile', 'destfile')
1475 self.assertTrue(srcfile._entered)
1476 self.assertTrue(destfile._entered)
1477 self.assertTrue(destfile._raised)
1478 self.assertTrue(srcfile._exited_with[0] is IOError)
1479 self.assertEqual(srcfile._exited_with[1].args,
1480 ('Cannot close',))
1481
1482 def test_w_source_close_fails(self):
1483
1484 srcfile = self.Faux(True)
1485 destfile = self.Faux()
1486
1487 def _open(filename, mode='r'):
1488 if filename == 'srcfile':
1489 return srcfile
1490 if filename == 'destfile':
1491 return destfile
1492 assert 0 # shouldn't reach here.
1493
1494 self._set_shutil_open(_open)
1495
1496 self.assertRaises(IOError,
1497 shutil.copyfile, 'srcfile', 'destfile')
1498 self.assertTrue(srcfile._entered)
1499 self.assertTrue(destfile._entered)
1500 self.assertFalse(destfile._raised)
1501 self.assertTrue(srcfile._exited_with[0] is None)
1502 self.assertTrue(srcfile._raised)
1503
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001504 def test_move_dir_caseinsensitive(self):
1505 # Renames a folder to the same name
1506 # but a different case.
1507
1508 self.src_dir = tempfile.mkdtemp()
1509 dst_dir = os.path.join(
1510 os.path.dirname(self.src_dir),
1511 os.path.basename(self.src_dir).upper())
1512 self.assertNotEqual(self.src_dir, dst_dir)
1513
1514 try:
1515 shutil.move(self.src_dir, dst_dir)
1516 self.assertTrue(os.path.isdir(dst_dir))
1517 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001518 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001519
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001520class TermsizeTests(unittest.TestCase):
1521 def test_does_not_crash(self):
1522 """Check if get_terminal_size() returns a meaningful value.
1523
1524 There's no easy portable way to actually check the size of the
1525 terminal, so let's check if it returns something sensible instead.
1526 """
1527 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001528 self.assertGreaterEqual(size.columns, 0)
1529 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001530
1531 def test_os_environ_first(self):
1532 "Check if environment variables have precedence"
1533
1534 with support.EnvironmentVarGuard() as env:
1535 env['COLUMNS'] = '777'
1536 size = shutil.get_terminal_size()
1537 self.assertEqual(size.columns, 777)
1538
1539 with support.EnvironmentVarGuard() as env:
1540 env['LINES'] = '888'
1541 size = shutil.get_terminal_size()
1542 self.assertEqual(size.lines, 888)
1543
1544 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1545 def test_stty_match(self):
1546 """Check if stty returns the same results ignoring env
1547
1548 This test will fail if stdin and stdout are connected to
1549 different terminals with different sizes. Nevertheless, such
1550 situations should be pretty rare.
1551 """
1552 try:
1553 size = subprocess.check_output(['stty', 'size']).decode().split()
1554 except (FileNotFoundError, subprocess.CalledProcessError):
1555 self.skipTest("stty invocation failed")
1556 expected = (int(size[1]), int(size[0])) # reversed order
1557
1558 with support.EnvironmentVarGuard() as env:
1559 del env['LINES']
1560 del env['COLUMNS']
1561 actual = shutil.get_terminal_size()
1562
1563 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001564
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001565
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001566def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001567 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001568 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001569
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001570if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001571 test_main()