source: test/test_path.py @ 1721:3557f65ded13

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