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)
293
self.assertFalse(isinstance(result, unicode))
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'))
304
self.assertRaises(InvalidURL, from_url, '/path/to/foo')
306
def test_win32_local_path_to_url(self):
307
to_url = urlutils._win32_local_path_to_url
308
self.assertEqual('file:///C:/path/to/foo',
309
to_url('C:/path/to/foo'))
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 '))
316
self.assertEqual('file:///C:/path/to/f%20oo',
317
to_url('C:/path/to/f oo'))
320
result = to_url(u'd:/path/to/r\xe4ksm\xf6rg\xe5s')
322
raise TestSkipped("local encoding cannot handle unicode")
324
self.assertEqual('file:///D:/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
325
self.assertFalse(isinstance(result, unicode))
327
def test_win32_unc_path_to_url(self):
328
to_url = urlutils._win32_local_path_to_url
329
self.assertEqual('file://HOST/path',
330
to_url(r'\\HOST\path'))
331
self.assertEqual('file://HOST/path',
332
to_url('//HOST/path'))
335
result = to_url(u'//HOST/path/to/r\xe4ksm\xf6rg\xe5s')
337
raise TestSkipped("local encoding cannot handle unicode")
339
self.assertEqual('file://HOST/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
340
self.assertFalse(isinstance(result, unicode))
342
def test_win32_local_path_from_url(self):
343
from_url = urlutils._win32_local_path_from_url
344
self.assertEqual('C:/path/to/foo',
345
from_url('file:///C|/path/to/foo'))
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'))
348
self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
349
from_url('file:///d:/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
351
self.assertRaises(InvalidURL, from_url, '/path/to/foo')
352
# Not a valid _win32 url, no drive letter
353
self.assertRaises(InvalidURL, from_url, 'file:///path/to/foo')
355
def test_win32_unc_path_from_url(self):
356
from_url = urlutils._win32_local_path_from_url
357
self.assertEqual('//HOST/path', from_url('file://HOST/path'))
358
# despite IE allows 2, 4, 5 and 6 slashes in URL to another machine
359
# we want to use only 2 slashes
360
# Firefox understand only 5 slashes in URL, but it's ugly
361
self.assertRaises(InvalidURL, from_url, 'file:////HOST/path')
362
self.assertRaises(InvalidURL, from_url, 'file://///HOST/path')
363
self.assertRaises(InvalidURL, from_url, 'file://////HOST/path')
364
# check for file://C:/ instead of file:///C:/
365
self.assertRaises(InvalidURL, from_url, 'file://C:/path')
367
def test_win32_extract_drive_letter(self):
368
extract = urlutils._win32_extract_drive_letter
369
self.assertEqual(('file:///C:', '/foo'), extract('file://', '/C:/foo'))
370
self.assertEqual(('file:///d|', '/path'), extract('file://', '/d|/path'))
371
self.assertRaises(InvalidURL, extract, 'file://', '/path')
373
def test_split(self):
374
# Test bzrlib.urlutils.split()
375
split = urlutils.split
376
if sys.platform == 'win32':
377
self.assertRaises(InvalidURL, split, 'file:///path/to/foo')
378
self.assertEqual(('file:///C|/', 'foo'), split('file:///C|/foo'))
379
self.assertEqual(('file:///C:/', ''), split('file:///C:/'))
381
self.assertEqual(('file:///', 'foo'), split('file:///foo'))
382
self.assertEqual(('file:///', ''), split('file:///'))
384
self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo'))
385
self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo/'))
386
self.assertEqual(('http://host/path/to/foo', ''),
387
split('http://host/path/to/foo/', exclude_trailing_slash=False))
388
self.assertEqual(('http://host/', 'path'), split('http://host/path'))
389
self.assertEqual(('http://host/', ''), split('http://host/'))
390
self.assertEqual(('http://host', ''), split('http://host'))
391
self.assertEqual(('http:///nohost', 'path'), split('http:///nohost/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/', 'path'),
396
split('random+scheme://user:pass@ahost:port/path/'))
397
self.assertEqual(('random+scheme://user:pass@ahost:port/', ''),
398
split('random+scheme://user:pass@ahost:port/'))
401
self.assertEqual(('path/to', 'foo'), split('path/to/foo'))
402
self.assertEqual(('path/to', 'foo'), split('path/to/foo/'))
403
self.assertEqual(('path/to/foo', ''),
404
split('path/to/foo/', exclude_trailing_slash=False))
405
self.assertEqual(('path/..', 'foo'), split('path/../foo'))
406
self.assertEqual(('../path', 'foo'), split('../path/foo'))
408
def test_win32_strip_local_trailing_slash(self):
409
strip = urlutils._win32_strip_local_trailing_slash
410
self.assertEqual('file://', strip('file://'))
411
self.assertEqual('file:///', strip('file:///'))
412
self.assertEqual('file:///C', strip('file:///C'))
413
self.assertEqual('file:///C:', strip('file:///C:'))
414
self.assertEqual('file:///d|', strip('file:///d|'))
415
self.assertEqual('file:///C:/', strip('file:///C:/'))
416
self.assertEqual('file:///C:/a', strip('file:///C:/a/'))
418
def test_strip_trailing_slash(self):
419
sts = urlutils.strip_trailing_slash
420
if sys.platform == 'win32':
421
self.assertEqual('file:///C|/', sts('file:///C|/'))
422
self.assertEqual('file:///C:/foo', sts('file:///C:/foo'))
423
self.assertEqual('file:///C|/foo', sts('file:///C|/foo/'))
425
self.assertEqual('file:///', sts('file:///'))
426
self.assertEqual('file:///foo', sts('file:///foo'))
427
self.assertEqual('file:///foo', sts('file:///foo/'))
429
self.assertEqual('http://host/', sts('http://host/'))
430
self.assertEqual('http://host/foo', sts('http://host/foo'))
431
self.assertEqual('http://host/foo', sts('http://host/foo/'))
433
# No need to fail just because the slash is missing
434
self.assertEqual('http://host', sts('http://host'))
435
# TODO: jam 20060502 Should this raise InvalidURL?
436
self.assertEqual('file://', sts('file://'))
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/path',
441
sts('random+scheme://user:pass@ahost:port/path/'))
442
self.assertEqual('random+scheme://user:pass@ahost:port/',
443
sts('random+scheme://user:pass@ahost:port/'))
445
# Make sure relative paths work too
446
self.assertEqual('path/to/foo', sts('path/to/foo'))
447
self.assertEqual('path/to/foo', sts('path/to/foo/'))
448
self.assertEqual('../to/foo', sts('../to/foo/'))
449
self.assertEqual('path/../foo', sts('path/../foo/'))
451
def test_unescape_for_display_utf8(self):
452
# Test that URLs are converted to nice unicode strings for display
453
def test(expected, url, encoding='utf-8'):
454
disp_url = urlutils.unescape_for_display(url, encoding=encoding)
455
self.assertIsInstance(disp_url, unicode)
456
self.assertEqual(expected, disp_url)
458
test('http://foo', 'http://foo')
459
if sys.platform == 'win32':
460
test('C:/foo/path', 'file:///C|/foo/path')
461
test('C:/foo/path', 'file:///C:/foo/path')
463
test('/foo/path', 'file:///foo/path')
465
test('http://foo/%2Fbaz', 'http://foo/%2Fbaz')
466
test(u'http://host/r\xe4ksm\xf6rg\xe5s',
467
'http://host/r%C3%A4ksm%C3%B6rg%C3%A5s')
469
# Make sure special escaped characters stay escaped
470
test(u'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23',
471
'http://host/%3B%2F%3F%3A%40%26%3D%2B%24%2C%23')
473
# Can we handle sections that don't have utf-8 encoding?
474
test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
475
'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s')
477
# Test encoding into output that can handle some characters
478
test(u'http://host/%EE%EE%EE/r\xe4ksm\xf6rg\xe5s',
479
'http://host/%EE%EE%EE/r%C3%A4ksm%C3%B6rg%C3%A5s',
480
encoding='iso-8859-1')
482
# This one can be encoded into utf8
483
test(u'http://host/\u062c\u0648\u062c\u0648',
484
'http://host/%d8%ac%d9%88%d8%ac%d9%88',
487
# This can't be put into 8859-1 and so stays as escapes
488
test(u'http://host/%d8%ac%d9%88%d8%ac%d9%88',
489
'http://host/%d8%ac%d9%88%d8%ac%d9%88',
490
encoding='iso-8859-1')
492
def test_escape(self):
493
self.assertEqual('%25', urlutils.escape('%'))
494
self.assertEqual('%C3%A5', urlutils.escape(u'\xe5'))
495
self.assertFalse(isinstance(urlutils.escape(u'\xe5'), unicode))
497
def test_unescape(self):
498
self.assertEqual('%', urlutils.unescape('%25'))
499
self.assertEqual(u'\xe5', urlutils.unescape('%C3%A5'))
501
self.assertRaises(InvalidURL, urlutils.unescape, u'\xe5')
502
self.assertRaises(InvalidURL, urlutils.unescape, '\xe5')
503
self.assertRaises(InvalidURL, urlutils.unescape, '%E5')
505
def test_escape_unescape(self):
506
self.assertEqual(u'\xe5', urlutils.unescape(urlutils.escape(u'\xe5')))
507
self.assertEqual('%', urlutils.unescape(urlutils.escape('%')))
509
def test_relative_url(self):
510
def test(expected, base, other):
511
result = urlutils.relative_url(base, other)
512
self.assertEqual(expected, result)
514
test('a', 'http://host/', 'http://host/a')
515
test('http://entirely/different', 'sftp://host/branch',
516
'http://entirely/different')
517
test('../person/feature', 'http://host/branch/mainline',
518
'http://host/branch/person/feature')
519
test('..', 'http://host/branch', 'http://host/')
520
test('http://host2/branch', 'http://host1/branch', 'http://host2/branch')
521
test('.', 'http://host1/branch', 'http://host1/branch')
522
test('../../../branch/2b', 'file:///home/jelmer/foo/bar/2b',
523
'file:///home/jelmer/branch/2b')
524
test('../../branch/2b', 'sftp://host/home/jelmer/bar/2b',
525
'sftp://host/home/jelmer/branch/2b')
526
test('../../branch/feature/%2b', 'http://host/home/jelmer/bar/%2b',
527
'http://host/home/jelmer/branch/feature/%2b')
528
test('../../branch/feature/2b', 'http://host/home/jelmer/bar/2b/',
529
'http://host/home/jelmer/branch/feature/2b')
530
# relative_url should preserve a trailing slash
531
test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b/',
532
'http://host/home/jelmer/branch/feature/2b/')
533
test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b',
534
'http://host/home/jelmer/branch/feature/2b/')
536
# TODO: treat http://host as http://host/
537
# relative_url is typically called from a branch.base or
538
# transport.base which always ends with a /
539
#test('a', 'http://host', 'http://host/a')
540
test('http://host/a', 'http://host', 'http://host/a')
541
#test('.', 'http://host', 'http://host/')
542
test('http://host/', 'http://host', 'http://host/')
543
#test('.', 'http://host/', 'http://host')
544
test('http://host', 'http://host/', 'http://host')
546
# On Windows file:///C:/path/to and file:///D:/other/path
547
# should not use relative url over the non-existent '/' directory.
548
if sys.platform == 'win32':
550
test('../../other/path',
551
'file:///C:/path/to', 'file:///C:/other/path')
552
#~next two tests is failed, i.e. urlutils.relative_url expects
553
#~to see normalized file URLs?
554
#~test('../../other/path',
555
#~ 'file:///C:/path/to', 'file:///c:/other/path')
556
#~test('../../other/path',
557
#~ 'file:///C:/path/to', 'file:///C|/other/path')
559
# check UNC paths too
560
test('../../other/path',
561
'file://HOST/base/path/to', 'file://HOST/base/other/path')
562
# on different drives
563
test('file:///D:/other/path',
564
'file:///C:/path/to', 'file:///D:/other/path')
565
# TODO: strictly saying in UNC path //HOST/base is full analog
566
# of drive letter for hard disk, and this situation is also
567
# should be exception from rules. [bialix 20071221]
570
class TestCwdToURL(TestCaseInTempDir):
571
"""Test that local_path_to_url works base on the cwd"""
574
# This test will fail if getcwd is not ascii
578
url = urlutils.local_path_to_url('.')
579
self.assertEndsWith(url, '/mytest')
581
def test_non_ascii(self):
582
if win32utils.winver == 'Windows 98':
583
raise TestSkipped('Windows 98 cannot handle unicode filenames')
588
raise TestSkipped('cannot create unicode directory')
592
# On Mac OSX this directory is actually:
593
# u'/dode\u0301' => '/dode\xcc\x81
594
# but we should normalize it back to
595
# u'/dod\xe9' => '/dod\xc3\xa9'
596
url = urlutils.local_path_to_url('.')
597
self.assertEndsWith(url, '/dod%C3%A9')
600
class TestDeriveToLocation(TestCase):
601
"""Test that the mapping of FROM_LOCATION to TO_LOCATION works."""
603
def test_to_locations_derived_from_paths(self):
604
derive = urlutils.derive_to_location
605
self.assertEqual("bar", derive("bar"))
606
self.assertEqual("bar", derive("../bar"))
607
self.assertEqual("bar", derive("/foo/bar"))
608
self.assertEqual("bar", derive("c:/foo/bar"))
609
self.assertEqual("bar", derive("c:bar"))
611
def test_to_locations_derived_from_urls(self):
612
derive = urlutils.derive_to_location
613
self.assertEqual("bar", derive("http://foo/bar"))
614
self.assertEqual("bar", derive("bzr+ssh://foo/bar"))
615
self.assertEqual("foo-bar", derive("lp:foo-bar"))