1
# Copyright (C) 2005 Canonical Ltd
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.
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.
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
17
"""Tests for the urlutils wrapper."""
23
from bzrlib import osutils, urlutils, win32utils
25
from bzrlib.errors import InvalidURL, InvalidURLJoin
26
from bzrlib.tests import TestCaseInTempDir, TestCase, TestSkipped
29
class TestUrlToPath(TestCase):
31
def test_basename(self):
32
# bzrlib.urlutils.basename
33
# Test bzrlib.urlutils.split()
34
basename = urlutils.basename
35
if sys.platform == 'win32':
36
self.assertRaises(InvalidURL, basename, 'file:///path/to/foo')
37
self.assertEqual('foo', basename('file:///C|/foo'))
38
self.assertEqual('foo', basename('file:///C:/foo'))
39
self.assertEqual('', basename('file:///C:/'))
41
self.assertEqual('foo', basename('file:///foo'))
42
self.assertEqual('', basename('file:///'))
44
self.assertEqual('foo', basename('http://host/path/to/foo'))
45
self.assertEqual('foo', basename('http://host/path/to/foo/'))
47
basename('http://host/path/to/foo/', exclude_trailing_slash=False))
48
self.assertEqual('path', basename('http://host/path'))
49
self.assertEqual('', basename('http://host/'))
50
self.assertEqual('', basename('http://host'))
51
self.assertEqual('path', basename('http:///nohost/path'))
53
self.assertEqual('path', basename('random+scheme://user:pass@ahost:port/path'))
54
self.assertEqual('path', basename('random+scheme://user:pass@ahost:port/path/'))
55
self.assertEqual('', basename('random+scheme://user:pass@ahost:port/'))
58
self.assertEqual('foo', basename('path/to/foo'))
59
self.assertEqual('foo', basename('path/to/foo/'))
60
self.assertEqual('', basename('path/to/foo/',
61
exclude_trailing_slash=False))
62
self.assertEqual('foo', basename('path/../foo'))
63
self.assertEqual('foo', basename('../path/foo'))
65
def test_normalize_url_files(self):
66
# Test that local paths are properly normalized
67
normalize_url = urlutils.normalize_url
69
def norm_file(expected, path):
70
url = normalize_url(path)
71
self.assertStartsWith(url, 'file:///')
72
if sys.platform == 'win32':
73
url = url[len('file:///C:'):]
75
url = url[len('file://'):]
77
self.assertEndsWith(url, expected)
79
norm_file('path/to/foo', 'path/to/foo')
80
norm_file('/path/to/foo', '/path/to/foo')
81
norm_file('path/to/foo', '../path/to/foo')
83
# Local paths are assumed to *not* be escaped at all
85
u'uni/\xb5'.encode(bzrlib.user_encoding)
87
# locale cannot handle unicode
90
norm_file('uni/%C2%B5', u'uni/\xb5')
92
norm_file('uni/%25C2%25B5', u'uni/%C2%B5')
93
norm_file('uni/%20b', u'uni/ b')
94
# All the crazy characters get escaped in local paths => file:/// urls
95
# The ' ' character must not be at the end, because on win32
96
# it gets stripped off by ntpath.abspath
97
norm_file('%27%20%3B/%3F%3A%40%26%3D%2B%24%2C%23', "' ;/?:@&=+$,#")
99
def test_normalize_url_hybrid(self):
100
# Anything with a scheme:// should be treated as a hybrid url
101
# which changes what characters get escaped.
102
normalize_url = urlutils.normalize_url
104
eq = self.assertEqual
105
eq('file:///foo/', normalize_url(u'file:///foo/'))
106
eq('file:///foo/%20', normalize_url(u'file:///foo/ '))
107
eq('file:///foo/%20', normalize_url(u'file:///foo/%20'))
108
# Don't escape reserved characters
109
eq('file:///ab_c.d-e/%f:?g&h=i+j;k,L#M$',
110
normalize_url('file:///ab_c.d-e/%f:?g&h=i+j;k,L#M$'))
111
eq('http://ab_c.d-e/%f:?g&h=i+j;k,L#M$',
112
normalize_url('http://ab_c.d-e/%f:?g&h=i+j;k,L#M$'))
114
# Escape unicode characters, but not already escaped chars
115
eq('http://host/ab/%C2%B5/%C2%B5',
116
normalize_url(u'http://host/ab/%C2%B5/\xb5'))
118
# Unescape characters that don't need to be escaped
119
eq('http://host/~bob%2525-._',
120
normalize_url('http://host/%7Ebob%2525%2D%2E%5F'))
121
eq('http://host/~bob%2525-._',
122
normalize_url(u'http://host/%7Ebob%2525%2D%2E%5F'))
124
# Normalize verifies URLs when they are not unicode
125
# (indicating they did not come from the user)
126
self.assertRaises(InvalidURL, normalize_url, 'http://host/\xb5')
127
self.assertRaises(InvalidURL, normalize_url, 'http://host/ ')
129
def test_url_scheme_re(self):
130
# Test paths that may be URLs
131
def test_one(url, scheme_and_path):
132
"""Assert that _url_scheme_re correctly matches
134
:param scheme_and_path: The (scheme, path) that should be matched
135
can be None, to indicate it should not match
137
m = urlutils._url_scheme_re.match(url)
138
if scheme_and_path is None:
139
self.assertEqual(None, m)
141
self.assertEqual(scheme_and_path[0], m.group('scheme'))
142
self.assertEqual(scheme_and_path[1], m.group('path'))
145
test_one('/path', None)
146
test_one('C:/path', None)
147
test_one('../path/to/foo', None)
148
test_one(u'../path/to/fo\xe5', None)
151
test_one('http://host/path/', ('http', 'host/path/'))
152
test_one('sftp://host/path/to/foo', ('sftp', 'host/path/to/foo'))
153
test_one('file:///usr/bin', ('file', '/usr/bin'))
154
test_one('file:///C:/Windows', ('file', '/C:/Windows'))
155
test_one('file:///C|/Windows', ('file', '/C|/Windows'))
156
test_one(u'readonly+sftp://host/path/\xe5', ('readonly+sftp', u'host/path/\xe5'))
159
# Can't have slashes or colons in the scheme
160
test_one('/path/to/://foo', None)
161
test_one('path:path://foo', None)
162
# Must have more than one character for scheme
163
test_one('C://foo', None)
164
test_one('ab://foo', ('ab', 'foo'))
166
def test_dirname(self):
167
# Test bzrlib.urlutils.dirname()
168
dirname = urlutils.dirname
169
if sys.platform == 'win32':
170
self.assertRaises(InvalidURL, dirname, 'file:///path/to/foo')
171
self.assertEqual('file:///C|/', dirname('file:///C|/foo'))
172
self.assertEqual('file:///C|/', dirname('file:///C|/'))
174
self.assertEqual('file:///', dirname('file:///foo'))
175
self.assertEqual('file:///', dirname('file:///'))
177
self.assertEqual('http://host/path/to', dirname('http://host/path/to/foo'))
178
self.assertEqual('http://host/path/to', dirname('http://host/path/to/foo/'))
179
self.assertEqual('http://host/path/to/foo',
180
dirname('http://host/path/to/foo/', exclude_trailing_slash=False))
181
self.assertEqual('http://host/', dirname('http://host/path'))
182
self.assertEqual('http://host/', dirname('http://host/'))
183
self.assertEqual('http://host', dirname('http://host'))
184
self.assertEqual('http:///nohost', dirname('http:///nohost/path'))
186
self.assertEqual('random+scheme://user:pass@ahost:port/',
187
dirname('random+scheme://user:pass@ahost:port/path'))
188
self.assertEqual('random+scheme://user:pass@ahost:port/',
189
dirname('random+scheme://user:pass@ahost:port/path/'))
190
self.assertEqual('random+scheme://user:pass@ahost:port/',
191
dirname('random+scheme://user:pass@ahost:port/'))
194
self.assertEqual('path/to', dirname('path/to/foo'))
195
self.assertEqual('path/to', dirname('path/to/foo/'))
196
self.assertEqual('path/to/foo',
197
dirname('path/to/foo/', exclude_trailing_slash=False))
198
self.assertEqual('path/..', dirname('path/../foo'))
199
self.assertEqual('../path', dirname('../path/foo'))
202
def test(expected, *args):
203
joined = urlutils.join(*args)
204
self.assertEqual(expected, joined)
206
# Test relative path joining
207
test('foo', 'foo') # relative fragment with nothing is preserved.
208
test('foo/bar', 'foo', 'bar')
209
test('http://foo/bar', 'http://foo', 'bar')
210
test('http://foo/bar', 'http://foo', '.', 'bar')
211
test('http://foo/baz', 'http://foo', 'bar', '../baz')
212
test('http://foo/bar/baz', 'http://foo', 'bar/baz')
213
test('http://foo/baz', 'http://foo', 'bar/../baz')
214
test('http://foo/baz', 'http://foo/bar/', '../baz')
217
test('http://foo', 'http://foo') # abs url with nothing is preserved.
218
test('http://bar', 'http://foo', 'http://bar')
219
test('sftp://bzr/foo', 'http://foo', 'bar', 'sftp://bzr/foo')
220
test('file:///bar', 'foo', 'file:///bar')
221
test('http://bar/', 'http://foo', 'http://bar/')
222
test('http://bar/a', 'http://foo', 'http://bar/a')
223
test('http://bar/a/', 'http://foo', 'http://bar/a/')
226
test('file:///foo', 'file:///', 'foo')
227
test('file:///bar/foo', 'file:///bar/', 'foo')
228
test('http://host/foo', 'http://host/', 'foo')
229
test('http://host/', 'http://host', '')
232
# Cannot go above root
233
# Implicitly at root:
234
self.assertRaises(InvalidURLJoin, urlutils.join,
235
'http://foo', '../baz')
236
self.assertRaises(InvalidURLJoin, urlutils.join,
238
# Joining from a path explicitly under the root.
239
self.assertRaises(InvalidURLJoin, urlutils.join,
240
'http://foo/a', '../../b')
242
def test_joinpath(self):
243
def test(expected, *args):
244
joined = urlutils.joinpath(*args)
245
self.assertEqual(expected, joined)
247
# Test a single element
250
# Test relative path joining
251
test('foo/bar', 'foo', 'bar')
252
test('foo/bar', 'foo', '.', 'bar')
253
test('foo/baz', 'foo', 'bar', '../baz')
254
test('foo/bar/baz', 'foo', 'bar/baz')
255
test('foo/baz', 'foo', 'bar/../baz')
257
# Test joining to an absolute path
259
test('/foo', '/foo', '.')
260
test('/foo/bar', '/foo', 'bar')
261
test('/', '/foo', '..')
263
# Test joining with an absolute path
264
test('/bar', 'foo', '/bar')
266
# Test joining to a path with a trailing slash
267
test('foo/bar', 'foo/', 'bar')
270
# Cannot go above root
271
self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '../baz')
272
self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '..')
273
self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '/..')
275
def test_function_type(self):
276
if sys.platform == 'win32':
277
self.assertEqual(urlutils._win32_local_path_to_url, urlutils.local_path_to_url)
278
self.assertEqual(urlutils._win32_local_path_from_url, urlutils.local_path_from_url)
280
self.assertEqual(urlutils._posix_local_path_to_url, urlutils.local_path_to_url)
281
self.assertEqual(urlutils._posix_local_path_from_url, urlutils.local_path_from_url)
283
def test_posix_local_path_to_url(self):
284
to_url = urlutils._posix_local_path_to_url
285
self.assertEqual('file:///path/to/foo',
286
to_url('/path/to/foo'))
289
result = to_url(u'/path/to/r\xe4ksm\xf6rg\xe5s')
291
raise TestSkipped("local encoding cannot handle unicode")
293
self.assertEqual('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
294
self.assertFalse(isinstance(result, unicode))
296
def test_posix_local_path_from_url(self):
297
from_url = urlutils._posix_local_path_from_url
298
self.assertEqual('/path/to/foo',
299
from_url('file:///path/to/foo'))
300
self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
301
from_url('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
302
self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
303
from_url('file:///path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
305
self.assertRaises(InvalidURL, from_url, '/path/to/foo')
307
def test_win32_local_path_to_url(self):
308
to_url = urlutils._win32_local_path_to_url
309
self.assertEqual('file:///C:/path/to/foo',
310
to_url('C:/path/to/foo'))
311
# BOGUS: on win32, ntpath.abspath will strip trailing
312
# whitespace, so this will always fail
313
# Though under linux, it fakes abspath support
314
# and thus will succeed
315
# self.assertEqual('file:///C:/path/to/foo%20',
316
# to_url('C:/path/to/foo '))
317
self.assertEqual('file:///C:/path/to/f%20oo',
318
to_url('C:/path/to/f oo'))
321
result = to_url(u'd:/path/to/r\xe4ksm\xf6rg\xe5s')
323
raise TestSkipped("local encoding cannot handle unicode")
325
self.assertEqual('file:///D:/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
326
self.assertFalse(isinstance(result, unicode))
328
def test_win32_unc_path_to_url(self):
329
to_url = urlutils._win32_local_path_to_url
330
self.assertEqual('file://HOST/path',
331
to_url(r'\\HOST\path'))
332
self.assertEqual('file://HOST/path',
333
to_url('//HOST/path'))
336
result = to_url(u'//HOST/path/to/r\xe4ksm\xf6rg\xe5s')
338
raise TestSkipped("local encoding cannot handle unicode")
340
self.assertEqual('file://HOST/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
341
self.assertFalse(isinstance(result, unicode))
343
def test_win32_local_path_from_url(self):
344
from_url = urlutils._win32_local_path_from_url
345
self.assertEqual('C:/path/to/foo',
346
from_url('file:///C|/path/to/foo'))
347
self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
348
from_url('file:///d|/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
349
self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
350
from_url('file:///d:/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
352
self.assertRaises(InvalidURL, from_url, '/path/to/foo')
353
# Not a valid _win32 url, no drive letter
354
self.assertRaises(InvalidURL, from_url, 'file:///path/to/foo')
356
def test_win32_unc_path_from_url(self):
357
from_url = urlutils._win32_local_path_from_url
358
self.assertEqual('//HOST/path', from_url('file://HOST/path'))
359
# despite IE allows 2, 4, 5 and 6 slashes in URL to another machine
360
# we want to use only 2 slashes
361
# Firefox understand only 5 slashes in URL, but it's ugly
362
self.assertRaises(InvalidURL, from_url, 'file:////HOST/path')
363
self.assertRaises(InvalidURL, from_url, 'file://///HOST/path')
364
self.assertRaises(InvalidURL, from_url, 'file://////HOST/path')
365
# check for file://C:/ instead of file:///C:/
366
self.assertRaises(InvalidURL, from_url, 'file://C:/path')
368
def test_win32_extract_drive_letter(self):
369
extract = urlutils._win32_extract_drive_letter
370
self.assertEqual(('file:///C:', '/foo'), extract('file://', '/C:/foo'))
371
self.assertEqual(('file:///d|', '/path'), extract('file://', '/d|/path'))
372
self.assertRaises(InvalidURL, extract, 'file://', '/path')
374
def test_split(self):
375
# Test bzrlib.urlutils.split()
376
split = urlutils.split
377
if sys.platform == 'win32':
378
self.assertRaises(InvalidURL, split, 'file:///path/to/foo')
379
self.assertEqual(('file:///C|/', 'foo'), split('file:///C|/foo'))
380
self.assertEqual(('file:///C:/', ''), split('file:///C:/'))
382
self.assertEqual(('file:///', 'foo'), split('file:///foo'))
383
self.assertEqual(('file:///', ''), split('file:///'))
385
self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo'))
386
self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo/'))
387
self.assertEqual(('http://host/path/to/foo', ''),
388
split('http://host/path/to/foo/', exclude_trailing_slash=False))
389
self.assertEqual(('http://host/', 'path'), split('http://host/path'))
390
self.assertEqual(('http://host/', ''), split('http://host/'))
391
self.assertEqual(('http://host', ''), split('http://host'))
392
self.assertEqual(('http:///nohost', 'path'), split('http:///nohost/path'))
394
self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
395
split('random+scheme://user:pass@ahost:port/path'))
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/', ''),
399
split('random+scheme://user:pass@ahost:port/'))
402
self.assertEqual(('path/to', 'foo'), split('path/to/foo'))
403
self.assertEqual(('path/to', 'foo'), split('path/to/foo/'))
404
self.assertEqual(('path/to/foo', ''),
405
split('path/to/foo/', exclude_trailing_slash=False))
406
self.assertEqual(('path/..', 'foo'), split('path/../foo'))
407
self.assertEqual(('../path', 'foo'), split('../path/foo'))
409
def test_win32_strip_local_trailing_slash(self):
410
strip = urlutils._win32_strip_local_trailing_slash
411
self.assertEqual('file://', strip('file://'))
412
self.assertEqual('file:///', strip('file:///'))
413
self.assertEqual('file:///C', strip('file:///C'))
414
self.assertEqual('file:///C:', strip('file:///C:'))
415
self.assertEqual('file:///d|', strip('file:///d|'))
416
self.assertEqual('file:///C:/', strip('file:///C:/'))
417
self.assertEqual('file:///C:/a', strip('file:///C:/a/'))
419
def test_strip_trailing_slash(self):
420
sts = urlutils.strip_trailing_slash
421
if sys.platform == 'win32':
422
self.assertEqual('file:///C|/', sts('file:///C|/'))
423
self.assertEqual('file:///C:/foo', sts('file:///C:/foo'))
424
self.assertEqual('file:///C|/foo', sts('file:///C|/foo/'))
426
self.assertEqual('file:///', sts('file:///'))
427
self.assertEqual('file:///foo', sts('file:///foo'))
428
self.assertEqual('file:///foo', sts('file:///foo/'))
430
self.assertEqual('http://host/', sts('http://host/'))
431
self.assertEqual('http://host/foo', sts('http://host/foo'))
432
self.assertEqual('http://host/foo', sts('http://host/foo/'))
434
# No need to fail just because the slash is missing
435
self.assertEqual('http://host', sts('http://host'))
436
# TODO: jam 20060502 Should this raise InvalidURL?
437
self.assertEqual('file://', sts('file://'))
439
self.assertEqual('random+scheme://user:pass@ahost:port/path',
440
sts('random+scheme://user:pass@ahost:port/path'))
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/',
444
sts('random+scheme://user:pass@ahost:port/'))
446
# Make sure relative paths work too
447
self.assertEqual('path/to/foo', sts('path/to/foo'))
448
self.assertEqual('path/to/foo', sts('path/to/foo/'))
449
self.assertEqual('../to/foo', sts('../to/foo/'))
450
self.assertEqual('path/../foo', sts('path/../foo/'))
452
def test_unescape_for_display_utf8(self):
453
# Test that URLs are converted to nice unicode strings for display
454
def test(expected, url, encoding='utf-8'):
455
disp_url = urlutils.unescape_for_display(url, encoding=encoding)
456
self.assertIsInstance(disp_url, unicode)
457
self.assertEqual(expected, disp_url)
459
test('http://foo', 'http://foo')
460
if sys.platform == 'win32':
461
test('C:/foo/path', 'file:///C|/foo/path')
462
test('C:/foo/path', 'file:///C:/foo/path')
464
test('/foo/path', 'file:///foo/path')
466
test('http://foo/%2Fbaz', 'http://foo/%2Fbaz')
467
test(u'http://host/r\xe4ksm\xf6rg\xe5s',
468
'http://host/r%C3%A4ksm%C3%B6rg%C3%A5s')
470
# Make sure special escaped characters stay escaped
471
test(u'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23',
472
'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23')
474
# Can we handle sections that don't have utf-8 encoding?
475
test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
476
'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s')
478
# Test encoding into output that can handle some characters
479
test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
480
'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s',
481
encoding='iso-8859-1')
483
# This one can be encoded into utf8
484
test(u'http://host/\u062c\u0648\u062c\u0648',
485
'http://host/%d8%ac%d9%88%d8%ac%d9%88',
488
# This can't be put into 8859-1 and so stays as escapes
489
test(u'http://host/%d8%ac%d9%88%d8%ac%d9%88',
490
'http://host/%d8%ac%d9%88%d8%ac%d9%88',
491
encoding='iso-8859-1')
493
def test_escape(self):
494
self.assertEqual('%25', urlutils.escape('%'))
495
self.assertEqual('%C3%A5', urlutils.escape(u'\xe5'))
496
self.assertFalse(isinstance(urlutils.escape(u'\xe5'), unicode))
498
def test_unescape(self):
499
self.assertEqual('%', urlutils.unescape('%25'))
500
self.assertEqual(u'\xe5', urlutils.unescape('%C3%A5'))
502
self.assertRaises(InvalidURL, urlutils.unescape, u'\xe5')
503
self.assertRaises(InvalidURL, urlutils.unescape, '\xe5')
504
self.assertRaises(InvalidURL, urlutils.unescape, '%E5')
506
def test_escape_unescape(self):
507
self.assertEqual(u'\xe5', urlutils.unescape(urlutils.escape(u'\xe5')))
508
self.assertEqual('%', urlutils.unescape(urlutils.escape('%')))
510
def test_relative_url(self):
511
def test(expected, base, other):
512
result = urlutils.relative_url(base, other)
513
self.assertEqual(expected, result)
515
test('a', 'http://host/', 'http://host/a')
516
test('http://entirely/different', 'sftp://host/branch',
517
'http://entirely/different')
518
test('../person/feature', 'http://host/branch/mainline',
519
'http://host/branch/person/feature')
520
test('..', 'http://host/branch', 'http://host/')
521
test('http://host2/branch', 'http://host1/branch', 'http://host2/branch')
522
test('.', 'http://host1/branch', 'http://host1/branch')
523
test('../../../branch/2b', 'file:///home/jelmer/foo/bar/2b',
524
'file:///home/jelmer/branch/2b')
525
test('../../branch/2b', 'sftp://host/home/jelmer/bar/2b',
526
'sftp://host/home/jelmer/branch/2b')
527
test('../../branch/feature/%2b', 'http://host/home/jelmer/bar/%2b',
528
'http://host/home/jelmer/branch/feature/%2b')
529
test('../../branch/feature/2b', 'http://host/home/jelmer/bar/2b/',
530
'http://host/home/jelmer/branch/feature/2b')
531
# relative_url should preserve a trailing slash
532
test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b/',
533
'http://host/home/jelmer/branch/feature/2b/')
534
test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b',
535
'http://host/home/jelmer/branch/feature/2b/')
537
# TODO: treat http://host as http://host/
538
# relative_url is typically called from a branch.base or
539
# transport.base which always ends with a /
540
#test('a', 'http://host', 'http://host/a')
541
test('http://host/a', 'http://host', 'http://host/a')
542
#test('.', 'http://host', 'http://host/')
543
test('http://host/', 'http://host', 'http://host/')
544
#test('.', 'http://host/', 'http://host')
545
test('http://host', 'http://host/', 'http://host')
547
# On Windows file:///C:/path/to and file:///D:/other/path
548
# should not use relative url over the non-existent '/' directory.
549
if sys.platform == 'win32':
551
test('../../other/path',
552
'file:///C:/path/to', 'file:///C:/other/path')
553
#~next two tests is failed, i.e. urlutils.relative_url expects
554
#~to see normalized file URLs?
555
#~test('../../other/path',
556
#~ 'file:///C:/path/to', 'file:///c:/other/path')
557
#~test('../../other/path',
558
#~ 'file:///C:/path/to', 'file:///C|/other/path')
560
# check UNC paths too
561
test('../../other/path',
562
'file://HOST/base/path/to', 'file://HOST/base/other/path')
563
# on different drives
564
test('file:///D:/other/path',
565
'file:///C:/path/to', 'file:///D:/other/path')
566
# TODO: strictly saying in UNC path //HOST/base is full analog
567
# of drive letter for hard disk, and this situation is also
568
# should be exception from rules. [bialix 20071221]
571
class TestCwdToURL(TestCaseInTempDir):
572
"""Test that local_path_to_url works base on the cwd"""
575
# This test will fail if getcwd is not ascii
579
url = urlutils.local_path_to_url('.')
580
self.assertEndsWith(url, '/mytest')
582
def test_non_ascii(self):
583
if win32utils.winver == 'Windows 98':
584
raise TestSkipped('Windows 98 cannot handle unicode filenames')
589
raise TestSkipped('cannot create unicode directory')
593
# On Mac OSX this directory is actually:
594
# u'/dode\u0301' => '/dode\xcc\x81
595
# but we should normalize it back to
596
# u'/dod\xe9' => '/dod\xc3\xa9'
597
url = urlutils.local_path_to_url('.')
598
self.assertEndsWith(url, '/dod%C3%A9')
601
class TestDeriveToLocation(TestCase):
602
"""Test that the mapping of FROM_LOCATION to TO_LOCATION works."""
604
def test_to_locations_derived_from_paths(self):
605
derive = urlutils.derive_to_location
606
self.assertEqual("bar", derive("bar"))
607
self.assertEqual("bar", derive("../bar"))
608
self.assertEqual("bar", derive("/foo/bar"))
609
self.assertEqual("bar", derive("c:/foo/bar"))
610
self.assertEqual("bar", derive("c:bar"))
612
def test_to_locations_derived_from_urls(self):
613
derive = urlutils.derive_to_location
614
self.assertEqual("bar", derive("http://foo/bar"))
615
self.assertEqual("bar", derive("bzr+ssh://foo/bar"))
616
self.assertEqual("foo-bar", derive("lp:foo-bar"))