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
24
from bzrlib.errors import InvalidURL, InvalidURLJoin
25
from bzrlib.tests import TestCaseInTempDir, TestCase, TestSkipped
28
class TestUrlToPath(TestCase):
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'))
37
self.assertEqual('foo', basename('file:///C:/foo'))
38
self.assertEqual('', basename('file:///C:/'))
40
self.assertEqual('foo', basename('file:///foo'))
41
self.assertEqual('', basename('file:///'))
43
self.assertEqual('foo', basename('http://host/path/to/foo'))
44
self.assertEqual('foo', basename('http://host/path/to/foo/'))
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'))
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/'))
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'))
64
def test_normalize_url_files(self):
65
# Test that local paths are properly normalized
66
normalize_url = urlutils.normalize_url
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:'):]
74
url = url[len('file://'):]
76
self.assertEndsWith(url, expected)
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')
82
# Local paths are assumed to *not* be escaped at all
84
u'uni/\xb5'.encode(osutils.get_user_encoding())
86
# locale cannot handle unicode
89
norm_file('uni/%C2%B5', u'uni/\xb5')
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
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', "' ;/?:@&=+$,#")
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
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$'))
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'))
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'))
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/ ')
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
133
:param scheme_and_path: The (scheme, path) that should be matched
134
can be None, to indicate it should not match
136
m = urlutils._url_scheme_re.match(url)
137
if scheme_and_path is None:
138
self.assertEqual(None, m)
140
self.assertEqual(scheme_and_path[0], m.group('scheme'))
141
self.assertEqual(scheme_and_path[1], m.group('path'))
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)
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'))
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'))
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|/'))
173
self.assertEqual('file:///', dirname('file:///foo'))
174
self.assertEqual('file:///', dirname('file:///'))
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'))
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/'))
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'))
201
def test(expected, *args):
202
joined = urlutils.join(*args)
203
self.assertEqual(expected, joined)
205
# Test relative path joining
206
test('foo', 'foo') # relative fragment with nothing is preserved.
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')
213
test('http://foo/baz', 'http://foo/bar/', '../baz')
216
test('http://foo', 'http://foo') # abs url with nothing is preserved.
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')
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/')
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', '')
231
# Cannot go above root
232
# Implicitly at root:
233
self.assertRaises(InvalidURLJoin, urlutils.join,
234
'http://foo', '../baz')
235
self.assertRaises(InvalidURLJoin, urlutils.join,
237
# Joining from a path explicitly under the root.
238
self.assertRaises(InvalidURLJoin, urlutils.join,
239
'http://foo/a', '../../b')
241
def test_joinpath(self):
242
def test(expected, *args):
243
joined = urlutils.joinpath(*args)
244
self.assertEqual(expected, joined)
246
# Test a single element
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')
256
# Test joining to an absolute path
258
test('/foo', '/foo', '.')
259
test('/foo/bar', '/foo', 'bar')
260
test('/', '/foo', '..')
262
# Test joining with an absolute path
263
test('/bar', 'foo', '/bar')
265
# Test joining to a path with a trailing slash
266
test('foo/bar', 'foo/', 'bar')
269
# Cannot go above root
270
self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '../baz')
271
self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '..')
272
self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '/..')
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)
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)
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'))
288
result = to_url(u'/path/to/r\xe4ksm\xf6rg\xe5s')
290
raise TestSkipped("local encoding cannot handle unicode")
292
self.assertEqual('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
294
def test_posix_local_path_from_url(self):
295
from_url = urlutils._posix_local_path_from_url
296
self.assertEqual('/path/to/foo',
297
from_url('file:///path/to/foo'))
298
self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
299
from_url('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
300
self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
301
from_url('file:///path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
303
self.assertRaises(InvalidURL, from_url, '/path/to/foo')
305
def test_win32_local_path_to_url(self):
306
to_url = urlutils._win32_local_path_to_url
307
self.assertEqual('file:///C:/path/to/foo',
308
to_url('C:/path/to/foo'))
309
# BOGUS: on win32, ntpath.abspath will strip trailing
310
# whitespace, so this will always fail
311
# Though under linux, it fakes abspath support
312
# and thus will succeed
313
# self.assertEqual('file:///C:/path/to/foo%20',
314
# to_url('C:/path/to/foo '))
315
self.assertEqual('file:///C:/path/to/f%20oo',
316
to_url('C:/path/to/f oo'))
319
result = to_url(u'd:/path/to/r\xe4ksm\xf6rg\xe5s')
321
raise TestSkipped("local encoding cannot handle unicode")
323
self.assertEqual('file:///D:/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
325
def test_win32_unc_path_to_url(self):
326
to_url = urlutils._win32_local_path_to_url
327
self.assertEqual('file://HOST/path',
328
to_url(r'\\HOST\path'))
329
self.assertEqual('file://HOST/path',
330
to_url('//HOST/path'))
333
result = to_url(u'//HOST/path/to/r\xe4ksm\xf6rg\xe5s')
335
raise TestSkipped("local encoding cannot handle unicode")
337
self.assertEqual('file://HOST/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
340
def test_win32_local_path_from_url(self):
341
from_url = urlutils._win32_local_path_from_url
342
self.assertEqual('C:/path/to/foo',
343
from_url('file:///C|/path/to/foo'))
344
self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
345
from_url('file:///d|/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
346
self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
347
from_url('file:///d:/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
349
self.assertRaises(InvalidURL, from_url, '/path/to/foo')
350
# Not a valid _win32 url, no drive letter
351
self.assertRaises(InvalidURL, from_url, 'file:///path/to/foo')
353
def test_win32_unc_path_from_url(self):
354
from_url = urlutils._win32_local_path_from_url
355
self.assertEqual('//HOST/path', from_url('file://HOST/path'))
356
# despite IE allows 2, 4, 5 and 6 slashes in URL to another machine
357
# we want to use only 2 slashes
358
# Firefox understand only 5 slashes in URL, but it's ugly
359
self.assertRaises(InvalidURL, from_url, 'file:////HOST/path')
360
self.assertRaises(InvalidURL, from_url, 'file://///HOST/path')
361
self.assertRaises(InvalidURL, from_url, 'file://////HOST/path')
362
# check for file://C:/ instead of file:///C:/
363
self.assertRaises(InvalidURL, from_url, 'file://C:/path')
365
def test_win32_extract_drive_letter(self):
366
extract = urlutils._win32_extract_drive_letter
367
self.assertEqual(('file:///C:', '/foo'), extract('file://', '/C:/foo'))
368
self.assertEqual(('file:///d|', '/path'), extract('file://', '/d|/path'))
369
self.assertRaises(InvalidURL, extract, 'file://', '/path')
371
def test_split(self):
372
# Test bzrlib.urlutils.split()
373
split = urlutils.split
374
if sys.platform == 'win32':
375
self.assertRaises(InvalidURL, split, 'file:///path/to/foo')
376
self.assertEqual(('file:///C|/', 'foo'), split('file:///C|/foo'))
377
self.assertEqual(('file:///C:/', ''), split('file:///C:/'))
379
self.assertEqual(('file:///', 'foo'), split('file:///foo'))
380
self.assertEqual(('file:///', ''), split('file:///'))
382
self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo'))
383
self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo/'))
384
self.assertEqual(('http://host/path/to/foo', ''),
385
split('http://host/path/to/foo/', exclude_trailing_slash=False))
386
self.assertEqual(('http://host/', 'path'), split('http://host/path'))
387
self.assertEqual(('http://host/', ''), split('http://host/'))
388
self.assertEqual(('http://host', ''), split('http://host'))
389
self.assertEqual(('http:///nohost', 'path'), split('http:///nohost/path'))
391
self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
392
split('random+scheme://user:pass@ahost:port/path'))
393
self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
394
split('random+scheme://user:pass@ahost:port/path/'))
395
self.assertEqual(('random+scheme://user:pass@ahost:port/', ''),
396
split('random+scheme://user:pass@ahost:port/'))
399
self.assertEqual(('path/to', 'foo'), split('path/to/foo'))
400
self.assertEqual(('path/to', 'foo'), split('path/to/foo/'))
401
self.assertEqual(('path/to/foo', ''),
402
split('path/to/foo/', exclude_trailing_slash=False))
403
self.assertEqual(('path/..', 'foo'), split('path/../foo'))
404
self.assertEqual(('../path', 'foo'), split('../path/foo'))
406
def test_win32_strip_local_trailing_slash(self):
407
strip = urlutils._win32_strip_local_trailing_slash
408
self.assertEqual('file://', strip('file://'))
409
self.assertEqual('file:///', strip('file:///'))
410
self.assertEqual('file:///C', strip('file:///C'))
411
self.assertEqual('file:///C:', strip('file:///C:'))
412
self.assertEqual('file:///d|', strip('file:///d|'))
413
self.assertEqual('file:///C:/', strip('file:///C:/'))
414
self.assertEqual('file:///C:/a', strip('file:///C:/a/'))
416
def test_strip_trailing_slash(self):
417
sts = urlutils.strip_trailing_slash
418
if sys.platform == 'win32':
419
self.assertEqual('file:///C|/', sts('file:///C|/'))
420
self.assertEqual('file:///C:/foo', sts('file:///C:/foo'))
421
self.assertEqual('file:///C|/foo', sts('file:///C|/foo/'))
423
self.assertEqual('file:///', sts('file:///'))
424
self.assertEqual('file:///foo', sts('file:///foo'))
425
self.assertEqual('file:///foo', sts('file:///foo/'))
427
self.assertEqual('http://host/', sts('http://host/'))
428
self.assertEqual('http://host/foo', sts('http://host/foo'))
429
self.assertEqual('http://host/foo', sts('http://host/foo/'))
431
# No need to fail just because the slash is missing
432
self.assertEqual('http://host', sts('http://host'))
433
# TODO: jam 20060502 Should this raise InvalidURL?
434
self.assertEqual('file://', sts('file://'))
436
self.assertEqual('random+scheme://user:pass@ahost:port/path',
437
sts('random+scheme://user:pass@ahost:port/path'))
438
self.assertEqual('random+scheme://user:pass@ahost:port/path',
439
sts('random+scheme://user:pass@ahost:port/path/'))
440
self.assertEqual('random+scheme://user:pass@ahost:port/',
441
sts('random+scheme://user:pass@ahost:port/'))
443
# Make sure relative paths work too
444
self.assertEqual('path/to/foo', sts('path/to/foo'))
445
self.assertEqual('path/to/foo', sts('path/to/foo/'))
446
self.assertEqual('../to/foo', sts('../to/foo/'))
447
self.assertEqual('path/../foo', sts('path/../foo/'))
449
def test_unescape_for_display_utf8(self):
450
# Test that URLs are converted to nice unicode strings for display
451
def test(expected, url, encoding='utf-8'):
452
disp_url = urlutils.unescape_for_display(url, encoding=encoding)
453
self.assertIsInstance(disp_url, unicode)
454
self.assertEqual(expected, disp_url)
456
test('http://foo', 'http://foo')
457
if sys.platform == 'win32':
458
test('C:/foo/path', 'file:///C|/foo/path')
459
test('C:/foo/path', 'file:///C:/foo/path')
461
test('/foo/path', 'file:///foo/path')
463
test('http://foo/%2Fbaz', 'http://foo/%2Fbaz')
464
test(u'http://host/r\xe4ksm\xf6rg\xe5s',
465
'http://host/r%C3%A4ksm%C3%B6rg%C3%A5s')
467
# Make sure special escaped characters stay escaped
468
test(u'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23',
469
'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23')
471
# Can we handle sections that don't have utf-8 encoding?
472
test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
473
'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s')
475
# Test encoding into output that can handle some characters
476
test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
477
'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s',
478
encoding='iso-8859-1')
480
# This one can be encoded into utf8
481
test(u'http://host/\u062c\u0648\u062c\u0648',
482
'http://host/%d8%ac%d9%88%d8%ac%d9%88',
485
# This can't be put into 8859-1 and so stays as escapes
486
test(u'http://host/%d8%ac%d9%88%d8%ac%d9%88',
487
'http://host/%d8%ac%d9%88%d8%ac%d9%88',
488
encoding='iso-8859-1')
490
def test_escape(self):
491
self.assertEqual('%25', urlutils.escape('%'))
492
self.assertEqual('%C3%A5', urlutils.escape(u'\xe5'))
494
def test_unescape(self):
495
self.assertEqual('%', urlutils.unescape('%25'))
496
self.assertEqual(u'\xe5', urlutils.unescape('%C3%A5'))
498
self.assertRaises(InvalidURL, urlutils.unescape, u'\xe5')
499
self.assertRaises(InvalidURL, urlutils.unescape, '\xe5')
500
self.assertRaises(InvalidURL, urlutils.unescape, '%E5')
502
def test_escape_unescape(self):
503
self.assertEqual(u'\xe5', urlutils.unescape(urlutils.escape(u'\xe5')))
504
self.assertEqual('%', urlutils.unescape(urlutils.escape('%')))
506
def test_relative_url(self):
507
def test(expected, base, other):
508
result = urlutils.relative_url(base, other)
509
self.assertEqual(expected, result)
511
test('a', 'http://host/', 'http://host/a')
512
test('http://entirely/different', 'sftp://host/branch',
513
'http://entirely/different')
514
test('../person/feature', 'http://host/branch/mainline',
515
'http://host/branch/person/feature')
516
test('..', 'http://host/branch', 'http://host/')
517
test('http://host2/branch', 'http://host1/branch', 'http://host2/branch')
518
test('.', 'http://host1/branch', 'http://host1/branch')
519
test('../../../branch/2b', 'file:///home/jelmer/foo/bar/2b',
520
'file:///home/jelmer/branch/2b')
521
test('../../branch/2b', 'sftp://host/home/jelmer/bar/2b',
522
'sftp://host/home/jelmer/branch/2b')
523
test('../../branch/feature/%2b', 'http://host/home/jelmer/bar/%2b',
524
'http://host/home/jelmer/branch/feature/%2b')
525
test('../../branch/feature/2b', 'http://host/home/jelmer/bar/2b/',
526
'http://host/home/jelmer/branch/feature/2b')
527
# relative_url should preserve a trailing slash
528
test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b/',
529
'http://host/home/jelmer/branch/feature/2b/')
530
test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b',
531
'http://host/home/jelmer/branch/feature/2b/')
533
# TODO: treat http://host as http://host/
534
# relative_url is typically called from a branch.base or
535
# transport.base which always ends with a /
536
#test('a', 'http://host', 'http://host/a')
537
test('http://host/a', 'http://host', 'http://host/a')
538
#test('.', 'http://host', 'http://host/')
539
test('http://host/', 'http://host', 'http://host/')
540
#test('.', 'http://host/', 'http://host')
541
test('http://host', 'http://host/', 'http://host')
543
# On Windows file:///C:/path/to and file:///D:/other/path
544
# should not use relative url over the non-existent '/' directory.
545
if sys.platform == 'win32':
547
test('../../other/path',
548
'file:///C:/path/to', 'file:///C:/other/path')
549
#~next two tests is failed, i.e. urlutils.relative_url expects
550
#~to see normalized file URLs?
551
#~test('../../other/path',
552
#~ 'file:///C:/path/to', 'file:///c:/other/path')
553
#~test('../../other/path',
554
#~ 'file:///C:/path/to', 'file:///C|/other/path')
556
# check UNC paths too
557
test('../../other/path',
558
'file://HOST/base/path/to', 'file://HOST/base/other/path')
559
# on different drives
560
test('file:///D:/other/path',
561
'file:///C:/path/to', 'file:///D:/other/path')
562
# TODO: strictly saying in UNC path //HOST/base is full analog
563
# of drive letter for hard disk, and this situation is also
564
# should be exception from rules. [bialix 20071221]
567
class TestCwdToURL(TestCaseInTempDir):
568
"""Test that local_path_to_url works base on the cwd"""
571
# This test will fail if getcwd is not ascii
575
url = urlutils.local_path_to_url('.')
576
self.assertEndsWith(url, '/mytest')
578
def test_non_ascii(self):
579
if win32utils.winver == 'Windows 98':
580
raise TestSkipped('Windows 98 cannot handle unicode filenames')
585
raise TestSkipped('cannot create unicode directory')
589
# On Mac OSX this directory is actually:
590
# u'/dode\u0301' => '/dode\xcc\x81
591
# but we should normalize it back to
592
# u'/dod\xe9' => '/dod\xc3\xa9'
593
url = urlutils.local_path_to_url('.')
594
self.assertEndsWith(url, '/dod%C3%A9')
597
class TestDeriveToLocation(TestCase):
598
"""Test that the mapping of FROM_LOCATION to TO_LOCATION works."""
600
def test_to_locations_derived_from_paths(self):
601
derive = urlutils.derive_to_location
602
self.assertEqual("bar", derive("bar"))
603
self.assertEqual("bar", derive("../bar"))
604
self.assertEqual("bar", derive("/foo/bar"))
605
self.assertEqual("bar", derive("c:/foo/bar"))
606
self.assertEqual("bar", derive("c:bar"))
608
def test_to_locations_derived_from_urls(self):
609
derive = urlutils.derive_to_location
610
self.assertEqual("bar", derive("http://foo/bar"))
611
self.assertEqual("bar", derive("bzr+ssh://foo/bar"))
612
self.assertEqual("foo-bar", derive("lp:foo-bar"))