/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-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

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