/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_urlutils.py

  • Committer: Jelmer Vernooij
  • Date: 2020-03-22 01:35:14 UTC
  • mfrom: (7490.7.6 work)
  • mto: This revision was merged to the branch mainline in revision 7499.
  • Revision ID: jelmer@jelmer.uk-20200322013514-7vw1ntwho04rcuj3
merge lp:brz/3.1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import os
20
20
import sys
21
21
 
22
 
from .. import osutils, urlutils, win32utils
 
22
from .. import osutils, urlutils
23
23
from ..errors import (
24
24
    PathNotChild,
25
25
    )
34
34
        basename = urlutils.basename
35
35
        if sys.platform == 'win32':
36
36
            self.assertRaises(urlutils.InvalidURL, basename,
37
 
                    'file:///path/to/foo')
 
37
                              'file:///path/to/foo')
38
38
            self.assertEqual('foo', basename('file:///C|/foo'))
39
39
            self.assertEqual('foo', basename('file:///C:/foo'))
40
40
            self.assertEqual('', basename('file:///C:/'))
44
44
 
45
45
        self.assertEqual('foo', basename('http://host/path/to/foo'))
46
46
        self.assertEqual('foo', basename('http://host/path/to/foo/'))
47
 
        self.assertEqual('',
48
 
            basename('http://host/path/to/foo/', exclude_trailing_slash=False))
 
47
        self.assertEqual(
 
48
            '', basename('http://host/path/to/foo/',
 
49
                         exclude_trailing_slash=False))
49
50
        self.assertEqual('path', basename('http://host/path'))
50
51
        self.assertEqual('', basename('http://host/'))
51
52
        self.assertEqual('', basename('http://host'))
52
53
        self.assertEqual('path', basename('http:///nohost/path'))
53
54
 
54
 
        self.assertEqual('path', basename('random+scheme://user:pass@ahost:port/path'))
55
 
        self.assertEqual('path', basename('random+scheme://user:pass@ahost:port/path/'))
 
55
        self.assertEqual('path', basename(
 
56
            'random+scheme://user:pass@ahost:port/path'))
 
57
        self.assertEqual('path', basename(
 
58
            'random+scheme://user:pass@ahost:port/path/'))
56
59
        self.assertEqual('', basename('random+scheme://user:pass@ahost:port/'))
57
60
 
58
61
        # relative paths
59
62
        self.assertEqual('foo', basename('path/to/foo'))
60
63
        self.assertEqual('foo', basename('path/to/foo/'))
61
64
        self.assertEqual('', basename('path/to/foo/',
62
 
            exclude_trailing_slash=False))
 
65
                                      exclude_trailing_slash=False))
63
66
        self.assertEqual('foo', basename('path/../foo'))
64
67
        self.assertEqual('foo', basename('../path/foo'))
65
68
 
118
121
 
119
122
        # Unescape characters that don't need to be escaped
120
123
        eq('http://host/~bob%2525-._',
121
 
                normalize_url('http://host/%7Ebob%2525%2D%2E%5F'))
 
124
           normalize_url('http://host/%7Ebob%2525%2D%2E%5F'))
122
125
        eq('http://host/~bob%2525-._',
123
 
                normalize_url(u'http://host/%7Ebob%2525%2D%2E%5F'))
124
 
 
125
 
        # Normalize verifies URLs when they are not unicode
126
 
        # (indicating they did not come from the user)
127
 
        self.assertRaises(urlutils.InvalidURL, normalize_url,
128
 
                'http://host/\xb5')
129
 
        self.assertRaises(urlutils.InvalidURL, normalize_url, 'http://host/ ')
 
126
           normalize_url(u'http://host/%7Ebob%2525%2D%2E%5F'))
130
127
 
131
128
    def test_url_scheme_re(self):
132
129
        # Test paths that may be URLs
155
152
        test_one('file:///usr/bin', ('file', '/usr/bin'))
156
153
        test_one('file:///C:/Windows', ('file', '/C:/Windows'))
157
154
        test_one('file:///C|/Windows', ('file', '/C|/Windows'))
158
 
        test_one(u'readonly+sftp://host/path/\xe5', ('readonly+sftp', u'host/path/\xe5'))
 
155
        test_one(u'readonly+sftp://host/path/\xe5',
 
156
                 ('readonly+sftp', u'host/path/\xe5'))
159
157
 
160
158
        # Weird stuff
161
159
        # Can't have slashes or colons in the scheme
170
168
        dirname = urlutils.dirname
171
169
        if sys.platform == 'win32':
172
170
            self.assertRaises(urlutils.InvalidURL, dirname,
173
 
                'file:///path/to/foo')
 
171
                              'file:///path/to/foo')
174
172
            self.assertEqual('file:///C|/', dirname('file:///C|/foo'))
175
173
            self.assertEqual('file:///C|/', dirname('file:///C|/'))
176
174
        else:
177
175
            self.assertEqual('file:///', dirname('file:///foo'))
178
176
            self.assertEqual('file:///', dirname('file:///'))
179
177
 
180
 
        self.assertEqual('http://host/path/to', dirname('http://host/path/to/foo'))
181
 
        self.assertEqual('http://host/path/to', dirname('http://host/path/to/foo/'))
 
178
        self.assertEqual('http://host/path/to',
 
179
                         dirname('http://host/path/to/foo'))
 
180
        self.assertEqual('http://host/path/to',
 
181
                         dirname('http://host/path/to/foo/'))
182
182
        self.assertEqual('http://host/path/to/foo',
183
 
            dirname('http://host/path/to/foo/', exclude_trailing_slash=False))
 
183
                         dirname('http://host/path/to/foo/',
 
184
                                 exclude_trailing_slash=False))
184
185
        self.assertEqual('http://host/', dirname('http://host/path'))
185
186
        self.assertEqual('http://host/', dirname('http://host/'))
186
187
        self.assertEqual('http://host', dirname('http://host'))
187
188
        self.assertEqual('http:///nohost', dirname('http:///nohost/path'))
188
189
 
189
190
        self.assertEqual('random+scheme://user:pass@ahost:port/',
190
 
            dirname('random+scheme://user:pass@ahost:port/path'))
191
 
        self.assertEqual('random+scheme://user:pass@ahost:port/',
192
 
            dirname('random+scheme://user:pass@ahost:port/path/'))
193
 
        self.assertEqual('random+scheme://user:pass@ahost:port/',
194
 
            dirname('random+scheme://user:pass@ahost:port/'))
 
191
                         dirname('random+scheme://user:pass@ahost:port/path'))
 
192
        self.assertEqual('random+scheme://user:pass@ahost:port/',
 
193
                         dirname('random+scheme://user:pass@ahost:port/path/'))
 
