1"""Tests for distutils.file_util.""" 2import unittest 3import os 4import errno 5from unittest.mock import patch 6 7from distutils.file_util import move_file, copy_file 8from distutils import log 9from distutils.tests import support 10from distutils.errors import DistutilsFileError 11from test.support import run_unittest, unlink 12 13class FileUtilTestCase(support.TempdirManager, unittest.TestCase): 14 15 def _log(self, msg, *args): 16 if len(args) > 0: 17 self._logs.append(msg % args) 18 else: 19 self._logs.append(msg) 20 21 def setUp(self): 22 super(FileUtilTestCase, self).setUp() 23 self._logs = [] 24 self.old_log = log.info 25 log.info = self._log 26 tmp_dir = self.mkdtemp() 27 self.source = os.path.join(tmp_dir, 'f1') 28 self.target = os.path.join(tmp_dir, 'f2') 29 self.target_dir = os.path.join(tmp_dir, 'd1') 30 31 def tearDown(self): 32 log.info = self.old_log 33 super(FileUtilTestCase, self).tearDown() 34 35 def test_move_file_verbosity(self): 36 f = open(self.source, 'w') 37 try: 38 f.write('some content') 39 finally: 40 f.close() 41 42 move_file(self.source, self.target, verbose=0) 43 wanted = [] 44 self.assertEqual(self._logs, wanted) 45 46 # back to original state 47 move_file(self.target, self.source, verbose=0) 48 49 move_file(self.source, self.target, verbose=1) 50 wanted = ['moving %s -> %s' % (self.source, self.target)] 51 self.assertEqual(self._logs, wanted) 52 53 # back to original state 54 move_file(self.target, self.source, verbose=0) 55 56 self._logs = [] 57 # now the target is a dir 58 os.mkdir(self.target_dir) 59 move_file(self.source, self.target_dir, verbose=1) 60 wanted = ['moving %s -> %s' % (self.source, self.target_dir)] 61 self.assertEqual(self._logs, wanted) 62 63 def test_move_file_exception_unpacking_rename(self): 64 # see issue 22182 65 with patch("os.rename", side_effect=OSError("wrong", 1)), \ 66 self.assertRaises(DistutilsFileError): 67 with open(self.source, 'w') as fobj: 68 fobj.write('spam eggs') 69 move_file(self.source, self.target, verbose=0) 70 71 def test_move_file_exception_unpacking_unlink(self): 72 # see issue 22182 73 with patch("os.rename", side_effect=OSError(errno.EXDEV, "wrong")), \ 74 patch("os.unlink", side_effect=OSError("wrong", 1)), \ 75 self.assertRaises(DistutilsFileError): 76 with open(self.source, 'w') as fobj: 77 fobj.write('spam eggs') 78 move_file(self.source, self.target, verbose=0) 79 80 def test_copy_file_hard_link(self): 81 with open(self.source, 'w') as f: 82 f.write('some content') 83 # Check first that copy_file() will not fall back on copying the file 84 # instead of creating the hard link. 85 try: 86 os.link(self.source, self.target) 87 except OSError as e: 88 self.skipTest('os.link: %s' % e) 89 else: 90 unlink(self.target) 91 st = os.stat(self.source) 92 copy_file(self.source, self.target, link='hard') 93 st2 = os.stat(self.source) 94 st3 = os.stat(self.target) 95 self.assertTrue(os.path.samestat(st, st2), (st, st2)) 96 self.assertTrue(os.path.samestat(st2, st3), (st2, st3)) 97 with open(self.source, 'r') as f: 98 self.assertEqual(f.read(), 'some content') 99 100 def test_copy_file_hard_link_failure(self): 101 # If hard linking fails, copy_file() falls back on copying file 102 # (some special filesystems don't support hard linking even under 103 # Unix, see issue #8876). 104 with open(self.source, 'w') as f: 105 f.write('some content') 106 st = os.stat(self.source) 107 with patch("os.link", side_effect=OSError(0, "linking unsupported")): 108 copy_file(self.source, self.target, link='hard') 109 st2 = os.stat(self.source) 110 st3 = os.stat(self.target) 111 self.assertTrue(os.path.samestat(st, st2), (st, st2)) 112 self.assertFalse(os.path.samestat(st2, st3), (st2, st3)) 113 for fn in (self.source, self.target): 114 with open(fn, 'r') as f: 115 self.assertEqual(f.read(), 'some content') 116 117 118def test_suite(): 119 return unittest.makeSuite(FileUtilTestCase) 120 121if __name__ == "__main__": 122 run_unittest(test_suite()) 123