blob: 192923770df289893d054d6e272740eaa940b300 [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)
Tim Peters4590c002004-11-01 02:40:52 +0000123 self.childpath = os.path.join(TESTFN, 'a')
Victor Stinnerbf816222011-06-30 23:25:47 +0200124 support.create_empty_file(self.childpath)
Tim Peters4590c002004-11-01 02:40:52 +0000125 old_dir_mode = os.stat(TESTFN).st_mode
126 old_child_mode = os.stat(self.childpath).st_mode
127 # Make unwritable.
128 os.chmod(self.childpath, stat.S_IREAD)
129 os.chmod(TESTFN, stat.S_IREAD)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000130
131 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000132 # Test whether onerror has actually been called.
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000133 self.assertEqual(self.errorState, 2,
134 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000135
Tim Peters4590c002004-11-01 02:40:52 +0000136 # Make writable again.
137 os.chmod(TESTFN, old_dir_mode)
138 os.chmod(self.childpath, old_child_mode)
139
140 # Clean up.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000141 shutil.rmtree(TESTFN)
142
143 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000144 # test_rmtree_errors deliberately runs rmtree
145 # on a directory that is chmod 400, which will fail.
146 # This function is run when shutil.rmtree fails.
147 # 99.9% of the time it initially fails to remove
148 # a file in the directory, so the first time through
149 # func is os.remove.
150 # However, some Linux machines running ZFS on
151 # FUSE experienced a failure earlier in the process
152 # at os.listdir. The first failure may legally
153 # be either.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000154 if self.errorState == 0:
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000155 if func is os.remove:
156 self.assertEqual(arg, self.childpath)
157 else:
158 self.assertIs(func, os.listdir,
159 "func must be either os.remove or os.listdir")
160 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000161 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000162 self.errorState = 1
163 else:
164 self.assertEqual(func, os.rmdir)
165 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000166 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000167 self.errorState = 2
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000168
Antoine Pitrou78091e62011-12-29 18:54:15 +0100169 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
170 @support.skip_unless_symlink
171 def test_copymode_follow_symlinks(self):
172 tmp_dir = self.mkdtemp()
173 src = os.path.join(tmp_dir, 'foo')
174 dst = os.path.join(tmp_dir, 'bar')
175 src_link = os.path.join(tmp_dir, 'baz')
176 dst_link = os.path.join(tmp_dir, 'quux')
177 write_file(src, 'foo')
178 write_file(dst, 'foo')
179 os.symlink(src, src_link)
180 os.symlink(dst, dst_link)
181 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
182 # file to file
183 os.chmod(dst, stat.S_IRWXO)
184 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
185 shutil.copymode(src, dst)
186 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
187 # follow src link
188 os.chmod(dst, stat.S_IRWXO)
189 shutil.copymode(src_link, dst)
190 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
191 # follow dst link
192 os.chmod(dst, stat.S_IRWXO)
193 shutil.copymode(src, dst_link)
194 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
195 # follow both links
196 os.chmod(dst, stat.S_IRWXO)
197 shutil.copymode(src_link, dst)
198 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
199
200 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
201 @support.skip_unless_symlink
202 def test_copymode_symlink_to_symlink(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 os.chmod(dst, stat.S_IRWXU)
214 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
215 # link to link
216 os.lchmod(dst_link, stat.S_IRWXO)
217 shutil.copymode(src_link, dst_link, symlinks=True)
218 self.assertEqual(os.lstat(src_link).st_mode,
219 os.lstat(dst_link).st_mode)
220 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
221 # src link - use chmod
222 os.lchmod(dst_link, stat.S_IRWXO)
223 shutil.copymode(src_link, dst, symlinks=True)
224 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
225 # dst link - use chmod
226 os.lchmod(dst_link, stat.S_IRWXO)
227 shutil.copymode(src, dst_link, symlinks=True)
228 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
229
230 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
231 @support.skip_unless_symlink
232 def test_copymode_symlink_to_symlink_wo_lchmod(self):
233 tmp_dir = self.mkdtemp()
234 src = os.path.join(tmp_dir, 'foo')
235 dst = os.path.join(tmp_dir, 'bar')
236 src_link = os.path.join(tmp_dir, 'baz')
237 dst_link = os.path.join(tmp_dir, 'quux')
238 write_file(src, 'foo')
239 write_file(dst, 'foo')
240 os.symlink(src, src_link)
241 os.symlink(dst, dst_link)
242 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
243
244 @support.skip_unless_symlink
245 def test_copystat_symlinks(self):
246 tmp_dir = self.mkdtemp()
247 src = os.path.join(tmp_dir, 'foo')
248 dst = os.path.join(tmp_dir, 'bar')
249 src_link = os.path.join(tmp_dir, 'baz')
250 dst_link = os.path.join(tmp_dir, 'qux')
251 write_file(src, 'foo')
252 src_stat = os.stat(src)
253 os.utime(src, (src_stat.st_atime,
254 src_stat.st_mtime - 42.0)) # ensure different mtimes
255 write_file(dst, 'bar')
256 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
257 os.symlink(src, src_link)
258 os.symlink(dst, dst_link)
259 if hasattr(os, 'lchmod'):
260 os.lchmod(src_link, stat.S_IRWXO)
261 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
262 os.lchflags(src_link, stat.UF_NODUMP)
263 src_link_stat = os.lstat(src_link)
264 # follow
265 if hasattr(os, 'lchmod'):
266 shutil.copystat(src_link, dst_link, symlinks=False)
267 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
268 # don't follow
269 shutil.copystat(src_link, dst_link, symlinks=True)
270 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700271 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100272 for attr in 'st_atime', 'st_mtime':
273 # The modification times may be truncated in the new file.
274 self.assertLessEqual(getattr(src_link_stat, attr),
275 getattr(dst_link_stat, attr) + 1)
276 if hasattr(os, 'lchmod'):
277 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
278 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
279 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
280 # tell to follow but dst is not a link
281 shutil.copystat(src_link, dst, symlinks=True)
282 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
283 00000.1)
284
Ned Deilybaf75712012-05-10 17:05:19 -0700285 @unittest.skipUnless(hasattr(os, 'chflags') and
286 hasattr(errno, 'EOPNOTSUPP') and
287 hasattr(errno, 'ENOTSUP'),
288 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
289 def test_copystat_handles_harmless_chflags_errors(self):
290 tmpdir = self.mkdtemp()
291 file1 = os.path.join(tmpdir, 'file1')
292 file2 = os.path.join(tmpdir, 'file2')
293 write_file(file1, 'xxx')
294 write_file(file2, 'xxx')
295
296 def make_chflags_raiser(err):
297 ex = OSError()
298
Larry Hastings90867a52012-06-22 17:01:41 -0700299 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700300 ex.errno = err
301 raise ex
302 return _chflags_raiser
303 old_chflags = os.chflags
304 try:
305 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
306 os.chflags = make_chflags_raiser(err)
307 shutil.copystat(file1, file2)
308 # assert others errors break it
309 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
310 self.assertRaises(OSError, shutil.copystat, file1, file2)
311 finally:
312 os.chflags = old_chflags
313
Antoine Pitrou424246f2012-05-12 19:02:01 +0200314 @support.skip_unless_xattr
315 def test_copyxattr(self):
316 tmp_dir = self.mkdtemp()
317 src = os.path.join(tmp_dir, 'foo')
318 write_file(src, 'foo')
319 dst = os.path.join(tmp_dir, 'bar')
320 write_file(dst, 'bar')
321
322 # no xattr == no problem
323 shutil._copyxattr(src, dst)
324 # common case
325 os.setxattr(src, 'user.foo', b'42')
326 os.setxattr(src, 'user.bar', b'43')
327 shutil._copyxattr(src, dst)
328 self.assertEqual(os.listxattr(src), os.listxattr(dst))
329 self.assertEqual(
330 os.getxattr(src, 'user.foo'),
331 os.getxattr(dst, 'user.foo'))
332 # check errors don't affect other attrs
333 os.remove(dst)
334 write_file(dst, 'bar')
335 os_error = OSError(errno.EPERM, 'EPERM')
336
Larry Hastings9cf065c2012-06-22 16:30:09 -0700337 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200338 if attr == 'user.foo':
339 raise os_error
340 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700341 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200342 try:
343 orig_setxattr = os.setxattr
344 os.setxattr = _raise_on_user_foo
345 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200346 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200347 finally:
348 os.setxattr = orig_setxattr
349
350 @support.skip_unless_symlink
351 @support.skip_unless_xattr
352 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
353 'root privileges required')
354 def test_copyxattr_symlinks(self):
355 # On Linux, it's only possible to access non-user xattr for symlinks;
356 # which in turn require root privileges. This test should be expanded
357 # as soon as other platforms gain support for extended attributes.
358 tmp_dir = self.mkdtemp()
359 src = os.path.join(tmp_dir, 'foo')
360 src_link = os.path.join(tmp_dir, 'baz')
361 write_file(src, 'foo')
362 os.symlink(src, src_link)
363 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700364 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200365 dst = os.path.join(tmp_dir, 'bar')
366 dst_link = os.path.join(tmp_dir, 'qux')
367 write_file(dst, 'bar')
368 os.symlink(dst, dst_link)
369 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700370 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200371 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
372 shutil._copyxattr(src_link, dst, symlinks=True)
373 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
374
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 @support.skip_unless_symlink
376 def test_copy_symlinks(self):
377 tmp_dir = self.mkdtemp()
378 src = os.path.join(tmp_dir, 'foo')
379 dst = os.path.join(tmp_dir, 'bar')
380 src_link = os.path.join(tmp_dir, 'baz')
381 write_file(src, 'foo')
382 os.symlink(src, src_link)
383 if hasattr(os, 'lchmod'):
384 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
385 # don't follow
386 shutil.copy(src_link, dst, symlinks=False)
387 self.assertFalse(os.path.islink(dst))
388 self.assertEqual(read_file(src), read_file(dst))
389 os.remove(dst)
390 # follow
391 shutil.copy(src_link, dst, symlinks=True)
392 self.assertTrue(os.path.islink(dst))
393 self.assertEqual(os.readlink(dst), os.readlink(src_link))
394 if hasattr(os, 'lchmod'):
395 self.assertEqual(os.lstat(src_link).st_mode,
396 os.lstat(dst).st_mode)
397
398 @support.skip_unless_symlink
399 def test_copy2_symlinks(self):
400 tmp_dir = self.mkdtemp()
401 src = os.path.join(tmp_dir, 'foo')
402 dst = os.path.join(tmp_dir, 'bar')
403 src_link = os.path.join(tmp_dir, 'baz')
404 write_file(src, 'foo')
405 os.symlink(src, src_link)
406 if hasattr(os, 'lchmod'):
407 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
408 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
409 os.lchflags(src_link, stat.UF_NODUMP)
410 src_stat = os.stat(src)
411 src_link_stat = os.lstat(src_link)
412 # follow
413 shutil.copy2(src_link, dst, symlinks=False)
414 self.assertFalse(os.path.islink(dst))
415 self.assertEqual(read_file(src), read_file(dst))
416 os.remove(dst)
417 # don't follow
418 shutil.copy2(src_link, dst, symlinks=True)
419 self.assertTrue(os.path.islink(dst))
420 self.assertEqual(os.readlink(dst), os.readlink(src_link))
421 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700422 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100423 for attr in 'st_atime', 'st_mtime':
424 # The modification times may be truncated in the new file.
425 self.assertLessEqual(getattr(src_link_stat, attr),
426 getattr(dst_stat, attr) + 1)
427 if hasattr(os, 'lchmod'):
428 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
429 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
430 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
431 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
432
Antoine Pitrou424246f2012-05-12 19:02:01 +0200433 @support.skip_unless_xattr
434 def test_copy2_xattr(self):
435 tmp_dir = self.mkdtemp()
436 src = os.path.join(tmp_dir, 'foo')
437 dst = os.path.join(tmp_dir, 'bar')
438 write_file(src, 'foo')
439 os.setxattr(src, 'user.foo', b'42')
440 shutil.copy2(src, dst)
441 self.assertEqual(
442 os.getxattr(src, 'user.foo'),
443 os.getxattr(dst, 'user.foo'))
444 os.remove(dst)
445
Antoine Pitrou78091e62011-12-29 18:54:15 +0100446 @support.skip_unless_symlink
447 def test_copyfile_symlinks(self):
448 tmp_dir = self.mkdtemp()
449 src = os.path.join(tmp_dir, 'src')
450 dst = os.path.join(tmp_dir, 'dst')
451 dst_link = os.path.join(tmp_dir, 'dst_link')
452 link = os.path.join(tmp_dir, 'link')
453 write_file(src, 'foo')
454 os.symlink(src, link)
455 # don't follow
456 shutil.copyfile(link, dst_link, symlinks=True)
457 self.assertTrue(os.path.islink(dst_link))
458 self.assertEqual(os.readlink(link), os.readlink(dst_link))
459 # follow
460 shutil.copyfile(link, dst)
461 self.assertFalse(os.path.islink(dst))
462
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000463 def test_rmtree_dont_delete_file(self):
464 # When called on a file instead of a directory, don't delete it.
465 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200466 os.close(handle)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000467 self.assertRaises(OSError, shutil.rmtree, path)
468 os.remove(path)
469
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000470 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000471 src_dir = tempfile.mkdtemp()
472 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200473 self.addCleanup(shutil.rmtree, src_dir)
474 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
475 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000476 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200477 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000478
Éric Araujoa7e33a12011-08-12 19:51:35 +0200479 shutil.copytree(src_dir, dst_dir)
480 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
481 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
482 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
483 'test.txt')))
484 actual = read_file((dst_dir, 'test.txt'))
485 self.assertEqual(actual, '123')
486 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
487 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000488
Antoine Pitrou78091e62011-12-29 18:54:15 +0100489 @support.skip_unless_symlink
490 def test_copytree_symlinks(self):
491 tmp_dir = self.mkdtemp()
492 src_dir = os.path.join(tmp_dir, 'src')
493 dst_dir = os.path.join(tmp_dir, 'dst')
494 sub_dir = os.path.join(src_dir, 'sub')
495 os.mkdir(src_dir)
496 os.mkdir(sub_dir)
497 write_file((src_dir, 'file.txt'), 'foo')
498 src_link = os.path.join(sub_dir, 'link')
499 dst_link = os.path.join(dst_dir, 'sub/link')
500 os.symlink(os.path.join(src_dir, 'file.txt'),
501 src_link)
502 if hasattr(os, 'lchmod'):
503 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
504 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
505 os.lchflags(src_link, stat.UF_NODUMP)
506 src_stat = os.lstat(src_link)
507 shutil.copytree(src_dir, dst_dir, symlinks=True)
508 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
509 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
510 os.path.join(src_dir, 'file.txt'))
511 dst_stat = os.lstat(dst_link)
512 if hasattr(os, 'lchmod'):
513 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
514 if hasattr(os, 'lchflags'):
515 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
516
Georg Brandl2ee470f2008-07-16 12:55:28 +0000517 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000518 # creating data
519 join = os.path.join
520 exists = os.path.exists
521 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000522 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000523 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200524 write_file((src_dir, 'test.txt'), '123')
525 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000526 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200527 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000528 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200529 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000530 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
531 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200532 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
533 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000534
535 # testing glob-like patterns
536 try:
537 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
538 shutil.copytree(src_dir, dst_dir, ignore=patterns)
539 # checking the result: some elements should not be copied
540 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200541 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
542 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000543 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200544 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000545 try:
546 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
547 shutil.copytree(src_dir, dst_dir, ignore=patterns)
548 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200549 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
550 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
551 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000552 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200553 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000554
555 # testing callable-style
556 try:
557 def _filter(src, names):
558 res = []
559 for name in names:
560 path = os.path.join(src, name)
561
562 if (os.path.isdir(path) and
563 path.split()[-1] == 'subdir'):
564 res.append(name)
565 elif os.path.splitext(path)[-1] in ('.py'):
566 res.append(name)
567 return res
568
569 shutil.copytree(src_dir, dst_dir, ignore=_filter)
570
571 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200572 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
573 'test.py')))
574 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000575
576 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200577 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000578 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000579 shutil.rmtree(src_dir)
580 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000581
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000582 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000583 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000584 # Temporarily disable test on Windows.
585 if os.name == 'nt':
586 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000587 # bug 851123.
588 os.mkdir(TESTFN)
589 src = os.path.join(TESTFN, 'cheese')
590 dst = os.path.join(TESTFN, 'shop')
591 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000592 with open(src, 'w') as f:
593 f.write('cheddar')
594 os.link(src, dst)
595 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
596 with open(src, 'r') as f:
597 self.assertEqual(f.read(), 'cheddar')
598 os.remove(dst)
599 finally:
600 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000601
Brian Curtin3b4499c2010-12-28 14:31:47 +0000602 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000603 def test_dont_copy_file_onto_symlink_to_itself(self):
604 # bug 851123.
605 os.mkdir(TESTFN)
606 src = os.path.join(TESTFN, 'cheese')
607 dst = os.path.join(TESTFN, 'shop')
608 try:
609 with open(src, 'w') as f:
610 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000611 # Using `src` here would mean we end up with a symlink pointing
612 # to TESTFN/TESTFN/cheese, while it should point at
613 # TESTFN/cheese.
614 os.symlink('cheese', dst)
615 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000616 with open(src, 'r') as f:
617 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000618 os.remove(dst)
619 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000620 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000621
Brian Curtin3b4499c2010-12-28 14:31:47 +0000622 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000623 def test_rmtree_on_symlink(self):
624 # bug 1669.
625 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000626 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000627 src = os.path.join(TESTFN, 'cheese')
628 dst = os.path.join(TESTFN, 'shop')
629 os.mkdir(src)
630 os.symlink(src, dst)
631 self.assertRaises(OSError, shutil.rmtree, dst)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000632 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000633 shutil.rmtree(TESTFN, ignore_errors=True)
634
635 if hasattr(os, "mkfifo"):
636 # Issue #3002: copyfile and copytree block indefinitely on named pipes
637 def test_copyfile_named_pipe(self):
638 os.mkfifo(TESTFN)
639 try:
640 self.assertRaises(shutil.SpecialFileError,
641 shutil.copyfile, TESTFN, TESTFN2)
642 self.assertRaises(shutil.SpecialFileError,
643 shutil.copyfile, __file__, TESTFN)
644 finally:
645 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000646
Brian Curtin3b4499c2010-12-28 14:31:47 +0000647 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000648 def test_copytree_named_pipe(self):
649 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000650 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000651 subdir = os.path.join(TESTFN, "subdir")
652 os.mkdir(subdir)
653 pipe = os.path.join(subdir, "mypipe")
654 os.mkfifo(pipe)
655 try:
656 shutil.copytree(TESTFN, TESTFN2)
657 except shutil.Error as e:
658 errors = e.args[0]
659 self.assertEqual(len(errors), 1)
660 src, dst, error_msg = errors[0]
661 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
662 else:
663 self.fail("shutil.Error should have been raised")
664 finally:
665 shutil.rmtree(TESTFN, ignore_errors=True)
666 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000667
Tarek Ziadé5340db32010-04-19 22:30:51 +0000668 def test_copytree_special_func(self):
669
670 src_dir = self.mkdtemp()
671 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200672 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000673 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200674 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000675
676 copied = []
677 def _copy(src, dst):
678 copied.append((src, dst))
679
680 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000681 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000682
Brian Curtin3b4499c2010-12-28 14:31:47 +0000683 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000684 def test_copytree_dangling_symlinks(self):
685
686 # a dangling symlink raises an error at the end
687 src_dir = self.mkdtemp()
688 dst_dir = os.path.join(self.mkdtemp(), 'destination')
689 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
690 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000692 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
693
694 # a dangling symlink is ignored with the proper flag
695 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
696 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
697 self.assertNotIn('test.txt', os.listdir(dst_dir))
698
699 # a dangling symlink is copied if symlinks=True
700 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
701 shutil.copytree(src_dir, dst_dir, symlinks=True)
702 self.assertIn('test.txt', os.listdir(dst_dir))
703
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400704 def _copy_file(self, method):
705 fname = 'test.txt'
706 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200707 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400708 file1 = os.path.join(tmpdir, fname)
709 tmpdir2 = self.mkdtemp()
710 method(file1, tmpdir2)
711 file2 = os.path.join(tmpdir2, fname)
712 return (file1, file2)
713
714 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
715 def test_copy(self):
716 # Ensure that the copied file exists and has the same mode bits.
717 file1, file2 = self._copy_file(shutil.copy)
718 self.assertTrue(os.path.exists(file2))
719 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
720
721 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700722 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400723 def test_copy2(self):
724 # Ensure that the copied file exists and has the same mode and
725 # modification time bits.
726 file1, file2 = self._copy_file(shutil.copy2)
727 self.assertTrue(os.path.exists(file2))
728 file1_stat = os.stat(file1)
729 file2_stat = os.stat(file2)
730 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
731 for attr in 'st_atime', 'st_mtime':
732 # The modification times may be truncated in the new file.
733 self.assertLessEqual(getattr(file1_stat, attr),
734 getattr(file2_stat, attr) + 1)
735 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
736 self.assertEqual(getattr(file1_stat, 'st_flags'),
737 getattr(file2_stat, 'st_flags'))
738
Ezio Melotti975077a2011-05-19 22:03:22 +0300739 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000740 def test_make_tarball(self):
741 # creating something to tar
742 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200743 write_file((tmpdir, 'file1'), 'xxx')
744 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000745 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200746 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000747
748 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400749 # force shutil to create the directory
750 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000751 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
752 "source and target should be on same drive")
753
754 base_name = os.path.join(tmpdir2, 'archive')
755
756 # working with relative paths to avoid tar warnings
757 old_dir = os.getcwd()
758 os.chdir(tmpdir)
759 try:
760 _make_tarball(splitdrive(base_name)[1], '.')
761 finally:
762 os.chdir(old_dir)
763
764 # check if the compressed tarball was created
765 tarball = base_name + '.tar.gz'
766 self.assertTrue(os.path.exists(tarball))
767
768 # trying an uncompressed one
769 base_name = os.path.join(tmpdir2, 'archive')
770 old_dir = os.getcwd()
771 os.chdir(tmpdir)
772 try:
773 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
774 finally:
775 os.chdir(old_dir)
776 tarball = base_name + '.tar'
777 self.assertTrue(os.path.exists(tarball))
778
779 def _tarinfo(self, path):
780 tar = tarfile.open(path)
781 try:
782 names = tar.getnames()
783 names.sort()
784 return tuple(names)
785 finally:
786 tar.close()
787
788 def _create_files(self):
789 # creating something to tar
790 tmpdir = self.mkdtemp()
791 dist = os.path.join(tmpdir, 'dist')
792 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200793 write_file((dist, 'file1'), 'xxx')
794 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000795 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200796 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000797 os.mkdir(os.path.join(dist, 'sub2'))
798 tmpdir2 = self.mkdtemp()
799 base_name = os.path.join(tmpdir2, 'archive')
800 return tmpdir, tmpdir2, base_name
801
Ezio Melotti975077a2011-05-19 22:03:22 +0300802 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000803 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
804 'Need the tar command to run')
805 def test_tarfile_vs_tar(self):
806 tmpdir, tmpdir2, base_name = self._create_files()
807 old_dir = os.getcwd()
808 os.chdir(tmpdir)
809 try:
810 _make_tarball(base_name, 'dist')
811 finally:
812 os.chdir(old_dir)
813
814 # check if the compressed tarball was created
815 tarball = base_name + '.tar.gz'
816 self.assertTrue(os.path.exists(tarball))
817
818 # now create another tarball using `tar`
819 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
820 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
821 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
822 old_dir = os.getcwd()
823 os.chdir(tmpdir)
824 try:
825 with captured_stdout() as s:
826 spawn(tar_cmd)
827 spawn(gzip_cmd)
828 finally:
829 os.chdir(old_dir)
830
831 self.assertTrue(os.path.exists(tarball2))
832 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000833 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000834
835 # trying an uncompressed one
836 base_name = os.path.join(tmpdir2, 'archive')
837 old_dir = os.getcwd()
838 os.chdir(tmpdir)
839 try:
840 _make_tarball(base_name, 'dist', compress=None)
841 finally:
842 os.chdir(old_dir)
843 tarball = base_name + '.tar'
844 self.assertTrue(os.path.exists(tarball))
845
846 # now for a dry_run
847 base_name = os.path.join(tmpdir2, 'archive')
848 old_dir = os.getcwd()
849 os.chdir(tmpdir)
850 try:
851 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
852 finally:
853 os.chdir(old_dir)
854 tarball = base_name + '.tar'
855 self.assertTrue(os.path.exists(tarball))
856
Ezio Melotti975077a2011-05-19 22:03:22 +0300857 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000858 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
859 def test_make_zipfile(self):
860 # creating something to tar
861 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200862 write_file((tmpdir, 'file1'), 'xxx')
863 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000864
865 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400866 # force shutil to create the directory
867 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000868 base_name = os.path.join(tmpdir2, 'archive')
869 _make_zipfile(base_name, tmpdir)
870
871 # check if the compressed tarball was created
872 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000873 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000874
875
876 def test_make_archive(self):
877 tmpdir = self.mkdtemp()
878 base_name = os.path.join(tmpdir, 'archive')
879 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
880
Ezio Melotti975077a2011-05-19 22:03:22 +0300881 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000882 def test_make_archive_owner_group(self):
883 # testing make_archive with owner and group, with various combinations
884 # this works even if there's not gid/uid support
885 if UID_GID_SUPPORT:
886 group = grp.getgrgid(0)[0]
887 owner = pwd.getpwuid(0)[0]
888 else:
889 group = owner = 'root'
890
891 base_dir, root_dir, base_name = self._create_files()
892 base_name = os.path.join(self.mkdtemp() , 'archive')
893 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
894 group=group)
895 self.assertTrue(os.path.exists(res))
896
897 res = make_archive(base_name, 'zip', root_dir, base_dir)
898 self.assertTrue(os.path.exists(res))
899
900 res = make_archive(base_name, 'tar', root_dir, base_dir,
901 owner=owner, group=group)
902 self.assertTrue(os.path.exists(res))
903
904 res = make_archive(base_name, 'tar', root_dir, base_dir,
905 owner='kjhkjhkjg', group='oihohoh')
906 self.assertTrue(os.path.exists(res))
907
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000908
Ezio Melotti975077a2011-05-19 22:03:22 +0300909 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
911 def test_tarfile_root_owner(self):
912 tmpdir, tmpdir2, base_name = self._create_files()
913 old_dir = os.getcwd()
914 os.chdir(tmpdir)
915 group = grp.getgrgid(0)[0]
916 owner = pwd.getpwuid(0)[0]
917 try:
918 archive_name = _make_tarball(base_name, 'dist', compress=None,
919 owner=owner, group=group)
920 finally:
921 os.chdir(old_dir)
922
923 # check if the compressed tarball was created
924 self.assertTrue(os.path.exists(archive_name))
925
926 # now checks the rights
927 archive = tarfile.open(archive_name)
928 try:
929 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000930 self.assertEqual(member.uid, 0)
931 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932 finally:
933 archive.close()
934
935 def test_make_archive_cwd(self):
936 current_dir = os.getcwd()
937 def _breaks(*args, **kw):
938 raise RuntimeError()
939
940 register_archive_format('xxx', _breaks, [], 'xxx file')
941 try:
942 try:
943 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
944 except Exception:
945 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000946 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000947 finally:
948 unregister_archive_format('xxx')
949
950 def test_register_archive_format(self):
951
952 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
953 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
954 1)
955 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
956 [(1, 2), (1, 2, 3)])
957
958 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
959 formats = [name for name, params in get_archive_formats()]
960 self.assertIn('xxx', formats)
961
962 unregister_archive_format('xxx')
963 formats = [name for name, params in get_archive_formats()]
964 self.assertNotIn('xxx', formats)
965
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000966 def _compare_dirs(self, dir1, dir2):
967 # check that dir1 and dir2 are equivalent,
968 # return the diff
969 diff = []
970 for root, dirs, files in os.walk(dir1):
971 for file_ in files:
972 path = os.path.join(root, file_)
973 target_path = os.path.join(dir2, os.path.split(path)[-1])
974 if not os.path.exists(target_path):
975 diff.append(file_)
976 return diff
977
Ezio Melotti975077a2011-05-19 22:03:22 +0300978 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000979 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000980 formats = ['tar', 'gztar', 'zip']
981 if BZ2_SUPPORTED:
982 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000983
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000984 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000985 tmpdir = self.mkdtemp()
986 base_dir, root_dir, base_name = self._create_files()
987 tmpdir2 = self.mkdtemp()
988 filename = make_archive(base_name, format, root_dir, base_dir)
989
990 # let's try to unpack it now
991 unpack_archive(filename, tmpdir2)
992 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000993 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000994
Nick Coghlanabf202d2011-03-16 13:52:20 -0400995 # and again, this time with the format specified
996 tmpdir3 = self.mkdtemp()
997 unpack_archive(filename, tmpdir3, format=format)
998 diff = self._compare_dirs(tmpdir, tmpdir3)
999 self.assertEqual(diff, [])
1000 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1001 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1002
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001003 def test_unpack_registery(self):
1004
1005 formats = get_unpack_formats()
1006
1007 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001008 self.assertEqual(extra, 1)
1009 self.assertEqual(filename, 'stuff.boo')
1010 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001011
1012 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1013 unpack_archive('stuff.boo', 'xx')
1014
1015 # trying to register a .boo unpacker again
1016 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1017 ['.boo'], _boo)
1018
1019 # should work now
1020 unregister_unpack_format('Boo')
1021 register_unpack_format('Boo2', ['.boo'], _boo)
1022 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1023 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1024
1025 # let's leave a clean state
1026 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001027 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001028
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001029 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1030 "disk_usage not available on this platform")
1031 def test_disk_usage(self):
1032 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001033 self.assertGreater(usage.total, 0)
1034 self.assertGreater(usage.used, 0)
1035 self.assertGreaterEqual(usage.free, 0)
1036 self.assertGreaterEqual(usage.total, usage.used)
1037 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001038
Sandro Tosid902a142011-08-22 23:28:27 +02001039 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1040 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1041 def test_chown(self):
1042
1043 # cleaned-up automatically by TestShutil.tearDown method
1044 dirname = self.mkdtemp()
1045 filename = tempfile.mktemp(dir=dirname)
1046 write_file(filename, 'testing chown function')
1047
1048 with self.assertRaises(ValueError):
1049 shutil.chown(filename)
1050
1051 with self.assertRaises(LookupError):
1052 shutil.chown(filename, user='non-exising username')
1053
1054 with self.assertRaises(LookupError):
1055 shutil.chown(filename, group='non-exising groupname')
1056
1057 with self.assertRaises(TypeError):
1058 shutil.chown(filename, b'spam')
1059
1060 with self.assertRaises(TypeError):
1061 shutil.chown(filename, 3.14)
1062
1063 uid = os.getuid()
1064 gid = os.getgid()
1065
1066 def check_chown(path, uid=None, gid=None):
1067 s = os.stat(filename)
1068 if uid is not None:
1069 self.assertEqual(uid, s.st_uid)
1070 if gid is not None:
1071 self.assertEqual(gid, s.st_gid)
1072
1073 shutil.chown(filename, uid, gid)
1074 check_chown(filename, uid, gid)
1075 shutil.chown(filename, uid)
1076 check_chown(filename, uid)
1077 shutil.chown(filename, user=uid)
1078 check_chown(filename, uid)
1079 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001080 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001081
1082 shutil.chown(dirname, uid, gid)
1083 check_chown(dirname, uid, gid)
1084 shutil.chown(dirname, uid)
1085 check_chown(dirname, uid)
1086 shutil.chown(dirname, user=uid)
1087 check_chown(dirname, uid)
1088 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001089 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001090
1091 user = pwd.getpwuid(uid)[0]
1092 group = grp.getgrgid(gid)[0]
1093 shutil.chown(filename, user, group)
1094 check_chown(filename, uid, gid)
1095 shutil.chown(dirname, user, group)
1096 check_chown(dirname, uid, gid)
1097
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001098 def test_copy_return_value(self):
1099 # copy and copy2 both return their destination path.
1100 for fn in (shutil.copy, shutil.copy2):
1101 src_dir = self.mkdtemp()
1102 dst_dir = self.mkdtemp()
1103 src = os.path.join(src_dir, 'foo')
1104 write_file(src, 'foo')
1105 rv = fn(src, dst_dir)
1106 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1107 rv = fn(src, os.path.join(dst_dir, 'bar'))
1108 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1109
1110 def test_copyfile_return_value(self):
1111 # copytree returns its destination path.
1112 src_dir = self.mkdtemp()
1113 dst_dir = self.mkdtemp()
1114 dst_file = os.path.join(dst_dir, 'bar')
1115 src_file = os.path.join(src_dir, 'foo')
1116 write_file(src_file, 'foo')
1117 rv = shutil.copyfile(src_file, dst_file)
1118 self.assertTrue(os.path.exists(rv))
1119 self.assertEqual(read_file(src_file), read_file(dst_file))
1120
1121 def test_copytree_return_value(self):
1122 # copytree returns its destination path.
1123 src_dir = self.mkdtemp()
1124 dst_dir = src_dir + "dest"
1125 src = os.path.join(src_dir, 'foo')
1126 write_file(src, 'foo')
1127 rv = shutil.copytree(src_dir, dst_dir)
1128 self.assertEqual(['foo'], os.listdir(rv))
1129
Christian Heimes9bd667a2008-01-20 15:14:11 +00001130
Brian Curtinc57a3452012-06-22 16:00:30 -05001131class TestWhich(unittest.TestCase):
1132
1133 def setUp(self):
1134 self.temp_dir = tempfile.mkdtemp()
1135 # Give the temp_file an ".exe" suffix for all.
1136 # It's needed on Windows and not harmful on other platforms.
1137 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1138 suffix=".exe")
1139 os.chmod(self.temp_file.name, stat.S_IXUSR)
1140 self.addCleanup(self.temp_file.close)
1141 self.dir, self.file = os.path.split(self.temp_file.name)
1142
1143 def test_basic(self):
1144 # Given an EXE in a directory, it should be returned.
1145 rv = shutil.which(self.file, path=self.dir)
1146 self.assertEqual(rv, self.temp_file.name)
1147
1148 def test_full_path_short_circuit(self):
1149 # When given the fully qualified path to an executable that exists,
1150 # it should be returned.
1151 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1152 self.assertEqual(self.temp_file.name, rv)
1153
1154 def test_non_matching_mode(self):
1155 # Set the file read-only and ask for writeable files.
1156 os.chmod(self.temp_file.name, stat.S_IREAD)
1157 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1158 self.assertIsNone(rv)
1159
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001160 def test_relative(self):
1161 old_cwd = os.getcwd()
1162 base_dir, tail_dir = os.path.split(self.dir)
1163 os.chdir(base_dir)
1164 try:
1165 rv = shutil.which(self.file, path=tail_dir)
1166 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1167 finally:
1168 os.chdir(old_cwd)
1169
Brian Curtinc57a3452012-06-22 16:00:30 -05001170 def test_nonexistent_file(self):
1171 # Return None when no matching executable file is found on the path.
1172 rv = shutil.which("foo.exe", path=self.dir)
1173 self.assertIsNone(rv)
1174
1175 @unittest.skipUnless(sys.platform == "win32",
1176 "pathext check is Windows-only")
1177 def test_pathext_checking(self):
1178 # Ask for the file without the ".exe" extension, then ensure that
1179 # it gets found properly with the extension.
1180 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1181 self.assertEqual(self.temp_file.name, rv)
1182
1183
Christian Heimesada8c3b2008-03-18 18:26:33 +00001184class TestMove(unittest.TestCase):
1185
1186 def setUp(self):
1187 filename = "foo"
1188 self.src_dir = tempfile.mkdtemp()
1189 self.dst_dir = tempfile.mkdtemp()
1190 self.src_file = os.path.join(self.src_dir, filename)
1191 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001192 with open(self.src_file, "wb") as f:
1193 f.write(b"spam")
1194
1195 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001196 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001197 try:
1198 if d:
1199 shutil.rmtree(d)
1200 except:
1201 pass
1202
1203 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001204 with open(src, "rb") as f:
1205 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001206 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001207 with open(real_dst, "rb") as f:
1208 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001209 self.assertFalse(os.path.exists(src))
1210
1211 def _check_move_dir(self, src, dst, real_dst):
1212 contents = sorted(os.listdir(src))
1213 shutil.move(src, dst)
1214 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1215 self.assertFalse(os.path.exists(src))
1216
1217 def test_move_file(self):
1218 # Move a file to another location on the same filesystem.
1219 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1220
1221 def test_move_file_to_dir(self):
1222 # Move a file inside an existing dir on the same filesystem.
1223 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1224
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001225 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001226 def test_move_file_other_fs(self):
1227 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001228 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001229
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001230 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001231 def test_move_file_to_dir_other_fs(self):
1232 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001233 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001234
1235 def test_move_dir(self):
1236 # Move a dir to another location on the same filesystem.
1237 dst_dir = tempfile.mktemp()
1238 try:
1239 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1240 finally:
1241 try:
1242 shutil.rmtree(dst_dir)
1243 except:
1244 pass
1245
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001246 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001247 def test_move_dir_other_fs(self):
1248 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001249 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001250
1251 def test_move_dir_to_dir(self):
1252 # Move a dir inside an existing dir on the same filesystem.
1253 self._check_move_dir(self.src_dir, self.dst_dir,
1254 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1255
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001256 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001257 def test_move_dir_to_dir_other_fs(self):
1258 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001259 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001260
1261 def test_existing_file_inside_dest_dir(self):
1262 # A file with the same name inside the destination dir already exists.
1263 with open(self.dst_file, "wb"):
1264 pass
1265 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1266
1267 def test_dont_move_dir_in_itself(self):
1268 # Moving a dir inside itself raises an Error.
1269 dst = os.path.join(self.src_dir, "bar")
1270 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1271
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001272 def test_destinsrc_false_negative(self):
1273 os.mkdir(TESTFN)
1274 try:
1275 for src, dst in [('srcdir', 'srcdir/dest')]:
1276 src = os.path.join(TESTFN, src)
1277 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001278 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001279 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001280 'dst (%s) is not in src (%s)' % (dst, src))
1281 finally:
1282 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001283
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001284 def test_destinsrc_false_positive(self):
1285 os.mkdir(TESTFN)
1286 try:
1287 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1288 src = os.path.join(TESTFN, src)
1289 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001290 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001291 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001292 'dst (%s) is in src (%s)' % (dst, src))
1293 finally:
1294 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001295
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001296 @support.skip_unless_symlink
1297 @mock_rename
1298 def test_move_file_symlink(self):
1299 dst = os.path.join(self.src_dir, 'bar')
1300 os.symlink(self.src_file, dst)
1301 shutil.move(dst, self.dst_file)
1302 self.assertTrue(os.path.islink(self.dst_file))
1303 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1304
1305 @support.skip_unless_symlink
1306 @mock_rename
1307 def test_move_file_symlink_to_dir(self):
1308 filename = "bar"
1309 dst = os.path.join(self.src_dir, filename)
1310 os.symlink(self.src_file, dst)
1311 shutil.move(dst, self.dst_dir)
1312 final_link = os.path.join(self.dst_dir, filename)
1313 self.assertTrue(os.path.islink(final_link))
1314 self.assertTrue(os.path.samefile(self.src_file, final_link))
1315
1316 @support.skip_unless_symlink
1317 @mock_rename
1318 def test_move_dangling_symlink(self):
1319 src = os.path.join(self.src_dir, 'baz')
1320 dst = os.path.join(self.src_dir, 'bar')
1321 os.symlink(src, dst)
1322 dst_link = os.path.join(self.dst_dir, 'quux')
1323 shutil.move(dst, dst_link)
1324 self.assertTrue(os.path.islink(dst_link))
1325 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1326
1327 @support.skip_unless_symlink
1328 @mock_rename
1329 def test_move_dir_symlink(self):
1330 src = os.path.join(self.src_dir, 'baz')
1331 dst = os.path.join(self.src_dir, 'bar')
1332 os.mkdir(src)
1333 os.symlink(src, dst)
1334 dst_link = os.path.join(self.dst_dir, 'quux')
1335 shutil.move(dst, dst_link)
1336 self.assertTrue(os.path.islink(dst_link))
1337 self.assertTrue(os.path.samefile(src, dst_link))
1338
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001339 def test_move_return_value(self):
1340 rv = shutil.move(self.src_file, self.dst_dir)
1341 self.assertEqual(rv,
1342 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1343
1344 def test_move_as_rename_return_value(self):
1345 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1346 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1347
Tarek Ziadé5340db32010-04-19 22:30:51 +00001348
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001349class TestCopyFile(unittest.TestCase):
1350
1351 _delete = False
1352
1353 class Faux(object):
1354 _entered = False
1355 _exited_with = None
1356 _raised = False
1357 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1358 self._raise_in_exit = raise_in_exit
1359 self._suppress_at_exit = suppress_at_exit
1360 def read(self, *args):
1361 return ''
1362 def __enter__(self):
1363 self._entered = True
1364 def __exit__(self, exc_type, exc_val, exc_tb):
1365 self._exited_with = exc_type, exc_val, exc_tb
1366 if self._raise_in_exit:
1367 self._raised = True
1368 raise IOError("Cannot close")
1369 return self._suppress_at_exit
1370
1371 def tearDown(self):
1372 if self._delete:
1373 del shutil.open
1374
1375 def _set_shutil_open(self, func):
1376 shutil.open = func
1377 self._delete = True
1378
1379 def test_w_source_open_fails(self):
1380 def _open(filename, mode='r'):
1381 if filename == 'srcfile':
1382 raise IOError('Cannot open "srcfile"')
1383 assert 0 # shouldn't reach here.
1384
1385 self._set_shutil_open(_open)
1386
1387 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1388
1389 def test_w_dest_open_fails(self):
1390
1391 srcfile = self.Faux()
1392
1393 def _open(filename, mode='r'):
1394 if filename == 'srcfile':
1395 return srcfile
1396 if filename == 'destfile':
1397 raise IOError('Cannot open "destfile"')
1398 assert 0 # shouldn't reach here.
1399
1400 self._set_shutil_open(_open)
1401
1402 shutil.copyfile('srcfile', 'destfile')
1403 self.assertTrue(srcfile._entered)
1404 self.assertTrue(srcfile._exited_with[0] is IOError)
1405 self.assertEqual(srcfile._exited_with[1].args,
1406 ('Cannot open "destfile"',))
1407
1408 def test_w_dest_close_fails(self):
1409
1410 srcfile = self.Faux()
1411 destfile = self.Faux(True)
1412
1413 def _open(filename, mode='r'):
1414 if filename == 'srcfile':
1415 return srcfile
1416 if filename == 'destfile':
1417 return destfile
1418 assert 0 # shouldn't reach here.
1419
1420 self._set_shutil_open(_open)
1421
1422 shutil.copyfile('srcfile', 'destfile')
1423 self.assertTrue(srcfile._entered)
1424 self.assertTrue(destfile._entered)
1425 self.assertTrue(destfile._raised)
1426 self.assertTrue(srcfile._exited_with[0] is IOError)
1427 self.assertEqual(srcfile._exited_with[1].args,
1428 ('Cannot close',))
1429
1430 def test_w_source_close_fails(self):
1431
1432 srcfile = self.Faux(True)
1433 destfile = self.Faux()
1434
1435 def _open(filename, mode='r'):
1436 if filename == 'srcfile':
1437 return srcfile
1438 if filename == 'destfile':
1439 return destfile
1440 assert 0 # shouldn't reach here.
1441
1442 self._set_shutil_open(_open)
1443
1444 self.assertRaises(IOError,
1445 shutil.copyfile, 'srcfile', 'destfile')
1446 self.assertTrue(srcfile._entered)
1447 self.assertTrue(destfile._entered)
1448 self.assertFalse(destfile._raised)
1449 self.assertTrue(srcfile._exited_with[0] is None)
1450 self.assertTrue(srcfile._raised)
1451
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001452 def test_move_dir_caseinsensitive(self):
1453 # Renames a folder to the same name
1454 # but a different case.
1455
1456 self.src_dir = tempfile.mkdtemp()
1457 dst_dir = os.path.join(
1458 os.path.dirname(self.src_dir),
1459 os.path.basename(self.src_dir).upper())
1460 self.assertNotEqual(self.src_dir, dst_dir)
1461
1462 try:
1463 shutil.move(self.src_dir, dst_dir)
1464 self.assertTrue(os.path.isdir(dst_dir))
1465 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001466 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001467
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001468class TermsizeTests(unittest.TestCase):
1469 def test_does_not_crash(self):
1470 """Check if get_terminal_size() returns a meaningful value.
1471
1472 There's no easy portable way to actually check the size of the
1473 terminal, so let's check if it returns something sensible instead.
1474 """
1475 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001476 self.assertGreaterEqual(size.columns, 0)
1477 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001478
1479 def test_os_environ_first(self):
1480 "Check if environment variables have precedence"
1481
1482 with support.EnvironmentVarGuard() as env:
1483 env['COLUMNS'] = '777'
1484 size = shutil.get_terminal_size()
1485 self.assertEqual(size.columns, 777)
1486
1487 with support.EnvironmentVarGuard() as env:
1488 env['LINES'] = '888'
1489 size = shutil.get_terminal_size()
1490 self.assertEqual(size.lines, 888)
1491
1492 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1493 def test_stty_match(self):
1494 """Check if stty returns the same results ignoring env
1495
1496 This test will fail if stdin and stdout are connected to
1497 different terminals with different sizes. Nevertheless, such
1498 situations should be pretty rare.
1499 """
1500 try:
1501 size = subprocess.check_output(['stty', 'size']).decode().split()
1502 except (FileNotFoundError, subprocess.CalledProcessError):
1503 self.skipTest("stty invocation failed")
1504 expected = (int(size[1]), int(size[0])) # reversed order
1505
1506 with support.EnvironmentVarGuard() as env:
1507 del env['LINES']
1508 del env['COLUMNS']
1509 actual = shutil.get_terminal_size()
1510
1511 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001512
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001513
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001514def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001515 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001516 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001517
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001518if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001519 test_main()