1# Test some Unicode file name semantics 2# We don't test many operations on files other than 3# that their names can be used with Unicode characters. 4import os, glob, time, shutil 5import unicodedata 6 7import unittest 8from test.support import (run_unittest, rmtree, change_cwd, 9 TESTFN_ENCODING, TESTFN_UNICODE, TESTFN_UNENCODABLE, create_empty_file) 10 11if not os.path.supports_unicode_filenames: 12 try: 13 TESTFN_UNICODE.encode(TESTFN_ENCODING) 14 except (UnicodeError, TypeError): 15 # Either the file system encoding is None, or the file name 16 # cannot be encoded in the file system encoding. 17 raise unittest.SkipTest("No Unicode filesystem semantics on this platform.") 18 19def remove_if_exists(filename): 20 if os.path.exists(filename): 21 os.unlink(filename) 22 23class TestUnicodeFiles(unittest.TestCase): 24 # The 'do_' functions are the actual tests. They generally assume the 25 # file already exists etc. 26 27 # Do all the tests we can given only a single filename. The file should 28 # exist. 29 def _do_single(self, filename): 30 self.assertTrue(os.path.exists(filename)) 31 self.assertTrue(os.path.isfile(filename)) 32 self.assertTrue(os.access(filename, os.R_OK)) 33 self.assertTrue(os.path.exists(os.path.abspath(filename))) 34 self.assertTrue(os.path.isfile(os.path.abspath(filename))) 35 self.assertTrue(os.access(os.path.abspath(filename), os.R_OK)) 36 os.chmod(filename, 0o777) 37 os.utime(filename, None) 38 os.utime(filename, (time.time(), time.time())) 39 # Copy/rename etc tests using the same filename 40 self._do_copyish(filename, filename) 41 # Filename should appear in glob output 42 self.assertTrue( 43 os.path.abspath(filename)==os.path.abspath(glob.glob(glob.escape(filename))[0])) 44 # basename should appear in listdir. 45 path, base = os.path.split(os.path.abspath(filename)) 46 file_list = os.listdir(path) 47 # Normalize the unicode strings, as round-tripping the name via the OS 48 # may return a different (but equivalent) value. 49 base = unicodedata.normalize("NFD", base) 50 file_list = [unicodedata.normalize("NFD", f) for f in file_list] 51 52 self.assertIn(base, file_list) 53 54 # Tests that copy, move, etc one file to another. 55 def _do_copyish(self, filename1, filename2): 56 # Should be able to rename the file using either name. 57 self.assertTrue(os.path.isfile(filename1)) # must exist. 58 os.rename(filename1, filename2 + ".new") 59 self.assertFalse(os.path.isfile(filename2)) 60 self.assertTrue(os.path.isfile(filename1 + '.new')) 61 os.rename(filename1 + ".new", filename2) 62 self.assertFalse(os.path.isfile(filename1 + '.new')) 63 self.assertTrue(os.path.isfile(filename2)) 64 65 shutil.copy(filename1, filename2 + ".new") 66 os.unlink(filename1 + ".new") # remove using equiv name. 67 # And a couple of moves, one using each name. 68 shutil.move(filename1, filename2 + ".new") 69 self.assertFalse(os.path.exists(filename2)) 70 self.assertTrue(os.path.exists(filename1 + '.new')) 71 shutil.move(filename1 + ".new", filename2) 72 self.assertFalse(os.path.exists(filename2 + '.new')) 73 self.assertTrue(os.path.exists(filename1)) 74 # Note - due to the implementation of shutil.move, 75 # it tries a rename first. This only fails on Windows when on 76 # different file systems - and this test can't ensure that. 77 # So we test the shutil.copy2 function, which is the thing most 78 # likely to fail. 79 shutil.copy2(filename1, filename2 + ".new") 80 self.assertTrue(os.path.isfile(filename1 + '.new')) 81 os.unlink(filename1 + ".new") 82 self.assertFalse(os.path.exists(filename2 + '.new')) 83 84 def _do_directory(self, make_name, chdir_name): 85 if os.path.isdir(make_name): 86 rmtree(make_name) 87 os.mkdir(make_name) 88 try: 89 with change_cwd(chdir_name): 90 cwd_result = os.getcwd() 91 name_result = make_name 92 93 cwd_result = unicodedata.normalize("NFD", cwd_result) 94 name_result = unicodedata.normalize("NFD", name_result) 95 96 self.assertEqual(os.path.basename(cwd_result),name_result) 97 finally: 98 os.rmdir(make_name) 99 100 # The '_test' functions 'entry points with params' - ie, what the 101 # top-level 'test' functions would be if they could take params 102 def _test_single(self, filename): 103 remove_if_exists(filename) 104 create_empty_file(filename) 105 try: 106 self._do_single(filename) 107 finally: 108 os.unlink(filename) 109 self.assertTrue(not os.path.exists(filename)) 110 # and again with os.open. 111 f = os.open(filename, os.O_CREAT) 112 os.close(f) 113 try: 114 self._do_single(filename) 115 finally: 116 os.unlink(filename) 117 118 # The 'test' functions are unittest entry points, and simply call our 119 # _test functions with each of the filename combinations we wish to test 120 def test_single_files(self): 121 self._test_single(TESTFN_UNICODE) 122 if TESTFN_UNENCODABLE is not None: 123 self._test_single(TESTFN_UNENCODABLE) 124 125 def test_directories(self): 126 # For all 'equivalent' combinations: 127 # Make dir with encoded, chdir with unicode, checkdir with encoded 128 # (or unicode/encoded/unicode, etc 129 ext = ".dir" 130 self._do_directory(TESTFN_UNICODE+ext, TESTFN_UNICODE+ext) 131 # Our directory name that can't use a non-unicode name. 132 if TESTFN_UNENCODABLE is not None: 133 self._do_directory(TESTFN_UNENCODABLE+ext, 134 TESTFN_UNENCODABLE+ext) 135 136def test_main(): 137 run_unittest(__name__) 138 139if __name__ == "__main__": 140 test_main() 141