source: test/test_path.py @ 1719:560867ae70f0

Last change on this file since 1719:560867ae70f0 was 1719:560867ae70f0, checked in by Stefan Schwarzer <sschwarzer@…>, 6 months ago
Remove `encoding: utf-8` lines These are no longer needed because we code for only Python 3 now and Python 3 uses UTF-8 encoding for source files by default.
File size: 8.6 KB
Line 
1# Copyright (C) 2003-2018, Stefan Schwarzer <sschwarzer@sschwarzer.net>
2# and ftputil contributors (see `doc/contributors.txt`)
3# See the file LICENSE for licensing terms.
4
5import ftplib
6import time
7
8import pytest
9
10import ftputil
11import ftputil.compat
12import ftputil.error
13import ftputil.tool
14
15from test import mock_ftplib
16from test import test_base
17
18
19class FailingFTPHost(ftputil.FTPHost):
20
21    def _dir(self, path):
22        raise ftputil.error.FTPOSError("simulate a failure, e. g. timeout")
23
24
25# Mock session, used for testing an inaccessible login directory
26class SessionWithInaccessibleLoginDirectory(mock_ftplib.MockSession):
27
28    def cwd(self, dir):
29        # Assume that `dir` is the inaccessible login directory.
30        raise ftplib.error_perm("can't change into this directory")
31
32
33class TestPath:
34    """Test operations in `FTPHost.path`."""
35
36    # TODO: Add unit tests for changes for ticket #113
37    # (commits [b4c9b089b6b8] and [4027740cdd2d]).
38    def test_regular_isdir_isfile_islink(self):
39        """Test regular `FTPHost._Path.isdir/isfile/islink`."""
40        host = test_base.ftp_host_factory()
41        testdir = "/home/sschwarzer"
42        host.chdir(testdir)
43        # Test a path which isn't there.
44        assert not host.path.isdir("notthere")
45        assert not host.path.isfile("notthere")
46        assert not host.path.islink("notthere")
47        #  This checks additional code (see ticket #66).
48        assert not host.path.isdir("/notthere/notthere")
49        assert not host.path.isfile("/notthere/notthere")
50        assert not host.path.islink("/notthere/notthere")
51        # Test a directory.
52        assert host.path.isdir(testdir)
53        assert not host.path.isfile(testdir)
54        assert not host.path.islink(testdir)
55        # Test a file.
56        testfile = "/home/sschwarzer/index.html"
57        assert not host.path.isdir(testfile)
58        assert host.path.isfile(testfile)
59        assert not host.path.islink(testfile)
60        # Test a link. Since the link target of `osup` doesn't exist,
61        # neither `isdir` nor `isfile` return `True`.
62        testlink = "/home/sschwarzer/osup"
63        assert not host.path.isdir(testlink)
64        assert not host.path.isfile(testlink)
65        assert host.path.islink(testlink)
66
67    def test_workaround_for_spaces(self):
68        """Test whether the workaround for space-containing paths is used."""
69        host = test_base.ftp_host_factory()
70        testdir = "/home/sschwarzer"
71        host.chdir(testdir)
72        # Test a file name containing spaces.
73        testfile = "/home/dir with spaces/file with spaces"
74        assert not host.path.isdir(testfile)
75        assert host.path.isfile(testfile)
76        assert not host.path.islink(testfile)
77
78    def test_inaccessible_home_directory_and_whitespace_workaround(self):
79        "Test combination of inaccessible home directory + whitespace in path."
80        host = test_base.ftp_host_factory(
81               session_factory=SessionWithInaccessibleLoginDirectory)
82        with pytest.raises(ftputil.error.InaccessibleLoginDirError):
83            host._dir("/home dir")
84
85    def test_isdir_isfile_islink_with_dir_failure(self):
86        """
87        Test failing `FTPHost._Path.isdir/isfile/islink` because of
88        failing `_dir` call.
89        """
90        host = test_base.ftp_host_factory(ftp_host_class=FailingFTPHost)
91        testdir = "/home/sschwarzer"
92        host.chdir(testdir)
93        # Test if exceptions are propagated.
94        FTPOSError = ftputil.error.FTPOSError
95        with pytest.raises(FTPOSError):
96            host.path.isdir("index.html")
97        with pytest.raises(FTPOSError):
98            host.path.isfile("index.html")
99        with pytest.raises(FTPOSError):
100            host.path.islink("index.html")
101
102    def test_isdir_isfile_with_infinite_link_chain(self):
103        """
104        Test if `isdir` and `isfile` return `False` if they encounter
105        an infinite link chain.
106        """
107        host = test_base.ftp_host_factory()
108        assert host.path.isdir("/home/bad_link") is False
109        assert host.path.isfile("/home/bad_link") is False
110
111    def test_exists(self):
112        """Test `FTPHost.path.exists`."""
113        # Regular use of `exists`
114        host = test_base.ftp_host_factory()
115        testdir = "/home/sschwarzer"
116        host.chdir(testdir)
117        assert host.path.exists("index.html")
118        assert not host.path.exists("notthere")
119        # Test if exceptions are propagated.
120        host = test_base.ftp_host_factory(ftp_host_class=FailingFTPHost)
121        with pytest.raises(ftputil.error.FTPOSError):
122            host.path.exists("index.html")
123
124
125class TestAcceptEitherBytesOrUnicode:
126
127    def setup_method(self, method):
128        self.host = test_base.ftp_host_factory()
129
130    def _test_method_string_types(self, method, path):
131        expected_type = type(path)
132        assert isinstance(method(path), expected_type)
133
134    def test_methods_that_take_and_return_one_string(self):
135        """
136        Test whether the same string type as for the argument is returned.
137        """
138        bytes_type = ftputil.compat.bytes_type
139        unicode_type = ftputil.compat.unicode_type
140        method_names = ("abspath basename dirname join normcase normpath".
141                        split())
142        for method_name in method_names:
143            method = getattr(self.host.path, method_name)
144            self._test_method_string_types(method, "/")
145            self._test_method_string_types(method, ".")
146            self._test_method_string_types(method, b"/")
147            self._test_method_string_types(method, b".")
148
149    def test_methods_that_take_a_string_and_return_a_bool(self):
150        """Test whether the methods accept byte and unicode strings."""
151        host = self.host
152        as_bytes = ftputil.tool.as_bytes
153        host.chdir("/home/file_name_test")
154        # `isabs`
155        assert not host.path.isabs("ä")
156        assert not host.path.isabs(as_bytes("ä"))
157        # `exists`
158        assert host.path.exists("ä")
159        assert host.path.exists(as_bytes("ä"))
160        # `isdir`, `isfile`, `islink`
161        assert host.path.isdir("ä")
162        assert host.path.isdir(as_bytes("ä"))
163        assert host.path.isfile("ö")
164        assert host.path.isfile(as_bytes("ö"))
165        assert host.path.islink("ü")
166        assert host.path.islink(as_bytes("ü"))
167
168    def test_join(self):
169        """
170        Test whether `FTPHost.path.join` accepts only arguments of
171        the same string type and returns the same string type.
172        """
173        join = self.host.path.join
174        as_bytes = ftputil.tool.as_bytes
175        # Only unicode
176        parts = list("äöü")
177        result = join(*parts)
178        assert result == "ä/ö/ü"
179        #  Need explicit type check for Python 2
180        assert isinstance(result, ftputil.compat.unicode_type)
181        # Only bytes
182        parts = [as_bytes(s) for s in "äöü"]
183        result = join(*parts)
184        assert result == as_bytes("ä/ö/ü")
185        #  Need explicit type check for Python 2
186        assert isinstance(result, ftputil.compat.bytes_type)
187        # Mixture of unicode and bytes
188        parts = ["ä", as_bytes("ö")]
189        with pytest.raises(TypeError):
190            join(*parts)
191        parts = [as_bytes("ä"), as_bytes("ö"), "ü"]
192        with pytest.raises(TypeError):
193            join(*parts)
194
195    def test_getmtime(self):
196        """
197        Test whether `FTPHost.path.getmtime` accepts byte and unicode
198        paths.
199        """
200        host = self.host
201        as_bytes = ftputil.tool.as_bytes
202        host.chdir("/home/file_name_test")
203        # We don't care about the _exact_ time, so don't bother with
204        # timezone differences. Instead, do a simple sanity check.
205        day = 24 * 60 * 60  # seconds
206        expected_mtime = time.mktime((2000, 5, 29, 0, 0, 0, 0, 0, 0))
207        mtime_makes_sense = (lambda mtime: expected_mtime - day <= mtime <=
208                                           expected_mtime + day)
209        assert mtime_makes_sense(host.path.getmtime("ä"))
210        assert mtime_makes_sense(host.path.getmtime(as_bytes("ä")))
211
212    def test_getsize(self):
213        """
214        Test whether `FTPHost.path.getsize` accepts byte and unicode paths.
215        """
216        host = self.host
217        as_bytes = ftputil.tool.as_bytes
218        host.chdir("/home/file_name_test")
219        assert host.path.getsize("ä") == 512
220        assert host.path.getsize(as_bytes("ä")) == 512
221
222    def test_walk(self):
223        """Test whether `FTPHost.path.walk` accepts bytes and unicode paths."""
224        host = self.host
225        as_bytes = ftputil.tool.as_bytes
226        def noop(arg, top, names):
227            del names[:]
228        host.path.walk("ä", noop, None)
229        host.path.walk(as_bytes("ä"), noop, None)
Note: See TracBrowser for help on using the repository browser.