Commit 8ed3cf3a authored by Nick Coghlan's avatar Nick Coghlan

Close #11560: Improve test coverage of shutil

parent abf202d7
...@@ -7,6 +7,7 @@ import sys ...@@ -7,6 +7,7 @@ import sys
import stat import stat
import os import os
import os.path import os.path
import functools
from test import support from test import support
from test.support import TESTFN from test.support import TESTFN
from os.path import splitdrive from os.path import splitdrive
...@@ -48,6 +49,21 @@ try: ...@@ -48,6 +49,21 @@ try:
except ImportError: except ImportError:
ZIP_SUPPORT = find_executable('zip') ZIP_SUPPORT = find_executable('zip')
def _fake_rename(*args, **kwargs):
# Pretend the destination path is on a different filesystem.
raise OSError()
def mock_rename(func):
@functools.wraps(func)
def wrap(*args, **kwargs):
try:
builtin_rename = os.rename
os.rename = _fake_rename
return func(*args, **kwargs)
finally:
os.rename = builtin_rename
return wrap
class TestShutil(unittest.TestCase): class TestShutil(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -393,6 +409,41 @@ class TestShutil(unittest.TestCase): ...@@ -393,6 +409,41 @@ class TestShutil(unittest.TestCase):
shutil.copytree(src_dir, dst_dir, symlinks=True) shutil.copytree(src_dir, dst_dir, symlinks=True)
self.assertIn('test.txt', os.listdir(dst_dir)) self.assertIn('test.txt', os.listdir(dst_dir))
def _copy_file(self, method):
fname = 'test.txt'
tmpdir = self.mkdtemp()
self.write_file([tmpdir, fname])
file1 = os.path.join(tmpdir, fname)
tmpdir2 = self.mkdtemp()
method(file1, tmpdir2)
file2 = os.path.join(tmpdir2, fname)
return (file1, file2)
@unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
def test_copy(self):
# Ensure that the copied file exists and has the same mode bits.
file1, file2 = self._copy_file(shutil.copy)
self.assertTrue(os.path.exists(file2))
self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
@unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
@unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.utime')
def test_copy2(self):
# Ensure that the copied file exists and has the same mode and
# modification time bits.
file1, file2 = self._copy_file(shutil.copy2)
self.assertTrue(os.path.exists(file2))
file1_stat = os.stat(file1)
file2_stat = os.stat(file2)
self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
for attr in 'st_atime', 'st_mtime':
# The modification times may be truncated in the new file.
self.assertLessEqual(getattr(file1_stat, attr),
getattr(file2_stat, attr) + 1)
if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
self.assertEqual(getattr(file1_stat, 'st_flags'),
getattr(file2_stat, 'st_flags'))
@unittest.skipUnless(zlib, "requires zlib") @unittest.skipUnless(zlib, "requires zlib")
def test_make_tarball(self): def test_make_tarball(self):
# creating something to tar # creating something to tar
...@@ -403,6 +454,8 @@ class TestShutil(unittest.TestCase): ...@@ -403,6 +454,8 @@ class TestShutil(unittest.TestCase):
self.write_file([tmpdir, 'sub', 'file3'], 'xxx') self.write_file([tmpdir, 'sub', 'file3'], 'xxx')
tmpdir2 = self.mkdtemp() tmpdir2 = self.mkdtemp()
# force shutil to create the directory
os.rmdir(tmpdir2)
unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
"source and target should be on same drive") "source and target should be on same drive")
...@@ -518,6 +571,8 @@ class TestShutil(unittest.TestCase): ...@@ -518,6 +571,8 @@ class TestShutil(unittest.TestCase):
self.write_file([tmpdir, 'file2'], 'xxx') self.write_file([tmpdir, 'file2'], 'xxx')
tmpdir2 = self.mkdtemp() tmpdir2 = self.mkdtemp()
# force shutil to create the directory
os.rmdir(tmpdir2)
base_name = os.path.join(tmpdir2, 'archive') base_name = os.path.join(tmpdir2, 'archive')
_make_zipfile(base_name, tmpdir) _make_zipfile(base_name, tmpdir)
...@@ -688,20 +743,11 @@ class TestMove(unittest.TestCase): ...@@ -688,20 +743,11 @@ class TestMove(unittest.TestCase):
self.dst_dir = tempfile.mkdtemp() self.dst_dir = tempfile.mkdtemp()
self.src_file = os.path.join(self.src_dir, filename) self.src_file = os.path.join(self.src_dir, filename)
self.dst_file = os.path.join(self.dst_dir, filename) self.dst_file = os.path.join(self.dst_dir, filename)
# Try to create a dir in the current directory, hoping that it is
# not located on the same filesystem as the system tmp dir.
try:
self.dir_other_fs = tempfile.mkdtemp(
dir=os.path.dirname(__file__))
self.file_other_fs = os.path.join(self.dir_other_fs,
filename)
except OSError:
self.dir_other_fs = None
with open(self.src_file, "wb") as f: with open(self.src_file, "wb") as f:
f.write(b"spam") f.write(b"spam")
def tearDown(self): def tearDown(self):
for d in (self.src_dir, self.dst_dir, self.dir_other_fs): for d in (self.src_dir, self.dst_dir):
try: try:
if d: if d:
shutil.rmtree(d) shutil.rmtree(d)
...@@ -730,21 +776,15 @@ class TestMove(unittest.TestCase): ...@@ -730,21 +776,15 @@ class TestMove(unittest.TestCase):
# Move a file inside an existing dir on the same filesystem. # Move a file inside an existing dir on the same filesystem.
self._check_move_file(self.src_file, self.dst_dir, self.dst_file) self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
@mock_rename
def test_move_file_other_fs(self): def test_move_file_other_fs(self):
# Move a file to an existing dir on another filesystem. # Move a file to an existing dir on another filesystem.
if not self.dir_other_fs: self.test_move_file()
# skip
return
self._check_move_file(self.src_file, self.file_other_fs,
self.file_other_fs)
@mock_rename
def test_move_file_to_dir_other_fs(self): def test_move_file_to_dir_other_fs(self):
# Move a file to another location on another filesystem. # Move a file to another location on another filesystem.
if not self.dir_other_fs: self.test_move_file_to_dir()
# skip
return
self._check_move_file(self.src_file, self.dir_other_fs,
self.file_other_fs)
def test_move_dir(self): def test_move_dir(self):
# Move a dir to another location on the same filesystem. # Move a dir to another location on the same filesystem.
...@@ -757,32 +797,20 @@ class TestMove(unittest.TestCase): ...@@ -757,32 +797,20 @@ class TestMove(unittest.TestCase):
except: except:
pass pass
@mock_rename
def test_move_dir_other_fs(self): def test_move_dir_other_fs(self):
# Move a dir to another location on another filesystem. # Move a dir to another location on another filesystem.
if not self.dir_other_fs: self.test_move_dir()
# skip
return
dst_dir = tempfile.mktemp(dir=self.dir_other_fs)
try:
self._check_move_dir(self.src_dir, dst_dir, dst_dir)
finally:
try:
shutil.rmtree(dst_dir)
except:
pass
def test_move_dir_to_dir(self): def test_move_dir_to_dir(self):
# Move a dir inside an existing dir on the same filesystem. # Move a dir inside an existing dir on the same filesystem.
self._check_move_dir(self.src_dir, self.dst_dir, self._check_move_dir(self.src_dir, self.dst_dir,
os.path.join(self.dst_dir, os.path.basename(self.src_dir))) os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
@mock_rename
def test_move_dir_to_dir_other_fs(self): def test_move_dir_to_dir_other_fs(self):
# Move a dir inside an existing dir on another filesystem. # Move a dir inside an existing dir on another filesystem.
if not self.dir_other_fs: self.test_move_dir_to_dir()
# skip
return
self._check_move_dir(self.src_dir, self.dir_other_fs,
os.path.join(self.dir_other_fs, os.path.basename(self.src_dir)))
def test_existing_file_inside_dest_dir(self): def test_existing_file_inside_dest_dir(self):
# A file with the same name inside the destination dir already exists. # A file with the same name inside the destination dir already exists.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment