/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: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-08-23 01:15:41 UTC
  • mfrom: (7520.1.4 merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200823011541-nv0oh7nzaganx2qy
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/merge-3.1/+merge/389690

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2012, 2015, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
19
19
import os
20
20
import sys
21
21
 
22
 
from bzrlib import osutils, urlutils, win32utils
23
 
from bzrlib.errors import InvalidURL, InvalidURLJoin, InvalidRebaseURLs
24
 
from bzrlib.tests import TestCaseInTempDir, TestCase, TestSkipped
 
22
from .. import osutils, urlutils
 
23
from ..errors import (
 
24
    PathNotChild,
 
25
    )
 
26
from . import features, TestCaseInTempDir, TestCase, TestSkipped
25
27
 
26
28
 
27
29
class TestUrlToPath(TestCase):
28
30
 
29
31
    def test_basename(self):
30
 
        # bzrlib.urlutils.basename
31
 
        # Test bzrlib.urlutils.split()
 
32
        # breezy.urlutils.basename
 
33
        # Test breezy.urlutils.split()
32
34
        basename = urlutils.basename
33
35
        if sys.platform == 'win32':
34
 
            self.assertRaises(InvalidURL, basename, 'file:///path/to/foo')
 
36
            self.assertRaises(urlutils.InvalidURL, basename,
 
37
                              'file:///path/to/foo')
35
38
            self.assertEqual('foo', basename('file:///C|/foo'))
36
39
            self.assertEqual('foo', basename('file:///C:/foo'))
37
40
            self.assertEqual('', basename('file:///C:/'))
41
44
 
42
45
        self.assertEqual('foo', basename('http://host/path/to/foo'))
43
46
        self.assertEqual('foo', basename('http://host/path/to/foo/'))
44
 
        self.assertEqual('',
45
 
            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))
46
50
        self.assertEqual('path', basename('http://host/path'))
47
51
        self.assertEqual('', basename('http://host/'))
48
52
        self.assertEqual('', basename('http://host'))
49
53
        self.assertEqual('path', basename('http:///nohost/path'))
50
54
 
51
 
        self.assertEqual('path', basename('random+scheme://user:pass@ahost:port/path'))
52
 
        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/'))
53
59
        self.assertEqual('', basename('random+scheme://user:pass@ahost:port/'))
54
60
 
55
61
        # relative paths
56
62
        self.assertEqual('foo', basename('path/to/foo'))
57
63
        self.assertEqual('foo', basename('path/to/foo/'))
58
64
        self.assertEqual('', basename('path/to/foo/',
59
 
            exclude_trailing_slash=False))
 
65
                                      exclude_trailing_slash=False))
60
66
        self.assertEqual('foo', basename('path/../foo'))
61
67
        self.assertEqual('foo', basename('../path/foo'))
62
68
 
115
121
 
116
122
        # Unescape characters that don't need to be escaped
117
123
        eq('http://host/~bob%2525-._',
118
 
                normalize_url('http://host/%7Ebob%2525%2D%2E%5F'))
 
124
           normalize_url('http://host/%7Ebob%2525%2D%2E%5F'))
119
125
        eq('http://host/~bob%2525-._',
120
 
                normalize_url(u'http://host/%7Ebob%2525%2D%2E%5F'))
121
 
 
122
 
        # Normalize verifies URLs when they are not unicode
123
 
        # (indicating they did not come from the user)
124
 
        self.assertRaises(InvalidURL, normalize_url, 'http://host/\xb5')
125
 
        self.assertRaises(InvalidURL, normalize_url, 'http://host/ ')
 
126
           normalize_url(u'http://host/%7Ebob%2525%2D%2E%5F'))
126
127
 
127
128
    def test_url_scheme_re(self):
128
129
        # Test paths that may be URLs
151
152
        test_one('file:///usr/bin', ('file', '/usr/bin'))
152
153
        test_one('file:///C:/Windows', ('file', '/C:/Windows'))
153
154
        test_one('file:///C|/Windows', ('file', '/C|/Windows'))
154
 
        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'))
155
157
 
156
158
        # Weird stuff
157
159
        # Can't have slashes or colons in the scheme
158
160
        test_one('/path/to/://foo', None)
159
 
        test_one('path:path://foo', None)
 
161
        test_one('scheme:stuff://foo', ('scheme', 'stuff://foo'))
160
162
        # Must have more than one character for scheme
161
163
        test_one('C://foo', None)
162
164
        test_one('ab://foo', ('ab', 'foo'))
163
165
 
164
166
    def test_dirname(self):
165
 
        # Test bzrlib.urlutils.dirname()
 
167
        # Test breezy.urlutils.dirname()
166
168
        dirname = urlutils.dirname
167
169
        if sys.platform == 'win32':
168
 
            self.assertRaises(InvalidURL, dirname, 'file:///path/to/foo')
 
170
            self.assertRaises(urlutils.InvalidURL, dirname,
 
171
                              'file:///path/to/foo')
169
172
            self.assertEqual('file:///C|/', dirname('file:///C|/foo'))
170
173
            self.assertEqual('file:///C|/', dirname('file:///C|/'))
171
174
        else:
172
175
            self.assertEqual('file:///', dirname('file:///foo'))
173
176
            self.assertEqual('file:///', dirname('file:///'))
174
177
 
175
 
        self.assertEqual('http://host/path/to', dirname('http://host/path/to/foo'))
176
 
        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/'))
177
182
        self.assertEqual('http://host/path/to/foo',
178
 
            dirname('http://host/path/to/foo/', exclude_trailing_slash=False))
 
183
                         dirname('http://host/path/to/foo/',
 
184
                                 exclude_trailing_slash=False))
179
185
        self.assertEqual('http://host/', dirname('http://host/path'))
180
186
        self.assertEqual('http://host/', dirname('http://host/'))
181
187
        self.assertEqual('http://host', dirname('http://host'))
182
188
        self.assertEqual('http:///nohost', dirname('http:///nohost/path'))
183
189
 
184
190
        self.assertEqual('random+scheme://user:pass@ahost:port/',
185
 
            dirname('random+scheme://user:pass@ahost:port/path'))
186
 
        self.assertEqual('random+scheme://user:pass@ahost:port/',
187
 
            dirname('random+scheme://user:pass@ahost:port/path/'))
188
 
        self.assertEqual('random+scheme://user:pass@ahost:port/',
189
 
            dirname('random+scheme://user:pass@ahost:port/'))
 
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/'))
190
196
 
191
197
        # relative paths
192
198
        self.assertEqual('path/to', dirname('path/to/foo'))
193
199
        self.assertEqual('path/to', dirname('path/to/foo/'))
194
200
        self.assertEqual('path/to/foo',
195
 
            dirname('path/to/foo/', exclude_trailing_slash=False))
 
201
                         dirname('path/to/foo/', exclude_trailing_slash=False))
196
202
        self.assertEqual('path/..', dirname('path/../foo'))
197
203
        self.assertEqual('../path', dirname('../path/foo'))
198
204
 
 
205
    def test_is_url(self):
 
206
        self.assertTrue(urlutils.is_url('http://foo/bar'))
 
207
        self.assertTrue(urlutils.is_url('bzr+ssh://foo/bar'))
 
208
        self.assertTrue(urlutils.is_url('lp:foo/bar'))
 
209
        self.assertTrue(urlutils.is_url('file:///foo/bar'))
 
210
        self.assertFalse(urlutils.is_url(''))
 
211
        self.assertFalse(urlutils.is_url('foo'))
 
212
        self.assertFalse(urlutils.is_url('foo/bar'))
 
213
        self.assertFalse(urlutils.is_url('/foo'))
 
214
        self.assertFalse(urlutils.is_url('/foo/bar'))
 
215
        self.assertFalse(urlutils.is_url('C:/'))
 
216
        self.assertFalse(urlutils.is_url('C:/foo'))
 
217
        self.assertFalse(urlutils.is_url('C:/foo/bar'))
 
218
 
199
219
    def test_join(self):
200
220
        def test(expected, *args):
201
221
            joined = urlutils.join(*args)
202
222
            self.assertEqual(expected, joined)
203
223
 
204
224
        # Test relative path joining
205
 
        test('foo', 'foo') # relative fragment with nothing is preserved.
 
225
        test('foo', 'foo')  # relative fragment with nothing is preserved.
206
226
        test('foo/bar', 'foo', 'bar')
207
227
        test('http://foo/bar', 'http://foo', 'bar')
208
228
        test('http://foo/bar', 'http://foo', '.', 'bar')
210
230
        test('http://foo/bar/baz', 'http://foo', 'bar/baz')
211
231
        test('http://foo/baz', 'http://foo', 'bar/../baz')
212
232
        test('http://foo/baz', 'http://foo/bar/', '../baz')
 
233
        test('lp:foo/bar', 'lp:foo', 'bar')
 
234
        test('lp:foo/bar/baz', 'lp:foo', 'bar/baz')
213
235
 
214
236
        # Absolute paths
215
 
        test('http://foo', 'http://foo') # abs url with nothing is preserved.
 
237
        test('http://foo', 'http://foo')  # abs url with nothing is preserved.
216
238
        test('http://bar', 'http://foo', 'http://bar')
217
239
        test('sftp://bzr/foo', 'http://foo', 'bar', 'sftp://bzr/foo')
218
240
        test('file:///bar', 'foo', 'file:///bar')
219
241
        test('http://bar/', 'http://foo', 'http://bar/')
220
242
        test('http://bar/a', 'http://foo', 'http://bar/a')
221
243
        test('http://bar/a/', 'http://foo', 'http://bar/a/')
 
244
        test('lp:bar', 'http://foo', 'lp:bar')
 
245
        test('lp:bar', 'lp:foo', 'lp:bar')
 
246
        test('file:///stuff', 'lp:foo', 'file:///stuff')
222
247
 
223
248
        # From a base path
224
249
        test('file:///foo', 'file:///', 'foo')
229
254
        # Invalid joinings
230
255
        # Cannot go above root
231
256
        # Implicitly at root:
232
 
        self.assertRaises(InvalidURLJoin, urlutils.join,
233
 
                'http://foo', '../baz')
234
 
        self.assertRaises(InvalidURLJoin, urlutils.join,
235
 
                'http://foo', '/..')
 
257
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.join,
 
258
                          'http://foo', '../baz')
 
259
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.join,
 
260
                          'http://foo', '/..')
236
261
        # Joining from a path explicitly under the root.
237
 
        self.assertRaises(InvalidURLJoin, urlutils.join,
238
 
                'http://foo/a', '../../b')
 
262
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.join,
 
263
                          'http://foo/a', '../../b')
239
264
 
240
265
    def test_joinpath(self):
241
266
        def test(expected, *args):
266
291
 
267
292
        # Invalid joinings
268
293
        # Cannot go above root
269
 
        self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '../baz')
270
 
        self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '..')
271
 
        self.assertRaises(InvalidURLJoin, urlutils.joinpath, '/', '/..')
 
294
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
 
295
                          '../baz')
 
296
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
 
297
                          '..')
 
298
        self.assertRaises(urlutils.InvalidURLJoin, urlutils.joinpath, '/',
 
299
                          '/..')
 
300
 
 
301
    def test_join_segment_parameters_raw(self):
 
302
        join_segment_parameters_raw = urlutils.join_segment_parameters_raw
 
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"))
 
308
        self.assertRaises(urlutils.InvalidURLJoin,
 
309
                          join_segment_parameters_raw, "/somedir/path",
 
310
                          "rawdata1,rawdata2,rawdata3")
 
311
        self.assertEqual("/somedir/path,bla,bar",
 
312
                         join_segment_parameters_raw(
 
313
                             "/somedir/path", "bla", "bar"))
 
314
        self.assertEqual(
 
315
            "/somedir,exist=some/path,bla,bar",
 
316
            join_segment_parameters_raw("/somedir,exist=some/path",
 
317
                                        "bla", "bar"))
 
318
        self.assertRaises(TypeError, join_segment_parameters_raw,
 
319
                          "/somepath", 42)
 
320
 
 
321
    def test_join_segment_parameters(self):
 
322
        join_segment_parameters = urlutils.join_segment_parameters
 
323
        self.assertEqual("/somedir/path",
 
324
                         join_segment_parameters("/somedir/path", {}))
 
325
        self.assertEqual(
 
326
            "/somedir/path,key1=val1",
 
327
            join_segment_parameters("/somedir/path", {"key1": "val1"}))
 
