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