blob: ddee1c38d8b4f0c5493c6bb0d81ba87b9b350977 [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
Коренберг Маркfbd60512017-12-21 17:16:17 +0500523 def test_urlsplit_scoped_IPv6(self):
524 p = urllib.parse.urlsplit('http://[FE80::822a:a8ff:fe49:470c%tESt]:1234')
525 self.assertEqual(p.hostname, "fe80::822a:a8ff:fe49:470c%tESt")
526 self.assertEqual(p.netloc, '[FE80::822a:a8ff:fe49:470c%tESt]:1234')
527
528 p = urllib.parse.urlsplit(b'http://[FE80::822a:a8ff:fe49:470c%tESt]:1234')
529 self.assertEqual(p.hostname, b"fe80::822a:a8ff:fe49:470c%tESt")
530 self.assertEqual(p.netloc, b'[FE80::822a:a8ff:fe49:470c%tESt]:1234')
531
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000532 def test_urlsplit_attributes(self):
533 url = "HTTP://WWW.PYTHON.ORG/doc/#frag"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000534 p = urllib.parse.urlsplit(url)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000535 self.assertEqual(p.scheme, "http")
536 self.assertEqual(p.netloc, "WWW.PYTHON.ORG")
537 self.assertEqual(p.path, "/doc/")
538 self.assertEqual(p.query, "")
539 self.assertEqual(p.fragment, "frag")
540 self.assertEqual(p.username, None)
541 self.assertEqual(p.password, None)
542 self.assertEqual(p.hostname, "www.python.org")
543 self.assertEqual(p.port, None)
544 # geturl() won't return exactly the original URL in this case
545 # since the scheme is always case-normalized
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000546 # We handle this by ignoring the first 4 characters of the URL
547 self.assertEqual(p.geturl()[4:], url[4:])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000548
549 url = "http://User:Pass@www.python.org:080/doc/?query=yes#frag"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000550 p = urllib.parse.urlsplit(url)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000551 self.assertEqual(p.scheme, "http")
552 self.assertEqual(p.netloc, "User:Pass@www.python.org:080")
553 self.assertEqual(p.path, "/doc/")
554 self.assertEqual(p.query, "query=yes")
555 self.assertEqual(p.fragment, "frag")
556 self.assertEqual(p.username, "User")
557 self.assertEqual(p.password, "Pass")
558 self.assertEqual(p.hostname, "www.python.org")
559 self.assertEqual(p.port, 80)
560 self.assertEqual(p.geturl(), url)
561
Christian Heimesfaf2f632008-01-06 16:59:19 +0000562 # Addressing issue1698, which suggests Username can contain
563 # "@" characters. Though not RFC compliant, many ftp sites allow
564 # and request email addresses as usernames.
565
566 url = "http://User@example.com:Pass@www.python.org:080/doc/?query=yes#frag"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000567 p = urllib.parse.urlsplit(url)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000568 self.assertEqual(p.scheme, "http")
569 self.assertEqual(p.netloc, "User@example.com:Pass@www.python.org:080")
570 self.assertEqual(p.path, "/doc/")
571 self.assertEqual(p.query, "query=yes")
572 self.assertEqual(p.fragment, "frag")
573 self.assertEqual(p.username, "User@example.com")
574 self.assertEqual(p.password, "Pass")
575 self.assertEqual(p.hostname, "www.python.org")
576 self.assertEqual(p.port, 80)
577 self.assertEqual(p.geturl(), url)
578
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000579 # And check them all again, only with bytes this time
580 url = b"HTTP://WWW.PYTHON.ORG/doc/#frag"
581 p = urllib.parse.urlsplit(url)
582 self.assertEqual(p.scheme, b"http")
583 self.assertEqual(p.netloc, b"WWW.PYTHON.ORG")
584 self.assertEqual(p.path, b"/doc/")
585 self.assertEqual(p.query, b"")
586 self.assertEqual(p.fragment, b"frag")
587 self.assertEqual(p.username, None)
588 self.assertEqual(p.password, None)
589 self.assertEqual(p.hostname, b"www.python.org")
590 self.assertEqual(p.port, None)
591 self.assertEqual(p.geturl()[4:], url[4:])
592
593 url = b"http://User:Pass@www.python.org:080/doc/?query=yes#frag"
594 p = urllib.parse.urlsplit(url)
595 self.assertEqual(p.scheme, b"http")
596 self.assertEqual(p.netloc, b"User:Pass@www.python.org:080")
597 self.assertEqual(p.path, b"/doc/")
598 self.assertEqual(p.query, b"query=yes")
599 self.assertEqual(p.fragment, b"frag")
600 self.assertEqual(p.username, b"User")
601 self.assertEqual(p.password, b"Pass")
602 self.assertEqual(p.hostname, b"www.python.org")
603 self.assertEqual(p.port, 80)
604 self.assertEqual(p.geturl(), url)
605
606 url = b"http://User@example.com:Pass@www.python.org:080/doc/?query=yes#frag"
607 p = urllib.parse.urlsplit(url)
608 self.assertEqual(p.scheme, b"http")
609 self.assertEqual(p.netloc, b"User@example.com:Pass@www.python.org:080")
610 self.assertEqual(p.path, b"/doc/")
611 self.assertEqual(p.query, b"query=yes")
612 self.assertEqual(p.fragment, b"frag")
613 self.assertEqual(p.username, b"User@example.com")
614 self.assertEqual(p.password, b"Pass")
615 self.assertEqual(p.hostname, b"www.python.org")
616 self.assertEqual(p.port, 80)
617 self.assertEqual(p.geturl(), url)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000618
Robert Collinsdfa95c92015-08-10 09:53:30 +1200619 # Verify an illegal port raises ValueError
Senthil Kumaran2fc5a502012-05-24 21:56:17 +0800620 url = b"HTTP://WWW.PYTHON.ORG:65536/doc/#frag"
621 p = urllib.parse.urlsplit(url)
Robert Collinsdfa95c92015-08-10 09:53:30 +1200622 with self.assertRaisesRegex(ValueError, "out of range"):
623 p.port
Senthil Kumaran2fc5a502012-05-24 21:56:17 +0800624
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000625 def test_attributes_bad_port(self):
Robert Collinsdfa95c92015-08-10 09:53:30 +1200626 """Check handling of invalid ports."""
627 for bytes in (False, True):
628 for parse in (urllib.parse.urlsplit, urllib.parse.urlparse):
629 for port in ("foo", "1.5", "-1", "0x10"):
630 with self.subTest(bytes=bytes, parse=parse, port=port):
631 netloc = "www.example.net:" + port
632 url = "http://" + netloc
633 if bytes:
634 netloc = netloc.encode("ascii")
635 url = url.encode("ascii")
636 p = parse(url)
637 self.assertEqual(p.netloc, netloc)
638 with self.assertRaises(ValueError):
639 p.port
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000640
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000641 def test_attributes_without_netloc(self):
642 # This example is straight from RFC 3261. It looks like it
643 # should allow the username, hostname, and port to be filled
644 # in, but doesn't. Since it's a URI and doesn't use the
645 # scheme://netloc syntax, the netloc and related attributes
646 # should be left empty.
647 uri = "sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000648 p = urllib.parse.urlsplit(uri)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000649 self.assertEqual(p.netloc, "")
650 self.assertEqual(p.username, None)
651 self.assertEqual(p.password, None)
652 self.assertEqual(p.hostname, None)
653 self.assertEqual(p.port, None)
654 self.assertEqual(p.geturl(), uri)
655
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000656 p = urllib.parse.urlparse(uri)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000657 self.assertEqual(p.netloc, "")
658 self.assertEqual(p.username, None)
659 self.assertEqual(p.password, None)
660 self.assertEqual(p.hostname, None)
661 self.assertEqual(p.port, None)
662 self.assertEqual(p.geturl(), uri)
663
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000664 # You guessed it, repeating the test with bytes input
665 uri = b"sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15"
666 p = urllib.parse.urlsplit(uri)
667 self.assertEqual(p.netloc, b"")
668 self.assertEqual(p.username, None)
669 self.assertEqual(p.password, None)
670 self.assertEqual(p.hostname, None)
671 self.assertEqual(p.port, None)
672 self.assertEqual(p.geturl(), uri)
673
674 p = urllib.parse.urlparse(uri)
675 self.assertEqual(p.netloc, b"")
676 self.assertEqual(p.username, None)
677 self.assertEqual(p.password, None)
678 self.assertEqual(p.hostname, None)
679 self.assertEqual(p.port, None)
680 self.assertEqual(p.geturl(), uri)
681
Christian Heimesfaf2f632008-01-06 16:59:19 +0000682 def test_noslash(self):
683 # Issue 1637: http://foo.com?query is legal
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000684 self.assertEqual(urllib.parse.urlparse("http://example.com?blahblah=/foo"),
Christian Heimesfaf2f632008-01-06 16:59:19 +0000685 ('http', 'example.com', '', '', 'blahblah=/foo', ''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000686 self.assertEqual(urllib.parse.urlparse(b"http://example.com?blahblah=/foo"),
687 (b'http', b'example.com', b'', b'', b'blahblah=/foo', b''))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000688
Senthil Kumaran84c7d9f2010-08-04 04:50:44 +0000689 def test_withoutscheme(self):
690 # Test urlparse without scheme
691 # Issue 754016: urlparse goes wrong with IP:port without scheme
692 # RFC 1808 specifies that netloc should start with //, urlparse expects
693 # the same, otherwise it classifies the portion of url as path.
694 self.assertEqual(urllib.parse.urlparse("path"),
695 ('','','path','','',''))
696 self.assertEqual(urllib.parse.urlparse("//www.python.org:80"),
697 ('','www.python.org:80','','','',''))
698 self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"),
699 ('http','www.python.org:80','','','',''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000700 # Repeat for bytes input
701 self.assertEqual(urllib.parse.urlparse(b"path"),
702 (b'',b'',b'path',b'',b'',b''))
703 self.assertEqual(urllib.parse.urlparse(b"//www.python.org:80"),
704 (b'',b'www.python.org:80',b'',b'',b'',b''))
705 self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"),
706 (b'http',b'www.python.org:80',b'',b'',b'',b''))
Senthil Kumaran84c7d9f2010-08-04 04:50:44 +0000707
708 def test_portseparator(self):
709 # Issue 754016 makes changes for port separator ':' from scheme separator
710 self.assertEqual(urllib.parse.urlparse("path:80"),
711 ('','','path:80','','',''))
712 self.assertEqual(urllib.parse.urlparse("http:"),('http','','','','',''))
713 self.assertEqual(urllib.parse.urlparse("https:"),('https','','','','',''))
714 self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"),
715 ('http','www.python.org:80','','','',''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000716 # As usual, need to check bytes input as well
717 self.assertEqual(urllib.parse.urlparse(b"path:80"),
718 (b'',b'',b'path:80',b'',b'',b''))
719 self.assertEqual(urllib.parse.urlparse(b"http:"),(b'http',b'',b'',b'',b'',b''))
720 self.assertEqual(urllib.parse.urlparse(b"https:"),(b'https',b'',b'',b'',b'',b''))
721 self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"),
722 (b'http',b'www.python.org:80',b'',b'',b'',b''))
Senthil Kumaran84c7d9f2010-08-04 04:50:44 +0000723
Facundo Batista2ac5de22008-07-07 18:24:11 +0000724 def test_usingsys(self):
725 # Issue 3314: sys module is used in the error
726 self.assertRaises(TypeError, urllib.parse.urlencode, "foo")
727
Senthil Kumaran6be85c52010-02-19 07:42:50 +0000728 def test_anyscheme(self):
729 # Issue 7904: s3://foo.com/stuff has netloc "foo.com".
Ezio Melotti5e15efa2010-02-19 14:49:02 +0000730 self.assertEqual(urllib.parse.urlparse("s3://foo.com/stuff"),
731 ('s3', 'foo.com', '/stuff', '', '', ''))
732 self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff"),
733 ('x-newscheme', 'foo.com', '/stuff', '', '', ''))
Senthil Kumaran1be320e2012-05-19 08:12:00 +0800734 self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query#fragment"),
735 ('x-newscheme', 'foo.com', '/stuff', '', 'query', 'fragment'))
736 self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query"),
737 ('x-newscheme', 'foo.com', '/stuff', '', 'query', ''))
738
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000739 # And for bytes...
740 self.assertEqual(urllib.parse.urlparse(b"s3://foo.com/stuff"),
741 (b's3', b'foo.com', b'/stuff', b'', b'', b''))
742 self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff"),
743 (b'x-newscheme', b'foo.com', b'/stuff', b'', b'', b''))
Senthil Kumaran1be320e2012-05-19 08:12:00 +0800744 self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query#fragment"),
745 (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b'fragment'))
746 self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query"),
747 (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b''))
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000748
Berker Peksag89584c92015-06-25 23:38:48 +0300749 def test_default_scheme(self):
750 # Exercise the scheme parameter of urlparse() and urlsplit()
751 for func in (urllib.parse.urlparse, urllib.parse.urlsplit):
752 with self.subTest(function=func):
753 result = func("http://example.net/", "ftp")
754 self.assertEqual(result.scheme, "http")
755 result = func(b"http://example.net/", b"ftp")
756 self.assertEqual(result.scheme, b"http")
757 self.assertEqual(func("path", "ftp").scheme, "ftp")
758 self.assertEqual(func("path", scheme="ftp").scheme, "ftp")
759 self.assertEqual(func(b"path", scheme=b"ftp").scheme, b"ftp")
760 self.assertEqual(func("path").scheme, "")
761 self.assertEqual(func(b"path").scheme, b"")
762 self.assertEqual(func(b"path", "").scheme, b"")
763
764 def test_parse_fragments(self):
765 # Exercise the allow_fragments parameter of urlparse() and urlsplit()
766 tests = (
postmasters90e01e52017-06-20 06:02:44 -0700767 ("http:#frag", "path", "frag"),
768 ("//example.net#frag", "path", "frag"),
769 ("index.html#frag", "path", "frag"),
770 (";a=b#frag", "params", "frag"),
771 ("?a=b#frag", "query", "frag"),
772 ("#frag", "path", "frag"),
773 ("abc#@frag", "path", "@frag"),
774 ("//abc#@frag", "path", "@frag"),
775 ("//abc:80#@frag", "path", "@frag"),
776 ("//abc#@frag:80", "path", "@frag:80"),
Berker Peksag89584c92015-06-25 23:38:48 +0300777 )
postmasters90e01e52017-06-20 06:02:44 -0700778 for url, attr, expected_frag in tests:
Berker Peksag89584c92015-06-25 23:38:48 +0300779 for func in (urllib.parse.urlparse, urllib.parse.urlsplit):
780 if attr == "params" and func is urllib.parse.urlsplit:
781 attr = "path"
782 with self.subTest(url=url, function=func):
783 result = func(url, allow_fragments=False)
784 self.assertEqual(result.fragment, "")
postmasters90e01e52017-06-20 06:02:44 -0700785 self.assertTrue(
786 getattr(result, attr).endswith("#" + expected_frag))
Berker Peksag89584c92015-06-25 23:38:48 +0300787 self.assertEqual(func(url, "", False).fragment, "")
788
789 result = func(url, allow_fragments=True)
postmasters90e01e52017-06-20 06:02:44 -0700790 self.assertEqual(result.fragment, expected_frag)
791 self.assertFalse(
792 getattr(result, attr).endswith(expected_frag))
793 self.assertEqual(func(url, "", True).fragment,
794 expected_frag)
795 self.assertEqual(func(url).fragment, expected_frag)
Berker Peksag89584c92015-06-25 23:38:48 +0300796
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000797 def test_mixed_types_rejected(self):
798 # Several functions that process either strings or ASCII encoded bytes
799 # accept multiple arguments. Check they reject mixed type input
Ezio Melottied3a7d22010-12-01 02:32:32 +0000800 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000801 urllib.parse.urlparse("www.python.org", b"http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000802 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000803 urllib.parse.urlparse(b"www.python.org", "http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000804 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000805 urllib.parse.urlsplit("www.python.org", b"http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000806 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000807 urllib.parse.urlsplit(b"www.python.org", "http")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000808 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000809 urllib.parse.urlunparse(( b"http", "www.python.org","","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000810 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000811 urllib.parse.urlunparse(("http", b"www.python.org","","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000812 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000813 urllib.parse.urlunsplit((b"http", "www.python.org","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000814 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000815 urllib.parse.urlunsplit(("http", b"www.python.org","","",""))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000816 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000817 urllib.parse.urljoin("http://python.org", b"http://python.org")
Ezio Melottied3a7d22010-12-01 02:32:32 +0000818 with self.assertRaisesRegex(TypeError, "Cannot mix str"):
Nick Coghlan9fc443c2010-11-30 15:48:08 +0000819 urllib.parse.urljoin(b"http://python.org", "http://python.org")
820
821 def _check_result_type(self, str_type):
822 num_args = len(str_type._fields)
823 bytes_type = str_type._encoded_counterpart
824 self.assertIs(bytes_type._decoded_counterpart, str_type)
825 str_args = ('',) * num_args
826 bytes_args = (b'',) * num_args
827 str_result = str_type(*str_args)
828 bytes_result = bytes_type(*bytes_args)
829 encoding = 'ascii'
830 errors = 'strict'
831 self.assertEqual(str_result, str_args)
832 self.assertEqual(bytes_result.decode(), str_args)
833 self.assertEqual(bytes_result.decode(), str_result)
834 self.assertEqual(bytes_result.decode(encoding), str_args)
835 self.assertEqual(bytes_result.decode(encoding), str_result)
836 self.assertEqual(bytes_result.decode(encoding, errors), str_args)
837 self.assertEqual(bytes_result.decode(encoding, errors), str_result)
838 self.assertEqual(bytes_result, bytes_args)
839 self.assertEqual(str_result.encode(), bytes_args)
840 self.assertEqual(str_result.encode(), bytes_result)
841 self.assertEqual(str_result.encode(encoding), bytes_args)
842 self.assertEqual(str_result.encode(encoding), bytes_result)
843 self.assertEqual(str_result.encode(encoding, errors), bytes_args)
844 self.assertEqual(str_result.encode(encoding, errors), bytes_result)
845
846 def test_result_pairs(self):
847 # Check encoding and decoding between result pairs
848 result_types = [
849 urllib.parse.DefragResult,
850 urllib.parse.SplitResult,
851 urllib.parse.ParseResult,
852 ]
853 for result_type in result_types:
854 self._check_result_type(result_type)
855
Victor Stinner1d87deb2011-01-14 13:05:19 +0000856 def test_parse_qs_encoding(self):
857 result = urllib.parse.parse_qs("key=\u0141%E9", encoding="latin-1")
858 self.assertEqual(result, {'key': ['\u0141\xE9']})
859 result = urllib.parse.parse_qs("key=\u0141%C3%A9", encoding="utf-8")
860 self.assertEqual(result, {'key': ['\u0141\xE9']})
861 result = urllib.parse.parse_qs("key=\u0141%C3%A9", encoding="ascii")
862 self.assertEqual(result, {'key': ['\u0141\ufffd\ufffd']})
863 result = urllib.parse.parse_qs("key=\u0141%E9-", encoding="ascii")
864 self.assertEqual(result, {'key': ['\u0141\ufffd-']})
865 result = urllib.parse.parse_qs("key=\u0141%E9-", encoding="ascii",
866 errors="ignore")
867 self.assertEqual(result, {'key': ['\u0141-']})
868
869 def test_parse_qsl_encoding(self):
870 result = urllib.parse.parse_qsl("key=\u0141%E9", encoding="latin-1")
871 self.assertEqual(result, [('key', '\u0141\xE9')])
872 result = urllib.parse.parse_qsl("key=\u0141%C3%A9", encoding="utf-8")
873 self.assertEqual(result, [('key', '\u0141\xE9')])
874 result = urllib.parse.parse_qsl("key=\u0141%C3%A9", encoding="ascii")
875 self.assertEqual(result, [('key', '\u0141\ufffd\ufffd')])
876 result = urllib.parse.parse_qsl("key=\u0141%E9-", encoding="ascii")
877 self.assertEqual(result, [('key', '\u0141\ufffd-')])
878 result = urllib.parse.parse_qsl("key=\u0141%E9-", encoding="ascii",
879 errors="ignore")
880 self.assertEqual(result, [('key', '\u0141-')])
881
Senthil Kumarande02a712011-07-23 18:27:45 +0800882 def test_urlencode_sequences(self):
883 # Other tests incidentally urlencode things; test non-covered cases:
884 # Sequence and object values.
885 result = urllib.parse.urlencode({'a': [1, 2], 'b': (3, 4, 5)}, True)
Georg Brandl09a7c722012-02-20 21:31:46 +0100886 # we cannot rely on ordering here
887 assert set(result.split('&')) == {'a=1', 'a=2', 'b=3', 'b=4', 'b=5'}
Senthil Kumarande02a712011-07-23 18:27:45 +0800888
889 class Trivial:
890 def __str__(self):
891 return 'trivial'
892
893 result = urllib.parse.urlencode({'a': Trivial()}, True)
894 self.assertEqual(result, 'a=trivial')
895
R David Murrayc17686f2015-05-17 20:44:50 -0400896 def test_urlencode_quote_via(self):
897 result = urllib.parse.urlencode({'a': 'some value'})
898 self.assertEqual(result, "a=some+value")
899 result = urllib.parse.urlencode({'a': 'some value/another'},
900 quote_via=urllib.parse.quote)
901 self.assertEqual(result, "a=some%20value%2Fanother")
902 result = urllib.parse.urlencode({'a': 'some value/another'},
903 safe='/', quote_via=urllib.parse.quote)
904 self.assertEqual(result, "a=some%20value/another")
905
Senthil Kumarande02a712011-07-23 18:27:45 +0800906 def test_quote_from_bytes(self):
907 self.assertRaises(TypeError, urllib.parse.quote_from_bytes, 'foo')
908 result = urllib.parse.quote_from_bytes(b'archaeological arcana')
909 self.assertEqual(result, 'archaeological%20arcana')
910 result = urllib.parse.quote_from_bytes(b'')
911 self.assertEqual(result, '')
912
913 def test_unquote_to_bytes(self):
914 result = urllib.parse.unquote_to_bytes('abc%20def')
915 self.assertEqual(result, b'abc def')
916 result = urllib.parse.unquote_to_bytes('')
917 self.assertEqual(result, b'')
918
919 def test_quote_errors(self):
920 self.assertRaises(TypeError, urllib.parse.quote, b'foo',
921 encoding='utf-8')
922 self.assertRaises(TypeError, urllib.parse.quote, b'foo', errors='strict')
Victor Stinner1d87deb2011-01-14 13:05:19 +0000923
Ezio Melotti6709b7d2012-05-19 17:15:19 +0300924 def test_issue14072(self):
925 p1 = urllib.parse.urlsplit('tel:+31-641044153')
926 self.assertEqual(p1.scheme, 'tel')
927 self.assertEqual(p1.path, '+31-641044153')
928 p2 = urllib.parse.urlsplit('tel:+31641044153')
929 self.assertEqual(p2.scheme, 'tel')
930 self.assertEqual(p2.path, '+31641044153')
Senthil Kumaraned301992012-12-24 14:00:20 -0800931 # assert the behavior for urlparse
932 p1 = urllib.parse.urlparse('tel:+31-641044153')
933 self.assertEqual(p1.scheme, 'tel')
934 self.assertEqual(p1.path, '+31-641044153')
935 p2 = urllib.parse.urlparse('tel:+31641044153')
936 self.assertEqual(p2.scheme, 'tel')
937 self.assertEqual(p2.path, '+31641044153')
938
939 def test_telurl_params(self):
940 p1 = urllib.parse.urlparse('tel:123-4;phone-context=+1-650-516')
941 self.assertEqual(p1.scheme, 'tel')
942 self.assertEqual(p1.path, '123-4')
943 self.assertEqual(p1.params, 'phone-context=+1-650-516')
944
945 p1 = urllib.parse.urlparse('tel:+1-201-555-0123')
946 self.assertEqual(p1.scheme, 'tel')
947 self.assertEqual(p1.path, '+1-201-555-0123')
948 self.assertEqual(p1.params, '')
949
950 p1 = urllib.parse.urlparse('tel:7042;phone-context=example.com')
951 self.assertEqual(p1.scheme, 'tel')
952 self.assertEqual(p1.path, '7042')
953 self.assertEqual(p1.params, 'phone-context=example.com')
954
955 p1 = urllib.parse.urlparse('tel:863-1234;phone-context=+1-914-555')
956 self.assertEqual(p1.scheme, 'tel')
957 self.assertEqual(p1.path, '863-1234')
958 self.assertEqual(p1.params, 'phone-context=+1-914-555')
959
R David Murrayf5163882013-03-21 20:56:51 -0400960 def test_Quoter_repr(self):
961 quoter = urllib.parse.Quoter(urllib.parse._ALWAYS_SAFE)
962 self.assertIn('Quoter', repr(quoter))
963
Serhiy Storchaka15154502015-04-07 19:09:01 +0300964 def test_all(self):
965 expected = []
966 undocumented = {
967 'splitattr', 'splithost', 'splitnport', 'splitpasswd',
968 'splitport', 'splitquery', 'splittag', 'splittype', 'splituser',
969 'splitvalue',
970 'Quoter', 'ResultBase', 'clear_cache', 'to_bytes', 'unwrap',
971 }
972 for name in dir(urllib.parse):
973 if name.startswith('_') or name in undocumented:
974 continue
975 object = getattr(urllib.parse, name)
976 if getattr(object, '__module__', None) == 'urllib.parse':
977 expected.append(name)
978 self.assertCountEqual(urllib.parse.__all__, expected)
979
Senthil Kumaran6be85c52010-02-19 07:42:50 +0000980
Serhiy Storchaka9270be72015-03-02 16:32:29 +0200981class Utility_Tests(unittest.TestCase):
982 """Testcase to test the various utility functions in the urllib."""
983 # In Python 2 this test class was in test_urllib.
984
985 def test_splittype(self):
986 splittype = urllib.parse.splittype
987 self.assertEqual(splittype('type:opaquestring'), ('type', 'opaquestring'))
988 self.assertEqual(splittype('opaquestring'), (None, 'opaquestring'))
989 self.assertEqual(splittype(':opaquestring'), (None, ':opaquestring'))
990 self.assertEqual(splittype('type:'), ('type', ''))
991 self.assertEqual(splittype('type:opaque:string'), ('type', 'opaque:string'))
992
993 def test_splithost(self):
994 splithost = urllib.parse.splithost
995 self.assertEqual(splithost('//www.example.org:80/foo/bar/baz.html'),
996 ('www.example.org:80', '/foo/bar/baz.html'))
997 self.assertEqual(splithost('//www.example.org:80'),
998 ('www.example.org:80', ''))
999 self.assertEqual(splithost('/foo/bar/baz.html'),
1000 (None, '/foo/bar/baz.html'))
1001
postmasters90e01e52017-06-20 06:02:44 -07001002 # bpo-30500: # starts a fragment.
1003 self.assertEqual(splithost('//127.0.0.1#@host.com'),
1004 ('127.0.0.1', '/#@host.com'))
1005 self.assertEqual(splithost('//127.0.0.1#@host.com:80'),
1006 ('127.0.0.1', '/#@host.com:80'))
1007 self.assertEqual(splithost('//127.0.0.1:80#@host.com'),
1008 ('127.0.0.1:80', '/#@host.com'))
1009
1010 # Empty host is returned as empty string.
1011 self.assertEqual(splithost("///file"),
1012 ('', '/file'))
1013
1014 # Trailing semicolon, question mark and hash symbol are kept.
1015 self.assertEqual(splithost("//example.net/file;"),
1016 ('example.net', '/file;'))
1017 self.assertEqual(splithost("//example.net/file?"),
1018 ('example.net', '/file?'))
1019 self.assertEqual(splithost("//example.net/file#"),
1020 ('example.net', '/file#'))
1021
Serhiy Storchaka9270be72015-03-02 16:32:29 +02001022 def test_splituser(self):
1023 splituser = urllib.parse.splituser
1024 self.assertEqual(splituser('User:Pass@www.python.org:080'),
1025 ('User:Pass', 'www.python.org:080'))
1026 self.assertEqual(splituser('@www.python.org:080'),
1027 ('', 'www.python.org:080'))
1028 self.assertEqual(splituser('www.python.org:080'),
1029 (None, 'www.python.org:080'))
1030 self.assertEqual(splituser('User:Pass@'),
1031 ('User:Pass', ''))
1032 self.assertEqual(splituser('User@example.com:Pass@www.python.org:080'),
1033 ('User@example.com:Pass', 'www.python.org:080'))
1034
1035 def test_splitpasswd(self):
1036 # Some of the password examples are not sensible, but it is added to
1037 # confirming to RFC2617 and addressing issue4675.
1038 splitpasswd = urllib.parse.splitpasswd
1039 self.assertEqual(splitpasswd('user:ab'), ('user', 'ab'))
1040 self.assertEqual(splitpasswd('user:a\nb'), ('user', 'a\nb'))
1041 self.assertEqual(splitpasswd('user:a\tb'), ('user', 'a\tb'))
1042 self.assertEqual(splitpasswd('user:a\rb'), ('user', 'a\rb'))
1043 self.assertEqual(splitpasswd('user:a\fb'), ('user', 'a\fb'))
1044 self.assertEqual(splitpasswd('user:a\vb'), ('user', 'a\vb'))
1045 self.assertEqual(splitpasswd('user:a:b'), ('user', 'a:b'))
1046 self.assertEqual(splitpasswd('user:a b'), ('user', 'a b'))
1047 self.assertEqual(splitpasswd('user 2:ab'), ('user 2', 'ab'))
1048 self.assertEqual(splitpasswd('user+1:a+b'), ('user+1', 'a+b'))
1049 self.assertEqual(splitpasswd('user:'), ('user', ''))
1050 self.assertEqual(splitpasswd('user'), ('user', None))
1051 self.assertEqual(splitpasswd(':ab'), ('', 'ab'))
1052
1053 def test_splitport(self):
1054 splitport = urllib.parse.splitport
1055 self.assertEqual(splitport('parrot:88'), ('parrot', '88'))
1056 self.assertEqual(splitport('parrot'), ('parrot', None))
1057 self.assertEqual(splitport('parrot:'), ('parrot', None))
1058 self.assertEqual(splitport('127.0.0.1'), ('127.0.0.1', None))
1059 self.assertEqual(splitport('parrot:cheese'), ('parrot:cheese', None))
1060 self.assertEqual(splitport('[::1]:88'), ('[::1]', '88'))
1061 self.assertEqual(splitport('[::1]'), ('[::1]', None))
1062 self.assertEqual(splitport(':88'), ('', '88'))
1063
1064 def test_splitnport(self):
1065 splitnport = urllib.parse.splitnport
1066 self.assertEqual(splitnport('parrot:88'), ('parrot', 88))
1067 self.assertEqual(splitnport('parrot'), ('parrot', -1))
1068 self.assertEqual(splitnport('parrot', 55), ('parrot', 55))
1069 self.assertEqual(splitnport('parrot:'), ('parrot', -1))
1070 self.assertEqual(splitnport('parrot:', 55), ('parrot', 55))
1071 self.assertEqual(splitnport('127.0.0.1'), ('127.0.0.1', -1))
1072 self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55))
1073 self.assertEqual(splitnport('parrot:cheese'), ('parrot', None))
1074 self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None))
1075
1076 def test_splitquery(self):
1077 # Normal cases are exercised by other tests; ensure that we also
1078 # catch cases with no port specified (testcase ensuring coverage)
1079 splitquery = urllib.parse.splitquery
1080 self.assertEqual(splitquery('http://python.org/fake?foo=bar'),
1081 ('http://python.org/fake', 'foo=bar'))
1082 self.assertEqual(splitquery('http://python.org/fake?foo=bar?'),
1083 ('http://python.org/fake?foo=bar', ''))
1084 self.assertEqual(splitquery('http://python.org/fake'),
1085 ('http://python.org/fake', None))
1086 self.assertEqual(splitquery('?foo=bar'), ('', 'foo=bar'))
1087
1088 def test_splittag(self):
1089 splittag = urllib.parse.splittag
1090 self.assertEqual(splittag('http://example.com?foo=bar#baz'),
1091 ('http://example.com?foo=bar', 'baz'))
1092 self.assertEqual(splittag('http://example.com?foo=bar#'),
1093 ('http://example.com?foo=bar', ''))
1094 self.assertEqual(splittag('#baz'), ('', 'baz'))
1095 self.assertEqual(splittag('http://example.com?foo=bar'),
1096 ('http://example.com?foo=bar', None))
1097 self.assertEqual(splittag('http://example.com?foo=bar#baz#boo'),
1098 ('http://example.com?foo=bar#baz', 'boo'))
1099
1100 def test_splitattr(self):
1101 splitattr = urllib.parse.splitattr
1102 self.assertEqual(splitattr('/path;attr1=value1;attr2=value2'),
1103 ('/path', ['attr1=value1', 'attr2=value2']))
1104 self.assertEqual(splitattr('/path;'), ('/path', ['']))
1105 self.assertEqual(splitattr(';attr1=value1;attr2=value2'),
1106 ('', ['attr1=value1', 'attr2=value2']))
1107 self.assertEqual(splitattr('/path'), ('/path', []))
1108
1109 def test_splitvalue(self):
1110 # Normal cases are exercised by other tests; test pathological cases
1111 # with no key/value pairs. (testcase ensuring coverage)
1112 splitvalue = urllib.parse.splitvalue
1113 self.assertEqual(splitvalue('foo=bar'), ('foo', 'bar'))
1114 self.assertEqual(splitvalue('foo='), ('foo', ''))
1115 self.assertEqual(splitvalue('=bar'), ('', 'bar'))
1116 self.assertEqual(splitvalue('foobar'), ('foobar', None))
1117 self.assertEqual(splitvalue('foo=bar=baz'), ('foo', 'bar=baz'))
1118
1119 def test_to_bytes(self):
1120 result = urllib.parse.to_bytes('http://www.python.org')
1121 self.assertEqual(result, 'http://www.python.org')
1122 self.assertRaises(UnicodeError, urllib.parse.to_bytes,
1123 'http://www.python.org/medi\u00e6val')
1124
1125 def test_unwrap(self):
1126 url = urllib.parse.unwrap('<URL:type://host/path>')
1127 self.assertEqual(url, 'type://host/path')
1128
Skip Montanaro6ec967d2002-03-23 05:32:10 +00001129
1130if __name__ == "__main__":
Serhiy Storchaka9270be72015-03-02 16:32:29 +02001131 unittest.main()