328
        self.assertRaises(urlutils.InvalidURLJoin,
 
329
                          join_segment_parameters, "/somedir/path",
 
330
                          {"branch": "brr,brr,brr"})
 
331
        self.assertRaises(
 
332
            urlutils.InvalidURLJoin,
 
333
            join_segment_parameters, "/somedir/path", {"key1=val1": "val2"})
 
334
        self.assertEqual("/somedir/path,key1=val1,key2=val2",
 
335
                         join_segment_parameters("/somedir/path", {
 
336
                             "key1": "val1", "key2": "val2"}))
 
337
        self.assertEqual("/somedir/path,key1=val1,key2=val2",
 
338
                         join_segment_parameters("/somedir/path,key1=val1", {
 
339
                             "key2": "val2"}))
 
340
        self.assertEqual("/somedir/path,key1=val2",
 
341
                         join_segment_parameters("/somedir/path,key1=val1", {
 
342
                             "key1": "val2"}))
 
343
        self.assertEqual("/somedir,exist=some/path,key1=val1",
 
344
                         join_segment_parameters("/somedir,exist=some/path",
 
345
                                                 {"key1": "val1"}))
 
346
        self.assertEqual(
 
347
            "/,key1=val1,key2=val2",
 
348
            join_segment_parameters("/,key1=val1", {"key2": "val2"}))
 
349
        self.assertRaises(TypeError,
 
350
                          join_segment_parameters, "/,key1=val1", {"foo": 42})
272
351
 
273
352
    def test_function_type(self):
274
353
        if sys.platform == 'win32':
275
 
            self.assertEqual(urlutils._win32_local_path_to_url, urlutils.local_path_to_url)
276
 
            self.assertEqual(urlutils._win32_local_path_from_url, urlutils.local_path_from_url)
 
354
            self.assertEqual(urlutils._win32_local_path_to_url,
 
355
                             urlutils.local_path_to_url)
 
356
            self.assertEqual(urlutils._win32_local_path_from_url,
 
357
                             urlutils.local_path_from_url)
277
358
        else:
278
 
            self.assertEqual(urlutils._posix_local_path_to_url, urlutils.local_path_to_url)
279
 
            self.assertEqual(urlutils._posix_local_path_from_url, urlutils.local_path_from_url)
 
359
            self.assertEqual(urlutils._posix_local_path_to_url,
 
360
                             urlutils.local_path_to_url)
 
361
            self.assertEqual(urlutils._posix_local_path_from_url,
 
362
                             urlutils.local_path_from_url)
280
363
 
281
364
    def test_posix_local_path_to_url(self):
282
365
        to_url = urlutils._posix_local_path_to_url
283
366
        self.assertEqual('file:///path/to/foo',
284
 
            to_url('/path/to/foo'))
 
367
                         to_url('/path/to/foo'))
 
368
 
 
369
        self.assertEqual('file:///path/to/foo%2Cbar',
 
370
                         to_url('/path/to/foo,bar'))
285
371
 
286
372
        try:
287
373
            result = to_url(u'/path/to/r\xe4ksm\xf6rg\xe5s')
289
375
            raise TestSkipped("local encoding cannot handle unicode")
290
376
 
291
377
        self.assertEqual('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
292
 
        self.assertFalse(isinstance(result, unicode))
 
378
        self.assertTrue(isinstance(result, str))
293
379
 
294
380
    def test_posix_local_path_from_url(self):
295
381
        from_url = urlutils._posix_local_path_from_url
296
382
        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'))
302
 
        self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
 
383
                         from_url('file:///path/to/foo'))
 
384
        self.assertEqual('/path/to/foo',
 
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',
303
392
            from_url('file://localhost/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
304
393
 
305
 
        self.assertRaises(InvalidURL, from_url, '/path/to/foo')
 
394
        self.assertRaises(urlutils.InvalidURL, from_url, '/path/to/foo')
306
395
        self.assertRaises(
307
 
            InvalidURL, from_url,
 
396
            urlutils.InvalidURL, from_url,
308
397
            'file://remotehost/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s')
309
398
 
310
399
    def test_win32_local_path_to_url(self):
311
400
        to_url = urlutils._win32_local_path_to_url
312
401
        self.assertEqual('file:///C:/path/to/foo',
313
 
            to_url('C:/path/to/foo'))
 
402
                         to_url('C:/path/to/foo'))
314
403
        # BOGUS: on win32, ntpath.abspath will strip trailing
315
404
        #       whitespace, so this will always fail
316
405
        #       Though under linux, it fakes abspath support
318
407
        # self.assertEqual('file:///C:/path/to/foo%20',
319
408
        #     to_url('C:/path/to/foo '))
320
409
        self.assertEqual('file:///C:/path/to/f%20oo',
321
 
            to_url('C:/path/to/f oo'))
 
410
                         to_url('C:/path/to/f oo'))
322
411
 
323
412
        self.assertEqual('file:///', to_url('/'))
324
413
 
 
414
        self.assertEqual('file:///C:/path/to/foo%2Cbar',
 
415
                         to_url('C:/path/to/foo,bar'))
325
416
        try:
326
417
            result = to_url(u'd:/path/to/r\xe4ksm\xf6rg\xe5s')
327
418
        except UnicodeError:
328
419
            raise TestSkipped("local encoding cannot handle unicode")
329
420
 
330
 
        self.assertEqual('file:///D:/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
331
 
        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)
332
424
 
333
425
    def test_win32_unc_path_to_url(self):
 
426
        self.requireFeature(features.win32_feature)
334
427
        to_url = urlutils._win32_local_path_to_url
335
428
        self.assertEqual('file://HOST/path',
336
 
            to_url(r'\\HOST\path'))
 
429
                         to_url(r'\\HOST\path'))
337
430
        self.assertEqual('file://HOST/path',
338
 
            to_url('//HOST/path'))
 
431
                         to_url('//HOST/path'))
339
432
 
340
433
        try:
341
434
            result = to_url(u'//HOST/path/to/r\xe4ksm\xf6rg\xe5s')
342
435
        except UnicodeError:
343
436
            raise TestSkipped("local encoding cannot handle unicode")
344
437
 
345
 
        self.assertEqual('file://HOST/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s', result)
346
 
        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))