194
        self.assertEqual('random+scheme://user:pass@ahost:port/',
 
195
                         dirname('random+scheme://user:pass@ahost:port/'))
195
196
 
196
197
        # relative paths
197
198
        self.assertEqual('path/to', dirname('path/to/foo'))
198
199
        self.assertEqual('path/to', dirname('path/to/foo/'))
199
200
        self.assertEqual('path/to/foo',
200
 
            dirname('path/to/foo/', exclude_trailing_slash=False))
 
201
                         dirname('path/to/foo/', exclude_trailing_slash=False))
201
202
        self.assertEqual('path/..', dirname('path/../foo'))
202
203
        self.assertEqual('../path', dirname('../path/foo'))
203
 
    
 
204
 
204
205
    def test_is_url(self):
205
206
        self.assertTrue(urlutils.is_url('http://foo/bar'))
206
207
        self.assertTrue(urlutils.is_url('bzr+ssh://foo/bar'))
221
222
            self.assertEqual(expected, joined)
222
223
 
223
224
        # Test relative path joining
224
 
        test('foo', 'foo') # relative fragment with nothing is preserved.
 
225
        test('foo', 'foo')  # relative fragment with nothing is preserved.
225
226
        test('foo/bar', 'foo', 'bar')
226
227
        test('http://foo/bar', 'http://foo', 'bar')
227
228
        test('http://foo/bar', 'http://foo', '.', 'bar')
233
234
        test('lp:foo/bar/baz', 'lp:foo', 'bar/baz')
234
235
 
235
236
        # Absolute paths
236
 
        test('http://foo', 'http://foo') # abs url with nothing is preserved.
 
237
        test('http://foo', 'http://foo')  # abs url with nothing is preserved.
237
238
        test('http://bar', 'http://foo', 'http://bar')
238
239
        test('sftp://bzr/foo', 'http://foo', 'bar', 'sftp://bzr/foo')
239
240
        test('file:///bar', 'foo', 'file:///bar')
254
255
        # Cannot go above root
255
256
        # Implicitly at root:
256
257
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.join,
257
 
                'http://foo', '../baz')
 
258
                          'http://foo', '../baz')
258
259
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.join,
259
 
                'http://foo', '/..')
 
260
                          'http://foo', '/..')
260
261
        # Joining from a path explicitly under the root.
261
262
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.join,
262
 
                'http://foo/a', '../../b')
 
263
                          'http://foo/a', '../../b')
263
264
 
264
265
    def test_joinpath(self):
265
266
        def test(expected, *args):
291
292
        # Invalid joinings
292
293
        # Cannot go above root
293
294
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
294
 
                '../baz')
295
 
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
296
 
                '..')
297
 
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
298
 
                '/..')
 
295
                          '../baz')
 
296
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
 
297
                          '..')
 
298
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
 
299
                          '/..')
299
300
 
300
301
    def test_join_segment_parameters_raw(self):
301
302
        join_segment_parameters_raw = urlutils.join_segment_parameters_raw
302
 
        self.assertEqual("/somedir/path", 
303
 
            join_segment_parameters_raw("/somedir/path"))
304
 
        self.assertEqual("/somedir/path,rawdata", 
305
 
            join_segment_parameters_raw("/somedir/path", "rawdata"))
 
303
        self.assertEqual("/somedir/path",
 
304
                         join_segment_parameters_raw("/somedir/path"))
 
305
        self.assertEqual("/somedir/path,rawdata",
 
306
                         join_segment_parameters_raw(
 
307
                             "/somedir/path", "rawdata"))
306
308
        self.assertRaises(urlutils.InvalidURLJoin,
307
 
            join_segment_parameters_raw, "/somedir/path",
308
 
                "rawdata1,rawdata2,rawdata3")
 
309
                          join_segment_parameters_raw, "/somedir/path",
 
310
                          "rawdata1,rawdata2,rawdata3")
309
311
        self.assertEqual("/somedir/path,bla,bar",
310
 
            join_segment_parameters_raw("/somedir/path", "bla", "bar"))
311
 
        self.assertEqual("/somedir,exist=some/path,bla,bar",
 
312
                         join_segment_parameters_raw(
 
313
                             "/somedir/path", "bla", "bar"))
 
314
        self.assertEqual(
 
315
            "/somedir,exist=some/path,bla,bar",
312
316
            join_segment_parameters_raw("/somedir,exist=some/path",
313
 
                "bla", "bar"))
314
 
        self.assertRaises(TypeError, join_segment_parameters_raw, 
315
 
            "/somepath", 42)
 
317
                                        "bla", "bar"))
 
318
        self.assertRaises(TypeError, join_segment_parameters_raw,
 
319
                          "/somepath", 42)
316
320
 
317
321
    def test_join_segment_parameters(self):
318
322
        join_segment_parameters = urlutils.join_segment_parameters
319
 
        self.assertEqual("/somedir/path", 
320
 
            join_segment_parameters("/somedir/path", {}))
321
 
        self.assertEqual("/somedir/path,key1=val1", 
 
323
        self.assertEqual("/somedir/path",
 
324
                         join_segment_parameters("/somedir/path", {}))
 
325
        self.assertEqual(
 
326
            "/somedir/path,key1=val1",
322
327
            join_segment_parameters("/somedir/path", {"key1": "val1"}))
323
328
        self.assertRaises(urlutils.InvalidURLJoin,
324
 
            join_segment_parameters, "/somedir/path",
325
 
            {"branch": "brr,brr,brr"})
326
 
        self.assertRaises(urlutils.InvalidURLJoin,
 
329
                          join_segment_parameters, "/somedir/path",
 
330
                          {"branch": "brr,brr,brr"})
 
331
        self.assertRaises(
 
332
            urlutils.InvalidURLJoin,
327
333
            join_segment_parameters, "/somedir/path", {"key1=val1": "val2"})
328
334
        self.assertEqual("/somedir/path,key1=val1,key2=val2",
329
 
            join_segment_parameters("/somedir/path", {
330
 
                "key1": "val1", "key2": "val2"}))
 
335
                         join_segment_parameters("/somedir/path", {
 
336
                             "key1": "val1", "key2": "val2"}))
331
337
        self.assertEqual("/somedir/path,key1=val1,key2=val2",
332
 
            join_segment_parameters("/somedir/path,key1=val1", {
333
 
                "key2": "val2"}))
 
338
                         join_segment_parameters("/somedir/path,key1=val1", {
 
339
                             "key2": "val2"}))
334
340
        self.assertEqual("/somedir/path,key1=val2",
335
 
            join_segment_parameters("/somedir/path,key1=val1", {
336
 
                "key1": "val2"}))
 
