source: test/test_path.py @ 1718:8bed138bc404

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