347
441
 
348
442
    def test_win32_local_path_from_url(self):
349
443
        from_url = urlutils._win32_local_path_from_url
350
444
        self.assertEqual('C:/path/to/foo',
351
 
            from_url('file:///C|/path/to/foo'))
352
 
        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',
353
448
            from_url('file:///d|/path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
354
 
        self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
 
449
        self.assertEqual(
 
450
            u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
355
451
            from_url('file:///d:/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
356
452
        self.assertEqual('/', from_url('file:///'))
 
453
        self.assertEqual('C:/path/to/foo',
 
454
                         from_url('file:///C|/path/to/foo,branch=foo'))
357
455
 
358
 
        self.assertRaises(InvalidURL, from_url, '/path/to/foo')
 
456
        self.assertRaises(urlutils.InvalidURL, from_url, 'file:///C:')
 
457
        self.assertRaises(urlutils.InvalidURL, from_url, 'file:///c')
 
458
        self.assertRaises(urlutils.InvalidURL, from_url, '/path/to/foo')
359
459
        # Not a valid _win32 url, no drive letter
360
 
        self.assertRaises(InvalidURL, from_url, 'file:///path/to/foo')
 
460
        self.assertRaises(urlutils.InvalidURL, from_url, 'file:///path/to/foo')
361
461
 
362
462
    def test_win32_unc_path_from_url(self):
363
463
        from_url = urlutils._win32_local_path_from_url
364
464
        self.assertEqual('//HOST/path', from_url('file://HOST/path'))
 
465
        self.assertEqual('//HOST/path',
 
466
                         from_url('file://HOST/path,branch=foo'))
365
467
        # despite IE allows 2, 4, 5 and 6 slashes in URL to another machine
366
468
        # we want to use only 2 slashes
367
469
        # Firefox understand only 5 slashes in URL, but it's ugly
368
 
        self.assertRaises(InvalidURL, from_url, 'file:////HOST/path')
369
 
        self.assertRaises(InvalidURL, from_url, 'file://///HOST/path')
370
 
        self.assertRaises(InvalidURL, from_url, 'file://////HOST/path')
 
470
        self.assertRaises(urlutils.InvalidURL, from_url, 'file:////HOST/path')
 
471
        self.assertRaises(urlutils.InvalidURL, from_url, 'file://///HOST/path')
 
472
        self.assertRaises(urlutils.InvalidURL, from_url,
 
473
                          'file://////HOST/path')
371
474
        # check for file://C:/ instead of file:///C:/
372
 
        self.assertRaises(InvalidURL, from_url, 'file://C:/path')
 
475
        self.assertRaises(urlutils.InvalidURL, from_url, 'file://C:/path')
373
476
 
374
477
    def test_win32_extract_drive_letter(self):
375
478
        extract = urlutils._win32_extract_drive_letter
376
479
        self.assertEqual(('file:///C:', '/foo'), extract('file://', '/C:/foo'))
377
 
        self.assertEqual(('file:///d|', '/path'), extract('file://', '/d|/path'))
378
 
        self.assertRaises(InvalidURL, extract, 'file://', '/path')
 
480
        self.assertEqual(('file:///d|', '/path'),
 
481
                         extract('file://', '/d|/path'))
 
482
        self.assertRaises(urlutils.InvalidURL, extract, 'file://', '/path')
 
483
        # Root drives without slash treated as invalid, see bug #841322
 
484
        self.assertEqual(('file:///C:', '/'), extract('file://', '/C:/'))
 
485
        self.assertRaises(urlutils.InvalidURL, extract, 'file://', '/C:')
 
486
        # Invalid without drive separator or following forward slash
 
487
        self.assertRaises(urlutils.InvalidURL, extract, 'file://', '/C')
 
488
        self.assertRaises(urlutils.InvalidURL, extract, 'file://', '/C:ool')
379
489
 
380
490
    def test_split(self):
381
 
        # Test bzrlib.urlutils.split()
 
491
        # Test breezy.urlutils.split()
382
492
        split = urlutils.split
383
493
        if sys.platform == 'win32':
384
 
            self.assertRaises(InvalidURL, split, 'file:///path/to/foo')
 
494
            self.assertRaises(urlutils.InvalidURL, split,
 
495
                              'file:///path/to/foo')
385
496
            self.assertEqual(('file:///C|/', 'foo'), split('file:///C|/foo'))
386
497
            self.assertEqual(('file:///C:/', ''), split('file:///C:/'))
387
498
        else:
388
499
            self.assertEqual(('file:///', 'foo'), split('file:///foo'))
389
500
            self.assertEqual(('file:///', ''), split('file:///'))
390
501
 
391
 
        self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo'))
392
 
        self.assertEqual(('http://host/path/to', 'foo'), split('http://host/path/to/foo/'))
393
 
        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', ''),
394
508
            split('http://host/path/to/foo/', exclude_trailing_slash=False))
395
509
        self.assertEqual(('http://host/', 'path'), split('http://host/path'))
396
510
        self.assertEqual(('http://host/', ''), split('http://host/'))
397
511
        self.assertEqual(('http://host', ''), split('http://host'))
398
 
        self.assertEqual(('http:///nohost', 'path'), split('http:///nohost/path'))
 
512
        self.assertEqual(('http:///nohost', 'path'),
 
513
                         split('http:///nohost/path'))
399
514
 
400
515
        self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
401
 
            split('random+scheme://user:pass@ahost:port/path'))
 
516
                         split('random+scheme://user:pass@ahost:port/path'))
402
517
        self.assertEqual(('random+scheme://user:pass@ahost:port/', 'path'),
403
 
            split('random+scheme://user:pass@ahost:port/path/'))
 
518
                         split('random+scheme://user:pass@ahost:port/path/'))
404
519
        self.assertEqual(('random+scheme://user:pass@ahost:port/', ''),
405
 
            split('random+scheme://user:pass@ahost:port/'))
 
520
                         split('random+scheme://user:pass@ahost:port/'))
406
521
 
407
522
        # relative paths
408
523
        self.assertEqual(('path/to', 'foo'), split('path/to/foo'))
409
524
        self.assertEqual(('path/to', 'foo'), split('path/to/foo/'))
410
525
        self.assertEqual(('path/to/foo', ''),
411
 
            split('path/to/foo/', exclude_trailing_slash=False))
 