341
                         join_segment_parameters("/somedir/path,key1=val1", {
 
342
                             "key1": "val2"}))
337
343
        self.assertEqual("/somedir,exist=some/path,key1=val1",
338
 
            join_segment_parameters("/somedir,exist=some/path",
339
 
                {"key1": "val1"}))
340
 
        self.assertEqual("/,key1=val1,key2=val2",
 
344
                         join_segment_parameters("/somedir,exist=some/path",
 
345
                                                 {"key1": "val1"}))
 
346
        self.assertEqual(
 
347
            "/,key1=val1,key2=val2",
341
348
            join_segment_parameters("/,key1=val1", {"key2": "val2"}))
342
349
        self.assertRaises(TypeError,
343
 
            join_segment_parameters, "/,key1=val1", {"foo": 42})
 
350
                          join_segment_parameters, "/,key1=val1", {"foo": 42})
344
351
 
345
352
    def test_function_type(self):
346
353
        if sys.platform == 'win32':
347
354
            self.assertEqual(urlutils._win32_local_path_to_url,
348
 
                urlutils.local_path_to_url)
 
355
                             urlutils.local_path_to_url)
349
356
            self.assertEqual(urlutils._win32_local_path_from_url,
350
 
                urlutils.local_path_from_url)
 
357
                             urlutils.local_path_from_url)
351
358
        else:
352
359
            self.assertEqual(urlutils._posix_local_path_to_url,
353
 
                urlutils.local_path_to_url)
 
360
                             urlutils.local_path_to_url)
354
361
            self.assertEqual(urlutils._posix_local_path_from_url,
355
 
                urlutils.local_path_from_url)
 
362
                             urlutils.local_path_from_url)
356
363
 
357
364
    def test_posix_local_path_to_url(self):
358
365
        to_url = urlutils._posix_local_path_to_url
359
366
        self.assertEqual('file:///path/to/foo',
360
 
            to_url('/path/to/foo'))
 
367
                         to_url('/path/to/foo'))
361
368
 
362
369
        self.assertEqual('file:///path/to/foo%2Cbar',
363
 
            to_url('/path/to/foo,bar'))
 
370
                         to_url('/path/to/foo,bar'))
364
371
 
365
372
        try:
366
373
            result = to_url(u'/path/to/r\xe4ksm\xf6rg\xe5s')
368
375
            raise TestSkipped("local encoding cannot handle unicode")
369
376
 
370
377
        self.assertEqual('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
371
 
        self.assertFalse(isinstance(result, unicode))
 
378
        self.assertTrue(isinstance(result, str))
372
379
 
373
380
    def test_posix_local_path_from_url(self):
374
381
        from_url = urlutils._posix_local_path_from_url
375
382
        self.assertEqual('/path/to/foo',
376
 
            from_url('file:///path/to/foo'))
 
383
                         from_url('file:///path/to/foo'))
377
384
        self.assertEqual('/path/to/foo',
378
 
            from_url('file:///path/to/foo,branch=foo'))
