test_unicode_file.py revision 6d459725a3f2f904a525739a63792b702aa32384
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.
4import os, glob, time, shutil
5
6import unittest
7from test.test_support import run_suite, TestSkipped, TESTFN_UNICODE
8from test.test_support import TESTFN_ENCODING, TESTFN_UNICODE_UNENCODEABLE
9try:
10    TESTFN_ENCODED = TESTFN_UNICODE.encode(TESTFN_ENCODING)
11except (UnicodeError, TypeError):
12    # Either the file system encoding is None, or the file name
13    # cannot be encoded in the file system encoding.
14    raise TestSkipped("No Unicode filesystem semantics on this platform.")
15
16def remove_if_exists(filename):
17    if os.path.exists(filename):
18        os.unlink(filename)
19
20class TestUnicodeFiles(unittest.TestCase):
21    # The 'do_' functions are the actual tests.  They generally assume the
22    # file already exists etc.
23
24    # Do all the tests we can given only a single filename.  The file should
25    # exist.
26    def _do_single(self, filename):
27        self.failUnless(os.path.exists(filename))
28        self.failUnless(os.path.isfile(filename))
29        self.failUnless(os.path.exists(os.path.abspath(filename)))
30        self.failUnless(os.path.isfile(os.path.abspath(filename)))
31        os.chmod(filename, 0777)
32        os.utime(filename, None)
33        os.utime(filename, (time.time(), time.time()))
34        # Copy/rename etc tests using the same filename
35        self._do_copyish(filename, filename)
36        # Filename should appear in glob output
37        self.failUnless(
38            os.path.abspath(filename)==os.path.abspath(glob.glob(filename)[0]))
39        # basename should appear in listdir.
40        path, base = os.path.split(os.path.abspath(filename))
41        self.failUnless(base in os.listdir(path))
42
43    # Do as many "equivalancy' tests as we can - ie, check that although we
44    # have different types for the filename, they refer to the same file.
45    def _do_equivilent(self, filename1, filename2):
46        # Note we only check "filename1 against filename2" - we don't bother
47        # checking "filename2 against 1", as we assume we are called again with
48        # the args reversed.
49        self.failUnless(type(filename1)!=type(filename2),
50                    "No point checking equivalent filenames of the same type")
51        # stat and lstat should return the same results.
52        self.failUnlessEqual(os.stat(filename1),
53                             os.stat(filename2))
54        self.failUnlessEqual(os.lstat(filename1),
55                             os.lstat(filename2))
56        # Copy/rename etc tests using equivalent filename
57        self._do_copyish(filename1, filename2)
58
59    # Tests that copy, move, etc one file to another.
60    def _do_copyish(self, filename1, filename2):
61        # Should be able to rename the file using either name.
62        self.failUnless(os.path.isfile(filename1)) # must exist.
63        os.rename(filename1, filename2 + ".new")
64        self.failUnless(os.path.isfile(filename1+".new"))
65        os.rename(filename1 + ".new", filename2)
66        self.failUnless(os.path.isfile(filename2))
67
68        # Try using shutil on the filenames.
69        try:
70            filename1==filename2
71        except UnicodeDecodeError:
72            # these filenames can't be compared - shutil.copy tries to do
73            # just that.  This is really a bug in 'shutil' - if one of shutil's
74            # 2 params are Unicode and the other isn't, it should coerce the
75            # string to Unicode with the filesystem encoding before comparison.
76            pass
77        else:
78            # filenames can be compared.
79            shutil.copy(filename1, filename2 + ".new")
80            os.unlink(filename1 + ".new") # remove using equiv name.
81            # And a couple of moves, one using each name.
82            shutil.move(filename1, filename2 + ".new")
83            self.failUnless(not os.path.exists(filename2))
84            shutil.move(filename1 + ".new", filename2)
85            self.failUnless(os.path.exists(filename1))
86            # Note - due to the implementation of shutil.move,
87            # it tries a rename first.  This only fails on Windows when on
88            # different file systems - and this test can't ensure that.
89            # So we test the shutil.copy2 function, which is the thing most
90            # likely to fail.
91            shutil.copy2(filename1, filename2 + ".new")
92            os.unlink(filename1 + ".new")
93
94    def _do_directory(self, make_name, chdir_name, getcwd_func):
95        cwd = os.getcwd()
96        if os.path.isdir(make_name):
97            os.rmdir(make_name)
98        os.mkdir(make_name)
99        try:
100            os.chdir(chdir_name)
101            try:
102                self.failUnlessEqual(os.path.basename(getcwd_func()),
103                                     make_name)
104            finally:
105                os.chdir(cwd)
106        finally:
107            os.rmdir(make_name)
108
109    # The '_test' functions 'entry points with params' - ie, what the
110    # top-level 'test' functions would be if they could take params
111    def _test_single(self, filename):
112        remove_if_exists(filename)
113        f = file(filename, "w")
114        f.close()
115        try:
116            self._do_single(filename)
117        finally:
118            os.unlink(filename)
119        self.failUnless(not os.path.exists(filename))
120        # and again with os.open.
121        f = os.open(filename, os.O_CREAT)
122        os.close(f)
123        try:
124            self._do_single(filename)
125        finally:
126            os.unlink(filename)
127
128    def _test_equivalent(self, filename1, filename2):
129        remove_if_exists(filename1)
130        self.failUnless(not os.path.exists(filename2))
131        f = file(filename1, "w")
132        f.close()
133        try:
134            self._do_equivilent(filename1, filename2)
135        finally:
136            os.unlink(filename1)
137
138    # The 'test' functions are unittest entry points, and simply call our
139    # _test functions with each of the filename combinations we wish to test
140    def test_single_files(self):
141        self._test_single(TESTFN_ENCODED)
142        self._test_single(TESTFN_UNICODE)
143        self._test_single(TESTFN_UNICODE_UNENCODEABLE)
144
145    def test_equivalent_files(self):
146        self._test_equivalent(TESTFN_ENCODED, TESTFN_UNICODE)
147        self._test_equivalent(TESTFN_UNICODE, TESTFN_ENCODED)
148
149    def test_directories(self):
150        # For all 'equivilent' combinations:
151        #  Make dir with encoded, chdir with unicode, checkdir with encoded
152        #  (or unicode/encoded/unicode, etc
153        ext = ".dir"
154        self._do_directory(TESTFN_ENCODED+ext, TESTFN_ENCODED+ext, os.getcwd)
155        self._do_directory(TESTFN_ENCODED+ext, TESTFN_UNICODE+ext, os.getcwd)
156        self._do_directory(TESTFN_UNICODE+ext, TESTFN_ENCODED+ext, os.getcwdu)
157        self._do_directory(TESTFN_UNICODE+ext, TESTFN_UNICODE+ext, os.getcwdu)
158        # Our directory name that can't use a non-unicode name.
159        self._do_directory(TESTFN_UNICODE_UNENCODEABLE+ext,
160                           TESTFN_UNICODE_UNENCODEABLE+ext,
161                           os.getcwdu)
162
163def test_main():
164    suite = unittest.TestSuite()
165    suite.addTest(unittest.makeSuite(TestUnicodeFiles))
166    run_suite(suite)
167
168if __name__ == "__main__":
169    test_main()
170