526
                         split('path/to/foo/', exclude_trailing_slash=False))
412
527
        self.assertEqual(('path/..', 'foo'), split('path/../foo'))
413
528
        self.assertEqual(('../path', 'foo'), split('../path/foo'))
414
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
 
 
557
    def test_split_segment_parameters_raw(self):
 
558
        split_segment_parameters_raw = urlutils.split_segment_parameters_raw
 
559
        # Check relative references with absolute paths
 
560
        self.assertEqual(("/some/path", []),
 
561
                         split_segment_parameters_raw("/some/path"))
 
562
        self.assertEqual(("/some/path", ["tip"]),
 
563
                         split_segment_parameters_raw("/some/path,tip"))
 
564
        self.assertEqual(("/some,dir/path", ["tip"]),
 
565
                         split_segment_parameters_raw("/some,dir/path,tip"))
 
566
        self.assertEqual(
 
567
            ("/somedir/path", ["heads%2Ftip"]),
 
568
            split_segment_parameters_raw("/somedir/path,heads%2Ftip"))
 
569
        self.assertEqual(
 
570
            ("/somedir/path", ["heads%2Ftip", "bar"]),
 
571
            split_segment_parameters_raw("/somedir/path,heads%2Ftip,bar"))
 
572
        # Check relative references with relative paths
 
573
        self.assertEqual(("", ["key1=val1"]),
 
574
                         split_segment_parameters_raw(",key1=val1"))
 
575
        self.assertEqual(("foo/", ["key1=val1"]),
 
576
                         split_segment_parameters_raw("foo/,key1=val1"))
 
577
        self.assertEqual(("foo", ["key1=val1"]),
 
578
                         split_segment_parameters_raw("foo,key1=val1"))
 
579
        self.assertEqual(
 
580
            ("foo/base,la=bla/other/elements", []),
 
581
            split_segment_parameters_raw("foo/base,la=bla/other/elements"))
 
582
        self.assertEqual(
 
583
            ("foo/base,la=bla/other/elements", ["a=b"]),
 
584
            split_segment_parameters_raw("foo/base,la=bla/other/elements,a=b"))
 
585
        # TODO: Check full URLs as well as relative references
 
586
 
 
587
    def test_split_segment_parameters(self):
 
588
        split_segment_parameters = urlutils.split_segment_parameters
 
589
        # Check relative references with absolute paths
 
590
        self.assertEqual(("/some/path", {}),
 
591
                         split_segment_parameters("/some/path"))
 
592
        self.assertEqual(("/some/path", {"branch": "tip"}),
 
593
                         split_segment_parameters("/some/path,branch=tip"))
 
594
        self.assertEqual(("/some,dir/path", {"branch": "tip"}),
 
595
                         split_segment_parameters("/some,dir/path,branch=tip"))
 
596
        self.assertEqual(
 
597
            ("/somedir/path", {"ref": "heads%2Ftip"}),
 
598
            split_segment_parameters("/somedir/path,ref=heads%2Ftip"))
 
599
        self.assertEqual(("/somedir/path",
 
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"}),
 
605
            split_segment_parameters("/somedir/path,ref=heads%2F=tip"))
 
606
        # Check relative references with relative paths
 
607
        self.assertEqual(("", {"key1": "val1"}),
 
608
                         split_segment_parameters(",key1=val1"))
 
609
        self.assertEqual(("foo/", {"key1": "val1"}),
 
610
                         split_segment_parameters("foo/,key1=val1"))
 
611
        self.assertEqual(
 
612
            ("foo/base,key1=val1/other/elements", {}),
 
613
            split_segment_parameters("foo/base,key1=val1/other/elements"))
 
614
        self.assertEqual(("foo/base,key1=val1/other/elements",
 
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")
 
620
        # TODO: Check full URLs as well as relative references
 
621
 
415
622
    def test_win32_strip_local_trailing_slash(self):
416
623
        strip = urlutils._win32_strip_local_trailing_slash
417
624
        self.assertEqual('file://', strip('file://'))
443
650
        self.assertEqual('file://', sts('file://'))
444
651
 
445
652
        self.assertEqual('random+scheme://user:pass@ahost:port/path',
446
 
            sts('random+scheme://user:pass@ahost:port/path'))
 
653
                         sts('random+scheme://user:pass@ahost:port/path'))
447
654
        self.assertEqual('random+scheme://user:pass@ahost:port/path',
448
 
            sts('random+scheme://user:pass@ahost:port/path/'))
 
655
                         sts('random+scheme://user:pass@ahost:port/path/'))
449
656
        self.assertEqual('random+scheme://user:pass@ahost:port/',
450
 
            sts('random+scheme://user:pass@ahost:port/'))
 
657
                         sts('random+scheme://user:pass@ahost:port/'))
451
658
 
452
659
        # Make sure relative paths work too
453
660
        self.assertEqual('path/to/foo', sts('path/to/foo'))
459
666
        # Test that URLs are converted to nice unicode strings for display
460
667
        def test(expected, url, encoding='utf-8'):
461
668
            disp_url = urlutils.unescape_for_display(url, encoding=encoding)
462
 
            self.assertIsInstance(disp_url, unicode)
 
669
            self.assertIsInstance(disp_url, str)
463
670
            self.assertEqual(expected, disp_url)
464
671
 
465
672
        test('http://foo', 'http://foo')
499
706
    def test_escape(self):
500
707
        self.assertEqual('%25', urlutils.escape('%'))
501
708
        self.assertEqual('%C3%A5', urlutils.escape(u'\xe5'))
502
 
        self.assertFalse(isinstance(urlutils.escape(u'\xe5'), unicode))
 
709
        self.assertIsInstance(urlutils.escape(u'\xe5'), str)
503
710
 
504
711
    def test_escape_tildes(self):
505
712
        self.assertEqual('~foo', urlutils.escape('~foo'))
508
715
        self.assertEqual('%', urlutils.unescape('%25'))
509
716
        self.assertEqual(u'\xe5', urlutils.unescape('%C3%A5'))
510
717
 
511
 
        self.assertRaises(InvalidURL, urlutils.unescape, u'\xe5')
512
 
        self.assertRaises(InvalidURL, urlutils.unescape, '\xe5')