379
 
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
380
 
            from_url('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
381
 
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
382
 
            from_url('file:///path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
383
 
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
 
385
                         from_url('file:///path/to/foo,branch=foo'))
 
386
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
 
387
                         from_url('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
 
388
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
 
389
                         from_url('file:///path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
 
390
        self.assertEqual(
 
391
            u'/path/to/r\xe4ksm\xf6rg\xe5s',
384
392
            from_url('file://localhost/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
385
393
 
386
394
        self.assertRaises(urlutils.InvalidURL, from_url, '/path/to/foo')
391
399
    def test_win32_local_path_to_url(self):
392
400
        to_url = urlutils._win32_local_path_to_url
393
401
        self.assertEqual('file:///C:/path/to/foo',
394
 
            to_url('C:/path/to/foo'))
 
402
                         to_url('C:/path/to/foo'))
395
403
        # BOGUS: on win32, ntpath.abspath will strip trailing
396
404
        #       whitespace, so this will always fail
397
405
        #       Though under linux, it fakes abspath support
399
407
        # self.assertEqual('file:///C:/path/to/foo%20',
400
408
        #     to_url('C:/path/to/foo '))
401
409
        self.assertEqual('file:///C:/path/to/f%20oo',
402
 
            to_url('C:/path/to/f oo'))
 
410
                         to_url('C:/path/to/f oo'))
403
411
 
404
412
        self.assertEqual('file:///', to_url('/'))
405
413
 
406
414
        self.assertEqual('file:///C:/path/to/foo%2Cbar',
407
 
            to_url('C:/path/to/foo,bar'))
 
415
                         to_url('C:/path/to/foo,bar'))
408
416
        try:
409
417
            result = to_url(u'd:/path/to/r\xe4ksm\xf6rg\xe5s')
410
418
        except UnicodeError:
411
419
            raise TestSkipped("local encoding cannot handle unicode")
412
420
 
413
 
        self.assertEqual('file:///D:/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
414
 
        self.assertFalse(isinstance(result, unicode))
 
421
        self.assertEqual(
 
422
            'file:///D:/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
 
423
        self.assertIsInstance(result, str)
415
424
 
416
425
    def test_win32_unc_path_to_url(self):
417
426
        self.requireFeature(features.win32_feature)
418
427
        to_url = urlutils._win32_local_path_to_url
419
428
        self.assertEqual('file://HOST/path',
420
 
            to_url(r'\\HOST\path'))
 
429
                         to_url(r'\\HOST\path'))
421
430
        self.assertEqual('file://HOST/path',
422
 
            to_url('//HOST/path'))
 
431
                         to_url('//HOST/path'))
423
432
 
424
433
        try:
425
434
            result = to_url(u'//HOST/path/to/r\xe4ksm\xf6rg\xe5s')
426
435
        except UnicodeError:
427
436
            raise TestSkipped("local encoding cannot handle unicode")
428
437
 
429
 
        self.assertEqual('file://HOST/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
430
 
        self.assertFalse(isinstance(result, unicode))
 
438
        self.assertEqual(
 
439
            'file://HOST/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
 
440
        self.assertFalse(isinstance(result, str))
431
441
 
432
442
    def test_win32_local_path_from_url(self):
433
443
        from_url = urlutils._win32_local_path_from_url
434
444
        self.assertEqual('C:/path/to/foo',
435
 
            from_url('file:///C|/path/to/foo'))
436
 
        self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
 
445
                         from_url('file:///C|/path/to/foo'))
 
446
        self.assertEqual(
 
447
            u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
437
448
            from_url('file:///d|/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
438
 
        self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
 
449
        self.assertEqual(
 
450
            u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
439
451
            from_url('file:///d:/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
440
452
        self.assertEqual('/', from_url('file:///'))
441
453
        self.assertEqual('C:/path/to/foo',
442
 
            from_url('file:///C|/path/to/foo,branch=foo'))
 
454
                         from_url('file:///C|/path/to/foo,branch=foo'))
443
455
 
444
456
        self.assertRaises(urlutils.InvalidURL, from_url, 'file:///C:')
445
457
        self.assertRaises(urlutils.InvalidURL, from_url, 'file:///c')
451
463
        from_url = urlutils._win32_local_path_from_url
452
464
        self.assertEqual('//HOST/path', from_url('file://HOST/path'))
453
465
        self.assertEqual('//HOST/path',
454
 
            from_url('file://HOST/path,branch=foo'))
 
466
                         from_url('file://HOST/path,branch=foo'))
455
467
        # despite IE allows 2, 4, 5 and 6 slashes in URL to another machine
456
468
        # we want to use only 2 slashes
457
469
        # Firefox understand only 5 slashes in URL, but it's ugly
458
470
        self.assertRaises(urlutils.InvalidURL, from_url, 'file:////HOST/path')
459
471
        self.assertRaises(urlutils.InvalidURL, from_url, 'file://///HOST/path')
460
 
        self.assertRaises(urlutils.InvalidURL, from_url, 'file://////HOST/path')
 
472
        self.assertRaises(urlutils.InvalidURL, from_url,
 
473
                          'file://////HOST/path')
461
474
        # check for file://C:/ instead of file:///C:/
462
475
        self.assertRaises(urlutils.InvalidURL, from_url, 'file://C:/path')
463
476
 
464
477
    def test_win32_extract_drive_letter(self):
465
478
        extract = urlutils._win32_extract_drive_letter
466
479
        self.assertEqual(('file:///C:', '/foo'), extract('file://', '/C:/foo'))
467
 
        self.assertEqual(('file:///d|', '/path'), extract('file://', '/d|/path'))
 
480
        self.assertEqual(('file:///d|', '/path'),
 
481
                         extract('file://', '/d|/path'))
468
482
        self.assertRaises(urlutils.InvalidURL, extract, 'file://', '/path')
469
483
        # Root drives without slash treated as invalid, see bug #841322
470
484
        self.assertEqual(('file:///C:', '/'), extract('file://', '/C:/'))
477
491
        # Test breezy.urlutils.split()
478
492
        split = urlutils.split
479
493
        if sys.platform == 'win32':
480
 
            self.assertRaises(urlutils.InvalidURL, split, 'file:///path/to/foo')
 
494
            self.assertRaises(urlutils.InvalidURL, split,
 
495
                              'file:///path/to/foo')
481
496
            self.assertEqual(('file:///C|/', 'foo'), split('file:///C|/foo'))
482
497
            self.assertEqual(('file:///C:/', ''), split('file:///C:/'))
483
498
        else:
484
499
            self.assertEqual(('file:///', 'foo'), split('file:///foo'))
485
500
            self.assertEqual(('file:///', ''), split('file:///'))
486
501
 
487
 
        self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo'))
488
 
        self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo/'))
489
 
        self.assertEqual(('http://host/path/to/foo', ''),
 
502
        self.assertEqual(('http://host/path/to', 'foo'),
 
503
                         split('http://host/path/to/foo'))
 
504
        self.assertEqual(('http://host/path/to', 'foo'),
 
505
                         split('http://host/path/to/foo/'))
 
506
        self.assertEqual(
 
507
            ('http://host/path/to/foo', ''),
490
508
            split('http://host/path/to/foo/', exclude_trailing_slash=False))
491
509
        self.assertEqual(('http://host/', 'path'), split('http://host/path'))
492
510
        self.assertEqual(('http://host/', ''), split('http://host/'))
493
511
        self.assertEqual(('http://host', ''), split('http://host'))
494
 
        self.assertEqual(('http:///nohost', 'path'), split('http:///nohost/path'))
 
512
        self.assertEqual(('http:///nohost', 'path'),
 
513
                         split('http:///nohost/path'))
495
514
 
496
515
        self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
497
 
            split('random+scheme://user:pass@ahost:port/path'))
 
516
                         split('random+scheme://user:pass@ahost:port/path'))
498
517
        self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
499
 
            split('random+scheme://user:pass@ahost:port/path/'))
 
518
                         split('random+scheme://user:pass@ahost:port/path/'))
500
519
        self.assertEqual(('random+scheme://user:pass@ahost:port/', ''),
501
 
            split('random+scheme://user:pass@ahost:port/'))
 
520
                         split('random+scheme://user:pass@ahost:port/'))
502
521
 
503
522
        # relative paths
504
523
        self.assertEqual(('path/to', 'foo'), split('path/to/foo'))
505
524
        self.assertEqual(('path/to', 'foo'), split('path/to/foo/'))
506
525
        self.assertEqual(('path/to/foo', ''),
507
 
            split('path/to/foo/', exclude_trailing_slash=False))
 
526
                         split('path/to/foo/', exclude_trailing_slash=False))
508
527
        self.assertEqual(('path/..', 'foo'), split('path/../foo'))
509
528
        self.assertEqual(('../path', 'foo'), split('../path/foo'))
510
529
 
 
530
    def test_strip_segment_parameters(self):
 
531
        strip_segment_parameters = urlutils.strip_segment_parameters
 
532
        # Check relative references with absolute paths
 
533
        self.assertEqual("/some/path",
 
534
                         strip_segment_parameters("/some/path"))
 
535
        self.assertEqual("/some/path",
 
536
                         strip_segment_parameters("/some/path,tip"))
 
537
        self.assertEqual("/some,dir/path",
 
538
                         strip_segment_parameters("/some,dir/path,tip"))
 
539
        self.assertEqual(
 
540
            "/somedir/path",
 
541
            strip_segment_parameters("/somedir/path,heads%2Ftip"))
 
542
        self.assertEqual(
 
543
            "/somedir/path",
 
544
            strip_segment_parameters("/somedir/path,heads%2Ftip,bar"))
 
545
        # Check relative references with relative paths
 
546
        self.assertEqual("", strip_segment_parameters(",key1=val1"))
 
547
        self.assertEqual("foo/", strip_segment_parameters("foo/,key1=val1"))
 
548
        self.assertEqual("foo", strip_segment_parameters("foo,key1=val1"))
 
549
        self.assertEqual(
 
550
            "foo/base,la=bla/other/elements",
 
551
            strip_segment_parameters("foo/base,la=bla/other/elements"))
 
552
        self.assertEqual(
 
553
            "foo/base,la=bla/other/elements",
 
554
            strip_segment_parameters("foo/base,la=bla/other/elements,a=b"))
 
