Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 1 | # Test some Unicode file name semantics |
| 2 | # We dont test many operations on files other than |
| 3 | # that their names can be used with Unicode characters. |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 4 | import os, glob, time, shutil |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 5 | import unicodedata |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 6 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 7 | import unittest |
Benjamin Peterson | e549ead | 2009-03-28 21:42:05 +0000 | [diff] [blame] | 8 | from test.support import run_unittest, TESTFN_UNICODE, rmtree |
Benjamin Peterson | ee8712c | 2008-05-20 21:35:26 +0000 | [diff] [blame] | 9 | from test.support import TESTFN_ENCODING, TESTFN_UNICODE_UNENCODEABLE |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 10 | try: |
Brett Cannon | 96d7e83 | 2007-07-30 01:34:07 +0000 | [diff] [blame] | 11 | TESTFN_UNICODE.encode(TESTFN_ENCODING) |
Martin v. Löwis | c2ca32d | 2003-03-17 18:30:15 +0000 | [diff] [blame] | 12 | except (UnicodeError, TypeError): |
Martin v. Löwis | c49435c | 2003-03-08 10:25:31 +0000 | [diff] [blame] | 13 | # Either the file system encoding is None, or the file name |
| 14 | # cannot be encoded in the file system encoding. |
Benjamin Peterson | e549ead | 2009-03-28 21:42:05 +0000 | [diff] [blame] | 15 | raise unittest.SkipTest("No Unicode filesystem semantics on this platform.") |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 16 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 17 | def remove_if_exists(filename): |
| 18 | if os.path.exists(filename): |
| 19 | os.unlink(filename) |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 20 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 21 | class TestUnicodeFiles(unittest.TestCase): |
| 22 | # The 'do_' functions are the actual tests. They generally assume the |
| 23 | # file already exists etc. |
Tim Peters | 58eb11c | 2004-01-18 20:29:55 +0000 | [diff] [blame] | 24 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 25 | # Do all the tests we can given only a single filename. The file should |
| 26 | # exist. |
| 27 | def _do_single(self, filename): |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 28 | self.assertTrue(os.path.exists(filename)) |
| 29 | self.assertTrue(os.path.isfile(filename)) |
| 30 | self.assertTrue(os.access(filename, os.R_OK)) |
| 31 | self.assertTrue(os.path.exists(os.path.abspath(filename))) |
| 32 | self.assertTrue(os.path.isfile(os.path.abspath(filename))) |
| 33 | self.assertTrue(os.access(os.path.abspath(filename), os.R_OK)) |
Guido van Rossum | cd16bf6 | 2007-06-13 18:07:49 +0000 | [diff] [blame] | 34 | os.chmod(filename, 0o777) |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 35 | os.utime(filename, None) |
| 36 | os.utime(filename, (time.time(), time.time())) |
| 37 | # Copy/rename etc tests using the same filename |
| 38 | self._do_copyish(filename, filename) |
| 39 | # Filename should appear in glob output |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 40 | self.assertTrue( |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 41 | os.path.abspath(filename)==os.path.abspath(glob.glob(filename)[0])) |
| 42 | # basename should appear in listdir. |
| 43 | path, base = os.path.split(os.path.abspath(filename)) |
Raymond Hettinger | 3b04ce8 | 2004-06-28 06:57:19 +0000 | [diff] [blame] | 44 | file_list = os.listdir(path) |
Raymond Hettinger | 3b04ce8 | 2004-06-28 06:57:19 +0000 | [diff] [blame] | 45 | # Normalize the unicode strings, as round-tripping the name via the OS |
| 46 | # may return a different (but equivalent) value. |
| 47 | base = unicodedata.normalize("NFD", base) |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 48 | file_list = [unicodedata.normalize("NFD", f) for f in file_list] |
| 49 | |
Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 50 | self.assertIn(base, file_list) |
Tim Peters | 58eb11c | 2004-01-18 20:29:55 +0000 | [diff] [blame] | 51 | |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 52 | # Do as many "equivalancy' tests as we can - ie, check that although we |
| 53 | # have different types for the filename, they refer to the same file. |
| 54 | def _do_equivalent(self, filename1, filename2): |
| 55 | # Note we only check "filename1 against filename2" - we don't bother |
| 56 | # checking "filename2 against 1", as we assume we are called again with |
| 57 | # the args reversed. |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 58 | self.assertTrue(type(filename1)!=type(filename2), |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 59 | "No point checking equivalent filenames of the same type") |
| 60 | # stat and lstat should return the same results. |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 61 | self.assertEqual(os.stat(filename1), |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 62 | os.stat(filename2)) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 63 | self.assertEqual(os.lstat(filename1), |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 64 | os.lstat(filename2)) |
| 65 | # Copy/rename etc tests using equivalent filename |
| 66 | self._do_copyish(filename1, filename2) |
| 67 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 68 | # Tests that copy, move, etc one file to another. |
| 69 | def _do_copyish(self, filename1, filename2): |
| 70 | # Should be able to rename the file using either name. |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 71 | self.assertTrue(os.path.isfile(filename1)) # must exist. |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 72 | os.rename(filename1, filename2 + ".new") |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 73 | self.assertTrue(os.path.isfile(filename1+".new")) |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 74 | os.rename(filename1 + ".new", filename2) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 75 | self.assertTrue(os.path.isfile(filename2)) |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 76 | |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 77 | shutil.copy(filename1, filename2 + ".new") |
| 78 | os.unlink(filename1 + ".new") # remove using equiv name. |
| 79 | # And a couple of moves, one using each name. |
| 80 | shutil.move(filename1, filename2 + ".new") |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 81 | self.assertTrue(not os.path.exists(filename2)) |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 82 | shutil.move(filename1 + ".new", filename2) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 83 | self.assertTrue(os.path.exists(filename1)) |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 84 | # Note - due to the implementation of shutil.move, |
| 85 | # it tries a rename first. This only fails on Windows when on |
| 86 | # different file systems - and this test can't ensure that. |
| 87 | # So we test the shutil.copy2 function, which is the thing most |
| 88 | # likely to fail. |
| 89 | shutil.copy2(filename1, filename2 + ".new") |
| 90 | os.unlink(filename1 + ".new") |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 91 | |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 92 | def _do_directory(self, make_name, chdir_name, encoded): |
Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 93 | cwd = os.getcwdb() |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 94 | if os.path.isdir(make_name): |
Amaury Forgeot d'Arc | 84e1715 | 2008-10-03 19:34:30 +0000 | [diff] [blame] | 95 | rmtree(make_name) |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 96 | os.mkdir(make_name) |
| 97 | try: |
| 98 | os.chdir(chdir_name) |
| 99 | try: |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 100 | if not encoded: |
Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 101 | cwd_result = os.getcwd() |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 102 | name_result = make_name |
| 103 | else: |
Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 104 | cwd_result = os.getcwdb().decode(TESTFN_ENCODING) |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 105 | name_result = make_name.decode(TESTFN_ENCODING) |
| 106 | |
| 107 | cwd_result = unicodedata.normalize("NFD", cwd_result) |
| 108 | name_result = unicodedata.normalize("NFD", name_result) |
| 109 | |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 110 | self.assertEqual(os.path.basename(cwd_result),name_result) |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 111 | finally: |
| 112 | os.chdir(cwd) |
| 113 | finally: |
| 114 | os.rmdir(make_name) |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 115 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 116 | # The '_test' functions 'entry points with params' - ie, what the |
| 117 | # top-level 'test' functions would be if they could take params |
| 118 | def _test_single(self, filename): |
| 119 | remove_if_exists(filename) |
Alex Martelli | 01c77c6 | 2006-08-24 02:58:11 +0000 | [diff] [blame] | 120 | f = open(filename, "w") |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 121 | f.close() |
| 122 | try: |
| 123 | self._do_single(filename) |
| 124 | finally: |
| 125 | os.unlink(filename) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 126 | self.assertTrue(not os.path.exists(filename)) |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 127 | # and again with os.open. |
| 128 | f = os.open(filename, os.O_CREAT) |
| 129 | os.close(f) |
| 130 | try: |
| 131 | self._do_single(filename) |
| 132 | finally: |
| 133 | os.unlink(filename) |
Tim Peters | 58eb11c | 2004-01-18 20:29:55 +0000 | [diff] [blame] | 134 | |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 135 | def _test_equivalent(self, filename1, filename2): |
| 136 | remove_if_exists(filename1) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 137 | self.assertTrue(not os.path.exists(filename2)) |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 138 | f = file(filename1, "w") |
| 139 | f.close() |
| 140 | try: |
| 141 | self._do_equivalent(filename1, filename2) |
| 142 | finally: |
| 143 | os.unlink(filename1) |
| 144 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 145 | # The 'test' functions are unittest entry points, and simply call our |
| 146 | # _test functions with each of the filename combinations we wish to test |
| 147 | def test_single_files(self): |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 148 | self._test_single(TESTFN_UNICODE) |
Mark Hammond | 2e8624c | 2003-12-03 22:16:47 +0000 | [diff] [blame] | 149 | if TESTFN_UNICODE_UNENCODEABLE is not None: |
| 150 | self._test_single(TESTFN_UNICODE_UNENCODEABLE) |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 151 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 152 | def test_directories(self): |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 153 | # For all 'equivalent' combinations: |
| 154 | # Make dir with encoded, chdir with unicode, checkdir with encoded |
| 155 | # (or unicode/encoded/unicode, etc |
Martin v. Löwis | a79f125 | 2007-08-30 10:08:57 +0000 | [diff] [blame] | 156 | ext = ".dir" |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 157 | self._do_directory(TESTFN_UNICODE+ext, TESTFN_UNICODE+ext, False) |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 158 | # Our directory name that can't use a non-unicode name. |
Mark Hammond | 2e8624c | 2003-12-03 22:16:47 +0000 | [diff] [blame] | 159 | if TESTFN_UNICODE_UNENCODEABLE is not None: |
| 160 | self._do_directory(TESTFN_UNICODE_UNENCODEABLE+ext, |
| 161 | TESTFN_UNICODE_UNENCODEABLE+ext, |
Nicholas Bastin | 6680341 | 2004-03-21 20:55:47 +0000 | [diff] [blame] | 162 | False) |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 163 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 164 | def test_main(): |
Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 165 | run_unittest(__name__) |
Mark Hammond | ef8b654 | 2001-05-13 08:04:26 +0000 | [diff] [blame] | 166 | |
Mark Hammond | 6d45972 | 2003-12-03 01:29:56 +0000 | [diff] [blame] | 167 | if __name__ == "__main__": |
| 168 | test_main() |