513
 
        self.assertRaises(InvalidURL, urlutils.unescape, '%E5')
 
718
        self.assertRaises((TypeError, urlutils.InvalidURL),
 
719
                          urlutils.unescape, b'\xe5')
 
720
        self.assertEqual('\xe5', urlutils.unescape('%C3%A5'))
514
721
 
515
722
    def test_escape_unescape(self):
516
723
        self.assertEqual(u'\xe5', urlutils.unescape(urlutils.escape(u'\xe5')))
523
730
 
524
731
        test('a', 'http://host/', 'http://host/a')
525
732
        test('http://entirely/different', 'sftp://host/branch',
526
 
                    'http://entirely/different')
 
733
             'http://entirely/different')
527
734
        test('../person/feature', 'http://host/branch/mainline',
528
 
                    'http://host/branch/person/feature')
 
735
             'http://host/branch/person/feature')
529
736
        test('..', 'http://host/branch', 'http://host/')
530
 
        test('http://host2/branch', 'http://host1/branch', 'http://host2/branch')
 
737
        test('http://host2/branch', 'http://host1/branch',
 
738
             'http://host2/branch')
531
739
        test('.', 'http://host1/branch', 'http://host1/branch')
532
740
        test('../../../branch/2b', 'file:///home/jelmer/foo/bar/2b',
533
 
                    'file:///home/jelmer/branch/2b')
 
741
             'file:///home/jelmer/branch/2b')
534
742
        test('../../branch/2b', 'sftp://host/home/jelmer/bar/2b',
535
 
                    'sftp://host/home/jelmer/branch/2b')
 
743
             'sftp://host/home/jelmer/branch/2b')
536
744
        test('../../branch/feature/%2b', 'http://host/home/jelmer/bar/%2b',
537
 
                    'http://host/home/jelmer/branch/feature/%2b')
 
745
             'http://host/home/jelmer/branch/feature/%2b')
538
746
        test('../../branch/feature/2b', 'http://host/home/jelmer/bar/2b/',
539
 
                    'http://host/home/jelmer/branch/feature/2b')
 
747
             'http://host/home/jelmer/branch/feature/2b')
540
748
        # relative_url should preserve a trailing slash
541
749
        test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b/',
542
 
                    'http://host/home/jelmer/branch/feature/2b/')
 
750
             'http://host/home/jelmer/branch/feature/2b/')
543
751
        test('../../branch/feature/2b/', 'http://host/home/jelmer/bar/2b',
544
 
                    'http://host/home/jelmer/branch/feature/2b/')
 
752
             'http://host/home/jelmer/branch/feature/2b/')
545
753
 
546
754
        # TODO: treat http://host as http://host/
547
755
        #       relative_url is typically called from a branch.base or
548
756
        #       transport.base which always ends with a /
549
 
        #test('a', 'http://host', 'http://host/a')
 
757
        # test('a', 'http://host', 'http://host/a')
550
758
        test('http://host/a', 'http://host', 'http://host/a')
551
 
        #test('.', 'http://host', 'http://host/')
 
759
        # test('.', 'http://host', 'http://host/')
552
760
        test('http://host/', 'http://host', 'http://host/')
553
 
        #test('.', 'http://host/', 'http://host')
 
761
        # test('.', 'http://host/', 'http://host')
554
762
        test('http://host', 'http://host/', 'http://host')
555
763
 
556
764
        # On Windows file:///C:/path/to and file:///D:/other/path
558
766
        if sys.platform == 'win32':
559
767
            # on the same drive
560
768
            test('../../other/path',
561
 
                'file:///C:/path/to', 'file:///C:/other/path')
562
 
            #~next two tests is failed, i.e. urlutils.relative_url expects
563
 
            #~to see normalized file URLs?
564
 
            #~test('../../other/path',
565
 
            #~    'file:///C:/path/to', 'file:///c:/other/path')
566
 
            #~test('../../other/path',
567
 
            #~    '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')
568
776
 
569
777
            # check UNC paths too
570
778
            test('../../other/path',
571
 
                'file://HOST/base/path/to', 'file://HOST/base/other/path')
 
779
                 'file://HOST/base/path/to', 'file://HOST/base/other/path')
572
780
            # on different drives
573
781
            test('file:///D:/other/path',
574
 
                'file:///C:/path/to', 'file:///D:/other/path')
 
782
                 'file:///C:/path/to', 'file:///D:/other/path')
575
783
            # TODO: strictly saying in UNC path //HOST/base is full analog
576
784
            # of drive letter for hard disk, and this situation is also
577
785
            # should be exception from rules. [bialix 20071221]
578
786
 
579
787
 
580
788
class TestCwdToURL(TestCaseInTempDir):
581
 
    """Test that local_path_to_url works base on the cwd"""
 
789
    """Test that local_path_to_url works based on the cwd"""
582
790
 
583
791
    def test_dot(self):
584
792
        # This test will fail if getcwd is not ascii
589
797
        self.assertEndsWith(url, '/mytest')
590
798
 
591
799
    def test_non_ascii(self):
592
 
        if win32utils.winver == 'Windows 98':
593
 
            raise TestSkipped('Windows 98 cannot handle unicode filenames')
594
 
 
595
800
        try:
596
801
            os.mkdir(u'dod\xe9')
597
802
        except UnicodeError:
637
842
        self.assertEqual('/foo', result)
638
843
 
639
844
    def test_different_ports(self):