555
        # TODO: Check full URLs as well as relative references
 
556
 
511
557
    def test_split_segment_parameters_raw(self):
512
558
        split_segment_parameters_raw = urlutils.split_segment_parameters_raw
513
559
        # Check relative references with absolute paths
514
560
        self.assertEqual(("/some/path", []),
515
 
            split_segment_parameters_raw("/some/path"))
 
561
                         split_segment_parameters_raw("/some/path"))
516
562
        self.assertEqual(("/some/path", ["tip"]),
517
 
            split_segment_parameters_raw("/some/path,tip"))
 
563
                         split_segment_parameters_raw("/some/path,tip"))
518
564
        self.assertEqual(("/some,dir/path", ["tip"]),
519
 
            split_segment_parameters_raw("/some,dir/path,tip"))
520
 
        self.assertEqual(("/somedir/path", ["heads%2Ftip"]),
 
565
                         split_segment_parameters_raw("/some,dir/path,tip"))
 
566
        self.assertEqual(
 
567
            ("/somedir/path", ["heads%2Ftip"]),
521
568
            split_segment_parameters_raw("/somedir/path,heads%2Ftip"))
522
 
        self.assertEqual(("/somedir/path", ["heads%2Ftip", "bar"]),
 
569
        self.assertEqual(
 
570
            ("/somedir/path", ["heads%2Ftip", "bar"]),
523
571
            split_segment_parameters_raw("/somedir/path,heads%2Ftip,bar"))
524
572
        # Check relative references with relative paths
525
573
        self.assertEqual(("", ["key1=val1"]),
526
 
            split_segment_parameters_raw(",key1=val1"))
 
574
                         split_segment_parameters_raw(",key1=val1"))
527
575
        self.assertEqual(("foo/", ["key1=val1"]),
528
 
            split_segment_parameters_raw("foo/,key1=val1"))
 
576
                         split_segment_parameters_raw("foo/,key1=val1"))
529
577
        self.assertEqual(("foo", ["key1=val1"]),
530
 
            split_segment_parameters_raw("foo,key1=val1"))
531
 
        self.assertEqual(("foo/base,la=bla/other/elements", []),
 
578
                         split_segment_parameters_raw("foo,key1=val1"))
 
579
        self.assertEqual(
 
580
            ("foo/base,la=bla/other/elements", []),
532
581
            split_segment_parameters_raw("foo/base,la=bla/other/elements"))
533
 
        self.assertEqual(("foo/base,la=bla/other/elements", ["a=b"]),
 
582
        self.assertEqual(
 
583
            ("foo/base,la=bla/other/elements", ["a=b"]),
534
584
            split_segment_parameters_raw("foo/base,la=bla/other/elements,a=b"))
535
585
        # TODO: Check full URLs as well as relative references
536
586
 
538
588
        split_segment_parameters = urlutils.split_segment_parameters
539
589
        # Check relative references with absolute paths
540
590
        self.assertEqual(("/some/path", {}),
541
 
            split_segment_parameters("/some/path"))
 
591
                         split_segment_parameters("/some/path"))
542
592
        self.assertEqual(("/some/path", {"branch": "tip"}),
543
 
            split_segment_parameters("/some/path,branch=tip"))
 
593
                         split_segment_parameters("/some/path,branch=tip"))
544
594
        self.assertEqual(("/some,dir/path", {"branch": "tip"}),
545
 
            split_segment_parameters("/some,dir/path,branch=tip"))
546
 
        self.assertEqual(("/somedir/path", {"ref": "heads%2Ftip"}),
 
595
                         split_segment_parameters("/some,dir/path,branch=tip"))
 
596
        self.assertEqual(
 
597
            ("/somedir/path", {"ref": "heads%2Ftip"}),
547
598
            split_segment_parameters("/somedir/path,ref=heads%2Ftip"))
548
599
        self.assertEqual(("/somedir/path",
549
 
            {"ref": "heads%2Ftip", "key1": "val1"}),
550
 
            split_segment_parameters(
551
 
                "/somedir/path,ref=heads%2Ftip,key1=val1"))
552
 
        self.assertEqual(("/somedir/path", {"ref": "heads%2F=tip"}),
 
600
                          {"ref": "heads%2Ftip", "key1": "val1"}),
 
601
                         split_segment_parameters(
 
602
            "/somedir/path,ref=heads%2Ftip,key1=val1"))
 
603
        self.assertEqual(
 
604
            ("/somedir/path", {"ref": "heads%2F=tip"}),
553
605
            split_segment_parameters("/somedir/path,ref=heads%2F=tip"))
554
606
        # Check relative references with relative paths
555
607
        self.assertEqual(("", {"key1": "val1"}),
556
 
            split_segment_parameters(",key1=val1"))
 
608
                         split_segment_parameters(",key1=val1"))
557
609
        self.assertEqual(("foo/", {"key1": "val1"}),
558
 
            split_segment_parameters("foo/,key1=val1"))
559
 
        self.assertEqual(("foo/base,key1=val1/other/elements", {}),
 
610
                         split_segment_parameters("foo/,key1=val1"))
 
611
        self.assertEqual(
 
612
            ("foo/base,key1=val1/other/elements", {}),
560
613
            split_segment_parameters("foo/base,key1=val1/other/elements"))
561
614
        self.assertEqual(("foo/base,key1=val1/other/elements",
562
 
            {"key2": "val2"}), split_segment_parameters(
563
 
                "foo/base,key1=val1/other/elements,key2=val2"))
 
615
                          {"key2": "val2"}), split_segment_parameters(
 
616
            "foo/base,key1=val1/other/elements,key2=val2"))
 
617
        self.assertRaises(
 
618
            urlutils.InvalidURL, split_segment_parameters,
 
619
            "foo/base,key1")
564
620
        # TODO: Check full URLs as well as relative references
565
621
 
566
622
    def test_win32_strip_local_trailing_slash(self):
594
650
        self.assertEqual('file://', sts('file://'))
595
651
 
596
652
        self.assertEqual('random+scheme://user:pass@ahost:port/path',
597
 
            sts('random+scheme://user:pass@ahost:port/path'))
 
653
                         sts('random+scheme://user:pass@ahost:port/path'))
598
654
        self.assertEqual('random+scheme://user:pass@ahost:port/path',
599
 
            sts('random+scheme://user:pass@ahost:port/path/'))
 
655
                         sts('random+scheme://user:pass@ahost:port/path/'))
600
656
        self.assertEqual('random+scheme://user:pass@ahost:port/',
601
 
            sts('random+scheme://user:pass@ahost:port/'))
 
657
                         sts('random+scheme://user:pass@ahost:port/'))
602
658
 
