blob: 067889e6b5bca644534b6353b647e9b14ab4895c [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test import support
14from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
17from shutil import (_make_tarball, _make_zipfile, make_archive,
18 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
21 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000022import tarfile
23import warnings
24
25from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030026from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Antoine Pitrou7fff0962009-05-01 21:09:44 +000034TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000035
Tarek Ziadé396fad72010-02-23 05:30:31 +000036try:
37 import grp
38 import pwd
39 UID_GID_SUPPORT = True
40except ImportError:
41 UID_GID_SUPPORT = False
42
43try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 import zipfile
45 ZIP_SUPPORT = True
46except ImportError:
47 ZIP_SUPPORT = find_executable('zip')
48
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040049def _fake_rename(*args, **kwargs):
50 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010051 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052
53def mock_rename(func):
54 @functools.wraps(func)
55 def wrap(*args, **kwargs):
56 try:
57 builtin_rename = os.rename
58 os.rename = _fake_rename
59 return func(*args, **kwargs)
60 finally:
61 os.rename = builtin_rename
62 return wrap
63
Éric Araujoa7e33a12011-08-12 19:51:35 +020064def write_file(path, content, binary=False):
65 """Write *content* to a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'wb' if binary else 'w') as fp:
74 fp.write(content)
75
76def read_file(path, binary=False):
77 """Return contents from a file located at *path*.
78
79 If *path* is a tuple instead of a string, os.path.join will be used to
80 make a path. If *binary* is true, the file will be opened in binary
81 mode.
82 """
83 if isinstance(path, tuple):
84 path = os.path.join(*path)
85 with open(path, 'rb' if binary else 'r') as fp:
86 return fp.read()
87
88
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000111 def test_rmtree_errors(self):
112 # filename is guaranteed not to exist
113 filename = tempfile.mktemp()
114 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000115
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000116 # See bug #1071513 for why we don't run this on cygwin
117 # and bug #1076467 for why we don't run this as root.
118 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000119 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000120 def test_on_error(self):
121 self.errorState = 0
122 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200123 self.addCleanup(shutil.rmtree, TESTFN)
124
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200125 self.child_file_path = os.path.join(TESTFN, 'a')
126 self.child_dir_path = os.path.join(TESTFN, 'b')
127 support.create_empty_file(self.child_file_path)
128 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000129 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200130 old_child_file_mode = os.stat(self.child_file_path).st_mode
131 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000132 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200133 new_mode = stat.S_IREAD|stat.S_IEXEC
134 os.chmod(self.child_file_path, new_mode)
135 os.chmod(self.child_dir_path, new_mode)
136 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000137
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200138 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
139 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
140 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
141
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000142 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000143 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200144 self.assertEqual(self.errorState, 3,
145 "Expected call to onerror function did not "
146 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000147
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000148 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000149 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200150 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000151 # This function is run when shutil.rmtree fails.
152 # 99.9% of the time it initially fails to remove
153 # a file in the directory, so the first time through
154 # func is os.remove.
155 # However, some Linux machines running ZFS on
156 # FUSE experienced a failure earlier in the process
157 # at os.listdir. The first failure may legally
158 # be either.
Antoine Pitrouf3a166d2012-06-23 21:32:36 +0200159 if support.verbose:
160 print("onerror [%d]: %r" % (self.errorState, (func, arg, exc[1])))
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200161 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200162 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200163 self.assertEqual(arg, self.child_file_path)
164 elif func is os.rmdir:
165 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000166 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200167 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200168 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000169 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200170 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000171 else:
172 self.assertEqual(func, os.rmdir)
173 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000174 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200175 self.errorState = 3
176
177 def test_rmtree_does_not_choke_on_failing_lstat(self):
178 try:
179 orig_lstat = os.lstat
180 def raiser(fn):
181 if fn != TESTFN:
182 raise OSError()
183 else:
184 return orig_lstat(fn)
185 os.lstat = raiser
186
187 os.mkdir(TESTFN)
188 write_file((TESTFN, 'foo'), 'foo')
189 shutil.rmtree(TESTFN)
190 finally:
191 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000192
Antoine Pitrou78091e62011-12-29 18:54:15 +0100193 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
194 @support.skip_unless_symlink
195 def test_copymode_follow_symlinks(self):
196 tmp_dir = self.mkdtemp()
197 src = os.path.join(tmp_dir, 'foo')
198 dst = os.path.join(tmp_dir, 'bar')
199 src_link = os.path.join(tmp_dir, 'baz')
200 dst_link = os.path.join(tmp_dir, 'quux')
201 write_file(src, 'foo')
202 write_file(dst, 'foo')
203 os.symlink(src, src_link)
204 os.symlink(dst, dst_link)
205 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
206 # file to file
207 os.chmod(dst, stat.S_IRWXO)
208 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
209 shutil.copymode(src, dst)
210 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
211 # follow src link
212 os.chmod(dst, stat.S_IRWXO)
213 shutil.copymode(src_link, dst)
214 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
215 # follow dst link
216 os.chmod(dst, stat.S_IRWXO)
217 shutil.copymode(src, dst_link)
218 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
219 # follow both links
220 os.chmod(dst, stat.S_IRWXO)
221 shutil.copymode(src_link, dst)
222 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
223
224 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
225 @support.skip_unless_symlink
226 def test_copymode_symlink_to_symlink(self):
227 tmp_dir = self.mkdtemp()
228 src = os.path.join(tmp_dir, 'foo')
229 dst = os.path.join(tmp_dir, 'bar')
230 src_link = os.path.join(tmp_dir, 'baz')
231 dst_link = os.path.join(tmp_dir, 'quux')
232 write_file(src, 'foo')
233 write_file(dst, 'foo')
234 os.symlink(src, src_link)
235 os.symlink(dst, dst_link)
236 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
237 os.chmod(dst, stat.S_IRWXU)
238 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
239 # link to link
240 os.lchmod(dst_link, stat.S_IRWXO)
241 shutil.copymode(src_link, dst_link, symlinks=True)
242 self.assertEqual(os.lstat(src_link).st_mode,
243 os.lstat(dst_link).st_mode)
244 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
245 # src link - use chmod
246 os.lchmod(dst_link, stat.S_IRWXO)
247 shutil.copymode(src_link, dst, symlinks=True)
248 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
249 # dst link - use chmod
250 os.lchmod(dst_link, stat.S_IRWXO)
251 shutil.copymode(src, dst_link, symlinks=True)
252 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
253
254 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
255 @support.skip_unless_symlink
256 def test_copymode_symlink_to_symlink_wo_lchmod(self):
257 tmp_dir = self.mkdtemp()
258 src = os.path.join(tmp_dir, 'foo')
259 dst = os.path.join(tmp_dir, 'bar')
260 src_link = os.path.join(tmp_dir, 'baz')
261 dst_link = os.path.join(tmp_dir, 'quux')
262 write_file(src, 'foo')
263 write_file(dst, 'foo')
264 os.symlink(src, src_link)
265 os.symlink(dst, dst_link)
266 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
267
268 @support.skip_unless_symlink
269 def test_copystat_symlinks(self):
270 tmp_dir = self.mkdtemp()
271 src = os.path.join(tmp_dir, 'foo')
272 dst = os.path.join(tmp_dir, 'bar')
273 src_link = os.path.join(tmp_dir, 'baz')
274 dst_link = os.path.join(tmp_dir, 'qux')
275 write_file(src, 'foo')
276 src_stat = os.stat(src)
277 os.utime(src, (src_stat.st_atime,
278 src_stat.st_mtime - 42.0)) # ensure different mtimes
279 write_file(dst, 'bar')
280 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
281 os.symlink(src, src_link)
282 os.symlink(dst, dst_link)
283 if hasattr(os, 'lchmod'):
284 os.lchmod(src_link, stat.S_IRWXO)
285 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
286 os.lchflags(src_link, stat.UF_NODUMP)
287 src_link_stat = os.lstat(src_link)
288 # follow
289 if hasattr(os, 'lchmod'):
290 shutil.copystat(src_link, dst_link, symlinks=False)
291 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
292 # don't follow
293 shutil.copystat(src_link, dst_link, symlinks=True)
294 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700295 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100296 for attr in 'st_atime', 'st_mtime':
297 # The modification times may be truncated in the new file.
298 self.assertLessEqual(getattr(src_link_stat, attr),
299 getattr(dst_link_stat, attr) + 1)
300 if hasattr(os, 'lchmod'):
301 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
302 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
303 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
304 # tell to follow but dst is not a link
305 shutil.copystat(src_link, dst, symlinks=True)
306 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
307 00000.1)
308
Ned Deilybaf75712012-05-10 17:05:19 -0700309 @unittest.skipUnless(hasattr(os, 'chflags') and
310 hasattr(errno, 'EOPNOTSUPP') and
311 hasattr(errno, 'ENOTSUP'),
312 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
313 def test_copystat_handles_harmless_chflags_errors(self):
314 tmpdir = self.mkdtemp()
315 file1 = os.path.join(tmpdir, 'file1')
316 file2 = os.path.join(tmpdir, 'file2')
317 write_file(file1, 'xxx')
318 write_file(file2, 'xxx')
319
320 def make_chflags_raiser(err):
321 ex = OSError()
322
Larry Hastings90867a52012-06-22 17:01:41 -0700323 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700324 ex.errno = err
325 raise ex
326 return _chflags_raiser
327 old_chflags = os.chflags
328 try:
329 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
330 os.chflags = make_chflags_raiser(err)
331 shutil.copystat(file1, file2)
332 # assert others errors break it
333 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
334 self.assertRaises(OSError, shutil.copystat, file1, file2)
335 finally:
336 os.chflags = old_chflags
337
Antoine Pitrou424246f2012-05-12 19:02:01 +0200338 @support.skip_unless_xattr
339 def test_copyxattr(self):
340 tmp_dir = self.mkdtemp()
341 src = os.path.join(tmp_dir, 'foo')
342 write_file(src, 'foo')
343 dst = os.path.join(tmp_dir, 'bar')
344 write_file(dst, 'bar')
345
346 # no xattr == no problem
347 shutil._copyxattr(src, dst)
348 # common case
349 os.setxattr(src, 'user.foo', b'42')
350 os.setxattr(src, 'user.bar', b'43')
351 shutil._copyxattr(src, dst)
352 self.assertEqual(os.listxattr(src), os.listxattr(dst))
353 self.assertEqual(
354 os.getxattr(src, 'user.foo'),
355 os.getxattr(dst, 'user.foo'))
356 # check errors don't affect other attrs
357 os.remove(dst)
358 write_file(dst, 'bar')
359 os_error = OSError(errno.EPERM, 'EPERM')
360
Larry Hastings9cf065c2012-06-22 16:30:09 -0700361 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200362 if attr == 'user.foo':
363 raise os_error
364 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700365 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200366 try:
367 orig_setxattr = os.setxattr
368 os.setxattr = _raise_on_user_foo
369 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200370 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200371 finally:
372 os.setxattr = orig_setxattr
373
374 @support.skip_unless_symlink
375 @support.skip_unless_xattr
376 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
377 'root privileges required')
378 def test_copyxattr_symlinks(self):
379 # On Linux, it's only possible to access non-user xattr for symlinks;
380 # which in turn require root privileges. This test should be expanded
381 # as soon as other platforms gain support for extended attributes.
382 tmp_dir = self.mkdtemp()
383 src = os.path.join(tmp_dir, 'foo')
384 src_link = os.path.join(tmp_dir, 'baz')
385 write_file(src, 'foo')
386 os.symlink(src, src_link)
387 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700388 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200389 dst = os.path.join(tmp_dir, 'bar')
390 dst_link = os.path.join(tmp_dir, 'qux')
391 write_file(dst, 'bar')
392 os.symlink(dst, dst_link)
393 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700394 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200395 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
396 shutil._copyxattr(src_link, dst, symlinks=True)
397 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
398
Antoine Pitrou78091e62011-12-29 18:54:15 +0100399 @support.skip_unless_symlink
400 def test_copy_symlinks(self):
401 tmp_dir = self.mkdtemp()
402 src = os.path.join(tmp_dir, 'foo')
403 dst = os.path.join(tmp_dir, 'bar')
404 src_link = os.path.join(tmp_dir, 'baz')
405 write_file(src, 'foo')
406 os.symlink(src, src_link)
407 if hasattr(os, 'lchmod'):
408 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
409 # don't follow
410 shutil.copy(src_link, dst, symlinks=False)
411 self.assertFalse(os.path.islink(dst))
412 self.assertEqual(read_file(src), read_file(dst))
413 os.remove(dst)
414 # follow
415 shutil.copy(src_link, dst, symlinks=True)
416 self.assertTrue(os.path.islink(dst))
417 self.assertEqual(os.readlink(dst), os.readlink(src_link))
418 if hasattr(os, 'lchmod'):
419 self.assertEqual(os.lstat(src_link).st_mode,
420 os.lstat(dst).st_mode)
421
422 @support.skip_unless_symlink
423 def test_copy2_symlinks(self):
424 tmp_dir = self.mkdtemp()
425 src = os.path.join(tmp_dir, 'foo')
426 dst = os.path.join(tmp_dir, 'bar')
427 src_link = os.path.join(tmp_dir, 'baz')
428 write_file(src, 'foo')
429 os.symlink(src, src_link)
430 if hasattr(os, 'lchmod'):
431 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
432 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
433 os.lchflags(src_link, stat.UF_NODUMP)
434 src_stat = os.stat(src)
435 src_link_stat = os.lstat(src_link)
436 # follow
437 shutil.copy2(src_link, dst, symlinks=False)
438 self.assertFalse(os.path.islink(dst))
439 self.assertEqual(read_file(src), read_file(dst))
440 os.remove(dst)
441 # don't follow
442 shutil.copy2(src_link, dst, symlinks=True)
443 self.assertTrue(os.path.islink(dst))
444 self.assertEqual(os.readlink(dst), os.readlink(src_link))
445 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700446 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100447 for attr in 'st_atime', 'st_mtime':
448 # The modification times may be truncated in the new file.
449 self.assertLessEqual(getattr(src_link_stat, attr),
450 getattr(dst_stat, attr) + 1)
451 if hasattr(os, 'lchmod'):
452 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
453 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
454 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
455 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
456
Antoine Pitrou424246f2012-05-12 19:02:01 +0200457 @support.skip_unless_xattr
458 def test_copy2_xattr(self):
459 tmp_dir = self.mkdtemp()
460 src = os.path.join(tmp_dir, 'foo')
461 dst = os.path.join(tmp_dir, 'bar')
462 write_file(src, 'foo')
463 os.setxattr(src, 'user.foo', b'42')
464 shutil.copy2(src, dst)
465 self.assertEqual(
466 os.getxattr(src, 'user.foo'),
467 os.getxattr(dst, 'user.foo'))
468 os.remove(dst)
469
Antoine Pitrou78091e62011-12-29 18:54:15 +0100470 @support.skip_unless_symlink
471 def test_copyfile_symlinks(self):
472 tmp_dir = self.mkdtemp()
473 src = os.path.join(tmp_dir, 'src')
474 dst = os.path.join(tmp_dir, 'dst')
475 dst_link = os.path.join(tmp_dir, 'dst_link')
476 link = os.path.join(tmp_dir, 'link')
477 write_file(src, 'foo')
478 os.symlink(src, link)
479 # don't follow
480 shutil.copyfile(link, dst_link, symlinks=True)
481 self.assertTrue(os.path.islink(dst_link))
482 self.assertEqual(os.readlink(link), os.readlink(dst_link))
483 # follow
484 shutil.copyfile(link, dst)
485 self.assertFalse(os.path.islink(dst))
486
Hynek Schlawack2100b422012-06-23 20:28:32 +0200487 def test_rmtree_uses_safe_fd_version_if_available(self):
488 if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd:
489 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000490 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200491 tmp_dir = self.mkdtemp()
492 d = os.path.join(tmp_dir, 'a')
493 os.mkdir(d)
494 try:
495 real_rmtree = shutil._rmtree_safe_fd
496 class Called(Exception): pass
497 def _raiser(*args, **kwargs):
498 raise Called
499 shutil._rmtree_safe_fd = _raiser
500 self.assertRaises(Called, shutil.rmtree, d)
501 finally:
502 shutil._rmtree_safe_fd = real_rmtree
503 else:
504 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000505 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200506
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000507 def test_rmtree_dont_delete_file(self):
508 # When called on a file instead of a directory, don't delete it.
509 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200510 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200511 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000512 os.remove(path)
513
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000514 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000515 src_dir = tempfile.mkdtemp()
516 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200517 self.addCleanup(shutil.rmtree, src_dir)
518 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
519 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000520 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200521 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000522
Éric Araujoa7e33a12011-08-12 19:51:35 +0200523 shutil.copytree(src_dir, dst_dir)
524 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
525 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
526 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
527 'test.txt')))
528 actual = read_file((dst_dir, 'test.txt'))
529 self.assertEqual(actual, '123')
530 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
531 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000532
Antoine Pitrou78091e62011-12-29 18:54:15 +0100533 @support.skip_unless_symlink
534 def test_copytree_symlinks(self):
535 tmp_dir = self.mkdtemp()
536 src_dir = os.path.join(tmp_dir, 'src')
537 dst_dir = os.path.join(tmp_dir, 'dst')
538 sub_dir = os.path.join(src_dir, 'sub')
539 os.mkdir(src_dir)
540 os.mkdir(sub_dir)
541 write_file((src_dir, 'file.txt'), 'foo')
542 src_link = os.path.join(sub_dir, 'link')
543 dst_link = os.path.join(dst_dir, 'sub/link')
544 os.symlink(os.path.join(src_dir, 'file.txt'),
545 src_link)
546 if hasattr(os, 'lchmod'):
547 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
548 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
549 os.lchflags(src_link, stat.UF_NODUMP)
550 src_stat = os.lstat(src_link)
551 shutil.copytree(src_dir, dst_dir, symlinks=True)
552 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
553 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
554 os.path.join(src_dir, 'file.txt'))
555 dst_stat = os.lstat(dst_link)
556 if hasattr(os, 'lchmod'):
557 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
558 if hasattr(os, 'lchflags'):
559 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
560
Georg Brandl2ee470f2008-07-16 12:55:28 +0000561 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000562 # creating data
563 join = os.path.join
564 exists = os.path.exists
565 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000566 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000567 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200568 write_file((src_dir, 'test.txt'), '123')
569 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000570 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200571 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000572 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200573 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000574 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
575 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200576 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
577 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000578
579 # testing glob-like patterns
580 try:
581 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
582 shutil.copytree(src_dir, dst_dir, ignore=patterns)
583 # checking the result: some elements should not be copied
584 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200585 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
586 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000587 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200588 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000589 try:
590 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
591 shutil.copytree(src_dir, dst_dir, ignore=patterns)
592 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200593 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
594 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
595 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000596 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200597 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000598
599 # testing callable-style
600 try:
601 def _filter(src, names):
602 res = []
603 for name in names:
604 path = os.path.join(src, name)
605
606 if (os.path.isdir(path) and
607 path.split()[-1] == 'subdir'):
608 res.append(name)
609 elif os.path.splitext(path)[-1] in ('.py'):
610 res.append(name)
611 return res
612
613 shutil.copytree(src_dir, dst_dir, ignore=_filter)
614
615 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200616 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
617 'test.py')))
618 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000619
620 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200621 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000622 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000623 shutil.rmtree(src_dir)
624 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000626 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000627 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000628 # Temporarily disable test on Windows.
629 if os.name == 'nt':
630 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000631 # bug 851123.
632 os.mkdir(TESTFN)
633 src = os.path.join(TESTFN, 'cheese')
634 dst = os.path.join(TESTFN, 'shop')
635 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000636 with open(src, 'w') as f:
637 f.write('cheddar')
638 os.link(src, dst)
639 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
640 with open(src, 'r') as f:
641 self.assertEqual(f.read(), 'cheddar')
642 os.remove(dst)
643 finally:
644 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000645
Brian Curtin3b4499c2010-12-28 14:31:47 +0000646 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000647 def test_dont_copy_file_onto_symlink_to_itself(self):
648 # bug 851123.
649 os.mkdir(TESTFN)
650 src = os.path.join(TESTFN, 'cheese')
651 dst = os.path.join(TESTFN, 'shop')
652 try:
653 with open(src, 'w') as f:
654 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000655 # Using `src` here would mean we end up with a symlink pointing
656 # to TESTFN/TESTFN/cheese, while it should point at
657 # TESTFN/cheese.
658 os.symlink('cheese', dst)
659 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000660 with open(src, 'r') as f:
661 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000662 os.remove(dst)
663 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000664 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000665
Brian Curtin3b4499c2010-12-28 14:31:47 +0000666 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000667 def test_rmtree_on_symlink(self):
668 # bug 1669.
669 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000670 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000671 src = os.path.join(TESTFN, 'cheese')
672 dst = os.path.join(TESTFN, 'shop')
673 os.mkdir(src)
674 os.symlink(src, dst)
675 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200676 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000677 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000678 shutil.rmtree(TESTFN, ignore_errors=True)
679
680 if hasattr(os, "mkfifo"):
681 # Issue #3002: copyfile and copytree block indefinitely on named pipes
682 def test_copyfile_named_pipe(self):
683 os.mkfifo(TESTFN)
684 try:
685 self.assertRaises(shutil.SpecialFileError,
686 shutil.copyfile, TESTFN, TESTFN2)
687 self.assertRaises(shutil.SpecialFileError,
688 shutil.copyfile, __file__, TESTFN)
689 finally:
690 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000691
Brian Curtin3b4499c2010-12-28 14:31:47 +0000692 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000693 def test_copytree_named_pipe(self):
694 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000695 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000696 subdir = os.path.join(TESTFN, "subdir")
697 os.mkdir(subdir)
698 pipe = os.path.join(subdir, "mypipe")
699 os.mkfifo(pipe)
700 try:
701 shutil.copytree(TESTFN, TESTFN2)
702 except shutil.Error as e:
703 errors = e.args[0]
704 self.assertEqual(len(errors), 1)
705 src, dst, error_msg = errors[0]
706 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
707 else:
708 self.fail("shutil.Error should have been raised")
709 finally:
710 shutil.rmtree(TESTFN, ignore_errors=True)
711 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000712
Tarek Ziadé5340db32010-04-19 22:30:51 +0000713 def test_copytree_special_func(self):
714
715 src_dir = self.mkdtemp()
716 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200717 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000718 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200719 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000720
721 copied = []
722 def _copy(src, dst):
723 copied.append((src, dst))
724
725 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000726 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000727
Brian Curtin3b4499c2010-12-28 14:31:47 +0000728 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000729 def test_copytree_dangling_symlinks(self):
730
731 # a dangling symlink raises an error at the end
732 src_dir = self.mkdtemp()
733 dst_dir = os.path.join(self.mkdtemp(), 'destination')
734 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
735 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200736 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000737 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
738
739 # a dangling symlink is ignored with the proper flag
740 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
741 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
742 self.assertNotIn('test.txt', os.listdir(dst_dir))
743
744 # a dangling symlink is copied if symlinks=True
745 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
746 shutil.copytree(src_dir, dst_dir, symlinks=True)
747 self.assertIn('test.txt', os.listdir(dst_dir))
748
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400749 def _copy_file(self, method):
750 fname = 'test.txt'
751 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200752 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400753 file1 = os.path.join(tmpdir, fname)
754 tmpdir2 = self.mkdtemp()
755 method(file1, tmpdir2)
756 file2 = os.path.join(tmpdir2, fname)
757 return (file1, file2)
758
759 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
760 def test_copy(self):
761 # Ensure that the copied file exists and has the same mode bits.
762 file1, file2 = self._copy_file(shutil.copy)
763 self.assertTrue(os.path.exists(file2))
764 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
765
766 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700767 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400768 def test_copy2(self):
769 # Ensure that the copied file exists and has the same mode and
770 # modification time bits.
771 file1, file2 = self._copy_file(shutil.copy2)
772 self.assertTrue(os.path.exists(file2))
773 file1_stat = os.stat(file1)
774 file2_stat = os.stat(file2)
775 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
776 for attr in 'st_atime', 'st_mtime':
777 # The modification times may be truncated in the new file.
778 self.assertLessEqual(getattr(file1_stat, attr),
779 getattr(file2_stat, attr) + 1)
780 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
781 self.assertEqual(getattr(file1_stat, 'st_flags'),
782 getattr(file2_stat, 'st_flags'))
783
Ezio Melotti975077a2011-05-19 22:03:22 +0300784 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000785 def test_make_tarball(self):
786 # creating something to tar
787 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200788 write_file((tmpdir, 'file1'), 'xxx')
789 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000790 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200791 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000792
793 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400794 # force shutil to create the directory
795 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000796 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
797 "source and target should be on same drive")
798
799 base_name = os.path.join(tmpdir2, 'archive')
800
801 # working with relative paths to avoid tar warnings
802 old_dir = os.getcwd()
803 os.chdir(tmpdir)
804 try:
805 _make_tarball(splitdrive(base_name)[1], '.')
806 finally:
807 os.chdir(old_dir)
808
809 # check if the compressed tarball was created
810 tarball = base_name + '.tar.gz'
811 self.assertTrue(os.path.exists(tarball))
812
813 # trying an uncompressed one
814 base_name = os.path.join(tmpdir2, 'archive')
815 old_dir = os.getcwd()
816 os.chdir(tmpdir)
817 try:
818 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
819 finally:
820 os.chdir(old_dir)
821 tarball = base_name + '.tar'
822 self.assertTrue(os.path.exists(tarball))
823
824 def _tarinfo(self, path):
825 tar = tarfile.open(path)
826 try:
827 names = tar.getnames()
828 names.sort()
829 return tuple(names)
830 finally:
831 tar.close()
832
833 def _create_files(self):
834 # creating something to tar
835 tmpdir = self.mkdtemp()
836 dist = os.path.join(tmpdir, 'dist')
837 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200838 write_file((dist, 'file1'), 'xxx')
839 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000840 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200841 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000842 os.mkdir(os.path.join(dist, 'sub2'))
843 tmpdir2 = self.mkdtemp()
844 base_name = os.path.join(tmpdir2, 'archive')
845 return tmpdir, tmpdir2, base_name
846
Ezio Melotti975077a2011-05-19 22:03:22 +0300847 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000848 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
849 'Need the tar command to run')
850 def test_tarfile_vs_tar(self):
851 tmpdir, tmpdir2, base_name = self._create_files()
852 old_dir = os.getcwd()
853 os.chdir(tmpdir)
854 try:
855 _make_tarball(base_name, 'dist')
856 finally:
857 os.chdir(old_dir)
858
859 # check if the compressed tarball was created
860 tarball = base_name + '.tar.gz'
861 self.assertTrue(os.path.exists(tarball))
862
863 # now create another tarball using `tar`
864 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
865 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
866 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
867 old_dir = os.getcwd()
868 os.chdir(tmpdir)
869 try:
870 with captured_stdout() as s:
871 spawn(tar_cmd)
872 spawn(gzip_cmd)
873 finally:
874 os.chdir(old_dir)
875
876 self.assertTrue(os.path.exists(tarball2))
877 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000878 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000879
880 # trying an uncompressed one
881 base_name = os.path.join(tmpdir2, 'archive')
882 old_dir = os.getcwd()
883 os.chdir(tmpdir)
884 try:
885 _make_tarball(base_name, 'dist', compress=None)
886 finally:
887 os.chdir(old_dir)
888 tarball = base_name + '.tar'
889 self.assertTrue(os.path.exists(tarball))
890
891 # now for a dry_run
892 base_name = os.path.join(tmpdir2, 'archive')
893 old_dir = os.getcwd()
894 os.chdir(tmpdir)
895 try:
896 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
897 finally:
898 os.chdir(old_dir)
899 tarball = base_name + '.tar'
900 self.assertTrue(os.path.exists(tarball))
901
Ezio Melotti975077a2011-05-19 22:03:22 +0300902 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000903 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
904 def test_make_zipfile(self):
905 # creating something to tar
906 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200907 write_file((tmpdir, 'file1'), 'xxx')
908 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000909
910 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400911 # force shutil to create the directory
912 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000913 base_name = os.path.join(tmpdir2, 'archive')
914 _make_zipfile(base_name, tmpdir)
915
916 # check if the compressed tarball was created
917 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000918 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000919
920
921 def test_make_archive(self):
922 tmpdir = self.mkdtemp()
923 base_name = os.path.join(tmpdir, 'archive')
924 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
925
Ezio Melotti975077a2011-05-19 22:03:22 +0300926 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000927 def test_make_archive_owner_group(self):
928 # testing make_archive with owner and group, with various combinations
929 # this works even if there's not gid/uid support
930 if UID_GID_SUPPORT:
931 group = grp.getgrgid(0)[0]
932 owner = pwd.getpwuid(0)[0]
933 else:
934 group = owner = 'root'
935
936 base_dir, root_dir, base_name = self._create_files()
937 base_name = os.path.join(self.mkdtemp() , 'archive')
938 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
939 group=group)
940 self.assertTrue(os.path.exists(res))
941
942 res = make_archive(base_name, 'zip', root_dir, base_dir)
943 self.assertTrue(os.path.exists(res))
944
945 res = make_archive(base_name, 'tar', root_dir, base_dir,
946 owner=owner, group=group)
947 self.assertTrue(os.path.exists(res))
948
949 res = make_archive(base_name, 'tar', root_dir, base_dir,
950 owner='kjhkjhkjg', group='oihohoh')
951 self.assertTrue(os.path.exists(res))
952
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000953
Ezio Melotti975077a2011-05-19 22:03:22 +0300954 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000955 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
956 def test_tarfile_root_owner(self):
957 tmpdir, tmpdir2, base_name = self._create_files()
958 old_dir = os.getcwd()
959 os.chdir(tmpdir)
960 group = grp.getgrgid(0)[0]
961 owner = pwd.getpwuid(0)[0]
962 try:
963 archive_name = _make_tarball(base_name, 'dist', compress=None,
964 owner=owner, group=group)
965 finally:
966 os.chdir(old_dir)
967
968 # check if the compressed tarball was created
969 self.assertTrue(os.path.exists(archive_name))
970
971 # now checks the rights
972 archive = tarfile.open(archive_name)
973 try:
974 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000975 self.assertEqual(member.uid, 0)
976 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000977 finally:
978 archive.close()
979
980 def test_make_archive_cwd(self):
981 current_dir = os.getcwd()
982 def _breaks(*args, **kw):
983 raise RuntimeError()
984
985 register_archive_format('xxx', _breaks, [], 'xxx file')
986 try:
987 try:
988 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
989 except Exception:
990 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000991 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000992 finally:
993 unregister_archive_format('xxx')
994
995 def test_register_archive_format(self):
996
997 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
998 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
999 1)
1000 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1001 [(1, 2), (1, 2, 3)])
1002
1003 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1004 formats = [name for name, params in get_archive_formats()]
1005 self.assertIn('xxx', formats)
1006
1007 unregister_archive_format('xxx')
1008 formats = [name for name, params in get_archive_formats()]
1009 self.assertNotIn('xxx', formats)
1010
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001011 def _compare_dirs(self, dir1, dir2):
1012 # check that dir1 and dir2 are equivalent,
1013 # return the diff
1014 diff = []
1015 for root, dirs, files in os.walk(dir1):
1016 for file_ in files:
1017 path = os.path.join(root, file_)
1018 target_path = os.path.join(dir2, os.path.split(path)[-1])
1019 if not os.path.exists(target_path):
1020 diff.append(file_)
1021 return diff
1022
Ezio Melotti975077a2011-05-19 22:03:22 +03001023 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001024 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001025 formats = ['tar', 'gztar', 'zip']
1026 if BZ2_SUPPORTED:
1027 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001028
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001029 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001030 tmpdir = self.mkdtemp()
1031 base_dir, root_dir, base_name = self._create_files()
1032 tmpdir2 = self.mkdtemp()
1033 filename = make_archive(base_name, format, root_dir, base_dir)
1034
1035 # let's try to unpack it now
1036 unpack_archive(filename, tmpdir2)
1037 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001038 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001039
Nick Coghlanabf202d2011-03-16 13:52:20 -04001040 # and again, this time with the format specified
1041 tmpdir3 = self.mkdtemp()
1042 unpack_archive(filename, tmpdir3, format=format)
1043 diff = self._compare_dirs(tmpdir, tmpdir3)
1044 self.assertEqual(diff, [])
1045 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1046 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1047
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001048 def test_unpack_registery(self):
1049
1050 formats = get_unpack_formats()
1051
1052 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001053 self.assertEqual(extra, 1)
1054 self.assertEqual(filename, 'stuff.boo')
1055 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001056
1057 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1058 unpack_archive('stuff.boo', 'xx')
1059
1060 # trying to register a .boo unpacker again
1061 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1062 ['.boo'], _boo)
1063
1064 # should work now
1065 unregister_unpack_format('Boo')
1066 register_unpack_format('Boo2', ['.boo'], _boo)
1067 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1068 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1069
1070 # let's leave a clean state
1071 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001072 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001073
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001074 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1075 "disk_usage not available on this platform")
1076 def test_disk_usage(self):
1077 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001078 self.assertGreater(usage.total, 0)
1079 self.assertGreater(usage.used, 0)
1080 self.assertGreaterEqual(usage.free, 0)
1081 self.assertGreaterEqual(usage.total, usage.used)
1082 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001083
Sandro Tosid902a142011-08-22 23:28:27 +02001084 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1085 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1086 def test_chown(self):
1087
1088 # cleaned-up automatically by TestShutil.tearDown method
1089 dirname = self.mkdtemp()
1090 filename = tempfile.mktemp(dir=dirname)
1091 write_file(filename, 'testing chown function')
1092
1093 with self.assertRaises(ValueError):
1094 shutil.chown(filename)
1095
1096 with self.assertRaises(LookupError):
1097 shutil.chown(filename, user='non-exising username')
1098
1099 with self.assertRaises(LookupError):
1100 shutil.chown(filename, group='non-exising groupname')
1101
1102 with self.assertRaises(TypeError):
1103 shutil.chown(filename, b'spam')
1104
1105 with self.assertRaises(TypeError):
1106 shutil.chown(filename, 3.14)
1107
1108 uid = os.getuid()
1109 gid = os.getgid()
1110
1111 def check_chown(path, uid=None, gid=None):
1112 s = os.stat(filename)
1113 if uid is not None:
1114 self.assertEqual(uid, s.st_uid)
1115 if gid is not None:
1116 self.assertEqual(gid, s.st_gid)
1117
1118 shutil.chown(filename, uid, gid)
1119 check_chown(filename, uid, gid)
1120 shutil.chown(filename, uid)
1121 check_chown(filename, uid)
1122 shutil.chown(filename, user=uid)
1123 check_chown(filename, uid)
1124 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001125 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001126
1127 shutil.chown(dirname, uid, gid)
1128 check_chown(dirname, uid, gid)
1129 shutil.chown(dirname, uid)
1130 check_chown(dirname, uid)
1131 shutil.chown(dirname, user=uid)
1132 check_chown(dirname, uid)
1133 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001134 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001135
1136 user = pwd.getpwuid(uid)[0]
1137 group = grp.getgrgid(gid)[0]
1138 shutil.chown(filename, user, group)
1139 check_chown(filename, uid, gid)
1140 shutil.chown(dirname, user, group)
1141 check_chown(dirname, uid, gid)
1142
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001143 def test_copy_return_value(self):
1144 # copy and copy2 both return their destination path.
1145 for fn in (shutil.copy, shutil.copy2):
1146 src_dir = self.mkdtemp()
1147 dst_dir = self.mkdtemp()
1148 src = os.path.join(src_dir, 'foo')
1149 write_file(src, 'foo')
1150 rv = fn(src, dst_dir)
1151 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1152 rv = fn(src, os.path.join(dst_dir, 'bar'))
1153 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1154
1155 def test_copyfile_return_value(self):
1156 # copytree returns its destination path.
1157 src_dir = self.mkdtemp()
1158 dst_dir = self.mkdtemp()
1159 dst_file = os.path.join(dst_dir, 'bar')
1160 src_file = os.path.join(src_dir, 'foo')
1161 write_file(src_file, 'foo')
1162 rv = shutil.copyfile(src_file, dst_file)
1163 self.assertTrue(os.path.exists(rv))
1164 self.assertEqual(read_file(src_file), read_file(dst_file))
1165
1166 def test_copytree_return_value(self):
1167 # copytree returns its destination path.
1168 src_dir = self.mkdtemp()
1169 dst_dir = src_dir + "dest"
1170 src = os.path.join(src_dir, 'foo')
1171 write_file(src, 'foo')
1172 rv = shutil.copytree(src_dir, dst_dir)
1173 self.assertEqual(['foo'], os.listdir(rv))
1174
Christian Heimes9bd667a2008-01-20 15:14:11 +00001175
Brian Curtinc57a3452012-06-22 16:00:30 -05001176class TestWhich(unittest.TestCase):
1177
1178 def setUp(self):
1179 self.temp_dir = tempfile.mkdtemp()
1180 # Give the temp_file an ".exe" suffix for all.
1181 # It's needed on Windows and not harmful on other platforms.
1182 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1183 suffix=".exe")
1184 os.chmod(self.temp_file.name, stat.S_IXUSR)
1185 self.addCleanup(self.temp_file.close)
1186 self.dir, self.file = os.path.split(self.temp_file.name)
1187
1188 def test_basic(self):
1189 # Given an EXE in a directory, it should be returned.
1190 rv = shutil.which(self.file, path=self.dir)
1191 self.assertEqual(rv, self.temp_file.name)
1192
1193 def test_full_path_short_circuit(self):
1194 # When given the fully qualified path to an executable that exists,
1195 # it should be returned.
1196 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1197 self.assertEqual(self.temp_file.name, rv)
1198
1199 def test_non_matching_mode(self):
1200 # Set the file read-only and ask for writeable files.
1201 os.chmod(self.temp_file.name, stat.S_IREAD)
1202 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1203 self.assertIsNone(rv)
1204
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001205 def test_relative(self):
1206 old_cwd = os.getcwd()
1207 base_dir, tail_dir = os.path.split(self.dir)
1208 os.chdir(base_dir)
1209 try:
1210 rv = shutil.which(self.file, path=tail_dir)
1211 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1212 finally:
1213 os.chdir(old_cwd)
1214
Brian Curtinc57a3452012-06-22 16:00:30 -05001215 def test_nonexistent_file(self):
1216 # Return None when no matching executable file is found on the path.
1217 rv = shutil.which("foo.exe", path=self.dir)
1218 self.assertIsNone(rv)
1219
1220 @unittest.skipUnless(sys.platform == "win32",
1221 "pathext check is Windows-only")
1222 def test_pathext_checking(self):
1223 # Ask for the file without the ".exe" extension, then ensure that
1224 # it gets found properly with the extension.
1225 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1226 self.assertEqual(self.temp_file.name, rv)
1227
1228
Christian Heimesada8c3b2008-03-18 18:26:33 +00001229class TestMove(unittest.TestCase):
1230
1231 def setUp(self):
1232 filename = "foo"
1233 self.src_dir = tempfile.mkdtemp()
1234 self.dst_dir = tempfile.mkdtemp()
1235 self.src_file = os.path.join(self.src_dir, filename)
1236 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001237 with open(self.src_file, "wb") as f:
1238 f.write(b"spam")
1239
1240 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001241 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001242 try:
1243 if d:
1244 shutil.rmtree(d)
1245 except:
1246 pass
1247
1248 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001249 with open(src, "rb") as f:
1250 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001251 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001252 with open(real_dst, "rb") as f:
1253 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001254 self.assertFalse(os.path.exists(src))
1255
1256 def _check_move_dir(self, src, dst, real_dst):
1257 contents = sorted(os.listdir(src))
1258 shutil.move(src, dst)
1259 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1260 self.assertFalse(os.path.exists(src))
1261
1262 def test_move_file(self):
1263 # Move a file to another location on the same filesystem.
1264 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1265
1266 def test_move_file_to_dir(self):
1267 # Move a file inside an existing dir on the same filesystem.
1268 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1269
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001270 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001271 def test_move_file_other_fs(self):
1272 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001273 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001274
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001275 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001276 def test_move_file_to_dir_other_fs(self):
1277 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001278 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001279
1280 def test_move_dir(self):
1281 # Move a dir to another location on the same filesystem.
1282 dst_dir = tempfile.mktemp()
1283 try:
1284 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1285 finally:
1286 try:
1287 shutil.rmtree(dst_dir)
1288 except:
1289 pass
1290
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001291 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001292 def test_move_dir_other_fs(self):
1293 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001294 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001295
1296 def test_move_dir_to_dir(self):
1297 # Move a dir inside an existing dir on the same filesystem.
1298 self._check_move_dir(self.src_dir, self.dst_dir,
1299 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1300
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001301 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001302 def test_move_dir_to_dir_other_fs(self):
1303 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001304 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001305
1306 def test_existing_file_inside_dest_dir(self):
1307 # A file with the same name inside the destination dir already exists.
1308 with open(self.dst_file, "wb"):
1309 pass
1310 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1311
1312 def test_dont_move_dir_in_itself(self):
1313 # Moving a dir inside itself raises an Error.
1314 dst = os.path.join(self.src_dir, "bar")
1315 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1316
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001317 def test_destinsrc_false_negative(self):
1318 os.mkdir(TESTFN)
1319 try:
1320 for src, dst in [('srcdir', 'srcdir/dest')]:
1321 src = os.path.join(TESTFN, src)
1322 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001323 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001324 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001325 'dst (%s) is not in src (%s)' % (dst, src))
1326 finally:
1327 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001328
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001329 def test_destinsrc_false_positive(self):
1330 os.mkdir(TESTFN)
1331 try:
1332 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1333 src = os.path.join(TESTFN, src)
1334 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001335 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001336 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001337 'dst (%s) is in src (%s)' % (dst, src))
1338 finally:
1339 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001340
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001341 @support.skip_unless_symlink
1342 @mock_rename
1343 def test_move_file_symlink(self):
1344 dst = os.path.join(self.src_dir, 'bar')
1345 os.symlink(self.src_file, dst)
1346 shutil.move(dst, self.dst_file)
1347 self.assertTrue(os.path.islink(self.dst_file))
1348 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1349
1350 @support.skip_unless_symlink
1351 @mock_rename
1352 def test_move_file_symlink_to_dir(self):
1353 filename = "bar"
1354 dst = os.path.join(self.src_dir, filename)
1355 os.symlink(self.src_file, dst)
1356 shutil.move(dst, self.dst_dir)
1357 final_link = os.path.join(self.dst_dir, filename)
1358 self.assertTrue(os.path.islink(final_link))
1359 self.assertTrue(os.path.samefile(self.src_file, final_link))
1360
1361 @support.skip_unless_symlink
1362 @mock_rename
1363 def test_move_dangling_symlink(self):
1364 src = os.path.join(self.src_dir, 'baz')
1365 dst = os.path.join(self.src_dir, 'bar')
1366 os.symlink(src, dst)
1367 dst_link = os.path.join(self.dst_dir, 'quux')
1368 shutil.move(dst, dst_link)
1369 self.assertTrue(os.path.islink(dst_link))
1370 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1371
1372 @support.skip_unless_symlink
1373 @mock_rename
1374 def test_move_dir_symlink(self):
1375 src = os.path.join(self.src_dir, 'baz')
1376 dst = os.path.join(self.src_dir, 'bar')
1377 os.mkdir(src)
1378 os.symlink(src, dst)
1379 dst_link = os.path.join(self.dst_dir, 'quux')
1380 shutil.move(dst, dst_link)
1381 self.assertTrue(os.path.islink(dst_link))
1382 self.assertTrue(os.path.samefile(src, dst_link))
1383
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001384 def test_move_return_value(self):
1385 rv = shutil.move(self.src_file, self.dst_dir)
1386 self.assertEqual(rv,
1387 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1388
1389 def test_move_as_rename_return_value(self):
1390 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1391 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1392
Tarek Ziadé5340db32010-04-19 22:30:51 +00001393
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001394class TestCopyFile(unittest.TestCase):
1395
1396 _delete = False
1397
1398 class Faux(object):
1399 _entered = False
1400 _exited_with = None
1401 _raised = False
1402 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1403 self._raise_in_exit = raise_in_exit
1404 self._suppress_at_exit = suppress_at_exit
1405 def read(self, *args):
1406 return ''
1407 def __enter__(self):
1408 self._entered = True
1409 def __exit__(self, exc_type, exc_val, exc_tb):
1410 self._exited_with = exc_type, exc_val, exc_tb
1411 if self._raise_in_exit:
1412 self._raised = True
1413 raise IOError("Cannot close")
1414 return self._suppress_at_exit
1415
1416 def tearDown(self):
1417 if self._delete:
1418 del shutil.open
1419
1420 def _set_shutil_open(self, func):
1421 shutil.open = func
1422 self._delete = True
1423
1424 def test_w_source_open_fails(self):
1425 def _open(filename, mode='r'):
1426 if filename == 'srcfile':
1427 raise IOError('Cannot open "srcfile"')
1428 assert 0 # shouldn't reach here.
1429
1430 self._set_shutil_open(_open)
1431
1432 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1433
1434 def test_w_dest_open_fails(self):
1435
1436 srcfile = self.Faux()
1437
1438 def _open(filename, mode='r'):
1439 if filename == 'srcfile':
1440 return srcfile
1441 if filename == 'destfile':
1442 raise IOError('Cannot open "destfile"')
1443 assert 0 # shouldn't reach here.
1444
1445 self._set_shutil_open(_open)
1446
1447 shutil.copyfile('srcfile', 'destfile')
1448 self.assertTrue(srcfile._entered)
1449 self.assertTrue(srcfile._exited_with[0] is IOError)
1450 self.assertEqual(srcfile._exited_with[1].args,
1451 ('Cannot open "destfile"',))
1452
1453 def test_w_dest_close_fails(self):
1454
1455 srcfile = self.Faux()
1456 destfile = self.Faux(True)
1457
1458 def _open(filename, mode='r'):
1459 if filename == 'srcfile':
1460 return srcfile
1461 if filename == 'destfile':
1462 return destfile
1463 assert 0 # shouldn't reach here.
1464
1465 self._set_shutil_open(_open)
1466
1467 shutil.copyfile('srcfile', 'destfile')
1468 self.assertTrue(srcfile._entered)
1469 self.assertTrue(destfile._entered)
1470 self.assertTrue(destfile._raised)
1471 self.assertTrue(srcfile._exited_with[0] is IOError)
1472 self.assertEqual(srcfile._exited_with[1].args,
1473 ('Cannot close',))
1474
1475 def test_w_source_close_fails(self):
1476
1477 srcfile = self.Faux(True)
1478 destfile = self.Faux()
1479
1480 def _open(filename, mode='r'):
1481 if filename == 'srcfile':
1482 return srcfile
1483 if filename == 'destfile':
1484 return destfile
1485 assert 0 # shouldn't reach here.
1486
1487 self._set_shutil_open(_open)
1488
1489 self.assertRaises(IOError,
1490 shutil.copyfile, 'srcfile', 'destfile')
1491 self.assertTrue(srcfile._entered)
1492 self.assertTrue(destfile._entered)
1493 self.assertFalse(destfile._raised)
1494 self.assertTrue(srcfile._exited_with[0] is None)
1495 self.assertTrue(srcfile._raised)
1496
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001497 def test_move_dir_caseinsensitive(self):
1498 # Renames a folder to the same name
1499 # but a different case.
1500
1501 self.src_dir = tempfile.mkdtemp()
1502 dst_dir = os.path.join(
1503 os.path.dirname(self.src_dir),
1504 os.path.basename(self.src_dir).upper())
1505 self.assertNotEqual(self.src_dir, dst_dir)
1506
1507 try:
1508 shutil.move(self.src_dir, dst_dir)
1509 self.assertTrue(os.path.isdir(dst_dir))
1510 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001511 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001512
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001513class TermsizeTests(unittest.TestCase):
1514 def test_does_not_crash(self):
1515 """Check if get_terminal_size() returns a meaningful value.
1516
1517 There's no easy portable way to actually check the size of the
1518 terminal, so let's check if it returns something sensible instead.
1519 """
1520 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001521 self.assertGreaterEqual(size.columns, 0)
1522 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001523
1524 def test_os_environ_first(self):
1525 "Check if environment variables have precedence"
1526
1527 with support.EnvironmentVarGuard() as env:
1528 env['COLUMNS'] = '777'
1529 size = shutil.get_terminal_size()
1530 self.assertEqual(size.columns, 777)
1531
1532 with support.EnvironmentVarGuard() as env:
1533 env['LINES'] = '888'
1534 size = shutil.get_terminal_size()
1535 self.assertEqual(size.lines, 888)
1536
1537 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1538 def test_stty_match(self):
1539 """Check if stty returns the same results ignoring env
1540
1541 This test will fail if stdin and stdout are connected to
1542 different terminals with different sizes. Nevertheless, such
1543 situations should be pretty rare.
1544 """
1545 try:
1546 size = subprocess.check_output(['stty', 'size']).decode().split()
1547 except (FileNotFoundError, subprocess.CalledProcessError):
1548 self.skipTest("stty invocation failed")
1549 expected = (int(size[1]), int(size[0])) # reversed order
1550
1551 with support.EnvironmentVarGuard() as env:
1552 del env['LINES']
1553 del env['COLUMNS']
1554 actual = shutil.get_terminal_size()
1555
1556 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001557
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001558
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001559def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001560 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001561 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001562
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001563if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001564 test_main()