640
 
        e = self.assertRaises(InvalidRebaseURLs, urlutils.rebase_url,
 
845
        e = self.assertRaises(urlutils.InvalidRebaseURLs, urlutils.rebase_url,
641
846
                              'foo', 'http://bar:80', 'http://bar:81')
642
847
        self.assertEqual(str(e), "URLs differ by more than path:"
643
848
                         " 'http://bar:80' and 'http://bar:81'")
644
849
 
645
850
    def test_different_hosts(self):
646
 
        e = self.assertRaises(InvalidRebaseURLs, urlutils.rebase_url,
 
851
        e = self.assertRaises(urlutils.InvalidRebaseURLs, urlutils.rebase_url,
647
852
                              'foo', 'http://bar', 'http://baz')
648
853
        self.assertEqual(str(e), "URLs differ by more than path: 'http://bar'"
649
854
                         " and 'http://baz'")
650
855
 
651
856
    def test_different_protocol(self):
652
 
        e = self.assertRaises(InvalidRebaseURLs, urlutils.rebase_url,
 
857
        e = self.assertRaises(urlutils.InvalidRebaseURLs, urlutils.rebase_url,
653
858
                              'foo', 'http://bar', 'ftp://bar')
654
859
        self.assertEqual(str(e), "URLs differ by more than path: 'http://bar'"
655
860
                         " and 'ftp://bar'")
656
861
 
657
862
    def test_rebase_success(self):
658
863
        self.assertEqual('../bar', urlutils.rebase_url('bar', 'http://baz/',
659
 
                         'http://baz/qux'))
660
 
        self.assertEqual('qux/bar', urlutils.rebase_url('bar',
661
 
                         'http://baz/qux', 'http://baz/'))
662
 
        self.assertEqual('.', urlutils.rebase_url('foo',
663
 
                         'http://bar/', 'http://bar/foo/'))
664
 
        self.assertEqual('qux/bar', urlutils.rebase_url('../bar',
665
 
                         '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/'))
666
873
 
667
874
    def test_determine_relative_path(self):
668
875
        self.assertEqual('../../baz/bar',
669
876
                         urlutils.determine_relative_path(
670
 
                         '/qux/quxx', '/baz/bar'))
 
877
                             '/qux/quxx', '/baz/bar'))
671
878
        self.assertEqual('..',
672
879
                         urlutils.determine_relative_path(
673
 
                         '/bar/baz', '/bar'))
 
880
                             '/bar/baz', '/bar'))
674
881
        self.assertEqual('baz',
675
882
                         urlutils.determine_relative_path(
676
 
                         '/bar', '/bar/baz'))
 
883
                             '/bar', '/bar/baz'))
677
884
        self.assertEqual('.', urlutils.determine_relative_path(
678
885
                         '/bar', '/bar'))
679
886
 
680
887
 
681
888
class TestParseURL(TestCase):
682
889
 
683
 
    def test_parse_url(self):
684
 
        self.assertEqual(urlutils.parse_url('http://example.com:80/one'),
685
 
            ('http', None, None, 'example.com', 80, '/one'))
686
 
        self.assertEqual(urlutils.parse_url('http://[1:2:3::40]/one'),
687
 
                ('http', None, None, '1:2:3::40', None, '/one'))
688
 
        self.assertEqual(urlutils.parse_url('http://[1:2:3::40]:80/one'),
689
 
                ('http', None, None, '1:2:3::40', 80, '/one'))
 
890
    def test_parse_simple(self):
 
891
        parsed = urlutils.parse_url('http://example.com:80/one')
 
892
        self.assertEqual(('http', None, None, 'example.com', 80, '/one'),
 
893
                         parsed)
 
894
 
 
895
    def test_ipv6(self):
 
896
        parsed = urlutils.parse_url('http://[1:2:3::40]/one')
 
897
        self.assertEqual(('http', None, None, '1:2:3::40', None, '/one'),
 
898
                         parsed)
 
899
 
 
900
    def test_ipv6_port(self):
 
901
        parsed = urlutils.parse_url('http://[1:2:3::40]:80/one')
 
902
        self.assertEqual(('http', None, None, '1:2:3::40', 80, '/one'),
 
903
                         parsed)
 
904
 
 
905
 
 
906
class TestURL(TestCase):
 
907
 
 
908
    def test_parse_simple(self):
 
909
        parsed = urlutils.URL.from_string('http://example.com:80/one')
 
910
        self.assertEqual('http', parsed.scheme)
 
911
        self.assertIs(None, parsed.user)
 
912
        self.assertIs(None, parsed.password)
 
913
        self.assertEqual('example.com', parsed.host)
 
914
        self.assertEqual(80, parsed.port)
 
915
        self.assertEqual('/one', parsed.path)
 
916
 
 
917
    def test_ipv6(self):
 
918
        parsed = urlutils.URL.from_string('http://[1:2:3::40]/one')
 
919
        self.assertEqual('http', parsed.scheme)
 
920
        self.assertIs(None, parsed.port)
 
921
        self.assertIs(None, parsed.user)
 
922
        self.assertIs(None, parsed.password)
 
923
        self.assertEqual('1:2:3::40', parsed.host)
 
924
        self.assertEqual('/one', parsed.path)
 
925
 
 
926
    def test_ipv6_port(self):
 
927
        parsed = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
 
928
        self.assertEqual('http', parsed.scheme)
 
929
        self.assertEqual('1:2:3::40', parsed.host)
 
930
        self.assertIs(None, parsed.user)
 
931
        self.assertIs(None, parsed.password)
 
932
        self.assertEqual(80, parsed.port)
 
933
        self.assertEqual('/one', parsed.path)
 
934
 
 
935
    def test_quoted(self):
 
936
        parsed = urlutils.URL.from_string(
 
937
            'http://ro%62ey:h%40t@ex%41mple.com:2222/path')
 
938
        self.assertEqual(parsed.quoted_host, 'ex%41mple.com')
 
939
        self.assertEqual(parsed.host, 'exAmple.com')
 
940
        self.assertEqual(parsed.port, 2222)
 
941
        self.assertEqual(parsed.quoted_user, 'ro%62ey')
 
942
        self.assertEqual(parsed.user, 'robey')
 
943
        self.assertEqual(parsed.quoted_password, 'h%40t')
 
944
        self.assertEqual(parsed.password, 'h@t')
 
945
        self.assertEqual(parsed.path, '/path')
 
946
 
 
947
    def test_eq(self):
 
948
        parsed1 = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
 
949
        parsed2 = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
 
950
        self.assertEqual(parsed1, parsed2)
 
951
        self.assertEqual(parsed1, parsed1)
 
952
        parsed2.path = '/two'
 
953
        self.assertNotEqual(parsed1, parsed2)
 
954
 
 
955
    def test_repr(self):
 
956
        parsed = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
 
957
        self.assertEqual(
 
958
            "<URL('http', None, None, '1:2:3::40', 80, '/one')>",
 
959
            repr(parsed))
 
960
 
 
961
    def test_str(self):
 
962
        parsed = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
 
963
        self.assertEqual('http://[1:2:3::40]:80/one', str(parsed))
 
964
 
 
965
    def test__combine_paths(self):
 