603
659
        # Make sure relative paths work too
604
660
        self.assertEqual('path/to/foo', sts('path/to/foo'))
610
666
        # Test that URLs are converted to nice unicode strings for display
611
667
        def test(expected, url, encoding='utf-8'):
612
668
            disp_url = urlutils.unescape_for_display(url, encoding=encoding)
613
 
            self.assertIsInstance(disp_url, unicode)
 
669
            self.assertIsInstance(disp_url, str)
614
670
            self.assertEqual(expected, disp_url)
615
671
 
616
672
        test('http://foo', 'http://foo')
650
706
    def test_escape(self):
651
707
        self.assertEqual('%25', urlutils.escape('%'))
652
708
        self.assertEqual('%C3%A5', urlutils.escape(u'\xe5'))
653
 
        self.assertFalse(isinstance(urlutils.escape(u'\xe5'), unicode))
 
709
        self.assertIsInstance(urlutils.escape(u'\xe5'), str)
654
710
 
655
711
    def test_escape_tildes(self):
656
712
        self.assertEqual('~foo', urlutils.escape('~foo'))
659
715
        self.assertEqual('%', urlutils.unescape('%25'))
660
716
        self.assertEqual(u'\xe5', urlutils.unescape('%C3%A5'))
661
717
 
662
 
        self.assertRaises(urlutils.InvalidURL, urlutils.unescape, u'\xe5')
663
 
        self.assertRaises(urlutils.InvalidURL, urlutils.unescape, '\xe5')
664
 
        self.assertRaises(urlutils.InvalidURL, urlutils.unescape, '%E5')
 
718
        self.assertRaises((TypeError, urlutils.InvalidURL),
 
719
                          urlutils.unescape, b'\xe5')
 
720
        self.assertEqual('\xe5', urlutils.unescape('%C3%A5'))
665
721
 
666
722
    def test_escape_unescape(self):
667
723
        self.assertEqual(u'\xe5', urlutils.unescape(urlutils.escape(u'\xe5')))
674
730
 
675
731
        test('a', 'http://host/', 'http://host/a')
676
732
        test('http://entirely/different', 'sftp://host/branch',
677
 
                    'http://entirely/different')
 
733
             'http://entirely/different')
678
734
        test('../person/feature', 'http://host/branch/mainline',
679
 
                    'http://host/branch/person/feature')
 
735
             'http://host/branch/person/feature')
680
736
        test('..', 'http://host/branch', 'http://host/')
681
 
        test('http://host2/branch', 'http://host1/branch', 'http://host2/branch')
 
737
        test('http://host2/branch', 'http://host1/branch',
 
738
             'http://host2/branch')
682
739
        test('.', 'http://host1/branch', 'http://host1/branch')
683
740
        test('../../../branch/2b', 'file:///home/jelmer/foo/bar/2b',
684
 
                    'file:///home/jelmer/branch/2b')
 
741
             'file:///home/jelmer/branch/2b')
685
742
        test('../../branch/2b', 'sftp://host/home/jelmer/bar/2b',
686
 
                    'sftp://host/home/jelmer/branch/2b')
 
743
             'sftp://host/home/jelmer/branch/2b')
687
744
        test('../../branch/feature/%2b', 'http://host/home/jelmer/bar/%2b',
688
 
                    'http://host/home/jelmer/branch/feature/%2b')
 
745
             'http://host/home/jelmer/branch/feature/%2b')
689
746
        test('../../branch/feature/2b', 'http://host/home/jelmer/bar/2b/',
690
 
                    'http://host/home/jelmer/branch/feature/2b')
 
747
             'http://host/home/jelmer/branch/feature/2b')
691
748
        # relative_url should preserve a trailing slash
692
749
        test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b/',
693
 
                    'http://host/home/jelmer/branch/feature/2b/')
 
750
             'http://host/home/jelmer/branch/feature/2b/')
694
751
        test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b',
695
 
                    'http://host/home/jelmer/branch/feature/2b/')
 
752
             'http://host/home/jelmer/branch/feature/2b/')
696
753
 
697
754
        # TODO: treat http://host as http://host/
698
755
        #       relative_url is typically called from a branch.base or
699
756
        #       transport.base which always ends with a /
700
 
        #test('a', 'http://host', 'http://host/a')
 
757
        # test('a', 'http://host', 'http://host/a')
701
758
        test('http://host/a', 'http://host', 'http://host/a')
702
 
        #test('.', 'http://host', 'http://host/')
 
759
        # test('.', 'http://host', 'http://host/')
703
760
        test('http://host/', 'http://host', 'http://host/')
704
 
        #test('.', 'http://host/', 'http://host')
 
761
        # test('.', 'http://host/', 'http://host')
705
762
        test('http://host', 'http://host/', 'http://host')
706
763
 
707
764
        # On Windows file:///C:/path/to and file:///D:/other/path
709
766
        if sys.platform == 'win32':
710
767
            # on the same drive
711
768
            test('../../other/path',
712
 
                'file:///C:/path/to', 'file:///C:/other/path')
713
 
            #~next two tests is failed, i.e. urlutils.relative_url expects
714
 
            #~to see normalized file URLs?
715
 
            #~test('../../other/path',
716
 
            #~    'file:///C:/path/to', 'file:///c:/other/path')
717
 
            #~test('../../other/path',
718
 
            #~    'file:///C:/path/to', 'file:///C|/other/path')
 
769
                 'file:///C:/path/to', 'file:///C:/other/path')
 
770
            # ~next two tests is failed, i.e. urlutils.relative_url expects
 
771
            # ~to see normalized file URLs?
 
772
            # ~test('../../other/path',
 
773
            # ~    'file:///C:/path/to', 'file:///c:/other/path')
 
774
            # ~test('../../other/path',
 
775
            # ~    'file:///C:/path/to', 'file:///C|/other/path')
719
776
 
720
777
            # check UNC paths too
721
778
            test('../../other/path',
722
 
                'file://HOST/base/path/to', 'file://HOST/base/other/path')
 
779
                 'file://HOST/base/path/to', 'file://HOST/base/other/path')
723
780
            # on different drives
724
781
            test('file:///D:/other/path',
725
 
                'file:///C:/path/to', 'file:///D:/other/path')
 
782
                 'file:///C:/path/to', 'file:///D:/other/path')
726
783
            # TODO: strictly saying in UNC path //HOST/base is full analog
727
784
            # of drive letter for hard disk, and this situation is also
728
785
            # should be exception from rules. [bialix 20071221]
804
861
 
805
862
    def test_rebase_success(self):
806
863
        self.assertEqual('../bar', urlutils.rebase_url('bar', 'http://baz/',
807
 
                         'http://baz/qux'))
