/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005 Canonical Ltd
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for the urlutils wrapper."""
18
19
import os
1830.3.17 by John Arbash Meinel
list_files() with wrong normalized_filename code raises exceptions. Fix this
20
import re
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
21
import sys
22
2279.4.2 by Alexander Belchenko
Don't do normpath after abspath, because this function is called inside abspath
23
from bzrlib import osutils, urlutils, win32utils
3242.3.33 by Aaron Bentley
Handle relative URL stacking cleanly
24
from bzrlib.errors import InvalidURL, InvalidURLJoin, InvalidRebaseURLs
1685.1.75 by Wouter van Heyst
more tests handle LANG=C
25
from bzrlib.tests import TestCaseInTempDir, TestCase, TestSkipped
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
26
27
28
class TestUrlToPath(TestCase):
29
    
1685.1.49 by John Arbash Meinel
Added bzrlib.urlutils.split and basename + dirname
30
    def test_basename(self):
31
        # bzrlib.urlutils.basename
32
        # Test bzrlib.urlutils.split()
33
        basename = urlutils.basename
34
        if sys.platform == 'win32':
35
            self.assertRaises(InvalidURL, basename, 'file:///path/to/foo')
36
            self.assertEqual('foo', basename('file:///C|/foo'))
1685.1.78 by Wouter van Heyst
more code cleanup
37
            self.assertEqual('foo', basename('file:///C:/foo'))
38
            self.assertEqual('', basename('file:///C:/'))
1685.1.49 by John Arbash Meinel
Added bzrlib.urlutils.split and basename + dirname
39
        else:
40
            self.assertEqual('foo', basename('file:///foo'))
41
            self.assertEqual('', basename('file:///'))
42
43
        self.assertEqual('foo', basename('http://host/path/to/foo'))
44
        self.assertEqual('foo', basename('http://host/path/to/foo/'))
45
        self.assertEqual('',
46
            basename('http://host/path/to/foo/', exclude_trailing_slash=False))
47
        self.assertEqual('path', basename('http://host/path'))
48
        self.assertEqual('', basename('http://host/'))
49
        self.assertEqual('', basename('http://host'))
50
        self.assertEqual('path', basename('http:///nohost/path'))
51
52
        self.assertEqual('path', basename('random+scheme://user:pass@ahost:port/path'))
53
        self.assertEqual('path', basename('random+scheme://user:pass@ahost:port/path/'))
54
        self.assertEqual('', basename('random+scheme://user:pass@ahost:port/'))
55
56
        # relative paths
57
        self.assertEqual('foo', basename('path/to/foo'))
58
        self.assertEqual('foo', basename('path/to/foo/'))
59
        self.assertEqual('', basename('path/to/foo/',
60
            exclude_trailing_slash=False))
61
        self.assertEqual('foo', basename('path/../foo'))
62
        self.assertEqual('foo', basename('../path/foo'))
63
1685.1.51 by John Arbash Meinel
Working on getting normalize_url working.
64
    def test_normalize_url_files(self):
65
        # Test that local paths are properly normalized
66
        normalize_url = urlutils.normalize_url
67
68
        def norm_file(expected, path):
69
            url = normalize_url(path)
70
            self.assertStartsWith(url, 'file:///')
71
            if sys.platform == 'win32':
72
                url = url[len('file:///C:'):]
73
            else:
74
                url = url[len('file://'):]
75
1685.1.53 by John Arbash Meinel
Updated normalize_url
76
            self.assertEndsWith(url, expected)
1685.1.51 by John Arbash Meinel
Working on getting normalize_url working.
77
78
        norm_file('path/to/foo', 'path/to/foo')
79
        norm_file('/path/to/foo', '/path/to/foo')
80
        norm_file('path/to/foo', '../path/to/foo')
81
82
        # Local paths are assumed to *not* be escaped at all
1685.1.75 by Wouter van Heyst
more tests handle LANG=C
83
        try:
3224.5.4 by Andrew Bennetts
Fix test suite, mainly weeding out uses of bzrlib.user_encoding.
84
            u'uni/\xb5'.encode(osutils.get_user_encoding())
1685.1.75 by Wouter van Heyst
more tests handle LANG=C
85
        except UnicodeError:
86
            # locale cannot handle unicode 
87
            pass
88
        else:
89
            norm_file('uni/%C2%B5', u'uni/\xb5')
90
1685.1.51 by John Arbash Meinel
Working on getting normalize_url working.
91
        norm_file('uni/%25C2%25B5', u'uni/%C2%B5')
92
        norm_file('uni/%20b', u'uni/ b')
93
        # All the crazy characters get escaped in local paths => file:/// urls
1711.4.4 by John Arbash Meinel
Fix some broken tests because of stupid ntpath.abspath behavior
94
        # The ' ' character must not be at the end, because on win32
95
        # it gets stripped off by ntpath.abspath
96
        norm_file('%27%20%3B/%3F%3A%40%26%3D%2B%24%2C%23', "' ;/?:@&=+$,#")
1685.1.51 by John Arbash Meinel
Working on getting normalize_url working.
97
98
    def test_normalize_url_hybrid(self):
99
        # Anything with a scheme:// should be treated as a hybrid url
100
        # which changes what characters get escaped.
101
        normalize_url = urlutils.normalize_url
102
103
        eq = self.assertEqual
104
        eq('file:///foo/', normalize_url(u'file:///foo/'))
105
        eq('file:///foo/%20', normalize_url(u'file:///foo/ '))
106
        eq('file:///foo/%20', normalize_url(u'file:///foo/%20'))
107
        # Don't escape reserved characters
108
        eq('file:///ab_c.d-e/%f:?g&h=i+j;k,L#M$',
109
            normalize_url('file:///ab_c.d-e/%f:?g&h=i+j;k,L#M$'))
110
        eq('http://ab_c.d-e/%f:?g&h=i+j;k,L#M$',
111
            normalize_url('http://ab_c.d-e/%f:?g&h=i+j;k,L#M$'))
112
113
        # Escape unicode characters, but not already escaped chars
114
        eq('http://host/ab/%C2%B5/%C2%B5',
115
            normalize_url(u'http://host/ab/%C2%B5/\xb5'))
116
2208.4.1 by Andrew Bennetts
normalize_url should normalise escaping of unreserved characters, like '~'.
117
        # Unescape characters that don't need to be escaped
118
        eq('http://host/~bob%2525-._',
119
                normalize_url('http://host/%7Ebob%2525%2D%2E%5F'))
120
        eq('http://host/~bob%2525-._',
121
                normalize_url(u'http://host/%7Ebob%2525%2D%2E%5F'))
122
1685.1.51 by John Arbash Meinel
Working on getting normalize_url working.
123
        # Normalize verifies URLs when they are not unicode
124
        # (indicating they did not come from the user)
125
        self.assertRaises(InvalidURL, normalize_url, 'http://host/\xb5')
126
        self.assertRaises(InvalidURL, normalize_url, 'http://host/ ')
1685.1.50 by John Arbash Meinel
Added an re for handling scheme paths.
127
128
    def test_url_scheme_re(self):
129
        # Test paths that may be URLs
130
        def test_one(url, scheme_and_path):
131
            """Assert that _url_scheme_re correctly matches
