]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | # Test some Unicode file name semantics\r |
2 | # We dont test many operations on files other than\r | |
3 | # that their names can be used with Unicode characters.\r | |
4 | import os, glob, time, shutil\r | |
5 | import unicodedata\r | |
6 | \r | |
7 | import unittest\r | |
8 | from test.test_support import run_unittest, TESTFN_UNICODE\r | |
9 | from test.test_support import TESTFN_ENCODING, TESTFN_UNENCODABLE\r | |
10 | try:\r | |
11 | TESTFN_ENCODED = TESTFN_UNICODE.encode(TESTFN_ENCODING)\r | |
12 | except (UnicodeError, TypeError):\r | |
13 | # Either the file system encoding is None, or the file name\r | |
14 | # cannot be encoded in the file system encoding.\r | |
15 | raise unittest.SkipTest("No Unicode filesystem semantics on this platform.")\r | |
16 | \r | |
17 | if TESTFN_ENCODED.decode(TESTFN_ENCODING) != TESTFN_UNICODE:\r | |
18 | # The file system encoding does not support Latin-1\r | |
19 | # (which test_support assumes), so try the file system\r | |
20 | # encoding instead.\r | |
21 | import sys\r | |
22 | try:\r | |
23 | TESTFN_UNICODE = unicode("@test-\xe0\xf2", sys.getfilesystemencoding())\r | |
24 | TESTFN_ENCODED = TESTFN_UNICODE.encode(TESTFN_ENCODING)\r | |
25 | if '?' in TESTFN_ENCODED:\r | |
26 | # MBCS will not report the error properly\r | |
27 | raise UnicodeError, "mbcs encoding problem"\r | |
28 | except (UnicodeError, TypeError):\r | |
29 | raise unittest.SkipTest("Cannot find a suiteable filename.")\r | |
30 | \r | |
31 | if TESTFN_ENCODED.decode(TESTFN_ENCODING) != TESTFN_UNICODE:\r | |
32 | raise unittest.SkipTest("Cannot find a suitable filename.")\r | |
33 | \r | |
34 | def remove_if_exists(filename):\r | |
35 | if os.path.exists(filename):\r | |
36 | os.unlink(filename)\r | |
37 | \r | |
38 | class TestUnicodeFiles(unittest.TestCase):\r | |
39 | # The 'do_' functions are the actual tests. They generally assume the\r | |
40 | # file already exists etc.\r | |
41 | \r | |
42 | # Do all the tests we can given only a single filename. The file should\r | |
43 | # exist.\r | |
44 | def _do_single(self, filename):\r | |
45 | self.assertTrue(os.path.exists(filename))\r | |
46 | self.assertTrue(os.path.isfile(filename))\r | |
47 | self.assertTrue(os.access(filename, os.R_OK))\r | |
48 | self.assertTrue(os.path.exists(os.path.abspath(filename)))\r | |
49 | self.assertTrue(os.path.isfile(os.path.abspath(filename)))\r | |
50 | self.assertTrue(os.access(os.path.abspath(filename), os.R_OK))\r | |
51 | os.chmod(filename, 0777)\r | |
52 | os.utime(filename, None)\r | |
53 | os.utime(filename, (time.time(), time.time()))\r | |
54 | # Copy/rename etc tests using the same filename\r | |
55 | self._do_copyish(filename, filename)\r | |
56 | # Filename should appear in glob output\r | |
57 | self.assertTrue(\r | |
58 | os.path.abspath(filename)==os.path.abspath(glob.glob(filename)[0]))\r | |
59 | # basename should appear in listdir.\r | |
60 | path, base = os.path.split(os.path.abspath(filename))\r | |
61 | if isinstance(base, str):\r | |
62 | base = base.decode(TESTFN_ENCODING)\r | |
63 | file_list = os.listdir(path)\r | |
64 | # listdir() with a unicode arg may or may not return Unicode\r | |
65 | # objects, depending on the platform.\r | |
66 | if file_list and isinstance(file_list[0], str):\r | |
67 | file_list = [f.decode(TESTFN_ENCODING) for f in file_list]\r | |
68 | \r | |
69 | # Normalize the unicode strings, as round-tripping the name via the OS\r | |
70 | # may return a different (but equivalent) value.\r | |
71 | base = unicodedata.normalize("NFD", base)\r | |
72 | file_list = [unicodedata.normalize("NFD", f) for f in file_list]\r | |
73 | \r | |
74 | self.assertIn(base, file_list)\r | |
75 | \r | |
76 | # Do as many "equivalancy' tests as we can - ie, check that although we\r | |
77 | # have different types for the filename, they refer to the same file.\r | |
78 | def _do_equivalent(self, filename1, filename2):\r | |
79 | # Note we only check "filename1 against filename2" - we don't bother\r | |
80 | # checking "filename2 against 1", as we assume we are called again with\r | |
81 | # the args reversed.\r | |
82 | self.assertTrue(type(filename1)!=type(filename2),\r | |
83 | "No point checking equivalent filenames of the same type")\r | |
84 | # stat and lstat should return the same results.\r | |
85 | self.assertEqual(os.stat(filename1),\r | |
86 | os.stat(filename2))\r | |
87 | self.assertEqual(os.lstat(filename1),\r | |
88 | os.lstat(filename2))\r | |
89 | # Copy/rename etc tests using equivalent filename\r | |
90 | self._do_copyish(filename1, filename2)\r | |
91 | \r | |
92 | # Tests that copy, move, etc one file to another.\r | |
93 | def _do_copyish(self, filename1, filename2):\r | |
94 | # Should be able to rename the file using either name.\r | |
95 | self.assertTrue(os.path.isfile(filename1)) # must exist.\r | |
96 | os.rename(filename1, filename2 + ".new")\r | |
97 | self.assertTrue(os.path.isfile(filename1+".new"))\r | |
98 | os.rename(filename1 + ".new", filename2)\r | |
99 | self.assertTrue(os.path.isfile(filename2))\r | |
100 | \r | |
101 | shutil.copy(filename1, filename2 + ".new")\r | |
102 | os.unlink(filename1 + ".new") # remove using equiv name.\r | |
103 | # And a couple of moves, one using each name.\r | |
104 | shutil.move(filename1, filename2 + ".new")\r | |
105 | self.assertTrue(not os.path.exists(filename2))\r | |
106 | shutil.move(filename1 + ".new", filename2)\r | |
107 | self.assertTrue(os.path.exists(filename1))\r | |
108 | # Note - due to the implementation of shutil.move,\r | |
109 | # it tries a rename first. This only fails on Windows when on\r | |
110 | # different file systems - and this test can't ensure that.\r | |
111 | # So we test the shutil.copy2 function, which is the thing most\r | |
112 | # likely to fail.\r | |
113 | shutil.copy2(filename1, filename2 + ".new")\r | |
114 | os.unlink(filename1 + ".new")\r | |
115 | \r | |
116 | def _do_directory(self, make_name, chdir_name, encoded):\r | |
117 | cwd = os.getcwd()\r | |
118 | if os.path.isdir(make_name):\r | |
119 | os.rmdir(make_name)\r | |
120 | os.mkdir(make_name)\r | |
121 | try:\r | |
122 | os.chdir(chdir_name)\r | |
123 | try:\r | |
124 | if not encoded:\r | |
125 | cwd_result = os.getcwdu()\r | |
126 | name_result = make_name\r | |
127 | else:\r | |
128 | cwd_result = os.getcwd().decode(TESTFN_ENCODING)\r | |
129 | name_result = make_name.decode(TESTFN_ENCODING)\r | |
130 | \r | |
131 | cwd_result = unicodedata.normalize("NFD", cwd_result)\r | |
132 | name_result = unicodedata.normalize("NFD", name_result)\r | |
133 | \r | |
134 | self.assertEqual(os.path.basename(cwd_result),name_result)\r | |
135 | finally:\r | |
136 | os.chdir(cwd)\r | |
137 | finally:\r | |
138 | os.rmdir(make_name)\r | |
139 | \r | |
140 | # The '_test' functions 'entry points with params' - ie, what the\r | |
141 | # top-level 'test' functions would be if they could take params\r | |
142 | def _test_single(self, filename):\r | |
143 | remove_if_exists(filename)\r | |
144 | f = file(filename, "w")\r | |
145 | f.close()\r | |
146 | try:\r | |
147 | self._do_single(filename)\r | |
148 | finally:\r | |
149 | os.unlink(filename)\r | |
150 | self.assertTrue(not os.path.exists(filename))\r | |
151 | # and again with os.open.\r | |
152 | f = os.open(filename, os.O_CREAT)\r | |
153 | os.close(f)\r | |
154 | try:\r | |
155 | self._do_single(filename)\r | |
156 | finally:\r | |
157 | os.unlink(filename)\r | |
158 | \r | |
159 | def _test_equivalent(self, filename1, filename2):\r | |
160 | remove_if_exists(filename1)\r | |
161 | self.assertTrue(not os.path.exists(filename2))\r | |
162 | f = file(filename1, "w")\r | |
163 | f.close()\r | |
164 | try:\r | |
165 | self._do_equivalent(filename1, filename2)\r | |
166 | finally:\r | |
167 | os.unlink(filename1)\r | |
168 | \r | |
169 | # The 'test' functions are unittest entry points, and simply call our\r | |
170 | # _test functions with each of the filename combinations we wish to test\r | |
171 | def test_single_files(self):\r | |
172 | self._test_single(TESTFN_ENCODED)\r | |
173 | self._test_single(TESTFN_UNICODE)\r | |
174 | if TESTFN_UNENCODABLE is not None:\r | |
175 | self._test_single(TESTFN_UNENCODABLE)\r | |
176 | \r | |
177 | def test_equivalent_files(self):\r | |
178 | self._test_equivalent(TESTFN_ENCODED, TESTFN_UNICODE)\r | |
179 | self._test_equivalent(TESTFN_UNICODE, TESTFN_ENCODED)\r | |
180 | \r | |
181 | def test_directories(self):\r | |
182 | # For all 'equivalent' combinations:\r | |
183 | # Make dir with encoded, chdir with unicode, checkdir with encoded\r | |
184 | # (or unicode/encoded/unicode, etc\r | |
185 | ext = ".dir"\r | |
186 | self._do_directory(TESTFN_ENCODED+ext, TESTFN_ENCODED+ext, True)\r | |
187 | self._do_directory(TESTFN_ENCODED+ext, TESTFN_UNICODE+ext, True)\r | |
188 | self._do_directory(TESTFN_UNICODE+ext, TESTFN_ENCODED+ext, False)\r | |
189 | self._do_directory(TESTFN_UNICODE+ext, TESTFN_UNICODE+ext, False)\r | |
190 | # Our directory name that can't use a non-unicode name.\r | |
191 | if TESTFN_UNENCODABLE is not None:\r | |
192 | self._do_directory(TESTFN_UNENCODABLE+ext,\r | |
193 | TESTFN_UNENCODABLE+ext,\r | |
194 | False)\r | |
195 | \r | |
196 | def test_main():\r | |
197 | run_unittest(__name__)\r | |
198 | \r | |
199 | if __name__ == "__main__":\r | |
200 | test_main()\r |