808
 
        self.assertEqual('qux/bar', urlutils.rebase_url('bar',
809
 
                         'http://baz/qux', 'http://baz/'))
810
 
        self.assertEqual('.', urlutils.rebase_url('foo',
811
 
                         'http://bar/', 'http://bar/foo/'))
812
 
        self.assertEqual('qux/bar', urlutils.rebase_url('../bar',
813
 
                         'http://baz/qux/foo', 'http://baz/'))
 
864
                                                       'http://baz/qux'))
 
865
        self.assertEqual(
 
866
            'qux/bar',
 
867
            urlutils.rebase_url('bar', 'http://baz/qux', 'http://baz/'))
 
868
        self.assertEqual(
 
869
            '.', urlutils.rebase_url('foo', 'http://bar/', 'http://bar/foo/'))
 
870
        self.assertEqual(
 
871
            'qux/bar',
 
872
            urlutils.rebase_url('../bar', 'http://baz/qux/foo', 'http://baz/'))
814
873
 
815
874
    def test_determine_relative_path(self):
816
875
        self.assertEqual('../../baz/bar',
817
876
                         urlutils.determine_relative_path(
818
 
                         '/qux/quxx', '/baz/bar'))
 
877
                             '/qux/quxx', '/baz/bar'))
819
878
        self.assertEqual('..',
820
879
                         urlutils.determine_relative_path(
821
 
                         '/bar/baz', '/bar'))
 
880
                             '/bar/baz', '/bar'))
822
881
        self.assertEqual('baz',
823
882
                         urlutils.determine_relative_path(
824
 
                         '/bar', '/bar/baz'))
 
883
                             '/bar', '/bar/baz'))
825
884
        self.assertEqual('.', urlutils.determine_relative_path(
826
885
                         '/bar', '/bar'))
827
886
 
831
890
    def test_parse_simple(self):
832
891
        parsed = urlutils.parse_url('http://example.com:80/one')
833
892
        self.assertEqual(('http', None, None, 'example.com', 80, '/one'),
834
 
            parsed)
 
893
                         parsed)
835
894
 
836
895
    def test_ipv6(self):
837
896
        parsed = urlutils.parse_url('http://[1:2:3::40]/one')
838
897
        self.assertEqual(('http', None, None, '1:2:3::40', None, '/one'),
839
 
            parsed)
 
898
                         parsed)
840
899
 
841
900
    def test_ipv6_port(self):
842
901
        parsed = urlutils.parse_url('http://[1:2:3::40]:80/one')
843
902
        self.assertEqual(('http', None, None, '1:2:3::40', 80, '/one'),
844
 
            parsed)
 
903
                         parsed)
845
904
 
846
905
 
847
906
class TestURL(TestCase):
924
983
        self.assertIsNot(url, url3)
925
984
        self.assertEqual(url, url3)
926
985
 
 
986
    def test_parse_empty_port(self):
 
987
        parsed = urlutils.URL.from_string('http://example.com:/one')
 
988
        self.assertEqual('http', parsed.scheme)
 
989
        self.assertIs(None, parsed.user)
 
990
        self.assertIs(None, parsed.password)
 
991
        self.assertEqual('example.com', parsed.host)
 
992
        self.assertIs(None, parsed.port)
 
993
        self.assertEqual('/one', parsed.path)
 
994
 
927
995
 
928
996
class TestFileRelpath(TestCase):
929
997
 
932
1000
 
933
1001
    def _with_posix_paths(self):
934
1002
        self.overrideAttr(urlutils, "local_path_from_url",
935
 
            urlutils._posix_local_path_from_url)
 
1003
                          urlutils._posix_local_path_from_url)
936
1004
        self.overrideAttr(urlutils, "MIN_ABS_FILEURL_LENGTH", len("file:///"))
937
1005
        self.overrideAttr(osutils, "normpath", osutils._posix_normpath)
938
1006
        self.overrideAttr(osutils, "abspath", osutils._posix_abspath)
943
1011
 
944
1012
    def _with_win32_paths(self):
945
1013
        self.overrideAttr(urlutils, "local_path_from_url",
946
 
            urlutils._win32_local_path_from_url)
 
1014
                          urlutils._win32_local_path_from_url)
947
1015
        self.overrideAttr(urlutils, "MIN_ABS_FILEURL_LENGTH",
948
 
            urlutils.WIN32_MIN_ABS_FILEURL_LENGTH)
 
1016
                          urlutils.WIN32_MIN_ABS_FILEURL_LENGTH)
949
1017
        self.overrideAttr(osutils, "abspath", osutils._win32_abspath)
950
1018
        self.overrideAttr(osutils, "normpath", osutils._win32_normpath)
951
1019
        self.overrideAttr(osutils, "pathjoin", osutils._win32_pathjoin)
955
1023
    def test_same_url_posix(self):
956
1024
        self._with_posix_paths()
957
1025
        self.assertEqual("",
958
 
            urlutils.file_relpath("file:///a", "file:///a"))
959
 
        self.assertEqual("",
960
 
            urlutils.file_relpath("file:///a", "file:///a/"))
961
 
        self.assertEqual("",
962
 
            urlutils.file_relpath("file:///a/", "file:///a"))
 
1026
                         urlutils.file_relpath("file:///a", "file:///a"))
 
1027
        self.assertEqual("",
 
1028
                         urlutils.file_relpath("file:///a", "file:///a/"))
 
1029
        self.assertEqual("",
 
1030
                         urlutils.file_relpath("file:///a/", "file:///a"))
963
1031
 
964
1032
    def test_same_url_win32(self):
965
1033
        self._with_win32_paths()
966
1034
        self.assertEqual("",
967
 
            urlutils.file_relpath("file:///A:/", "file:///A:/"))
968
 
        self.assertEqual("",
969
 
            urlutils.file_relpath("file:///A|/", "file:///A:/"))
970
 
        self.assertEqual("",
971
 
            urlutils.file_relpath("file:///A:/b/", "file:///A:/b/"))
972
 
        self.assertEqual("",
973
 
            urlutils.file_relpath("file:///A:/b", "file:///A:/b/"))
974
 
        self.assertEqual("",
975
 
            urlutils.file_relpath("file:///A:/b/", "file:///A:/b"))
 
1035
                         urlutils.file_relpath("file:///A:/", "file:///A:/"))
 
1036
        self.assertEqual("",
 
1037
                         urlutils.file_relpath("file:///A|/", "file:///A:/"))
 
1038
        self.assertEqual(
 
1039
            "", urlutils.file_relpath("file:///A:/b/", "file:///A:/b/"))
 
1040
        self.assertEqual(
 
1041
            "", urlutils.file_relpath("file:///A:/b", "file:///A:/b/"))
 