966
        combine = urlutils.URL._combine_paths
 
967
        self.assertEqual('/home/sarah/project/foo',
 
968
                         combine('/home/sarah', 'project/foo'))
 
969
        self.assertEqual('/etc',
 
970
                         combine('/home/sarah', '../../etc'))
 
971
        self.assertEqual('/etc',
 
972
                         combine('/home/sarah', '../../../etc'))
 
973
        self.assertEqual('/etc',
 
974
                         combine('/home/sarah', '/etc'))
 
975
 
 
976
    def test_clone(self):
 
977
        url = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
 
978
        url1 = url.clone("two")
 
979
        self.assertEqual("/one/two", url1.path)
 
980
        url2 = url.clone("/two")
 
981
        self.assertEqual("/two", url2.path)
 
982
        url3 = url.clone()
 
983
        self.assertIsNot(url, url3)
 
984
        self.assertEqual(url, url3)
 
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
 
 
995
 
 
996
class TestFileRelpath(TestCase):
 
997
 
 
998
    # GZ 2011-11-18: A way to override all path handling functions to one
 
999
    #                platform or another for testing would be nice.
 
1000
 
 
1001
    def _with_posix_paths(self):
 
1002
        self.overrideAttr(urlutils, "local_path_from_url",
 
1003
                          urlutils._posix_local_path_from_url)
 
1004
        self.overrideAttr(urlutils, "MIN_ABS_FILEURL_LENGTH", len("file:///"))
 
1005
        self.overrideAttr(osutils, "normpath", osutils._posix_normpath)
 
1006
        self.overrideAttr(osutils, "abspath", osutils._posix_abspath)
 
1007
        self.overrideAttr(osutils, "normpath", osutils._posix_normpath)
 
1008
        self.overrideAttr(osutils, "pathjoin", osutils.posixpath.join)
 
1009
        self.overrideAttr(osutils, "split", osutils.posixpath.split)
 
1010
        self.overrideAttr(osutils, "MIN_ABS_PATHLENGTH", 1)
 
1011
 
 
1012
    def _with_win32_paths(self):
 
1013
        self.overrideAttr(urlutils, "local_path_from_url",
 
1014
                          urlutils._win32_local_path_from_url)
 
1015
        self.overrideAttr(urlutils, "MIN_ABS_FILEURL_LENGTH",
 
1016
                          urlutils.WIN32_MIN_ABS_FILEURL_LENGTH)
 
1017
        self.overrideAttr(osutils, "abspath", osutils._win32_abspath)
 
1018
        self.overrideAttr(osutils, "normpath", osutils._win32_normpath)
 
1019
        self.overrideAttr(osutils, "pathjoin", osutils._win32_pathjoin)
 
1020
        self.overrideAttr(osutils, "split", osutils.ntpath.split)
 
1021
        self.overrideAttr(osutils, "MIN_ABS_PATHLENGTH", 3)
 
1022
 
 
1023
    def test_same_url_posix(self):
 
1024
        self._with_posix_paths()
 
1025
        self.assertEqual("",
 
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"))
 
1031
 
 
1032
    def test_same_url_win32(self):
 
1033
        self._with_win32_paths()
 
1034
        self.assertEqual("",
 
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"))
 
1044
 
 
1045
    def test_child_posix(self):
 
1046
        self._with_posix_paths()
 
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"))
 
1053
 
 
1054
    def test_child_win32(self):
 
1055
        self._with_win32_paths()
 
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"))
 
1066
 
 
1067
    def test_sibling_posix(self):
 
1068
        self._with_posix_paths()
 
1069
        self.assertRaises(
 
1070
            PathNotChild,
 
1071
            urlutils.file_relpath, "file:///a/b", "file:///a/c")
 
1072
        self.assertRaises(
 
1073
            PathNotChild,
 
1074
            urlutils.file_relpath, "file:///a/b/", "file:///a/c")
 
1075
        self.assertRaises(
 
1076
            PathNotChild,
 
1077
            urlutils.file_relpath, "file:///a/b/", "file:///a/c/")
 
1078
 
 
1079
    def test_sibling_win32(self):
 
1080
        self._with_win32_paths()
 
1081
        self.assertRaises(
 
1082
            PathNotChild,
 
1083
            urlutils.file_relpath, "file:///A:/b", "file:///A:/c")
 
1084
        self.assertRaises(
 
1085
            PathNotChild,
 
1086
            urlutils.file_relpath, "file:///A:/b/", "file:///A:/c")
 
1087
        self.assertRaises(
 
1088
            PathNotChild,
 
1089
            urlutils.file_relpath, "file:///A:/b/", "file:///A:/c/")
 
1090
 
 
1091
    def test_parent_posix(self):
 
1092
        self._with_posix_paths()
 
1093
        self.assertRaises(PathNotChild,
 
1094
                          urlutils.file_relpath, "file:///a/b", "file:///a")
 
1095
        self.assertRaises(PathNotChild,
 
1096
                          urlutils.file_relpath, "file:///a/b", "file:///a/")
 
1097
 
 
1098
    def test_parent_win32(self):
 
1099
        self._with_win32_paths()
 
1100
        self.assertRaises(
 
1101
            PathNotChild,
 
1102
            urlutils.file_relpath, "file:///A:/b", "file:///A:/")
 
1103
        self.assertRaises(
 
1104
            PathNotChild,
 
1105
            urlutils.file_relpath, "file:///A:/b/c", "file:///A:/b")
 
1106
 
 
1107
 
 
1108
class QuoteTests(TestCase):
 
1109
 
 
1110
    def test_quote(self):
 
1111
        self.assertEqual('abc%20def', urlutils.quote('abc def'))
 
1112
        self.assertEqual('abc%2Fdef', urlutils.quote('abc/def', safe=''))
 
1113
        self.assertEqual('abc/def', urlutils.quote('abc/def', safe='/'))
 
1114
 
 
1115
    def test_quote_tildes(self):
 
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'))
 
1122
        self.assertEqual('~foo', urlutils.quote('~foo', safe='/~'))
 
1123
 
 
1124
    def test_unquote(self):
 
1125
        self.assertEqual('%', urlutils.unquote('%25'))
 
1126
        self.assertEqual('\xe5', urlutils.unquote('%C3%A5'))
 
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'))