summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_urlparse.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_urlparse.py')
-rw-r--r--Lib/test/test_urlparse.py138
1 files changed, 120 insertions, 18 deletions
diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
index 1775ef3..71abc14 100644
--- a/Lib/test/test_urlparse.py
+++ b/Lib/test/test_urlparse.py
@@ -17,7 +17,6 @@ parse_qsl_test_cases = [
("=a", [('', 'a')]),
("a", [('a', '')]),
("a=", [('a', '')]),
- ("a=", [('a', '')]),
("&a=b", [('a', 'b')]),
("a=a+b&b=b+c", [('a', 'a b'), ('b', 'b c')]),
("a=1&a=2", [('a', '1'), ('a', '2')]),
@@ -28,10 +27,52 @@ parse_qsl_test_cases = [
(b"=a", [(b'', b'a')]),
(b"a", [(b'a', b'')]),
(b"a=", [(b'a', b'')]),
- (b"a=", [(b'a', b'')]),
(b"&a=b", [(b'a', b'b')]),
(b"a=a+b&b=b+c", [(b'a', b'a b'), (b'b', b'b c')]),
(b"a=1&a=2", [(b'a', b'1'), (b'a', b'2')]),
+ (";", []),
+ (";;", []),
+ (";a=b", [('a', 'b')]),
+ ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]),
+ ("a=1;a=2", [('a', '1'), ('a', '2')]),
+ (b";", []),
+ (b";;", []),
+ (b";a=b", [(b'a', b'b')]),
+ (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]),
+ (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]),
+]
+
+parse_qs_test_cases = [
+ ("", {}),
+ ("&", {}),
+ ("&&", {}),
+ ("=", {'': ['']}),
+ ("=a", {'': ['a']}),
+ ("a", {'a': ['']}),
+ ("a=", {'a': ['']}),
+ ("&a=b", {'a': ['b']}),
+ ("a=a+b&b=b+c", {'a': ['a b'], 'b': ['b c']}),
+ ("a=1&a=2", {'a': ['1', '2']}),
+ (b"", {}),
+ (b"&", {}),
+ (b"&&", {}),
+ (b"=", {b'': [b'']}),
+ (b"=a", {b'': [b'a']}),
+ (b"a", {b'a': [b'']}),
+ (b"a=", {b'a': [b'']}),
+ (b"&a=b", {b'a': [b'b']}),
+ (b"a=a+b&b=b+c", {b'a': [b'a b'], b'b': [b'b c']}),
+ (b"a=1&a=2", {b'a': [b'1', b'2']}),
+ (";", {}),
+ (";;", {}),
+ (";a=b", {'a': ['b']}),
+ ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}),
+ ("a=1;a=2", {'a': ['1', '2']}),
+ (b";", {}),
+ (b";;", {}),
+ (b";a=b", {b'a': [b'b']}),
+ (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}),
+ (b"a=1;a=2", {b'a': [b'1', b'2']}),
]
class UrlParseTestCase(unittest.TestCase):
@@ -96,6 +137,16 @@ class UrlParseTestCase(unittest.TestCase):
self.assertEqual(result, expect_without_blanks,
"Error parsing %r" % orig)
+ def test_qs(self):
+ for orig, expect in parse_qs_test_cases:
+ result = urllib.parse.parse_qs(orig, keep_blank_values=True)
+ self.assertEqual(result, expect, "Error parsing %r" % orig)
+ expect_without_blanks = {v: expect[v]
+ for v in expect if len(expect[v][0])}
+ result = urllib.parse.parse_qs(orig, keep_blank_values=False)
+ self.assertEqual(result, expect_without_blanks,
+ "Error parsing %r" % orig)
+
def test_roundtrips(self):
str_cases = [
('file:///tmp/junk.txt',
@@ -210,10 +261,6 @@ class UrlParseTestCase(unittest.TestCase):
# "abnormal" cases from RFC 1808:
self.checkJoin(RFC1808_BASE, '', 'http://a/b/c/d;p?q#f')
- self.checkJoin(RFC1808_BASE, '../../../g', 'http://a/../g')
- self.checkJoin(RFC1808_BASE, '../../../../g', 'http://a/../../g')
- self.checkJoin(RFC1808_BASE, '/./g', 'http://a/./g')
- self.checkJoin(RFC1808_BASE, '/../g', 'http://a/../g')
self.checkJoin(RFC1808_BASE, 'g.', 'http://a/b/c/g.')
self.checkJoin(RFC1808_BASE, '.g', 'http://a/b/c/.g')
self.checkJoin(RFC1808_BASE, 'g..', 'http://a/b/c/g..')
@@ -228,6 +275,13 @@ class UrlParseTestCase(unittest.TestCase):
#self.checkJoin(RFC1808_BASE, 'http:g', 'http:g')
#self.checkJoin(RFC1808_BASE, 'http:', 'http:')
+ # XXX: The following tests are no longer compatible with RFC3986
+ # self.checkJoin(RFC1808_BASE, '../../../g', 'http://a/../g')
+ # self.checkJoin(RFC1808_BASE, '../../../../g', 'http://a/../../g')
+ # self.checkJoin(RFC1808_BASE, '/./g', 'http://a/./g')
+ # self.checkJoin(RFC1808_BASE, '/../g', 'http://a/../g')
+
+
def test_RFC2368(self):
# Issue 11467: path that starts with a number is not parsed correctly
self.assertEqual(urllib.parse.urlparse('mailto:1337@example.org'),
@@ -258,10 +312,6 @@ class UrlParseTestCase(unittest.TestCase):
self.checkJoin(RFC2396_BASE, '../../', 'http://a/')
self.checkJoin(RFC2396_BASE, '../../g', 'http://a/g')
self.checkJoin(RFC2396_BASE, '', RFC2396_BASE)
- self.checkJoin(RFC2396_BASE, '../../../g', 'http://a/../g')
- self.checkJoin(RFC2396_BASE, '../../../../g', 'http://a/../../g')
- self.checkJoin(RFC2396_BASE, '/./g', 'http://a/./g')
- self.checkJoin(RFC2396_BASE, '/../g', 'http://a/../g')
self.checkJoin(RFC2396_BASE, 'g.', 'http://a/b/c/g.')
self.checkJoin(RFC2396_BASE, '.g', 'http://a/b/c/.g')
self.checkJoin(RFC2396_BASE, 'g..', 'http://a/b/c/g..')
@@ -277,10 +327,17 @@ class UrlParseTestCase(unittest.TestCase):
self.checkJoin(RFC2396_BASE, 'g#s/./x', 'http://a/b/c/g#s/./x')
self.checkJoin(RFC2396_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x')
+ # XXX: The following tests are no longer compatible with RFC3986
+ # self.checkJoin(RFC2396_BASE, '../../../g', 'http://a/../g')
+ # self.checkJoin(RFC2396_BASE, '../../../../g', 'http://a/../../g')
+ # self.checkJoin(RFC2396_BASE, '/./g', 'http://a/./g')
+ # self.checkJoin(RFC2396_BASE, '/../g', 'http://a/../g')
+
+
def test_RFC3986(self):
# Test cases from RFC3986
self.checkJoin(RFC3986_BASE, '?y','http://a/b/c/d;p?y')
- self.checkJoin(RFC2396_BASE, ';x', 'http://a/b/c/;x')
+ self.checkJoin(RFC3986_BASE, ';x', 'http://a/b/c/;x')
self.checkJoin(RFC3986_BASE, 'g:h','g:h')
self.checkJoin(RFC3986_BASE, 'g','http://a/b/c/g')
self.checkJoin(RFC3986_BASE, './g','http://a/b/c/g')
@@ -304,17 +361,17 @@ class UrlParseTestCase(unittest.TestCase):
self.checkJoin(RFC3986_BASE, '../..','http://a/')
self.checkJoin(RFC3986_BASE, '../../','http://a/')
self.checkJoin(RFC3986_BASE, '../../g','http://a/g')
+ self.checkJoin(RFC3986_BASE, '../../../g', 'http://a/g')
#Abnormal Examples
# The 'abnormal scenarios' are incompatible with RFC2986 parsing
# Tests are here for reference.
- #self.checkJoin(RFC3986_BASE, '../../../g','http://a/g')
- #self.checkJoin(RFC3986_BASE, '../../../../g','http://a/g')
- #self.checkJoin(RFC3986_BASE, '/./g','http://a/g')
- #self.checkJoin(RFC3986_BASE, '/../g','http://a/g')
-
+ self.checkJoin(RFC3986_BASE, '../../../g','http://a/g')
+ self.checkJoin(RFC3986_BASE, '../../../../g','http://a/g')
+ self.checkJoin(RFC3986_BASE, '/./g','http://a/g')
+ self.checkJoin(RFC3986_BASE, '/../g','http://a/g')
self.checkJoin(RFC3986_BASE, 'g.','http://a/b/c/g.')
self.checkJoin(RFC3986_BASE, '.g','http://a/b/c/.g')
self.checkJoin(RFC3986_BASE, 'g..','http://a/b/c/g..')
@@ -354,10 +411,8 @@ class UrlParseTestCase(unittest.TestCase):
self.checkJoin(SIMPLE_BASE, '../g','http://a/b/g')
self.checkJoin(SIMPLE_BASE, '../..','http://a/')
self.checkJoin(SIMPLE_BASE, '../../g','http://a/g')
- self.checkJoin(SIMPLE_BASE, '../../../g','http://a/../g')
self.checkJoin(SIMPLE_BASE, './../g','http://a/b/g')
self.checkJoin(SIMPLE_BASE, './g/.','http://a/b/c/g/')
- self.checkJoin(SIMPLE_BASE, '/./g','http://a/./g')
self.checkJoin(SIMPLE_BASE, 'g/./h','http://a/b/c/g/h')
self.checkJoin(SIMPLE_BASE, 'g/../h','http://a/b/c/h')
self.checkJoin(SIMPLE_BASE, 'http:g','http://a/b/c/g')
@@ -370,6 +425,27 @@ class UrlParseTestCase(unittest.TestCase):
self.checkJoin('', 'http://a/./g', 'http://a/./g')
self.checkJoin('svn://pathtorepo/dir1', 'dir2', 'svn://pathtorepo/dir2')
self.checkJoin('svn+ssh://pathtorepo/dir1', 'dir2', 'svn+ssh://pathtorepo/dir2')
+ self.checkJoin('ws://a/b','g','ws://a/g')
+ self.checkJoin('wss://a/b','g','wss://a/g')
+
+ # XXX: The following tests are no longer compatible with RFC3986
+ # self.checkJoin(SIMPLE_BASE, '../../../g','http://a/../g')
+ # self.checkJoin(SIMPLE_BASE, '/./g','http://a/./g')
+
+ # test for issue22118 duplicate slashes
+ self.checkJoin(SIMPLE_BASE + '/', 'foo', SIMPLE_BASE + '/foo')
+
+ # Non-RFC-defined tests, covering variations of base and trailing
+ # slashes
+ self.checkJoin('http://a/b/c/d/e/', '../../f/g/', 'http://a/b/c/f/g/')
+ self.checkJoin('http://a/b/c/d/e', '../../f/g/', 'http://a/b/f/g/')
+ self.checkJoin('http://a/b/c/d/e/', '/../../f/g/', 'http://a/f/g/')
+ self.checkJoin('http://a/b/c/d/e', '/../../f/g/', 'http://a/f/g/')
+ self.checkJoin('http://a/b/c/d/e/', '../../f/g', 'http://a/b/c/f/g')
+ self.checkJoin('http://a/b/', '../../f/g/', 'http://a/f/g/')
+
+ # issue 23703: don't duplicate filename
+ self.checkJoin('a', 'b', 'b')
def test_RFC2732(self):
str_cases = [
@@ -803,6 +879,16 @@ class UrlParseTestCase(unittest.TestCase):
result = urllib.parse.urlencode({'a': Trivial()}, True)
self.assertEqual(result, 'a=trivial')
+ def test_urlencode_quote_via(self):
+ result = urllib.parse.urlencode({'a': 'some value'})
+ self.assertEqual(result, "a=some+value")
+ result = urllib.parse.urlencode({'a': 'some value/another'},
+ quote_via=urllib.parse.quote)
+ self.assertEqual(result, "a=some%20value%2Fanother")
+ result = urllib.parse.urlencode({'a': 'some value/another'},
+ safe='/', quote_via=urllib.parse.quote)
+ self.assertEqual(result, "a=some%20value/another")
+
def test_quote_from_bytes(self):
self.assertRaises(TypeError, urllib.parse.quote_from_bytes, 'foo')
result = urllib.parse.quote_from_bytes(b'archaeological arcana')
@@ -861,6 +947,22 @@ class UrlParseTestCase(unittest.TestCase):
quoter = urllib.parse.Quoter(urllib.parse._ALWAYS_SAFE)
self.assertIn('Quoter', repr(quoter))
+ def test_all(self):
+ expected = []
+ undocumented = {
+ 'splitattr', 'splithost', 'splitnport', 'splitpasswd',
+ 'splitport', 'splitquery', 'splittag', 'splittype', 'splituser',
+ 'splitvalue',
+ 'Quoter', 'ResultBase', 'clear_cache', 'to_bytes', 'unwrap',
+ }
+ for name in dir(urllib.parse):
+ if name.startswith('_') or name in undocumented:
+ continue
+ object = getattr(urllib.parse, name)
+ if getattr(object, '__module__', None) == 'urllib.parse':
+ expected.append(name)
+ self.assertCountEqual(urllib.parse.__all__, expected)
+
class Utility_Tests(unittest.TestCase):
"""Testcase to test the various utility functions in the urllib."""