1042
        self.assertEqual(
 
1043
            "", urlutils.file_relpath("file:///A:/b/", "file:///A:/b"))
976
1044
 
977
1045
    def test_child_posix(self):
978
1046
        self._with_posix_paths()
979
 
        self.assertEqual("b",
980
 
            urlutils.file_relpath("file:///a", "file:///a/b"))
981
 
        self.assertEqual("b",
982
 
            urlutils.file_relpath("file:///a/", "file:///a/b"))
983
 
        self.assertEqual("b/c",
984
 
            urlutils.file_relpath("file:///a", "file:///a/b/c"))
 
1047
        self.assertEqual(
 
1048
            "b", urlutils.file_relpath("file:///a", "file:///a/b"))
 
1049
        self.assertEqual(
 
1050
            "b", urlutils.file_relpath("file:///a/", "file:///a/b"))
 
1051
        self.assertEqual(
 
1052
            "b/c", urlutils.file_relpath("file:///a", "file:///a/b/c"))
985
1053
 
986
1054
    def test_child_win32(self):
987
1055
        self._with_win32_paths()
988
 
        self.assertEqual("b",
989
 
            urlutils.file_relpath("file:///A:/", "file:///A:/b"))
990
 
        self.assertEqual("b",
991
 
            urlutils.file_relpath("file:///A|/", "file:///A:/b"))
992
 
        self.assertEqual("c",
993
 
            urlutils.file_relpath("file:///A:/b", "file:///A:/b/c"))
994
 
        self.assertEqual("c",
995
 
            urlutils.file_relpath("file:///A:/b/", "file:///A:/b/c"))
996
 
        self.assertEqual("c/d",
997
 
            urlutils.file_relpath("file:///A:/b", "file:///A:/b/c/d"))
 
1056
        self.assertEqual(
 
1057
            "b", urlutils.file_relpath("file:///A:/", "file:///A:/b"))
 
1058
        self.assertEqual(
 
1059
            "b", urlutils.file_relpath("file:///A|/", "file:///A:/b"))
 
1060
        self.assertEqual(
 
1061
            "c", urlutils.file_relpath("file:///A:/b", "file:///A:/b/c"))
 
1062
        self.assertEqual(
 
1063
            "c", urlutils.file_relpath("file:///A:/b/", "file:///A:/b/c"))
 
1064
        self.assertEqual(
 
1065
            "c/d", urlutils.file_relpath("file:///A:/b", "file:///A:/b/c/d"))
998
1066
 
999
1067
    def test_sibling_posix(self):
1000
1068
        self._with_posix_paths()
1001
 
        self.assertRaises(PathNotChild,
 
1069
        self.assertRaises(
 
1070
            PathNotChild,
1002
1071
            urlutils.file_relpath, "file:///a/b", "file:///a/c")
1003
 
        self.assertRaises(PathNotChild,
 
1072
        self.assertRaises(
 
1073
            PathNotChild,
1004
1074
            urlutils.file_relpath, "file:///a/b/", "file:///a/c")
1005
 
        self.assertRaises(PathNotChild,
 
1075
        self.assertRaises(
 
1076
            PathNotChild,
1006
1077
            urlutils.file_relpath, "file:///a/b/", "file:///a/c/")
1007
1078
 
1008
1079
    def test_sibling_win32(self):
1009
1080
        self._with_win32_paths()
1010
 
        self.assertRaises(PathNotChild,
 
1081
        self.assertRaises(
 
1082
            PathNotChild,
1011
1083
            urlutils.file_relpath, "file:///A:/b", "file:///A:/c")
1012
 
        self.assertRaises(PathNotChild,
 
1084
        self.assertRaises(
 
1085
            PathNotChild,
1013
1086
            urlutils.file_relpath, "file:///A:/b/", "file:///A:/c")
1014
 
        self.assertRaises(PathNotChild,
 
1087
        self.assertRaises(
 
1088
            PathNotChild,
1015
1089
            urlutils.file_relpath, "file:///A:/b/", "file:///A:/c/")
1016
1090
 
1017
1091
    def test_parent_posix(self):
1018
1092
        self._with_posix_paths()
1019
1093
        self.assertRaises(PathNotChild,
1020
 
            urlutils.file_relpath, "file:///a/b", "file:///a")
 
1094
                          urlutils.file_relpath, "file:///a/b", "file:///a")
1021
1095
        self.assertRaises(PathNotChild,
1022
 
            urlutils.file_relpath, "file:///a/b", "file:///a/")
 
1096
                          urlutils.file_relpath, "file:///a/b", "file:///a/")
1023
1097
 
1024
1098
    def test_parent_win32(self):
1025
1099
        self._with_win32_paths()
1026
 
        self.assertRaises(PathNotChild,
 
1100
        self.assertRaises(
 
1101
            PathNotChild,
1027
1102
            urlutils.file_relpath, "file:///A:/b", "file:///A:/")
1028
 
        self.assertRaises(PathNotChild,
 
1103
        self.assertRaises(
 
1104
            PathNotChild,
1029
1105
            urlutils.file_relpath, "file:///A:/b/c", "file:///A:/b")
1030
1106
 
1031
1107
 
1037
1113
        self.assertEqual('abc/def', urlutils.quote('abc/def', safe='/'))
1038
1114
 
1039
1115
    def test_quote_tildes(self):
1040
 
        self.assertEqual('%7Efoo', urlutils.quote('~foo'))
 
1116
        # Whether ~ is quoted by default depends on the python version
 
1117
        if sys.version_info[:2] >= (3, 7):
 
1118
            # https://docs.python.org/3/whatsnew/3.7.html#urllib-parse
 
1119
            self.assertEqual('~foo', urlutils.quote('~foo'))
 
1120
        else:
 
1121
            self.assertEqual('%7Efoo', urlutils.quote('~foo'))
1041
1122
        self.assertEqual('~foo', urlutils.quote('~foo', safe='/~'))
1042
1123
 
1043
1124
    def test_unquote(self):
1044
1125
        self.assertEqual('%', urlutils.unquote('%25'))
1045
 
        self.assertEqual('\xc3\xa5', urlutils.unquote('%C3%A5'))
 
1126
        self.assertEqual('\xe5', urlutils.unquote('%C3%A5'))
1046
1127
        self.assertEqual(u"\xe5", urlutils.unquote(u'\xe5'))
 
1128
 
 
1129
    def test_unquote_to_bytes(self):
 
1130
        self.assertEqual(b'%', urlutils.unquote_to_bytes('%25'))
 
1131
        self.assertEqual(b'\xc3\xa5', urlutils.unquote_to_bytes('%C3%A5'))