blob: e5f6130e4a075e4e0b552bb03740f9f7f7925531 [file] [log] [blame]
Skip Montanaro6ec967d2002-03-23 05:32:10 +00001import unittest
Jeremy Hylton1afc1692008-06-18 20:49:58 +00002import urllib.parse
Fred Drakea4d18a02001-01-05 05:57:04 +00003
Fred Drakea4d18a02001-01-05 05:57:04 +00004RFC1808_BASE = "http://a/b/c/d;p?q#f"
Skip Montanaro6ec967d2002-03-23 05:32:10 +00005RFC2396_BASE = "http://a/b/c/d;p?q"
Senthil Kumarandd3820f2010-05-07 04:19:23 +00006RFC3986_BASE = 'http://a/b/c/d;p?q'
Senthil Kumaranaa69d4d2010-07-14 10:21:22 +00007SIMPLE_BASE = 'http://a/b/c/d'
Fred Drakea4d18a02001-01-05 05:57:04 +00008
Senthil Kumaran257b9802017-04-04 21:19:43 -07009# Each parse_qsl testcase is a two-tuple that contains
10# a string with the query and a list with the expected result.
Facundo Batistac469d4c2008-09-03 22:49:01 +000011
12parse_qsl_test_cases = [
13 ("", []),
14 ("&", []),
15 ("&&", []),
16 ("=", [('', '')]),
17 ("=a", [('', 'a')]),
18 ("a", [('a', '')]),
19 ("a=", [('a', '')]),
Facundo Batistac469d4c2008-09-03 22:49:01 +000020 ("&a=b", [('a', 'b')]),
21 ("a=a+b&b=b+c", [('a', 'a b'), ('b', 'b c')]),
22 ("a=1&a=2", [('a', '1'), ('a', '2')]),
Nick Coghlan9fc443c2010-11-30 15:48:08 +000023 (b"", []),
24 (b"&", []),
25 (b"&&", []),
26 (b"=", [(b'', b'')]),
27 (b"=a", [(b'', b'a')]),
28 (b"a", [(b'a', b'')]),
29 (b"a=", [(b'a', b'')]),
Nick Coghlan9fc443c2010-11-30 15:48:08 +000030 (b"&a=b", [(b'a', b'b')]),
31 (b"a=a+b&b=b+c", [(b'a', b'a b'), (b'b', b'b c')]),
32 (b"a=1&a=2", [(b'a', b'1'), (b'a', b'2')]),
Senthil Kumarane38415e2016-04-16 07:33:15 -070033 (";", []),
34 (";;", []),
35 (";a=b", [('a', 'b')]),
36 ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]),
37 ("a=1;a=2", [('a', '1'), ('a', '2')]),
38 (b";", []),
39 (b";;", []),
40 (b";a=b", [(b'a', b'b')]),
41 (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]),
42 (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]),
43]
44
Senthil Kumaran257b9802017-04-04 21:19:43 -070045# Each parse_qs testcase is a two-tuple that contains
46# a string with the query and a dictionary with the expected result.
47
Senthil Kumarane38415e2016-04-16 07:33:15 -070048parse_qs_test_cases = [
49 ("", {}),
50 ("&", {}),
51 ("&&", {}),
52 ("=", {'': ['']}),
53 ("=a", {'': ['a']}),
54 ("a", {'a': ['']}),
55 ("a=", {'a': ['']}),
56 ("&a=b", {'a': ['b']}),
57 ("a=a+b&b=b+c", {'a': ['a b'], 'b': ['b c']}),
58 ("a=1&a=2", {'a': ['1', '2']}),
59 (b"", {}),
60 (b"&", {}),
61 (b"&&", {}),
62 (b"=", {b'': [b'']}),
63 (b"=a", {b'': [b'a']}),
64 (b"a", {b'a': [b'']}),
65 (b"a=", {b'a': [b'']}),
66 (b"&a=b", {b'a': [b'b']}),
67 (b"a=a+b&b=b+c", {b'a': [b'a b'], b'b': [b'b c']}),
68 (b"a=1&a=2", {b'a': [b'1', b'2']}),
69 (";", {}),
70 (";;", {}),
71 (";a=b", {'a': ['b']}),
72 ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}),
73 ("a=1;a=2", {'a': ['1', '2']}),
74 (b";", {}),
75 (b";;", {}),
76 (b";a=b", {b'a': [b'b']}),
77 (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}),
78 (b"a=1;a=2", {b'a': [b'1', b'2']}),
Facundo Batistac469d4c2008-09-03 22:49:01 +000079]
80
Skip Montanaro6ec967d2002-03-23 05:32:10 +000081class UrlParseTestCase(unittest.TestCase):
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +000082
83 def checkRoundtrips(self, url, parsed, split):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000084 result = urllib.parse.urlparse(url)
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +000085 self.assertEqual(result, parsed)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000086 t = (result.scheme, result.netloc, result.path,
87 result.params, result.query, result.fragment)
88 self.assertEqual(t, parsed)
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +000089 # put it back together and it should be the same
Jeremy Hylton1afc1692008-06-18 20:49:58 +000090 result2 = urllib.parse.urlunparse(result)
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +000091 self.assertEqual(result2, url)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000092 self.assertEqual(result2, result.geturl())
93
94 # the result of geturl() is a fixpoint; we can always parse it
95 # again to get the same result:
Jeremy Hylton1afc1692008-06-18 20:49:58 +000096 result3 = urllib.parse.urlparse(result.geturl())
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000097 self.assertEqual(result3.geturl(), result.geturl())
98 self.assertEqual(result3, result)
99 self.assertEqual(result3.scheme, result.scheme)
100 self.assertEqual(result3.netloc, result.netloc)
101 self.assertEqual(result3.path, result.path)
102 self.assertEqual(result3.params, result.params)
103 self.assertEqual(result3.query, result.query)
104 self.assertEqual(result3.fragment, result.fragment)
105 self.assertEqual(result3.username, result.username)
106 self.assertEqual(result3.password, result.password)
107 self.assertEqual(result3.hostname, result.hostname)
108 self.assertEqual(result3.port, result.port)
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000109
110 # check the roundtrip using urlsplit() as well
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000111 result = urllib.parse.urlsplit(url)
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000112 self.assertEqual(result, split)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000113 t = (result.scheme, result.netloc, result.path,
114 result.query, result.fragment)
115 self.assertEqual(t, split)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000116 result2 = urllib.parse.urlunsplit(result)
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000117 self.assertEqual(result2, url)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000118 self.assertEqual(result2, result.geturl())
119
120 # check the fixpoint property of re-parsing the result of geturl()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000121 result3 = urllib.parse.urlsplit(result.geturl())
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000122 self.assertEqual(result3.geturl(), result.geturl())
123 self.assertEqual(result3, result)
124 self.assertEqual(result3.scheme, result.scheme)
125 self.assertEqual(result3.netloc, result.netloc)
126 self.assertEqual(result3.path, result.path)
127 self.assertEqual(result3.query, result.query)
128 self.assertEqual(result3.fragment, result.fragment)
129 self.assertEqual(result3.username, result.username)
130 self.assertEqual(result3.password, result.password)
131 self.assertEqual(result3.hostname, result.hostname)
132 self.assertEqual(result3.port, result.port)
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000133
Facundo Batistac469d4c2008-09-03 22:49:01 +0000134 def test_qsl(self):
135 for orig, expect in parse_qsl_test_cases:
136 result = urllib.parse.parse_qsl(orig, keep_blank_values=True)
Senthil Kumarande02a712011-07-23 18:27:45 +0800137 self.assertEqual(result, expect, "Error parsing %r" % orig)
138 expect_without_blanks = [v for v in expect if len(v[1])]
139 result = urllib.parse.parse_qsl(orig, keep_blank_values=False)
140 self.assertEqual(result, expect_without_blanks,
141 "Error parsing %r" % orig)
Facundo Batistac469d4c2008-09-03 22:49:01 +0000142
Senthil Kumarane38415e2016-04-16 07:33:15 -0700143 def test_qs(self):
144 for orig, expect in parse_qs_test_cases:
145 result = urllib.parse.parse_qs(orig, keep_blank_values=True)
146 self.assertEqual(result, expect, "Error parsing %r" % orig)
147 expect_without_blanks = {v: expect[v]
148 for v in expect if len(expect[v][0])}
149 result = urllib.parse.parse_qs(orig, keep_blank_values=False)
150 self.assertEqual(result, expect_without_blanks,
151 "Error parsing %r" % orig)
152
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000153 def test_roundtrips(self):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000154 str_cases = [
Fred Drake70705652002-10-16 21:02:36 +0000155 ('file:///tmp/junk.txt',
156 ('file', '', '/tmp/junk.txt', '', '', ''),
157 ('file', '', '/tmp/junk.txt', '', '')),
Neal Norwitz68b539e2003-01-06 06:58:31 +0000158 ('imap://mail.python.org/mbox1',
159 ('imap', 'mail.python.org', '/mbox1', '', '', ''),
160 ('imap', 'mail.python.org', '/mbox1', '', '')),
Skip Montanarof09b88e2003-01-06 20:27:03 +0000161 ('mms://wms.sys.hinet.net/cts/Drama/09006251100.asf',
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000162 ('mms', 'wms.sys.hinet.net', '/cts/Drama/09006251100.asf',
163 '', '', ''),
164 ('mms', 'wms.sys.hinet.net', '/cts/Drama/09006251100.asf',
165 '', '')),
Senthil Kumaraneaaec272009-03-30 21:54:41 +0000166 ('nfs://server/path/to/file.txt',
167 ('nfs', 'server', '/path/to/file.txt', '', '', ''),
168 ('nfs', 'server', '/path/to/file.txt', '', '')),
Fred Drake50747fc2005-07-29 15:56:32 +0000169 ('svn+ssh://svn.zope.org/repos/main/ZConfig/trunk/',
170 ('svn+ssh', 'svn.zope.org', '/repos/main/ZConfig/trunk/',
171 '', '', ''),
172 ('svn+ssh', 'svn.zope.org', '/repos/main/ZConfig/trunk/',
Senthil Kumaranead169d2010-05-13 03:37:23 +0000173 '', '')),
174 ('git+ssh://git@github.com/user/project.git',
175 ('git+ssh', 'git@github.com','/user/project.git',
176 '','',''),
177 ('git+ssh', 'git@github.com','/user/project.git',
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000178 '', '')),
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000179 ]
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000180 def _encode(t):
181 return (t[0].encode('ascii'),
182 tuple(x.encode('ascii') for x in t[1]),
183 tuple(x.encode('ascii') for x in t[2]))
184 bytes_cases = [_encode(x) for x in str_cases]
185 for url, parsed, split in str_cases + bytes_cases:
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000186 self.checkRoundtrips(url, parsed, split)
Michael W. Hudsonbd3e7712002-03-18 13:06:00 +0000187
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000188 def test_http_roundtrips(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000189 # urllib.parse.urlsplit treats 'http:' as an optimized special case,
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000190 # so we test both 'http:' and 'https:' in all the following.
191 # Three cheers for white box knowledge!
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000192 str_cases = [
Johannes Gijsbers41e4faa2005-01-09 15:29:10 +0000193 ('://www.python.org',
194 ('www.python.org', '', '', '', ''),
195 ('www.python.org', '', '', '')),
196 ('://www.python.org#abc',
197 ('www.python.org', '', '', '', 'abc'),
198 ('www.python.org', '', '', 'abc')),
199 ('://www.python.org?q=abc',
200 ('www.python.org', '', '', 'q=abc', ''),
201 ('www.python.org', '', 'q=abc', '')),
202 ('://www.python.org/#abc',
203 ('www.python.org', '/', '', '', 'abc'),
204 ('www.python.org', '/', '', 'abc')),
205 ('://a/b/c/d;p?q#f',
206 ('a', '/b/c/d', 'p', 'q', 'f'),
207 ('a', '/b/c/d;p', 'q', 'f')),
208 ]
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000209 def _encode(t):
210 return (t[0].encode('ascii'),
211 tuple(x.encode('ascii') for x in t[1]),
212 tuple(x.encode('ascii') for x in t[2]))
213 bytes_cases = [_encode(x) for x in str_cases]
214 str_schemes = ('http', 'https')
215 bytes_schemes = (b'http', b'https')
216 str_tests = str_schemes, str_cases
217 bytes_tests = bytes_schemes, bytes_cases
218 for schemes, test_cases in (str_tests, bytes_tests):
219 for scheme in schemes:
220 for url, parsed, split in test_cases:
221 url = scheme + url
222 parsed = (scheme,) + parsed
223 split = (scheme,) + split
224 self.checkRoundtrips(url, parsed, split)
Fred Drake70705652002-10-16 21:02:36 +0000225
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000226 def checkJoin(self, base, relurl, expected):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000227 str_components = (base, relurl, expected)
228 self.assertEqual(urllib.parse.urljoin(base, relurl), expected)
229 bytes_components = baseb, relurlb, expectedb = [
230 x.encode('ascii') for x in str_components]
231 self.assertEqual(urllib.parse.urljoin(baseb, relurlb), expectedb)
Guido van Rossumbbc05682002-10-14 19:59:54 +0000232
233 def test_unparse_parse(self):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000234 str_cases = ['Python', './Python','x-newscheme://foo.com/stuff','x://y','x:/y','x:/','/',]
235 bytes_cases = [x.encode('ascii') for x in str_cases]
236 for u in str_cases + bytes_cases:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000237 self.assertEqual(urllib.parse.urlunsplit(urllib.parse.urlsplit(u)), u)
238 self.assertEqual(urllib.parse.urlunparse(urllib.parse.urlparse(u)), u)
Fred Drakea4d18a02001-01-05 05:57:04 +0000239
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000240 def test_RFC1808(self):
241 # "normal" cases from RFC 1808:
242 self.checkJoin(RFC1808_BASE, 'g:h', 'g:h')
243 self.checkJoin(RFC1808_BASE, 'g', 'http://a/b/c/g')
244 self.checkJoin(RFC1808_BASE, './g', 'http://a/b/c/g')
245 self.checkJoin(RFC1808_BASE, 'g/', 'http://a/b/c/g/')
246 self.checkJoin(RFC1808_BASE, '/g', 'http://a/g')
247 self.checkJoin(RFC1808_BASE, '//g', 'http://g')
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000248 self.checkJoin(RFC1808_BASE, 'g?y', 'http://a/b/c/g?y')
249 self.checkJoin(RFC1808_BASE, 'g?y/./x', 'http://a/b/c/g?y/./x')
250 self.checkJoin(RFC1808_BASE, '#s', 'http://a/b/c/d;p?q#s')
251 self.checkJoin(RFC1808_BASE, 'g#s', 'http://a/b/c/g#s')
252 self.checkJoin(RFC1808_BASE, 'g#s/./x', 'http://a/b/c/g#s/./x')
253 self.checkJoin(RFC1808_BASE, 'g?y#s', 'http://a/b/c/g?y#s')
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000254 self.checkJoin(RFC1808_BASE, 'g;x', 'http://a/b/c/g;x')
255 self.checkJoin(RFC1808_BASE, 'g;x?y#s', 'http://a/b/c/g;x?y#s')
256 self.checkJoin(RFC1808_BASE, '.', 'http://a/b/c/')
257 self.checkJoin(RFC1808_BASE, './', 'http://a/b/c/')
258 self.checkJoin(RFC1808_BASE, '..', 'http://a/b/')
259 self.checkJoin(RFC1808_BASE, '../', 'http://a/b/')
260 self.checkJoin(RFC1808_BASE, '../g', 'http://a/b/g')
261 self.checkJoin(RFC1808_BASE, '../..', 'http://a/')
262 self.checkJoin(RFC1808_BASE, '../../', 'http://a/')
263 self.checkJoin(RFC1808_BASE, '../../g', 'http://a/g')
Fred Drakea4d18a02001-01-05 05:57:04 +0000264
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000265 # "abnormal" cases from RFC 1808:
266 self.checkJoin(RFC1808_BASE, '', 'http://a/b/c/d;p?q#f')
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000267 self.checkJoin(RFC1808_BASE, 'g.', 'http://a/b/c/g.')
268 self.checkJoin(RFC1808_BASE, '.g', 'http://a/b/c/.g')
269 self.checkJoin(RFC1808_BASE, 'g..', 'http://a/b/c/g..')
270 self.checkJoin(RFC1808_BASE, '..g', 'http://a/b/c/..g')
271 self.checkJoin(RFC1808_BASE, './../g', 'http://a/b/g')
272 self.checkJoin(RFC1808_BASE, './g/.', 'http://a/b/c/g/')
273 self.checkJoin(RFC1808_BASE, 'g/./h', 'http://a/b/c/g/h')
274 self.checkJoin(RFC1808_BASE, 'g/../h', 'http://a/b/c/h')
Fred Drakea4d18a02001-01-05 05:57:04 +0000275
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000276 # RFC 1808 and RFC 1630 disagree on these (according to RFC 1808),
277 # so we'll not actually run these tests (which expect 1808 behavior).
278 #self.checkJoin(RFC1808_BASE, 'http:g', 'http:g')
279 #self.checkJoin(RFC1808_BASE, 'http:', 'http:')
Fred Drakea4d18a02001-01-05 05:57:04 +0000280
Antoine Pitrou55ac5b32014-08-21 19:16:17 -0400281 # XXX: The following tests are no longer compatible with RFC3986
282 # self.checkJoin(RFC1808_BASE, '../../../g', 'http://a/../g')
283 # self.checkJoin(RFC1808_BASE, '../../../../g', 'http://a/../../g')
284 # self.checkJoin(RFC1808_BASE, '/./g', 'http://a/./g')
285 # self.checkJoin(RFC1808_BASE, '/../g', 'http://a/../g')
286
287
Senthil Kumaran397eb442011-04-15 18:20:24 +0800288 def test_RFC2368(self):
289 # Issue 11467: path that starts with a number is not parsed correctly
290 self.assertEqual(urllib.parse.urlparse('mailto:1337@example.org'),
291 ('mailto', '', '1337@example.org', '', '', ''))
292
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000293 def test_RFC2396(self):
294 # cases from RFC 2396
Fred Drakea4d18a02001-01-05 05:57:04 +0000295
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000296 self.checkJoin(RFC2396_BASE, 'g:h', 'g:h')
297 self.checkJoin(RFC2396_BASE, 'g', 'http://a/b/c/g')
298 self.checkJoin(RFC2396_BASE, './g', 'http://a/b/c/g')
299 self.checkJoin(RFC2396_BASE, 'g/', 'http://a/b/c/g/')
300 self.checkJoin(RFC2396_BASE, '/g', 'http://a/g')
301 self.checkJoin(RFC2396_BASE, '//g', 'http://g')
302 self.checkJoin(RFC2396_BASE, 'g?y', 'http://a/b/c/g?y')
303 self.checkJoin(RFC2396_BASE, '#s', 'http://a/b/c/d;p?q#s')
304 self.checkJoin(RFC2396_BASE, 'g#s', 'http://a/b/c/g#s')
305 self.checkJoin(RFC2396_BASE, 'g?y#s', 'http://a/b/c/g?y#s')
306 self.checkJoin(RFC2396_BASE, 'g;x', 'http://a/b/c/g;x')
307 self.checkJoin(RFC2396_BASE, 'g;x?y#s', 'http://a/b/c/g;x?y#s')
308 self.checkJoin(RFC2396_BASE, '.', 'http://a/b/c/')
309 self.checkJoin(RFC2396_BASE, './', 'http://a/b/c/')
310 self.checkJoin(RFC2396_BASE, '..', 'http://a/b/')
311 self.checkJoin(RFC2396_BASE, '../', 'http://a/b/')
312 self.checkJoin(RFC2396_BASE, '../g', 'http://a/b/g')
313 self.checkJoin(RFC2396_BASE, '../..', 'http://a/')
314 self.checkJoin(RFC2396_BASE, '../../', 'http://a/')
315 self.checkJoin(RFC2396_BASE, '../../g', 'http://a/g')
316 self.checkJoin(RFC2396_BASE, '', RFC2396_BASE)
Skip Montanaro6ec967d2002-03-23 05:32:10 +0000317 self.checkJoin(RFC2396_BASE, 'g.', 'http://a/b/c/g.')
318 self.checkJoin(RFC2396_BASE, '.g', 'http://a/b/c/.g')
319 self.checkJoin(RFC2396_BASE, 'g..', 'http://a/b/c/g..')
320 self.checkJoin(RFC2396_BASE, '..g', 'http://a/b/c/..g')
321 self.checkJoin(RFC2396_BASE, './../g', 'http://a/b/g')
322 self.checkJoin(RFC2396_BASE, './g/.', 'http://a/b/c/g/')
323 self.checkJoin(RFC2396_BASE, 'g/./h', 'http://a/b/c/g/h')
324 self.checkJoin(RFC2396_BASE, 'g/../h', 'http://a/b/c/h')
325 self.checkJoin(RFC2396_BASE, 'g;x=1/./y', 'http://a/b/c/g;x=1/y')
326 self.checkJoin(RFC2396_BASE, 'g;x=1/../y', 'http://a/b/c/y')
327 self.checkJoin(RFC2396_BASE, 'g?y/./x', 'http://a/b/c/g?y/./x')
328 self.checkJoin(RFC2396_BASE, 'g?y/../x', 'http://a/b/c/g?y/../x')
329 self.checkJoin(RFC2396_BASE, 'g#s/./x', 'http://a/b/c/g#s/./x')
330 self.checkJoin(RFC2396_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x')
331
Antoine Pitrou55ac5b32014-08-21 19:16:17 -0400332 # XXX: The following tests are no longer compatible with RFC3986
333 # self.checkJoin(RFC2396_BASE, '../../../g', 'http://a/../g')
334 # self.checkJoin(RFC2396_BASE, '../../../../g', 'http://a/../../g')
335 # self.checkJoin(RFC2396_BASE, '/./g', 'http://a/./g')
336 # self.checkJoin(RFC2396_BASE, '/../g', 'http://a/../g')
337
Facundo Batista23e38562008-08-14 16:55:14 +0000338 def test_RFC3986(self):
339 self.checkJoin(RFC3986_BASE, '?y','http://a/b/c/d;p?y')
Antoine Pitrou55ac5b32014-08-21 19:16:17 -0400340 self.checkJoin(RFC3986_BASE, ';x', 'http://a/b/c/;x')
Senthil Kumarandd3820f2010-05-07 04:19:23 +0000341 self.checkJoin(RFC3986_BASE, 'g:h','g:h')
342 self.checkJoin(RFC3986_BASE, 'g','http://a/b/c/g')
343 self.checkJoin(RFC3986_BASE, './g','http://a/b/c/g')
344 self.checkJoin(RFC3986_BASE, 'g/','http://a/b/c/g/')
345 self.checkJoin(RFC3986_BASE, '/g','http://a/g')
346 self.checkJoin(RFC3986_BASE, '//g','http://g')
347 self.checkJoin(RFC3986_BASE, '?y','http://a/b/c/d;p?y')
348 self.checkJoin(RFC3986_BASE, 'g?y','http://a/b/c/g?y')
349 self.checkJoin(RFC3986_BASE, '#s','http://a/b/c/d;p?q#s')
350 self.checkJoin(RFC3986_BASE, 'g#s','http://a/b/c/g#s')
351 self.checkJoin(RFC3986_BASE, 'g?y#s','http://a/b/c/g?y#s')
352 self.checkJoin(RFC3986_BASE, ';x','http://a/b/c/;x')
353 self.checkJoin(RFC3986_BASE, 'g;x','http://a/b/c/g;x')
354 self.checkJoin(RFC3986_BASE, 'g;x?y#s','http://a/b/c/g;x?y#s')
355 self.checkJoin(RFC3986_BASE, '','http://a/b/c/d;p?q')
356 self.checkJoin(RFC3986_BASE, '.','http://a/b/c/')
357 self.checkJoin(RFC3986_BASE, './','http://a/b/c/')
358 self.checkJoin(RFC3986_BASE, '..','http://a/b/')
359 self.checkJoin(RFC3986_BASE, '../','http://a/b/')
360 self.checkJoin(RFC3986_BASE, '../g','http://a/b/g')
361 self.checkJoin(RFC3986_BASE, '../..','http://a/')
362 self.checkJoin(RFC3986_BASE, '../../','http://a/')
363 self.checkJoin(RFC3986_BASE, '../../g','http://a/g')
Antoine Pitrou55ac5b32014-08-21 19:16:17 -0400364 self.checkJoin(RFC3986_BASE, '../../../g', 'http://a/g')
Senthil Kumarandd3820f2010-05-07 04:19:23 +0000365
Senthil Kumaran257b9802017-04-04 21:19:43 -0700366 # Abnormal Examples
Senthil Kumarandd3820f2010-05-07 04:19:23 +0000367
368 # The 'abnormal scenarios' are incompatible with RFC2986 parsing
369 # Tests are here for reference.
370
Antoine Pitrou55ac5b32014-08-21 19:16:17 -0400371 self.checkJoin(RFC3986_BASE, '../../../g','http://a/g')
372 self.checkJoin(RFC3986_BASE, '../../../../g','http://a/g')
373 self.checkJoin(RFC3986_BASE, '/./g','http://a/g')
374 self.checkJoin(RFC3986_BASE, '/../g','http://a/g')
Senthil Kumarandd3820f2010-05-07 04:19:23 +0000375 self.checkJoin(RFC3986_BASE, 'g.','http://a/b/c/g.')
376 self.checkJoin(RFC3986_BASE, '.g','http://a/b/c/.g')
377 self.checkJoin(RFC3986_BASE, 'g..','http://a/b/c/g..')
378 self.checkJoin(RFC3986_BASE, '..g','http://a/b/c/..g')
379 self.checkJoin(RFC3986_BASE, './../g','http://a/b/g')
380 self.checkJoin(RFC3986_BASE, './g/.','http://a/b/c/g/')
381 self.checkJoin(RFC3986_BASE, 'g/./h','http://a/b/c/g/h')
382 self.checkJoin(RFC3986_BASE, 'g/../h','http://a/b/c/h')
383 self.checkJoin(RFC3986_BASE, 'g;x=1/./y','http://a/b/c/g;x=1/y')
384 self.checkJoin(RFC3986_BASE, 'g;x=1/../y','http://a/b/c/y')
385 self.checkJoin(RFC3986_BASE, 'g?y/./x','http://a/b/c/g?y/./x')
386 self.checkJoin(RFC3986_BASE, 'g?y/../x','http://a/b/c/g?y/../x')
387 self.checkJoin(RFC3986_BASE, 'g#s/./x','http://a/b/c/g#s/./x')
388 self.checkJoin(RFC3986_BASE, 'g#s/../x','http://a/b/c/g#s/../x')
389 #self.checkJoin(RFC3986_BASE, 'http:g','http:g') # strict parser
390 self.checkJoin(RFC3986_BASE, 'http:g','http://a/b/c/g') #relaxed parser
Facundo Batista23e38562008-08-14 16:55:14 +0000391
Senthil Kumarandca5b862010-12-17 04:48:45 +0000392 # Test for issue9721
393 self.checkJoin('http://a/b/c/de', ';x','http://a/b/c/;x')
394
Senthil Kumaranaa69d4d2010-07-14 10:21:22 +0000395 def test_urljoins(self):
396 self.checkJoin(SIMPLE_BASE, 'g:h','g:h')
397 self.checkJoin(SIMPLE_BASE, 'http:g','http://a/b/c/g')
398 self.checkJoin(SIMPLE_BASE, 'http:','http://a/b/c/d')
399 self.checkJoin(SIMPLE_BASE, 'g','http://a/b/c/g')
400 self.checkJoin(SIMPLE_BASE, './g','http://a/b/c/g')
401 self.checkJoin(SIMPLE_BASE, 'g/','http://a/b/c/g/')
402 self.checkJoin(SIMPLE_BASE, '/g','http://a/g')
403 self.checkJoin(SIMPLE_BASE, '//g','http://g')
404 self.checkJoin(SIMPLE_BASE, '?y','http://a/b/c/d?y')
405 self.checkJoin(SIMPLE_BASE, 'g?y','http://a/b/c/g?y')
406 self.checkJoin(SIMPLE_BASE, 'g?y/./x','http://a/b/c/g?y/./x')
407 self.checkJoin(SIMPLE_BASE, '.','http://a/b/c/')
408 self.checkJoin(SIMPLE_BASE, './','http://a/b/c/')
409 self.checkJoin(SIMPLE_BASE, '..','http://a/b/')
410 self.checkJoin(SIMPLE_BASE, '../','http://a/b/')
411 self.checkJoin(SIMPLE_BASE, '../g','http://a/b/g')
412 self.checkJoin(SIMPLE_BASE, '../..','http://a/')
413 self.checkJoin(SIMPLE_BASE, '../../g','http://a/g')
Senthil Kumaranaa69d4d2010-07-14 10:21:22 +0000414 self.checkJoin(SIMPLE_BASE, './../g','http://a/b/g')
415 self.checkJoin(SIMPLE_BASE, './g/.','http://a/b/c/g/')
Senthil Kumaranaa69d4d2010-07-14 10:21:22 +0000416 self.checkJoin(SIMPLE_BASE, 'g/./h','http://a/b/c/g/h')
417 self.checkJoin(SIMPLE_BASE, 'g/../h','http://a/b/c/h')
418 self.checkJoin(SIMPLE_BASE, 'http:g','http://a/b/c/g')
419 self.checkJoin(SIMPLE_BASE, 'http:','http://a/b/c/d')
420 self.checkJoin(SIMPLE_BASE, 'http:?y','http://a/b/c/d?y')
421 self.checkJoin(SIMPLE_BASE, 'http:g?y','http://a/b/c/g?y')
422 self.checkJoin(SIMPLE_BASE, 'http:g?y/./x','http://a/b/c/g?y/./x')
Senthil Kumarande02a712011-07-23 18:27:45 +0800423 self.checkJoin('http:///', '..','http:///')
424 self.checkJoin('', 'http://a/b/c/g?y/./x','http://a/b/c/g?y/./x')
425 self.checkJoin('', 'http://a/./g', 'http://a/./g')
Senthil Kumaran2a157d22011-08-03 18:37:22 +0800426 self.checkJoin('svn://pathtorepo/dir1', 'dir2', 'svn://pathtorepo/dir2')
Senthil Kumaran7ce71f62011-08-03 22:08:46 +0800427 self.checkJoin('svn+ssh://pathtorepo/dir1', 'dir2', 'svn+ssh://pathtorepo/dir2')
Berker Peksagf6767482016-09-16 14:43:58 +0300428 self.checkJoin('ws://a/b','g','ws://a/g')
429 self.checkJoin('wss://a/b','g','wss://a/g')
Senthil Kumaranaa69d4d2010-07-14 10:21:22 +0000430
Antoine Pitrou55ac5b32014-08-21 19:16:17 -0400431 # XXX: The following tests are no longer compatible with RFC3986
432 # self.checkJoin(SIMPLE_BASE, '../../../g','http://a/../g')
433 # self.checkJoin(SIMPLE_BASE, '/./g','http://a/./g')
434
Senthil Kumarana66e3882014-09-22 15:49:16 +0800435 # test for issue22118 duplicate slashes
436 self.checkJoin(SIMPLE_BASE + '/', 'foo', SIMPLE_BASE + '/foo')
437
438 # Non-RFC-defined tests, covering variations of base and trailing
439 # slashes
440 self.checkJoin('http://a/b/c/d/e/', '../../f/g/', 'http://a/b/c/f/g/')
441 self.checkJoin('http://a/b/c/d/e', '../../f/g/', 'http://a/b/f/g/')
442 self.checkJoin('http://a/b/c/d/e/', '/../../f/g/', 'http://a/f/g/')
443 self.checkJoin('http://a/b/c/d/e', '/../../f/g/', 'http://a/f/g/')
444 self.checkJoin('http://a/b/c/d/e/', '../../f/g', 'http://a/b/c/f/g')
445 self.checkJoin('http://a/b/', '../../f/g/', 'http://a/f/g/')
446
Berker Peksag20416f72015-04-16 02:31:14 +0300447 # issue 23703: don't duplicate filename
448 self.checkJoin('a', 'b', 'b')
449
Senthil Kumaranad02d232010-04-16 03:02:13 +0000450 def test_RFC2732(self):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000451 str_cases = [
Senthil Kumaranad02d232010-04-16 03:02:13 +0000452 ('http://Test.python.org:5432/foo/', 'test.python.org', 5432),
453 ('http://12.34.56.78:5432/foo/', '12.34.56.78', 5432),
454 ('http://[::1]:5432/foo/', '::1', 5432),
455 ('http://[dead:beef::1]:5432/foo/', 'dead:beef::1', 5432),
456 ('http://[dead:beef::]:5432/foo/', 'dead:beef::', 5432),
457 ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:5432/foo/',
458 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', 5432),
459 ('http://[::12.34.56.78]:5432/foo/', '::12.34.56.78', 5432),
460 ('http://[::ffff:12.34.56.78]:5432/foo/',
461 '::ffff:12.34.56.78', 5432),
462 ('http://Test.python.org/foo/', 'test.python.org', None),
463 ('http://12.34.56.78/foo/', '12.34.56.78', None),
464 ('http://[::1]/foo/', '::1', None),
465 ('http://[dead:beef::1]/foo/', 'dead:beef::1', None),
466 ('http://[dead:beef::]/foo/', 'dead:beef::', None),
467 ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/',
468 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', None),
469 ('http://[::12.34.56.78]/foo/', '::12.34.56.78', None),
470 ('http://[::ffff:12.34.56.78]/foo/',
471 '::ffff:12.34.56.78', None),
Serhiy Storchakaff97b082014-01-18 18:30:33 +0200472 ('http://Test.python.org:/foo/', 'test.python.org', None),
473 ('http://12.34.56.78:/foo/', '12.34.56.78', None),
474 ('http://[::1]:/foo/', '::1', None),
475 ('http://[dead:beef::1]:/foo/', 'dead:beef::1', None),
476 ('http://[dead:beef::]:/foo/', 'dead:beef::', None),
477 ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:/foo/',
478 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', None),
479 ('http://[::12.34.56.78]:/foo/', '::12.34.56.78', None),
480 ('http://[::ffff:12.34.56.78]:/foo/',
481 '::ffff:12.34.56.78', None),
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000482 ]
483 def _encode(t):
484 return t[0].encode('ascii'), t[1].encode('ascii'), t[2]
485 bytes_cases = [_encode(x) for x in str_cases]
486 for url, hostname, port in str_cases + bytes_cases:
Senthil Kumaranad02d232010-04-16 03:02:13 +0000487 urlparsed = urllib.parse.urlparse(url)
488 self.assertEqual((urlparsed.hostname, urlparsed.port) , (hostname, port))
489
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000490 str_cases = [
Senthil Kumaranad02d232010-04-16 03:02:13 +0000491 'http://::12.34.56.78]/',
492 'http://[::1/foo/',
Senthil Kumaran7a1e09f2010-04-22 12:19:46 +0000493 'ftp://[::1/foo/bad]/bad',
Senthil Kumaran2eaef052010-04-20 20:42:50 +0000494 'http://[::1/foo/bad]/bad',
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000495 'http://[::ffff:12.34.56.78']
496 bytes_cases = [x.encode('ascii') for x in str_cases]
497 for invalid_url in str_cases + bytes_cases:
Senthil Kumaran7a1e09f2010-04-22 12:19:46 +0000498 self.assertRaises(ValueError, urllib.parse.urlparse, invalid_url)
Senthil Kumaranad02d232010-04-16 03:02:13 +0000499
Fred Drake70705652002-10-16 21:02:36 +0000500 def test_urldefrag(self):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000501 str_cases = [
Fred Drake70705652002-10-16 21:02:36 +0000502 ('http://python.org#frag', 'http://python.org', 'frag'),
503 ('http://python.org', 'http://python.org', ''),
504 ('http://python.org/#frag', 'http://python.org/', 'frag'),
505 ('http://python.org/', 'http://python.org/', ''),
506 ('http://python.org/?q#frag', 'http://python.org/?q', 'frag'),
507 ('http://python.org/?q', 'http://python.org/?q', ''),
508 ('http://python.org/p#frag', 'http://python.org/p', 'frag'),
509 ('http://python.org/p?q', 'http://python.org/p?q', ''),
510 (RFC1808_BASE, 'http://a/b/c/d;p?q', 'f'),
511 (RFC2396_BASE, 'http://a/b/c/d;p?q', ''),
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000512 ]
513 def _encode(t):
514 return type(t)(x.encode('ascii') for x in t)
515 bytes_cases = [_encode(x) for x in str_cases]
516 for url, defrag, frag in str_cases + bytes_cases:
517 result = urllib.parse.urldefrag(url)
518 self.assertEqual(result.geturl(), url)
519 self.assertEqual(result, (defrag, frag))
520 self.assertEqual(result.url, defrag)
521 self.assertEqual(result.fragment, frag)
Fred Drake70705652002-10-16 21:02:36 +0000522
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000523 def test_urlsplit_attributes(self):
524 url = "HTTP://WWW.PYTHON.ORG/doc/#frag"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000525 p = urllib.parse.urlsplit(url)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000526 self.assertEqual(p.scheme, "http")
527 self.assertEqual(p.netloc, "WWW.PYTHON.ORG")
528 self.assertEqual(p.path, "/doc/")
529 self.assertEqual(p.query, "")
530 self.assertEqual(p.fragment, "frag")
531 self.assertEqual(p.username, None)
532 self.assertEqual(p.password, None)
533 self.assertEqual(p.hostname, "www.python.org")
534 self.assertEqual(p.port, None)
535 # geturl() won't return exactly the original URL in this case
536 # since the scheme is always case-normalized
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000537 # We handle this by ignoring the first 4 characters of the URL
538 self.assertEqual(p.geturl()[4:], url[4:])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000539
540 url = "http://User:Pass@www.python.org:080/doc/?query=yes#frag"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000541 p = urllib.parse.urlsplit(url)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000542 self.assertEqual(p.scheme, "http")
543 self.assertEqual(p.netloc, "User:Pass@www.python.org:080")
544 self.assertEqual(p.path, "/doc/")
545 self.assertEqual(p.query, "query=yes")
546 self.assertEqual(p.fragment, "frag")
547 self.assertEqual(p.username, "User")
548 self.assertEqual(p.password, "Pass")
549 self.assertEqual(p.hostname, "www.python.org")
550 self.assertEqual(p.port, 80)
551 self.assertEqual(p.geturl(), url)
552
Christian Heimesfaf2f632008-01-06 16:59:19 +0000553 # Addressing issue1698, which suggests Username can contain
554 # "@" characters. Though not RFC compliant, many ftp sites allow
555 # and request email addresses as usernames.
556
557 url = "http://User@example.com:Pass@www.python.org:080/doc/?query=yes#frag"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000558 p = urllib.parse.urlsplit(url)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000559 self.assertEqual(p.scheme, "http")
560 self.assertEqual(p.netloc, "User@example.com:Pass@www.python.org:080")
561 self.assertEqual(p.path, "/doc/")
562 self.assertEqual(p.query, "query=yes")
563 self.assertEqual(p.fragment, "frag")
564 self.assertEqual(p.username, "User@example.com")
565 self.assertEqual(p.password, "Pass")
566 self.assertEqual(p.hostname, "www.python.org")
567 self.assertEqual(p.port, 80)
568 self.assertEqual(p.geturl(), url)
569
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000570 # And check them all again, only with bytes this time
571 url = b"HTTP://WWW.PYTHON.ORG/doc/#frag"
572 p = urllib.parse.urlsplit(url)
573 self.assertEqual(p.scheme, b"http")
574 self.assertEqual(p.netloc, b"WWW.PYTHON.ORG")
575 self.assertEqual(p.path, b"/doc/")
576 self.assertEqual(p.query, b"")
577 self.assertEqual(p.fragment, b"frag")
578 self.assertEqual(p.username, None)
579 self.assertEqual(p.password, None)
580 self.assertEqual(p.hostname, b"www.python.org")
581 self.assertEqual(p.port, None)
582 self.assertEqual(p.geturl()[4:], url[4:])
583
584 url = b"http://User:Pass@www.python.org:080/doc/?query=yes#frag"
585 p = urllib.parse.urlsplit(url)
586 self.assertEqual(p.scheme, b"http")
587 self.assertEqual(p.netloc, b"User:Pass@www.python.org:080")
588 self.assertEqual(p.path, b"/doc/")
589 self.assertEqual(p.query, b"query=yes")
590 self.assertEqual(p.fragment, b"frag")
591 self.assertEqual(p.username, b"User")
592 self.assertEqual(p.password, b"Pass")
593 self.assertEqual(p.hostname, b"www.python.org")
594 self.assertEqual(p.port, 80)
595 self.assertEqual(p.geturl(), url)
596
597 url = b"http://User@example.com:Pass@www.python.org:080/doc/?query=yes#frag"
598 p = urllib.parse.urlsplit(url)
599 self.assertEqual(p.scheme, b"http")
600 self.assertEqual(p.netloc, b"User@example.com:Pass@www.python.org:080")
601 self.assertEqual(p.path, b"/doc/")
602 self.assertEqual(p.query, b"query=yes")
603 self.assertEqual(p.fragment, b"frag")
604 self.assertEqual(p.username, b"User@example.com")
605 self.assertEqual(p.password, b"Pass")
606 self.assertEqual(p.hostname, b"www.python.org")
607 self.assertEqual(p.port, 80)
608 self.assertEqual(p.geturl(), url)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000609
Robert Collinsdfa95c92015-08-10 09:53:30 +1200610 # Verify an illegal port raises ValueError
Senthil Kumaran2fc5a502012-05-24 21:56:17 +0800611 url = b"HTTP://WWW.PYTHON.ORG:65536/doc/#frag"
612 p = urllib.parse.urlsplit(url)
Robert Collinsdfa95c92015-08-10 09:53:30 +1200613 with self.assertRaisesRegex(ValueError, "out of range"):
614 p.port
Senthil Kumaran2fc5a502012-05-24 21:56:17 +0800615
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000616 def test_attributes_bad_port(self):
Robert Collinsdfa95c92015-08-10 09:53:30 +1200617 """Check handling of invalid ports."""
618 for bytes in (False, True):
619 for parse in (urllib.parse.urlsplit, urllib.parse.urlparse):
620 for port in ("foo", "1.5", "-1", "0x10"):
621 with self.subTest(bytes=bytes, parse=parse, port=port):
622 netloc = "www.example.net:" + port
623 url = "http://" + netloc
624 if bytes:
625 netloc = netloc.encode("ascii")
626 url = url.encode("ascii")
627 p = parse(url)
628 self.assertEqual(p.netloc, netloc)
629 with self.assertRaises(ValueError):
630 p.port
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000631
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000632 def test_attributes_without_netloc(self):
633 # This example is straight from RFC 3261. It looks like it
634 # should allow the username, hostname, and port to be filled
635 # in, but doesn't. Since it's a URI and doesn't use the
636 # scheme://netloc syntax, the netloc and related attributes
637 # should be left empty.
638 uri = "sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000639 p = urllib.parse.urlsplit(uri)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000640 self.assertEqual(p.netloc, "")
641 self.assertEqual(p.username, None)
642 self.assertEqual(p.password, None)
643 self.assertEqual(p.hostname, None)
644 self.assertEqual(p.port, None)
645 self.assertEqual(p.geturl(), uri)
646
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000647 p = urllib.parse.urlparse(uri)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000648 self.assertEqual(p.netloc, "")
649 self.assertEqual(p.username, None)
650 self.assertEqual(p.password, None)
651 self.assertEqual(p.hostname, None)
652 self.assertEqual(p.port, None)
653 self.assertEqual(p.geturl(), uri)
654
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000655 # You guessed it, repeating the test with bytes input
656 uri = b"sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15"
657 p = urllib.parse.urlsplit(uri)
658 self.assertEqual(p.netloc, b"")
659 self.assertEqual(p.username, None)
660 self.assertEqual(p.password, None)
661 self.assertEqual(p.hostname, None)
662 self.assertEqual(p.port, None)
663 self.assertEqual(p.geturl(), uri)
664
665 p = urllib.parse.urlparse(uri)
666 self.assertEqual(p.netloc, b"")
667 self.assertEqual(p.username, None)
668 self.assertEqual(p.password, None)
669 self.assertEqual(p.hostname, None)
670 self.assertEqual(p.port, None)
671 self.assertEqual(p.geturl(), uri)
672
Christian Heimesfaf2f632008-01-06 16:59:19 +0000673 def test_noslash(self):
674 # Issue 1637: http://foo.com?query is legal
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000675 self.assertEqual(urllib.parse.urlparse("http://example.com?blahblah=/foo"),
Christian Heimesfaf2f632008-01-06 16:59:19 +0000676 ('http', 'example.com', '', '', 'blahblah=/foo', ''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000677 self.assertEqual(urllib.parse.urlparse(b"http://example.com?blahblah=/foo"),
678 (b'http', b'example.com', b'', b'', b'blahblah=/foo', b''))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000679
Senthil Kumaran84c7d9f2010-08-04 04:50:44 +0000680 def test_withoutscheme(self):
681 # Test urlparse without scheme
682 # Issue 754016: urlparse goes wrong with IP:port without scheme
683 # RFC 1808 specifies that netloc should start with //, urlparse expects
684 # the same, otherwise it classifies the portion of url as path.
685 self.assertEqual(urllib.parse.urlparse("path"),
686 ('','','path','','',''))
687 self.assertEqual(urllib.parse.urlparse("//www.python.org:80"),
688 ('','www.python.org:80','','','',''))
689 self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"),
690 ('http','www.python.org:80','','','',''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000691 # Repeat for bytes input
692 self.assertEqual(urllib.parse.urlparse(b"path"),
693 (b'',b'',b'path',b'',b'',b''))
694 self.assertEqual(urllib.parse.urlparse(b"//www.python.org:80"),
695 (b'',b'www.python.org:80',b'',b'',b'',b''))
696 self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"),
697 (b'http',b'www.python.org:80',b'',b'',b'',b''))
Senthil Kumaran84c7d9f2010-08-04 04:50:44 +0000698
699 def test_portseparator(self):
700 # Issue 754016 makes changes for port separator ':' from scheme separator
701 self.assertEqual(urllib.parse.urlparse("path:80"),
702 ('','','path:80','','',''))
703 self.assertEqual(urllib.parse.urlparse("http:"),('http','','','','',''))
704 self.assertEqual(urllib.parse.urlparse("https:"),('https','','','','',''))
705 self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"),
706 ('http','www.python.org:80','','','',''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000707 # As usual, need to check bytes input as well
708 self.assertEqual(urllib.parse.urlparse(b"path:80"),
709 (b'',b'',b'path:80',b'',b'',b''))
710 self.assertEqual(urllib.parse.urlparse(b"http:"),(b'http',b'',b'',b'',b'',b''))
711 self.assertEqual(urllib.parse.urlparse(b"https:"),(b'https',b'',b'',b'',b'',b''))
712 self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"),
713 (b'http',b'www.python.org:80',b'',b'',b'',b''))
Senthil Kumaran84c7d9f2010-08-04 04:50:44 +0000714
Facundo Batista2ac5de22008-07-07 18:24:11 +0000715 def test_usingsys(self):
716 # Issue 3314: sys module is used in the error
717 self.assertRaises(TypeError, urllib.parse.urlencode, "foo")
718
Senthil Kumaran6be85c52010-02-19 07:42:50 +0000719 def test_anyscheme(self):
720 # Issue 7904: s3://foo.com/stuff has netloc "foo.com".
Ezio Melotti5e15efa2010-02-19 14:49:02 +0000721 self.assertEqual(urllib.parse.urlparse("s3://foo.com/stuff"),
722 ('s3', 'foo.com', '/stuff', '', '', ''))
723 self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff"),
724 ('x-newscheme', 'foo.com', '/stuff', '', '', ''))
Senthil Kumaran1be320e2012-05-19 08:12:00 +0800725 self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query#fragment"),
726 ('x-newscheme', 'foo.com', '/stuff', '', 'query', 'fragment'))
727 self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query"),
728 ('x-newscheme', 'foo.com', '/stuff', '', 'query', ''))
729
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000730 # And for bytes...
731 self.assertEqual(urllib.parse.urlparse(b"s3://foo.com/stuff"),
732 (b's3', b'foo.com', b'/stuff', b'', b'', b''))
733 self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff"),
734 (b'x-newscheme', b'foo.com', b'/stuff', b'', b'', b''))
Senthil Kumaran1be320e2012-05-19 08:12:00 +0800735 self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query#fragment"),
736 (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b'fragment'))
737 self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query"),
738 (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000739
Berker Peksag89584c92015-06-25 23:38:48 +0300740 def test_default_scheme(self):
741 # Exercise the scheme parameter of urlparse() and urlsplit()
742 for func in (urllib.parse.urlparse, urllib.parse.urlsplit):
743 with self.subTest(function=func):
744 result = func("http://example.net/", "ftp")
745 self.assertEqual(result.scheme, "http")
746 result = func(b"http://example.net/", b"ftp")
747 self.assertEqual(result.scheme, b"http")
748 self.assertEqual(func("path", "ftp").scheme, "ftp")
749 self.assertEqual(func("path", scheme="ftp").scheme, "ftp")
750 self.assertEqual(func(b"path", scheme=b"ftp").scheme, b"ftp")
751 self.assertEqual(func("path").scheme, "")
752 self.assertEqual(func(b"path").scheme, b"")
753 self.assertEqual(func(b"path", "").scheme, b"")
754
755 def test_parse_fragments(self):
756 # Exercise the allow_fragments parameter of urlparse() and urlsplit()
757 tests = (
postmasters90e01e52017-06-20 06:02:44 -0700758 ("http:#frag", "path", "frag"),
759 ("//example.net#frag", "path", "frag"),
760 ("index.html#frag", "path", "frag"),
761 (";a=b#frag", "params", "frag"),
762 ("?a=b#frag", "query", "frag"),
763 ("#frag", "path", "frag"),
764 ("abc#@frag", "path", "@frag"),
765 ("//abc#@frag", "path", "@frag"),
766 ("//abc:80#@frag", "path", "@frag"),
767 ("//abc#@frag:80", "path", "@frag:80"),
Berker Peksag89584c92015-06-25 23:38:48 +0300768 )
postmasters90e01e52017-06-20 06:02:44 -0700769 for url, attr, expected_frag in tests:
Berker Peksag89584c92015-06-25 23:38:48 +0300770 for func in (urllib.parse.urlparse, urllib.parse.urlsplit):
771 if attr == "params" and func is urllib.parse.urlsplit:
772 attr = "path"
773 with self.subTest(url=url, function=func):
774 result = func(url, allow_fragments=False)
775 self.assertEqual(result.fragment, "")
postmasters90e01e52017-06-20 06:02:44 -0700776 self.assertTrue(
777 getattr(result, attr).endswith("#" + expected_frag))
Berker Peksag89584c92015-06-25 23:38:48 +0300778 self.assertEqual(func(url, "", False).fragment, "")
779
780 result = func(url, allow_fragments=True)
postmasters90e01e52017-06-20 06:02:44 -0700781 self.assertEqual(result.fragment, expected_frag)
782 self.assertFalse(
783 getattr(result, attr).endswith(expected_frag))
784 self.assertEqual(func(url, "", True).fragment,
785 expected_frag)
786 self.assertEqual(func(url).fragment, expected_frag)
Berker Peksag89584c92015-06-25 23:38:48 +0300787
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000788 def test_mixed_types_rejected(self):
789 # Several functions that process either strings or ASCII encoded bytes
790 # accept multiple arguments. Check they reject mixed type input
Ezio Melottied3a7d22010-12-01 02:32:32 +0000791 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000792 urllib.parse.urlparse("www.python.org", b"http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000793 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000794 urllib.parse.urlparse(b"www.python.org", "http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000795 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000796 urllib.parse.urlsplit("www.python.org", b"http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000797 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000798 urllib.parse.urlsplit(b"www.python.org", "http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000799 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000800 urllib.parse.urlunparse(( b"http", "www.python.org","","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000801 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000802 urllib.parse.urlunparse(("http", b"www.python.org","","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000803 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000804 urllib.parse.urlunsplit((b"http", "www.python.org","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000805 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000806 urllib.parse.urlunsplit(("http", b"www.python.org","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000807 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000808 urllib.parse.urljoin("http://python.org", b"http://python.org")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000809 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000810 urllib.parse.urljoin(b"http://python.org", "http://python.org")
811
812 def _check_result_type(self, str_type):
813 num_args = len(str_type._fields)
814 bytes_type = str_type._encoded_counterpart
815 self.assertIs(bytes_type._decoded_counterpart, str_type)
816 str_args = ('',) * num_args
817 bytes_args = (b'',) * num_args
818 str_result = str_type(*str_args)
819 bytes_result = bytes_type(*bytes_args)
820 encoding = 'ascii'
821 errors = 'strict'
822 self.assertEqual(str_result, str_args)
823 self.assertEqual(bytes_result.decode(), str_args)
824 self.assertEqual(bytes_result.decode(), str_result)
825 self.assertEqual(bytes_result.decode(encoding), str_args)
826 self.assertEqual(bytes_result.decode(encoding), str_result)
827 self.assertEqual(bytes_result.decode(encoding, errors), str_args)
828 self.assertEqual(bytes_result.decode(encoding, errors), str_result)
829 self.assertEqual(bytes_result, bytes_args)
830 self.assertEqual(str_result.encode(), bytes_args)
831 self.assertEqual(str_result.encode(), bytes_result)
832 self.assertEqual(str_result.encode(encoding), bytes_args)
833 self.assertEqual(str_result.encode(encoding), bytes_result)
834 self.assertEqual(str_result.encode(encoding, errors), bytes_args)
835 self.assertEqual(str_result.encode(encoding, errors), bytes_result)
836
837 def test_result_pairs(self):
838 # Check encoding and decoding between result pairs
839 result_types = [
840 urllib.parse.DefragResult,
841 urllib.parse.SplitResult,
842 urllib.parse.ParseResult,
843 ]
844 for result_type in result_types:
845 self._check_result_type(result_type)
846
Victor Stinner1d87deb2011-01-14 13:05:19 +0000847 def test_parse_qs_encoding(self):
848 result = urllib.parse.parse_qs("key=\u0141%E9", encoding="latin-1")
849 self.assertEqual(result, {'key': ['\u0141\xE9']})
850 result = urllib.parse.parse_qs("key=\u0141%C3%A9", encoding="utf-8")
851 self.assertEqual(result, {'key': ['\u0141\xE9']})
852 result = urllib.parse.parse_qs("key=\u0141%C3%A9", encoding="ascii")
853 self.assertEqual(result, {'key': ['\u0141\ufffd\ufffd']})
854 result = urllib.parse.parse_qs("key=\u0141%E9-", encoding="ascii")
855 self.assertEqual(result, {'key': ['\u0141\ufffd-']})
856 result = urllib.parse.parse_qs("key=\u0141%E9-", encoding="ascii",
857 errors="ignore")
858 self.assertEqual(result, {'key': ['\u0141-']})
859
860 def test_parse_qsl_encoding(self):
861 result = urllib.parse.parse_qsl("key=\u0141%E9", encoding="latin-1")
862 self.assertEqual(result, [('key', '\u0141\xE9')])
863 result = urllib.parse.parse_qsl("key=\u0141%C3%A9", encoding="utf-8")
864 self.assertEqual(result, [('key', '\u0141\xE9')])
865 result = urllib.parse.parse_qsl("key=\u0141%C3%A9", encoding="ascii")
866 self.assertEqual(result, [('key', '\u0141\ufffd\ufffd')])
867 result = urllib.parse.parse_qsl("key=\u0141%E9-", encoding="ascii")
868 self.assertEqual(result, [('key', '\u0141\ufffd-')])
869 result = urllib.parse.parse_qsl("key=\u0141%E9-", encoding="ascii",
870 errors="ignore")
871 self.assertEqual(result, [('key', '\u0141-')])
872
Senthil Kumarande02a712011-07-23 18:27:45 +0800873 def test_urlencode_sequences(self):
874 # Other tests incidentally urlencode things; test non-covered cases:
875 # Sequence and object values.
876 result = urllib.parse.urlencode({'a': [1, 2], 'b': (3, 4, 5)}, True)
Georg Brandl09a7c722012-02-20 21:31:46 +0100877 # we cannot rely on ordering here
878 assert set(result.split('&')) == {'a=1', 'a=2', 'b=3', 'b=4', 'b=5'}
Senthil Kumarande02a712011-07-23 18:27:45 +0800879
880 class Trivial:
881 def __str__(self):
882 return 'trivial'
883
884 result = urllib.parse.urlencode({'a': Trivial()}, True)
885 self.assertEqual(result, 'a=trivial')
886
R David Murrayc17686f2015-05-17 20:44:50 -0400887 def test_urlencode_quote_via(self):
888 result = urllib.parse.urlencode({'a': 'some value'})
889 self.assertEqual(result, "a=some+value")
890 result = urllib.parse.urlencode({'a': 'some value/another'},
891 quote_via=urllib.parse.quote)
892 self.assertEqual(result, "a=some%20value%2Fanother")
893 result = urllib.parse.urlencode({'a': 'some value/another'},
894 safe='/', quote_via=urllib.parse.quote)
895 self.assertEqual(result, "a=some%20value/another")
896
Senthil Kumarande02a712011-07-23 18:27:45 +0800897 def test_quote_from_bytes(self):
898 self.assertRaises(TypeError, urllib.parse.quote_from_bytes, 'foo')
899 result = urllib.parse.quote_from_bytes(b'archaeological arcana')
900 self.assertEqual(result, 'archaeological%20arcana')
901 result = urllib.parse.quote_from_bytes(b'')
902 self.assertEqual(result, '')
903
904 def test_unquote_to_bytes(self):
905 result = urllib.parse.unquote_to_bytes('abc%20def')
906 self.assertEqual(result, b'abc def')
907 result = urllib.parse.unquote_to_bytes('')
908 self.assertEqual(result, b'')
909
910 def test_quote_errors(self):
911 self.assertRaises(TypeError, urllib.parse.quote, b'foo',
912 encoding='utf-8')
913 self.assertRaises(TypeError, urllib.parse.quote, b'foo', errors='strict')
Victor Stinner1d87deb2011-01-14 13:05:19 +0000914
Ezio Melotti6709b7d2012-05-19 17:15:19 +0300915 def test_issue14072(self):
916 p1 = urllib.parse.urlsplit('tel:+31-641044153')
917 self.assertEqual(p1.scheme, 'tel')
918 self.assertEqual(p1.path, '+31-641044153')
919 p2 = urllib.parse.urlsplit('tel:+31641044153')
920 self.assertEqual(p2.scheme, 'tel')
921 self.assertEqual(p2.path, '+31641044153')
Senthil Kumaraned301992012-12-24 14:00:20 -0800922 # assert the behavior for urlparse
923 p1 = urllib.parse.urlparse('tel:+31-641044153')
924 self.assertEqual(p1.scheme, 'tel')
925 self.assertEqual(p1.path, '+31-641044153')
926 p2 = urllib.parse.urlparse('tel:+31641044153')
927 self.assertEqual(p2.scheme, 'tel')
928 self.assertEqual(p2.path, '+31641044153')
929
930 def test_telurl_params(self):
931 p1 = urllib.parse.urlparse('tel:123-4;phone-context=+1-650-516')
932 self.assertEqual(p1.scheme, 'tel')
933 self.assertEqual(p1.path, '123-4')
934 self.assertEqual(p1.params, 'phone-context=+1-650-516')
935
936 p1 = urllib.parse.urlparse('tel:+1-201-555-0123')
937 self.assertEqual(p1.scheme, 'tel')
938 self.assertEqual(p1.path, '+1-201-555-0123')
939 self.assertEqual(p1.params, '')
940
941 p1 = urllib.parse.urlparse('tel:7042;phone-context=example.com')
942 self.assertEqual(p1.scheme, 'tel')
943 self.assertEqual(p1.path, '7042')
944 self.assertEqual(p1.params, 'phone-context=example.com')
945
946 p1 = urllib.parse.urlparse('tel:863-1234;phone-context=+1-914-555')
947 self.assertEqual(p1.scheme, 'tel')
948 self.assertEqual(p1.path, '863-1234')
949 self.assertEqual(p1.params, 'phone-context=+1-914-555')
950
R David Murrayf5163882013-03-21 20:56:51 -0400951 def test_Quoter_repr(self):
952 quoter = urllib.parse.Quoter(urllib.parse._ALWAYS_SAFE)
953 self.assertIn('Quoter', repr(quoter))
954
Serhiy Storchaka15154502015-04-07 19:09:01 +0300955 def test_all(self):
956 expected = []
957 undocumented = {
958 'splitattr', 'splithost', 'splitnport', 'splitpasswd',
959 'splitport', 'splitquery', 'splittag', 'splittype', 'splituser',
960 'splitvalue',
961 'Quoter', 'ResultBase', 'clear_cache', 'to_bytes', 'unwrap',
962 }
963 for name in dir(urllib.parse):
964 if name.startswith('_') or name in undocumented:
965 continue
966 object = getattr(urllib.parse, name)
967 if getattr(object, '__module__', None) == 'urllib.parse':
968 expected.append(name)
969 self.assertCountEqual(urllib.parse.__all__, expected)
970
Senthil Kumaran6be85c52010-02-19 07:42:50 +0000971
Serhiy Storchaka9270be72015-03-02 16:32:29 +0200972class Utility_Tests(unittest.TestCase):
973 """Testcase to test the various utility functions in the urllib."""
974 # In Python 2 this test class was in test_urllib.
975
976 def test_splittype(self):
977 splittype = urllib.parse.splittype
978 self.assertEqual(splittype('type:opaquestring'), ('type', 'opaquestring'))
979 self.assertEqual(splittype('opaquestring'), (None, 'opaquestring'))
980 self.assertEqual(splittype(':opaquestring'), (None, ':opaquestring'))
981 self.assertEqual(splittype('type:'), ('type', ''))
982 self.assertEqual(splittype('type:opaque:string'), ('type', 'opaque:string'))
983
984 def test_splithost(self):
985 splithost = urllib.parse.splithost
986 self.assertEqual(splithost('//www.example.org:80/foo/bar/baz.html'),
987 ('www.example.org:80', '/foo/bar/baz.html'))
988 self.assertEqual(splithost('//www.example.org:80'),
989 ('www.example.org:80', ''))
990 self.assertEqual(splithost('/foo/bar/baz.html'),
991 (None, '/foo/bar/baz.html'))
992
postmasters90e01e52017-06-20 06:02:44 -0700993 # bpo-30500: # starts a fragment.
994 self.assertEqual(splithost('//127.0.0.1#@host.com'),
995 ('127.0.0.1', '/#@host.com'))
996 self.assertEqual(splithost('//127.0.0.1#@host.com:80'),
997 ('127.0.0.1', '/#@host.com:80'))
998 self.assertEqual(splithost('//127.0.0.1:80#@host.com'),
999 ('127.0.0.1:80', '/#@host.com'))
1000
1001 # Empty host is returned as empty string.
1002 self.assertEqual(splithost("///file"),
1003 ('', '/file'))
1004
1005 # Trailing semicolon, question mark and hash symbol are kept.
1006 self.assertEqual(splithost("//example.net/file;"),
1007 ('example.net', '/file;'))
1008 self.assertEqual(splithost("//example.net/file?"),
1009 ('example.net', '/file?'))
1010 self.assertEqual(splithost("//example.net/file#"),
1011 ('example.net', '/file#'))
1012
Serhiy Storchaka9270be72015-03-02 16:32:29 +02001013 def test_splituser(self):
1014 splituser = urllib.parse.splituser
1015 self.assertEqual(splituser('User:Pass@www.python.org:080'),
1016 ('User:Pass', 'www.python.org:080'))
1017 self.assertEqual(splituser('@www.python.org:080'),
1018 ('', 'www.python.org:080'))
1019 self.assertEqual(splituser('www.python.org:080'),
1020 (None, 'www.python.org:080'))
1021 self.assertEqual(splituser('User:Pass@'),
1022 ('User:Pass', ''))
1023 self.assertEqual(splituser('User@example.com:Pass@www.python.org:080'),
1024 ('User@example.com:Pass', 'www.python.org:080'))
1025
1026 def test_splitpasswd(self):
1027 # Some of the password examples are not sensible, but it is added to
1028 # confirming to RFC2617 and addressing issue4675.
1029 splitpasswd = urllib.parse.splitpasswd
1030 self.assertEqual(splitpasswd('user:ab'), ('user', 'ab'))
1031 self.assertEqual(splitpasswd('user:a\nb'), ('user', 'a\nb'))
1032 self.assertEqual(splitpasswd('user:a\tb'), ('user', 'a\tb'))
1033 self.assertEqual(splitpasswd('user:a\rb'), ('user', 'a\rb'))
1034 self.assertEqual(splitpasswd('user:a\fb'), ('user', 'a\fb'))
1035 self.assertEqual(splitpasswd('user:a\vb'), ('user', 'a\vb'))
1036 self.assertEqual(splitpasswd('user:a:b'), ('user', 'a:b'))
1037 self.assertEqual(splitpasswd('user:a b'), ('user', 'a b'))
1038 self.assertEqual(splitpasswd('user 2:ab'), ('user 2', 'ab'))
1039 self.assertEqual(splitpasswd('user+1:a+b'), ('user+1', 'a+b'))
1040 self.assertEqual(splitpasswd('user:'), ('user', ''))
1041 self.assertEqual(splitpasswd('user'), ('user', None))
1042 self.assertEqual(splitpasswd(':ab'), ('', 'ab'))
1043
1044 def test_splitport(self):
1045 splitport = urllib.parse.splitport
1046 self.assertEqual(splitport('parrot:88'), ('parrot', '88'))
1047 self.assertEqual(splitport('parrot'), ('parrot', None))
1048 self.assertEqual(splitport('parrot:'), ('parrot', None))
1049 self.assertEqual(splitport('127.0.0.1'), ('127.0.0.1', None))
1050 self.assertEqual(splitport('parrot:cheese'), ('parrot:cheese', None))
1051 self.assertEqual(splitport('[::1]:88'), ('[::1]', '88'))
1052 self.assertEqual(splitport('[::1]'), ('[::1]', None))
1053 self.assertEqual(splitport(':88'), ('', '88'))
1054
1055 def test_splitnport(self):
1056 splitnport = urllib.parse.splitnport
1057 self.assertEqual(splitnport('parrot:88'), ('parrot', 88))
1058 self.assertEqual(splitnport('parrot'), ('parrot', -1))
1059 self.assertEqual(splitnport('parrot', 55), ('parrot', 55))
1060 self.assertEqual(splitnport('parrot:'), ('parrot', -1))
1061 self.assertEqual(splitnport('parrot:', 55), ('parrot', 55))
1062 self.assertEqual(splitnport('127.0.0.1'), ('127.0.0.1', -1))
1063 self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55))
1064 self.assertEqual(splitnport('parrot:cheese'), ('parrot', None))
1065 self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None))
1066
1067 def test_splitquery(self):
1068 # Normal cases are exercised by other tests; ensure that we also
1069 # catch cases with no port specified (testcase ensuring coverage)
1070 splitquery = urllib.parse.splitquery
1071 self.assertEqual(splitquery('http://python.org/fake?foo=bar'),
1072 ('http://python.org/fake', 'foo=bar'))
1073 self.assertEqual(splitquery('http://python.org/fake?foo=bar?'),
1074 ('http://python.org/fake?foo=bar', ''))
1075 self.assertEqual(splitquery('http://python.org/fake'),
1076 ('http://python.org/fake', None))
1077 self.assertEqual(splitquery('?foo=bar'), ('', 'foo=bar'))
1078
1079 def test_splittag(self):
1080 splittag = urllib.parse.splittag
1081 self.assertEqual(splittag('http://example.com?foo=bar#baz'),
1082 ('http://example.com?foo=bar', 'baz'))
1083 self.assertEqual(splittag('http://example.com?foo=bar#'),
1084 ('http://example.com?foo=bar', ''))
1085 self.assertEqual(splittag('#baz'), ('', 'baz'))
1086 self.assertEqual(splittag('http://example.com?foo=bar'),
1087 ('http://example.com?foo=bar', None))
1088 self.assertEqual(splittag('http://example.com?foo=bar#baz#boo'),
1089 ('http://example.com?foo=bar#baz', 'boo'))
1090
1091 def test_splitattr(self):
1092 splitattr = urllib.parse.splitattr
1093 self.assertEqual(splitattr('/path;attr1=value1;attr2=value2'),
1094 ('/path', ['attr1=value1', 'attr2=value2']))
1095 self.assertEqual(splitattr('/path;'), ('/path', ['']))
1096 self.assertEqual(splitattr(';attr1=value1;attr2=value2'),
1097 ('', ['attr1=value1', 'attr2=value2']))
1098 self.assertEqual(splitattr('/path'), ('/path', []))
1099
1100 def test_splitvalue(self):
1101 # Normal cases are exercised by other tests; test pathological cases
1102 # with no key/value pairs. (testcase ensuring coverage)
1103 splitvalue = urllib.parse.splitvalue
1104 self.assertEqual(splitvalue('foo=bar'), ('foo', 'bar'))
1105 self.assertEqual(splitvalue('foo='), ('foo', ''))
1106 self.assertEqual(splitvalue('=bar'), ('', 'bar'))
1107 self.assertEqual(splitvalue('foobar'), ('foobar', None))
1108 self.assertEqual(splitvalue('foo=bar=baz'), ('foo', 'bar=baz'))
1109
1110 def test_to_bytes(self):
1111 result = urllib.parse.to_bytes('http://www.python.org')
1112 self.assertEqual(result, 'http://www.python.org')
1113 self.assertRaises(UnicodeError, urllib.parse.to_bytes,
1114 'http://www.python.org/medi\u00e6val')
1115
1116 def test_unwrap(self):
1117 url = urllib.parse.unwrap('<URL:type://host/path>')
1118 self.assertEqual(url, 'type://host/path')
1119
Skip Montanaro6ec967d2002-03-23 05:32:10 +00001120
1121if __name__ == "__main__":
Serhiy Storchaka9270be72015-03-02 16:32:29 +02001122 unittest.main()