blob: 49be391ec53653113d3e35472d9a97113b5e6d71 [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"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001177 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001178 src = os.path.join(src_dir, 'foo')
1179 write_file(src, 'foo')
1180 rv = shutil.copytree(src_dir, dst_dir)
1181 self.assertEqual(['foo'], os.listdir(rv))
1182
Christian Heimes9bd667a2008-01-20 15:14:11 +00001183
Brian Curtinc57a3452012-06-22 16:00:30 -05001184class TestWhich(unittest.TestCase):
1185
1186 def setUp(self):
1187 self.temp_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001188 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001189 # Give the temp_file an ".exe" suffix for all.
1190 # It's needed on Windows and not harmful on other platforms.
1191 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1192 suffix=".exe")
1193 os.chmod(self.temp_file.name, stat.S_IXUSR)
1194 self.addCleanup(self.temp_file.close)
1195 self.dir, self.file = os.path.split(self.temp_file.name)
1196
1197 def test_basic(self):
1198 # Given an EXE in a directory, it should be returned.
1199 rv = shutil.which(self.file, path=self.dir)
1200 self.assertEqual(rv, self.temp_file.name)
1201
1202 def test_full_path_short_circuit(self):
1203 # When given the fully qualified path to an executable that exists,
1204 # it should be returned.
1205 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1206 self.assertEqual(self.temp_file.name, rv)
1207
1208 def test_non_matching_mode(self):
1209 # Set the file read-only and ask for writeable files.
1210 os.chmod(self.temp_file.name, stat.S_IREAD)
1211 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1212 self.assertIsNone(rv)
1213
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001214 def test_relative(self):
1215 old_cwd = os.getcwd()
1216 base_dir, tail_dir = os.path.split(self.dir)
1217 os.chdir(base_dir)
1218 try:
1219 rv = shutil.which(self.file, path=tail_dir)
1220 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1221 finally:
1222 os.chdir(old_cwd)
1223
Brian Curtinc57a3452012-06-22 16:00:30 -05001224 def test_nonexistent_file(self):
1225 # Return None when no matching executable file is found on the path.
1226 rv = shutil.which("foo.exe", path=self.dir)
1227 self.assertIsNone(rv)
1228
1229 @unittest.skipUnless(sys.platform == "win32",
1230 "pathext check is Windows-only")
1231 def test_pathext_checking(self):
1232 # Ask for the file without the ".exe" extension, then ensure that
1233 # it gets found properly with the extension.
1234 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1235 self.assertEqual(self.temp_file.name, rv)
1236
1237
Christian Heimesada8c3b2008-03-18 18:26:33 +00001238class TestMove(unittest.TestCase):
1239
1240 def setUp(self):
1241 filename = "foo"
1242 self.src_dir = tempfile.mkdtemp()
1243 self.dst_dir = tempfile.mkdtemp()
1244 self.src_file = os.path.join(self.src_dir, filename)
1245 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001246 with open(self.src_file, "wb") as f:
1247 f.write(b"spam")
1248
1249 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001250 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001251 try:
1252 if d:
1253 shutil.rmtree(d)
1254 except:
1255 pass
1256
1257 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001258 with open(src, "rb") as f:
1259 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001260 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001261 with open(real_dst, "rb") as f:
1262 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001263 self.assertFalse(os.path.exists(src))
1264
1265 def _check_move_dir(self, src, dst, real_dst):
1266 contents = sorted(os.listdir(src))
1267 shutil.move(src, dst)
1268 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1269 self.assertFalse(os.path.exists(src))
1270
1271 def test_move_file(self):
1272 # Move a file to another location on the same filesystem.
1273 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1274
1275 def test_move_file_to_dir(self):
1276 # Move a file inside an existing dir on the same filesystem.
1277 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1278
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001279 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001280 def test_move_file_other_fs(self):
1281 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001282 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001283
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001284 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001285 def test_move_file_to_dir_other_fs(self):
1286 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001287 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001288
1289 def test_move_dir(self):
1290 # Move a dir to another location on the same filesystem.
1291 dst_dir = tempfile.mktemp()
1292 try:
1293 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1294 finally:
1295 try:
1296 shutil.rmtree(dst_dir)
1297 except:
1298 pass
1299
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001300 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001301 def test_move_dir_other_fs(self):
1302 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001303 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001304
1305 def test_move_dir_to_dir(self):
1306 # Move a dir inside an existing dir on the same filesystem.
1307 self._check_move_dir(self.src_dir, self.dst_dir,
1308 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1309
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001310 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001311 def test_move_dir_to_dir_other_fs(self):
1312 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001313 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001314
1315 def test_existing_file_inside_dest_dir(self):
1316 # A file with the same name inside the destination dir already exists.
1317 with open(self.dst_file, "wb"):
1318 pass
1319 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1320
1321 def test_dont_move_dir_in_itself(self):
1322 # Moving a dir inside itself raises an Error.
1323 dst = os.path.join(self.src_dir, "bar")
1324 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1325
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001326 def test_destinsrc_false_negative(self):
1327 os.mkdir(TESTFN)
1328 try:
1329 for src, dst in [('srcdir', 'srcdir/dest')]:
1330 src = os.path.join(TESTFN, src)
1331 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001332 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001333 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001334 'dst (%s) is not in src (%s)' % (dst, src))
1335 finally:
1336 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001337
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001338 def test_destinsrc_false_positive(self):
1339 os.mkdir(TESTFN)
1340 try:
1341 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1342 src = os.path.join(TESTFN, src)
1343 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001344 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001345 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001346 'dst (%s) is in src (%s)' % (dst, src))
1347 finally:
1348 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001349
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001350 @support.skip_unless_symlink
1351 @mock_rename
1352 def test_move_file_symlink(self):
1353 dst = os.path.join(self.src_dir, 'bar')
1354 os.symlink(self.src_file, dst)
1355 shutil.move(dst, self.dst_file)
1356 self.assertTrue(os.path.islink(self.dst_file))
1357 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1358
1359 @support.skip_unless_symlink
1360 @mock_rename
1361 def test_move_file_symlink_to_dir(self):
1362 filename = "bar"
1363 dst = os.path.join(self.src_dir, filename)
1364 os.symlink(self.src_file, dst)
1365 shutil.move(dst, self.dst_dir)
1366 final_link = os.path.join(self.dst_dir, filename)
1367 self.assertTrue(os.path.islink(final_link))
1368 self.assertTrue(os.path.samefile(self.src_file, final_link))
1369
1370 @support.skip_unless_symlink
1371 @mock_rename
1372 def test_move_dangling_symlink(self):
1373 src = os.path.join(self.src_dir, 'baz')
1374 dst = os.path.join(self.src_dir, 'bar')
1375 os.symlink(src, dst)
1376 dst_link = os.path.join(self.dst_dir, 'quux')
1377 shutil.move(dst, dst_link)
1378 self.assertTrue(os.path.islink(dst_link))
1379 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1380
1381 @support.skip_unless_symlink
1382 @mock_rename
1383 def test_move_dir_symlink(self):
1384 src = os.path.join(self.src_dir, 'baz')
1385 dst = os.path.join(self.src_dir, 'bar')
1386 os.mkdir(src)
1387 os.symlink(src, dst)
1388 dst_link = os.path.join(self.dst_dir, 'quux')
1389 shutil.move(dst, dst_link)
1390 self.assertTrue(os.path.islink(dst_link))
1391 self.assertTrue(os.path.samefile(src, dst_link))
1392
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001393 def test_move_return_value(self):
1394 rv = shutil.move(self.src_file, self.dst_dir)
1395 self.assertEqual(rv,
1396 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1397
1398 def test_move_as_rename_return_value(self):
1399 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1400 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1401
Tarek Ziadé5340db32010-04-19 22:30:51 +00001402
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001403class TestCopyFile(unittest.TestCase):
1404
1405 _delete = False
1406
1407 class Faux(object):
1408 _entered = False
1409 _exited_with = None
1410 _raised = False
1411 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1412 self._raise_in_exit = raise_in_exit
1413 self._suppress_at_exit = suppress_at_exit
1414 def read(self, *args):
1415 return ''
1416 def __enter__(self):
1417 self._entered = True
1418 def __exit__(self, exc_type, exc_val, exc_tb):
1419 self._exited_with = exc_type, exc_val, exc_tb
1420 if self._raise_in_exit:
1421 self._raised = True
1422 raise IOError("Cannot close")
1423 return self._suppress_at_exit
1424
1425 def tearDown(self):
1426 if self._delete:
1427 del shutil.open
1428
1429 def _set_shutil_open(self, func):
1430 shutil.open = func
1431 self._delete = True
1432
1433 def test_w_source_open_fails(self):
1434 def _open(filename, mode='r'):
1435 if filename == 'srcfile':
1436 raise IOError('Cannot open "srcfile"')
1437 assert 0 # shouldn't reach here.
1438
1439 self._set_shutil_open(_open)
1440
1441 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1442
1443 def test_w_dest_open_fails(self):
1444
1445 srcfile = self.Faux()
1446
1447 def _open(filename, mode='r'):
1448 if filename == 'srcfile':
1449 return srcfile
1450 if filename == 'destfile':
1451 raise IOError('Cannot open "destfile"')
1452 assert 0 # shouldn't reach here.
1453
1454 self._set_shutil_open(_open)
1455
1456 shutil.copyfile('srcfile', 'destfile')
1457 self.assertTrue(srcfile._entered)
1458 self.assertTrue(srcfile._exited_with[0] is IOError)
1459 self.assertEqual(srcfile._exited_with[1].args,
1460 ('Cannot open "destfile"',))
1461
1462 def test_w_dest_close_fails(self):
1463
1464 srcfile = self.Faux()
1465 destfile = self.Faux(True)
1466
1467 def _open(filename, mode='r'):
1468 if filename == 'srcfile':
1469 return srcfile
1470 if filename == 'destfile':
1471 return destfile
1472 assert 0 # shouldn't reach here.
1473
1474 self._set_shutil_open(_open)
1475
1476 shutil.copyfile('srcfile', 'destfile')
1477 self.assertTrue(srcfile._entered)
1478 self.assertTrue(destfile._entered)
1479 self.assertTrue(destfile._raised)
1480 self.assertTrue(srcfile._exited_with[0] is IOError)
1481 self.assertEqual(srcfile._exited_with[1].args,
1482 ('Cannot close',))
1483
1484 def test_w_source_close_fails(self):
1485
1486 srcfile = self.Faux(True)
1487 destfile = self.Faux()
1488
1489 def _open(filename, mode='r'):
1490 if filename == 'srcfile':
1491 return srcfile
1492 if filename == 'destfile':
1493 return destfile
1494 assert 0 # shouldn't reach here.
1495
1496 self._set_shutil_open(_open)
1497
1498 self.assertRaises(IOError,
1499 shutil.copyfile, 'srcfile', 'destfile')
1500 self.assertTrue(srcfile._entered)
1501 self.assertTrue(destfile._entered)
1502 self.assertFalse(destfile._raised)
1503 self.assertTrue(srcfile._exited_with[0] is None)
1504 self.assertTrue(srcfile._raised)
1505
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001506 def test_move_dir_caseinsensitive(self):
1507 # Renames a folder to the same name
1508 # but a different case.
1509
1510 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001511 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001512 dst_dir = os.path.join(
1513 os.path.dirname(self.src_dir),
1514 os.path.basename(self.src_dir).upper())
1515 self.assertNotEqual(self.src_dir, dst_dir)
1516
1517 try:
1518 shutil.move(self.src_dir, dst_dir)
1519 self.assertTrue(os.path.isdir(dst_dir))
1520 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001521 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001522
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001523class TermsizeTests(unittest.TestCase):
1524 def test_does_not_crash(self):
1525 """Check if get_terminal_size() returns a meaningful value.
1526
1527 There's no easy portable way to actually check the size of the
1528 terminal, so let's check if it returns something sensible instead.
1529 """
1530 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001531 self.assertGreaterEqual(size.columns, 0)
1532 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001533
1534 def test_os_environ_first(self):
1535 "Check if environment variables have precedence"
1536
1537 with support.EnvironmentVarGuard() as env:
1538 env['COLUMNS'] = '777'
1539 size = shutil.get_terminal_size()
1540 self.assertEqual(size.columns, 777)
1541
1542 with support.EnvironmentVarGuard() as env:
1543 env['LINES'] = '888'
1544 size = shutil.get_terminal_size()
1545 self.assertEqual(size.lines, 888)
1546
1547 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1548 def test_stty_match(self):
1549 """Check if stty returns the same results ignoring env
1550
1551 This test will fail if stdin and stdout are connected to
1552 different terminals with different sizes. Nevertheless, such
1553 situations should be pretty rare.
1554 """
1555 try:
1556 size = subprocess.check_output(['stty', 'size']).decode().split()
1557 except (FileNotFoundError, subprocess.CalledProcessError):
1558 self.skipTest("stty invocation failed")
1559 expected = (int(size[1]), int(size[0])) # reversed order
1560
1561 with support.EnvironmentVarGuard() as env:
1562 del env['LINES']
1563 del env['COLUMNS']
1564 actual = shutil.get_terminal_size()
1565
1566 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001567
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001568
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001569def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001570 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001571 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001572
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001573if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001574 test_main()