132
133
            :param scheme_and_path: The (scheme, path) that should be matched
134
                can be None, to indicate it should not match
135
            """
136
            m = urlutils._url_scheme_re.match(url)
137
            if scheme_and_path is None:
138
                self.assertEqual(None, m)
139
            else:
140
                self.assertEqual(scheme_and_path[0], m.group('scheme'))
141
                self.assertEqual(scheme_and_path[1], m.group('path'))
142
143
        # Local paths
144
        test_one('/path', None)
145
        test_one('C:/path', None)
146
        test_one('../path/to/foo', None)
147
        test_one(u'../path/to/fo\xe5', None)
148
149
        # Real URLS
150
        test_one('http://host/path/', ('http', 'host/path/'))
151
        test_one('sftp://host/path/to/foo', ('sftp', 'host/path/to/foo'))
152
        test_one('file:///usr/bin', ('file', '/usr/bin'))
153
        test_one('file:///C:/Windows', ('file', '/C:/Windows'))
154
        test_one('file:///C|/Windows', ('file', '/C|/Windows'))
155
        test_one(u'readonly+sftp://host/path/\xe5', ('readonly+sftp', u'host/path/\xe5'))
156
157
        # Weird stuff
158
        # Can't have slashes or colons in the scheme
159
        test_one('/path/to/://foo', None)
160
        test_one('path:path://foo', None)
161
        # Must have more than one character for scheme
162
        test_one('C://foo', None)
163
        test_one('ab://foo', ('ab', 'foo'))
164
1685.1.49 by John Arbash Meinel
Added bzrlib.urlutils.split and basename + dirname
165
    def test_dirname(self):
166
        # Test bzrlib.urlutils.dirname()
167
        dirname = urlutils.dirname
168
        if sys.platform == 'win32':
169
            self.assertRaises(InvalidURL, dirname, 'file:///path/to/foo')
170
            self.assertEqual('file:///C|/', dirname('file:///C|/foo'))
171
            self.assertEqual('file:///C|/', dirname('file:///C|/'))
172
        else:
173
            self.assertEqual('file:///', dirname('file:///foo'))
174
            self.assertEqual('file:///', dirname('file:///'))
175
176
        self.assertEqual('http://host/path/to', dirname('http://host/path/to/foo'))
177
        self.assertEqual('http://host/path/to', dirname('http://host/path/to/foo/'))
178
        self.assertEqual('http://host/path/to/foo',
179
            dirname('http://host/path/to/foo/', exclude_trailing_slash=False))
180
        self.assertEqual('http://host/', dirname('http://host/path'))
181
        self.assertEqual('http://host/', dirname('http://host/'))
182
        self.assertEqual('http://host', dirname('http://host'))
183
        self.assertEqual('http:///nohost', dirname('http:///nohost/path'))
184
185
        self.assertEqual('random+scheme://user:pass@ahost:port/',
186
            dirname('random+scheme://user:pass@ahost:port/path'))
187
        self.assertEqual('random+scheme://user:pass@ahost:port/',
188
            dirname('random+scheme://user:pass@ahost:port/path/'))
189
        self.assertEqual('random+scheme://user:pass@ahost:port/',
190
            dirname('random+scheme://user:pass@ahost:port/'))
191
192
        # relative paths
193
        self.assertEqual('path/to', dirname('path/to/foo'))
194
        self.assertEqual('path/to', dirname('path/to/foo/'))
195
        self.assertEqual('path/to/foo',
196
            dirname('path/to/foo/', exclude_trailing_slash=False))
197
        self.assertEqual('path/..', dirname('path/../foo'))
198
        self.assertEqual('../path', dirname('../path/foo'))
199
1685.1.55 by John Arbash Meinel
Adding bzrlib.urlutils.join() to handle joining URLs
200
    def test_join(self):
201
        def test(expected, *args):
202
            joined = urlutils.join(*args)
203
            self.assertEqual(expected, joined)
204
205
        # Test relative path joining
2018.5.100 by Andrew Bennetts
Fix IndexError in urlutils.join with 'http://host/a' and '../../b'.
206
        test('foo', 'foo') # relative fragment with nothing is preserved.
1685.1.55 by John Arbash Meinel
Adding bzrlib.urlutils.join() to handle joining URLs
207
        test('foo/bar', 'foo', 'bar')
208
        test('http://foo/bar', 'http://foo', 'bar')
209
        test('http://foo/bar', 'http://foo', '.', 'bar')
210
        test('http://foo/baz', 'http://foo', 'bar', '../baz')
211
        test('http://foo/bar/baz', 'http://foo', 'bar/baz')
212
        test('http://foo/baz', 'http://foo', 'bar/../baz')
2018.5.93 by Andrew Bennetts
Fix another bug in urlutils.join.
213
        test('http://foo/baz', 'http://foo/bar/', '../baz')
1685.1.55 by John Arbash Meinel
Adding bzrlib.urlutils.join() to handle joining URLs
214
215
        # Absolute paths
2018.5.100 by Andrew Bennetts
Fix IndexError in urlutils.join with 'http://host/a' and '../../b'.
216
        test('http://foo', 'http://foo') # abs url with nothing is preserved.
1685.1.55 by John Arbash Meinel
Adding bzrlib.urlutils.join() to handle joining URLs
217
        test('http://bar', 'http://foo', 'http://bar')
218
        test('sftp://bzr/foo', 'http://foo', 'bar', 'sftp://bzr/foo')
219
        test('file:///bar', 'foo', 'file:///bar')
2018.5.92 by Andrew Bennetts
Small bugfix to urlutils.join: join('anything', 'http://bar/a/') should not strip the trailing slash.
220
        test('http://bar/', 'http://foo', 'http://bar/')
221
        test('http://bar/a', 'http://foo', 'http://bar/a')
222
        test('http://bar/a/', 'http://foo', 'http://bar/a/')
1711.2.49 by John Arbash Meinel
urlutils.join should work for root paths.
223
224
        # From a base path
225
        test('file:///foo', 'file:///', 'foo')
226
        test('file:///bar/foo', 'file:///bar/', 'foo')
227
        test('http://host/foo', 'http://host/', 'foo')
228
        test('http://host/', 'http://host', '')
1685.1.55 by John Arbash Meinel
Adding bzrlib.urlutils.join() to handle joining URLs
229
        
230
        # Invalid joinings
231
        # Cannot go above root
2018.5.100 by Andrew Bennetts
Fix IndexError in urlutils.join with 'http://host/a' and '../../b'.
232
        # Implicitly at root:
1685.1.55 by John Arbash Meinel
Adding bzrlib.urlutils.join() to handle joining URLs
233
        self.assertRaises(InvalidURLJoin, urlutils.join,
234
                'http://foo', '../baz')
2018.5.54 by Andrew Bennetts
Fix ChrootTransportDecorator's abspath method to be consistent with its clone
235
        self.assertRaises(InvalidURLJoin, urlutils.join,
236
                'http://foo', '/..')
2018.5.100 by Andrew Bennetts
Fix IndexError in urlutils.join with 'http://host/a' and '../../b'.
237
        # Joining from a path explicitly under the root.
238
        self.assertRaises(InvalidURLJoin, urlutils.join,
239
                'http://foo/a', '../../b')
2379.1.1 by Robert Collins
urlutils improvements from hpss.
240
2018.5.46 by Andrew Bennetts
Fix ChrootTransportDecorator's clone to pass less surprising offsets to the decorated transport's clone.
241
    def test_joinpath(self):
242
        def test(expected, *args):
243
            joined = urlutils.joinpath(*args)
244
            self.assertEqual(expected, joined)
245
246
        # Test a single element
247
        test('foo', 'foo')
248
249
        # Test relative path joining
250
        test('foo/bar', 'foo', 'bar')
251
        test('foo/bar', 'foo', '.', 'bar')
252
        test('foo/baz', 'foo', 'bar', '../baz')
253
        test('foo/bar/baz', 'foo', 'bar/baz')
254
        test('foo/baz', 'foo', 'bar/../baz')
255
256
        # Test joining to an absolute path
257
        test('/foo', '/foo')
258
        test('/foo', '/foo', '.')
259
        test('/foo/bar', '/foo', 'bar')
260
        test('/', '/foo', '..')
261
262
        # Test joining with an absolute path
263
        test('/bar', 'foo', '/bar')
2018.5.53 by Andrew Bennetts
Small fix to urlutils.joinpath that was causing a misbehaviour in
264
265
        # Test joining to a path with a trailing slash
266
        test('foo/bar', 'foo/', 'bar')
2018.5.46 by Andrew Bennetts
Fix ChrootTransportDecorator's clone to pass less surprising offsets to the decorated transport's clone.
267
        
268
        # Invalid joinings
269
        # Cannot go above root
270
        self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '../baz')
2018.5.54 by Andrew Bennetts
Fix ChrootTransportDecorator's abspath method to be consistent with its clone
271
        self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '..')
272
        self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '/..')
2018.5.46 by Andrew Bennetts
Fix ChrootTransportDecorator's clone to pass less surprising offsets to the decorated transport's clone.
273
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
274
    def test_function_type(self):
275
        if sys.platform == 'win32':
276
            self.assertEqual(urlutils._win32_local_path_to_url, urlutils.local_path_to_url)
277
            self.assertEqual(urlutils._win32_local_path_from_url, urlutils.local_path_from_url)
278
        else:
279
            self.assertEqual(urlutils._posix_local_path_to_url, urlutils.local_path_to_url)
280
            self.assertEqual(urlutils._posix_local_path_from_url, urlutils.local_path_from_url)
281
282
    def test_posix_local_path_to_url(self):
283
        to_url = urlutils._posix_local_path_to_url
284
        self.assertEqual('file:///path/to/foo',
285
            to_url('/path/to/foo'))
1685.1.75 by Wouter van Heyst
more tests handle LANG=C
286
287
        try:
288
            result = to_url(u'/path/to/r\xe4ksm\xf6rg\xe5s')
289
        except UnicodeError:
290
            raise TestSkipped("local encoding cannot handle unicode")
291
292
        self.assertEqual('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
3234.3.1 by Alexander Belchenko
ensure that local_path_to_url() always returns plain string, not unicode.
293
        self.assertFalse(isinstance(result, unicode))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
294
295
    def test_posix_local_path_from_url(self):
296
        from_url = urlutils._posix_local_path_from_url
297
        self.assertEqual('/path/to/foo',
298
            from_url('file:///path/to/foo'))
299
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
300
            from_url('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
301
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
302
            from_url('file:///path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
303
304
        self.assertRaises(InvalidURL, from_url, '/path/to/foo')
305
306
    def test_win32_local_path_to_url(self):
307
        to_url = urlutils._win32_local_path_to_url
1711.4.28 by John Arbash Meinel
Update the test suite for Alexander's patch.
308
        self.assertEqual('file:///C:/path/to/foo',
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
309
            to_url('C:/path/to/foo'))
1711.4.4 by John Arbash Meinel
Fix some broken tests because of stupid ntpath.abspath behavior
310
        # BOGUS: on win32, ntpath.abspath will strip trailing
311
        #       whitespace, so this will always fail
312
        #       Though under linux, it fakes abspath support
313
        #       and thus will succeed
314
        # self.assertEqual('file:///C:/path/to/foo%20',
315
        #     to_url('C:/path/to/foo '))
1711.4.28 by John Arbash Meinel
Update the test suite for Alexander's patch.
316
        self.assertEqual('file:///C:/path/to/f%20oo',
1711.4.4 by John Arbash Meinel
Fix some broken tests because of stupid ntpath.abspath behavior
317
            to_url('C:/path/to/f oo'))
3503.1.2 by adwi2
Permits Windows to serve all paths on all drives.
318
        
319
        self.assertEqual('file:///', to_url('/'))
1685.1.75 by Wouter van Heyst
more tests handle LANG=C
320
321
        try:
322
            result = to_url(u'd:/path/to/r\xe4ksm\xf6rg\xe5s')
323
        except UnicodeError:
324
            raise TestSkipped("local encoding cannot handle unicode")
325
1711.4.28 by John Arbash Meinel
Update the test suite for Alexander's patch.
326
        self.assertEqual('file:///D:/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
3234.3.1 by Alexander Belchenko
ensure that local_path_to_url() always returns plain string, not unicode.
327
        self.assertFalse(isinstance(result, unicode))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
328
2162.2.1 by Alexander Belchenko
Testing UNC path conversion
329
    def test_win32_unc_path_to_url(self):
330
        to_url = urlutils._win32_local_path_to_url
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
331
        self.assertEqual('file://HOST/path',
2162.2.1 by Alexander Belchenko
Testing UNC path conversion
332
            to_url(r'\\HOST\path'))
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
333
        self.assertEqual('file://HOST/path',
2162.2.1 by Alexander Belchenko
Testing UNC path conversion
334
            to_url('//HOST/path'))
335
2162.2.5 by Alexander Belchenko
Expand test_win32_unc_path_to_url to check unicode
336
        try:
337
            result = to_url(u'//HOST/path/to/r\xe4ksm\xf6rg\xe5s')
338
        except UnicodeError:
339
            raise TestSkipped("local encoding cannot handle unicode")
340
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
341
        self.assertEqual('file://HOST/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
3234.3.1 by Alexander Belchenko
ensure that local_path_to_url() always returns plain string, not unicode.
342
        self.assertFalse(isinstance(result, unicode))
2162.2.5 by Alexander Belchenko
Expand test_win32_unc_path_to_url to check unicode
343
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
344
    def test_win32_local_path_from_url(self):
345
        from_url = urlutils._win32_local_path_from_url
1711.4.28 by John Arbash Meinel
Update the test suite for Alexander's patch.
346
        self.assertEqual('C:/path/to/foo',
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
347
            from_url('file:///C|/path/to/foo'))
1711.4.28 by John Arbash Meinel
Update the test suite for Alexander's patch.
348
        self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
349
            from_url('file:///d|/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
1711.4.28 by John Arbash Meinel
Update the test suite for Alexander's patch.
350
        self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
1685.1.79 by Wouter van Heyst
cleanup urlutils
351
            from_url('file:///d:/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
3503.1.2 by adwi2
Permits Windows to serve all paths on all drives.
352
        self.assertEqual('/', from_url('file:///'))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
353
354
        self.assertRaises(InvalidURL, from_url, '/path/to/foo')
355
        # Not a valid _win32 url, no drive letter
356
        self.assertRaises(InvalidURL, from_url, 'file:///path/to/foo')
357
2162.2.1 by Alexander Belchenko
Testing UNC path conversion
358
    def test_win32_unc_path_from_url(self):
359
        from_url = urlutils._win32_local_path_from_url
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
360
        self.assertEqual('//HOST/path', from_url('file://HOST/path'))
361
        # despite IE allows 2, 4, 5 and 6 slashes in URL to another machine
362
        # we want to use only 2 slashes
363
        # Firefox understand only 5 slashes in URL, but it's ugly
2162.2.1 by Alexander Belchenko
Testing UNC path conversion
364
        self.assertRaises(InvalidURL, from_url, 'file:////HOST/path')
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
365
        self.assertRaises(InvalidURL, from_url, 'file://///HOST/path')
2162.2.1 by Alexander Belchenko
Testing UNC path conversion
366
        self.assertRaises(InvalidURL, from_url, 'file://////HOST/path')
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
367
        # check for file://C:/ instead of file:///C:/
368
        self.assertRaises(InvalidURL, from_url, 'file://C:/path')
2162.2.1 by Alexander Belchenko
Testing UNC path conversion
369
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
370
    def test_win32_extract_drive_letter(self):
1711.2.43 by John Arbash Meinel
Split out win32 specific code so that it can be tested on all platforms.
371
        extract = urlutils._win32_extract_drive_letter
372
        self.assertEqual(('file:///C:', '/foo'), extract('file://', '/C:/foo'))
373
        self.assertEqual(('file:///d|', '/path'), extract('file://', '/d|/path'))
374
        self.assertRaises(InvalidURL, extract, 'file://', '/path')
375
1685.1.49 by John Arbash Meinel
Added bzrlib.urlutils.split and basename + dirname
376
    def test_split(self):
377
        # Test bzrlib.urlutils.split()
378
        split = urlutils.split
379
        if sys.platform == 'win32':
380
            self.assertRaises(InvalidURL, split, 'file:///path/to/foo')
381
            self.assertEqual(('file:///C|/', 'foo'), split('file:///C|/foo'))
1685.1.79 by Wouter van Heyst
cleanup urlutils
382
            self.assertEqual(('file:///C:/', ''), split('file:///C:/'))
1685.1.49 by John Arbash Meinel
Added bzrlib.urlutils.split and basename + dirname
383
        else:
384
            self.assertEqual(('file:///', 'foo'), split('file:///foo'))
385
            self.assertEqual(('file:///', ''), split('file:///'))
386
387
        self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo'))
388
        self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo/'))
389
        self.assertEqual(('http://host/path/to/foo', ''),
390
            split('http://host/path/to/foo/', exclude_trailing_slash=False))
391
        self.assertEqual(('http://host/', 'path'), split('http://host/path'))
392
        self.assertEqual(('http://host/', ''), split('http://host/'))
393
        self.assertEqual(('http://host', ''), split('http://host'))
394
        self.assertEqual(('http:///nohost', 'path'), split('http:///nohost/path'))
395
396
        self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
397
            split('random+scheme://user:pass@ahost:port/path'))
398
        self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
399
            split('random+scheme://user:pass@ahost:port/path/'))
400
        self.assertEqual(('random+scheme://user:pass@ahost:port/', ''),
401
            split('random+scheme://user:pass@ahost:port/'))
402
403
        # relative paths
404
        self.assertEqual(('path/to', 'foo'), split('path/to/foo'))
405
        self.assertEqual(('path/to', 'foo'), split('path/to/foo/'))
406
        self.assertEqual(('path/to/foo', ''),
407
            split('path/to/foo/', exclude_trailing_slash=False))
408
        self.assertEqual(('path/..', 'foo'), split('path/../foo'))
409
        self.assertEqual(('../path', 'foo'), split('../path/foo'))
410
2162.2.6 by Alexander Belchenko
Change tests for win32 UNC path to new file://HOST/path scheme
411
    def test_win32_strip_local_trailing_slash(self):
1711.2.44 by John Arbash Meinel
Factor out another win32 special case and add platform independent tests for it.
412
        strip = urlutils._win32_strip_local_trailing_slash
413
        self.assertEqual('file://', strip('file://'))
414
        self.assertEqual('file:///', strip('file:///'))
415
        self.assertEqual('file:///C', strip('file:///C'))
416
        self.assertEqual('file:///C:', strip('file:///C:'))
417
        self.assertEqual('file:///d|', strip('file:///d|'))
418
        self.assertEqual('file:///C:/', strip('file:///C:/'))
419
        self.assertEqual('file:///C:/a', strip('file:///C:/a/'))
420
1685.1.48 by John Arbash Meinel
Updated strip_trailing_slash to support lots more url stuff, added tests
421
    def test_strip_trailing_slash(self):
422
        sts = urlutils.strip_trailing_slash
423
        if sys.platform == 'win32':
424
            self.assertEqual('file:///C|/', sts('file:///C|/'))
1685.1.79 by Wouter van Heyst
cleanup urlutils
425
            self.assertEqual('file:///C:/foo', sts('file:///C:/foo'))
1685.1.48 by John Arbash Meinel
Updated strip_trailing_slash to support lots more url stuff, added tests
426
            self.assertEqual('file:///C|/foo', sts('file:///C|/foo/'))
427
        else:
428
            self.assertEqual('file:///', sts('file:///'))
429
            self.assertEqual('file:///foo', sts('file:///foo'))
430
            self.assertEqual('file:///foo', sts('file:///foo/'))
431
432
        self.assertEqual('http://host/', sts('http://host/'))
433
        self.assertEqual('http://host/foo', sts('http://host/foo'))
434
        self.assertEqual('http://host/foo', sts('http://host/foo/'))
435
436
        # No need to fail just because the slash is missing
437
        self.assertEqual('http://host', sts('http://host'))
438
        # TODO: jam 20060502 Should this raise InvalidURL?
439
        self.assertEqual('file://', sts('file://'))
440
441
        self.assertEqual('random+scheme://user:pass@ahost:port/path',
442
            sts('random+scheme://user:pass@ahost:port/path'))
443
        self.assertEqual('random+scheme://user:pass@ahost:port/path',
444
            sts('random+scheme://user:pass@ahost:port/path/'))
445
        self.assertEqual('random+scheme://user:pass@ahost:port/',
446
            sts('random+scheme://user:pass@ahost:port/'))
447
448
        # Make sure relative paths work too
449
        self.assertEqual('path/to/foo', sts('path/to/foo'))
450
        self.assertEqual('path/to/foo', sts('path/to/foo/'))
451
        self.assertEqual('../to/foo', sts('../to/foo/'))
452
        self.assertEqual('path/../foo', sts('path/../foo/'))
453
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
454
    def test_unescape_for_display_utf8(self):
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
455
        # Test that URLs are converted to nice unicode strings for display
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
456
        def test(expected, url, encoding='utf-8'):
457
            disp_url = urlutils.unescape_for_display(url, encoding=encoding)
1685.1.58 by Martin Pool
urlutils.unescape_for_display should return Unicode
458
            self.assertIsInstance(disp_url, unicode)
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
459
            self.assertEqual(expected, disp_url)
1685.1.79 by Wouter van Heyst
cleanup urlutils
460
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
461
        test('http://foo', 'http://foo')
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
462
        if sys.platform == 'win32':
1711.7.13 by John Arbash Meinel
Fix expected value for urlutils tests
463
            test('C:/foo/path', 'file:///C|/foo/path')
464
            test('C:/foo/path', 'file:///C:/foo/path')
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
465
        else:
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
466
            test('/foo/path', 'file:///foo/path')
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
467
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
468
        test('http://foo/%2Fbaz', 'http://foo/%2Fbaz')
1685.1.58 by Martin Pool
urlutils.unescape_for_display should return Unicode
469
        test(u'http://host/r\xe4ksm\xf6rg\xe5s',
470
             'http://host/r%C3%A4ksm%C3%B6rg%C3%A5s')
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
471
472
        # Make sure special escaped characters stay escaped
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
473
        test(u'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23',
1685.1.58 by Martin Pool
urlutils.unescape_for_display should return Unicode
474
             'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23')
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
475
476
        # Can we handle sections that don't have utf-8 encoding?
1685.1.58 by Martin Pool
urlutils.unescape_for_display should return Unicode
477
        test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
478
             'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s')
1685.1.54 by John Arbash Meinel
url_for_display now makes sure output can be properly encoded.
479
480
        # Test encoding into output that can handle some characters
1685.1.58 by Martin Pool
urlutils.unescape_for_display should return Unicode
481
        test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
482
             'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s',
483
             encoding='iso-8859-1')
484
485
        # This one can be encoded into utf8
486
        test(u'http://host/\u062c\u0648\u062c\u0648',
487
             'http://host/%d8%ac%d9%88%d8%ac%d9%88',
488
             encoding='utf-8')
489
490
        # This can't be put into 8859-1 and so stays as escapes
491
        test(u'http://host/%d8%ac%d9%88%d8%ac%d9%88',
492
             'http://host/%d8%ac%d9%88%d8%ac%d9%88',
493
             encoding='iso-8859-1')
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
494
495
    def test_escape(self):
496
        self.assertEqual('%25', urlutils.escape('%'))
497
        self.assertEqual('%C3%A5', urlutils.escape(u'\xe5'))
3234.3.1 by Alexander Belchenko
ensure that local_path_to_url() always returns plain string, not unicode.
498
        self.assertFalse(isinstance(urlutils.escape(u'\xe5'), unicode))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
499
500
    def test_unescape(self):
501
        self.assertEqual('%', urlutils.unescape('%25'))
502
        self.assertEqual(u'\xe5', urlutils.unescape('%C3%A5'))
503
504
        self.assertRaises(InvalidURL, urlutils.unescape, u'\xe5')
505
        self.assertRaises(InvalidURL, urlutils.unescape, '\xe5')
506
        self.assertRaises(InvalidURL, urlutils.unescape, '%E5')
507
508
    def test_escape_unescape(self):
509
        self.assertEqual(u'\xe5', urlutils.unescape(urlutils.escape(u'\xe5')))
510
        self.assertEqual('%', urlutils.unescape(urlutils.escape('%')))
511
1685.1.70 by Wouter van Heyst
working on get_parent, set_parent and relative urls, broken
512
    def test_relative_url(self):
513
        def test(expected, base, other):
514
            result = urlutils.relative_url(base, other)
515
            self.assertEqual(expected, result)
516
            
517
        test('a', 'http://host/', 'http://host/a')
1685.1.71 by Wouter van Heyst
change branch.{get,set}_parent to store a relative path but return full urls
518
        test('http://entirely/different', 'sftp://host/branch',
519
                    'http://entirely/different')
520
        test('../person/feature', 'http://host/branch/mainline',
521
                    'http://host/branch/person/feature')
1685.1.70 by Wouter van Heyst
working on get_parent, set_parent and relative urls, broken
522
        test('..', 'http://host/branch', 'http://host/')
523
        test('http://host2/branch', 'http://host1/branch', 'http://host2/branch')
1685.1.71 by Wouter van Heyst
change branch.{get,set}_parent to store a relative path but return full urls
524
        test('.', 'http://host1/branch', 'http://host1/branch')
525
        test('../../../branch/2b', 'file:///home/jelmer/foo/bar/2b',
526
                    'file:///home/jelmer/branch/2b')
527
        test('../../branch/2b', 'sftp://host/home/jelmer/bar/2b',
528
                    'sftp://host/home/jelmer/branch/2b')
1685.1.79 by Wouter van Heyst
cleanup urlutils
529
        test('../../branch/feature/%2b', 'http://host/home/jelmer/bar/%2b',
530
                    'http://host/home/jelmer/branch/feature/%2b')
1685.1.71 by Wouter van Heyst
change branch.{get,set}_parent to store a relative path but return full urls
531
        test('../../branch/feature/2b', 'http://host/home/jelmer/bar/2b/', 
532
                    'http://host/home/jelmer/branch/feature/2b')
533
        # relative_url should preserve a trailing slash
534
        test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b/',
535
                    'http://host/home/jelmer/branch/feature/2b/')
536
        test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b',
537
                    'http://host/home/jelmer/branch/feature/2b/')
538
539
        # TODO: treat http://host as http://host/
540
        #       relative_url is typically called from a branch.base or
541
        #       transport.base which always ends with a /
542
        #test('a', 'http://host', 'http://host/a')
543
        test('http://host/a', 'http://host', 'http://host/a')
544
        #test('.', 'http://host', 'http://host/')
545
        test('http://host/', 'http://host', 'http://host/')
546
        #test('.', 'http://host/', 'http://host')
547
        test('http://host', 'http://host/', 'http://host')
1830.3.13 by John Arbash Meinel
Add a test that urlutils creates normalized paths
548
3139.2.1 by Alexander Belchenko
bugfix #90847: fix problem with parent location on another logical drive
549
        # On Windows file:///C:/path/to and file:///D:/other/path
550
        # should not use relative url over the non-existent '/' directory.
551
        if sys.platform == 'win32':
552
            # on the same drive
553
            test('../../other/path',
554
                'file:///C:/path/to', 'file:///C:/other/path')
555
            #~next two tests is failed, i.e. urlutils.relative_url expects
556
            #~to see normalized file URLs?
557
            #~test('../../other/path',
558
            #~    'file:///C:/path/to', 'file:///c:/other/path')
559
            #~test('../../other/path',
560
            #~    'file:///C:/path/to', 'file:///C|/other/path')
561
562
            # check UNC paths too
563
            test('../../other/path',
564
                'file://HOST/base/path/to', 'file://HOST/base/other/path')
565
            # on different drives
566
            test('file:///D:/other/path',
567
                'file:///C:/path/to', 'file:///D:/other/path')
568
            # TODO: strictly saying in UNC path //HOST/base is full analog
569
            # of drive letter for hard disk, and this situation is also
570
            # should be exception from rules. [bialix 20071221]
571
1830.3.13 by John Arbash Meinel
Add a test that urlutils creates normalized paths
572
573
class TestCwdToURL(TestCaseInTempDir):
574
    """Test that local_path_to_url works base on the cwd"""
575
576
    def test_dot(self):
577
        # This test will fail if getcwd is not ascii
1830.3.17 by John Arbash Meinel
list_files() with wrong normalized_filename code raises exceptions. Fix this
578
        os.mkdir('mytest')
579
        os.chdir('mytest')
1830.3.13 by John Arbash Meinel
Add a test that urlutils creates normalized paths
580
581
        url = urlutils.local_path_to_url('.')
1830.3.17 by John Arbash Meinel
list_files() with wrong normalized_filename code raises exceptions. Fix this
582
        self.assertEndsWith(url, '/mytest')
1830.3.13 by John Arbash Meinel
Add a test that urlutils creates normalized paths
583
584
    def test_non_ascii(self):
2279.4.2 by Alexander Belchenko
Don't do normpath after abspath, because this function is called inside abspath
585
        if win32utils.winver == 'Windows 98':
586
            raise TestSkipped('Windows 98 cannot handle unicode filenames')
587
1830.3.13 by John Arbash Meinel
Add a test that urlutils creates normalized paths
588
        try:
589
            os.mkdir(u'dod\xe9')
590
        except UnicodeError:
591
            raise TestSkipped('cannot create unicode directory')
592
593
        os.chdir(u'dod\xe9')
594
595
        # On Mac OSX this directory is actually: 
596
        #   u'/dode\u0301' => '/dode\xcc\x81
597
        # but we should normalize it back to 
598
        #   u'/dod\xe9' => '/dod\xc3\xa9'
599
        url = urlutils.local_path_to_url('.')
600
        self.assertEndsWith(url, '/dod%C3%A9')
2512.4.1 by Ian Clatworthy
Fixes #115491 - 'branch lp:projname' now creates ./projname as exected
601
602
603
class TestDeriveToLocation(TestCase):
604
    """Test that the mapping of FROM_LOCATION to TO_LOCATION works."""
605
606
    def test_to_locations_derived_from_paths(self):
607
        derive = urlutils.derive_to_location
608
        self.assertEqual("bar", derive("bar"))
609
        self.assertEqual("bar", derive("../bar"))
610
        self.assertEqual("bar", derive("/foo/bar"))
611
        self.assertEqual("bar", derive("c:/foo/bar"))
612
        self.assertEqual("bar", derive("c:bar"))
613
614
    def test_to_locations_derived_from_urls(self):
615
        derive = urlutils.derive_to_location
616
        self.assertEqual("bar", derive("http://foo/bar"))
617
        self.assertEqual("bar", derive("bzr+ssh://foo/bar"))
618
        self.assertEqual("foo-bar", derive("lp:foo-bar"))
3242.3.26 by Aaron Bentley
Implement rebase_url
619
620
621
class TestRebaseURL(TestCase):
622
    """Test the behavior of rebase_url."""
623
624
    def test_non_relative(self):
625
        result = urlutils.rebase_url('file://foo', 'file://foo',
626
                                     'file://foo/bar')
627
        self.assertEqual('file://foo', result)
628
        result = urlutils.rebase_url('/foo', 'file://foo',
629
                                     'file://foo/bar')
630
        self.assertEqual('/foo', result)
631
3242.3.36 by Aaron Bentley
Updates from review comments
632
    def test_different_ports(self):
633
        e = self.assertRaises(InvalidRebaseURLs, urlutils.rebase_url,
634
                              'foo', 'http://bar:80', 'http://bar:81')
635
        self.assertEqual(str(e), "URLs differ by more than path:"
636
                         " 'http://bar:80' and 'http://bar:81'")
637
638
    def test_different_hosts(self):
3242.3.33 by Aaron Bentley
Handle relative URL stacking cleanly
639
        e = self.assertRaises(InvalidRebaseURLs, urlutils.rebase_url,
640
                              'foo', 'http://bar', 'http://baz')
641
        self.assertEqual(str(e), "URLs differ by more than path: 'http://bar'"
642
                         " and 'http://baz'")
3242.3.26 by Aaron Bentley
Implement rebase_url
643
3242.3.36 by Aaron Bentley
Updates from review comments
644
    def test_different_protocol(self):
645
        e = self.assertRaises(InvalidRebaseURLs, urlutils.rebase_url,
646
                              'foo', 'http://bar', 'ftp://bar')
647
        self.assertEqual(str(e), "URLs differ by more than path: 'http://bar'"
648
                         " and 'ftp://bar'")
649
3242.3.26 by Aaron Bentley
Implement rebase_url
650
    def test_rebase_success(self):
651
        self.assertEqual('../bar', urlutils.rebase_url('bar', 'http://baz/',
652
                         'http://baz/qux'))
653
        self.assertEqual('qux/bar', urlutils.rebase_url('bar',
654
                         'http://baz/qux', 'http://baz/'))
655
        self.assertEqual('.', urlutils.rebase_url('foo',
656
                         'http://bar/', 'http://bar/foo/'))
3567.2.1 by Michael Hudson
urlutils.rebase_url handles '..' path segments in 'url'
657
        self.assertEqual('qux/bar', urlutils.rebase_url('../bar',
658
                         'http://baz/qux/foo', 'http://baz/'))
3242.3.26 by Aaron Bentley
Implement rebase_url
659
660
    def test_determine_relative_path(self):
661
        self.assertEqual('../../baz/bar',
662
                         urlutils.determine_relative_path(
663
                         '/qux/quxx', '/baz/bar'))
664
        self.assertEqual('..',
665
                         urlutils.determine_relative_path(
666
                         '/bar/baz', '/bar'))
667
        self.assertEqual('baz',
668
                         urlutils.determine_relative_path(
669
                         '/bar', '/bar/baz'))
670
        self.assertEqual('.', urlutils.determine_relative_path(
671
                         '/bar', '/bar'))