blob: e7e54a2dd89d178045b11ba84f26e4e455ce5ef5 [file] [log] [blame]
Brett Cannon74bfd702003-04-25 09:39:47 +00001"""Regresssion tests for urllib"""
2
Jeremy Hylton6102e292000-08-31 15:48:10 +00003import urllib
Hye-Shik Chang39aef792004-06-05 13:30:56 +00004import httplib
Brett Cannon74bfd702003-04-25 09:39:47 +00005import unittest
6from test import test_support
7import os
Senthil Kumarana99b7612011-04-14 12:54:35 +08008import sys
Brett Cannon74bfd702003-04-25 09:39:47 +00009import mimetools
Georg Brandl5a650a22005-08-26 08:51:34 +000010import tempfile
Hye-Shik Chang39aef792004-06-05 13:30:56 +000011import StringIO
Jeremy Hylton6102e292000-08-31 15:48:10 +000012
Brett Cannon74bfd702003-04-25 09:39:47 +000013def hexescape(char):
14 """Escape char as RFC 2396 specifies"""
15 hex_repr = hex(ord(char))[2:].upper()
16 if len(hex_repr) == 1:
17 hex_repr = "0%s" % hex_repr
18 return "%" + hex_repr
Jeremy Hylton6102e292000-08-31 15:48:10 +000019
Brett Cannon74bfd702003-04-25 09:39:47 +000020class urlopen_FileTests(unittest.TestCase):
21 """Test urlopen() opening a temporary file.
Jeremy Hylton6102e292000-08-31 15:48:10 +000022
Brett Cannon74bfd702003-04-25 09:39:47 +000023 Try to test as much functionality as possible so as to cut down on reliance
Andrew M. Kuchlingf1a2f9e2004-06-29 13:07:53 +000024 on connecting to the Net for testing.
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000025
Brett Cannon74bfd702003-04-25 09:39:47 +000026 """
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000027
Brett Cannon74bfd702003-04-25 09:39:47 +000028 def setUp(self):
29 """Setup of a temp file to use for testing"""
30 self.text = "test_urllib: %s\n" % self.__class__.__name__
Guido van Rossum51735b02003-04-25 15:01:05 +000031 FILE = file(test_support.TESTFN, 'wb')
Brett Cannon74bfd702003-04-25 09:39:47 +000032 try:
33 FILE.write(self.text)
34 finally:
35 FILE.close()
36 self.pathname = test_support.TESTFN
37 self.returned_obj = urllib.urlopen("file:%s" % self.pathname)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000038
Brett Cannon74bfd702003-04-25 09:39:47 +000039 def tearDown(self):
40 """Shut down the open object"""
41 self.returned_obj.close()
Brett Cannon19691362003-04-29 05:08:06 +000042 os.remove(test_support.TESTFN)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000043
Brett Cannon74bfd702003-04-25 09:39:47 +000044 def test_interface(self):
45 # Make sure object returned by urlopen() has the specified methods
46 for attr in ("read", "readline", "readlines", "fileno",
Georg Brandl9b0d46d2008-01-20 11:43:03 +000047 "close", "info", "geturl", "getcode", "__iter__"):
Benjamin Peterson5c8da862009-06-30 22:57:08 +000048 self.assertTrue(hasattr(self.returned_obj, attr),
Brett Cannon74bfd702003-04-25 09:39:47 +000049 "object returned by urlopen() lacks %s attribute" %
50 attr)
Skip Montanaroe78b92a2001-01-20 20:22:30 +000051
Brett Cannon74bfd702003-04-25 09:39:47 +000052 def test_read(self):
53 self.assertEqual(self.text, self.returned_obj.read())
Skip Montanaro080c9972001-01-28 21:12:22 +000054
Brett Cannon74bfd702003-04-25 09:39:47 +000055 def test_readline(self):
56 self.assertEqual(self.text, self.returned_obj.readline())
57 self.assertEqual('', self.returned_obj.readline(),
58 "calling readline() after exhausting the file did not"
59 " return an empty string")
Skip Montanaro080c9972001-01-28 21:12:22 +000060
Brett Cannon74bfd702003-04-25 09:39:47 +000061 def test_readlines(self):
62 lines_list = self.returned_obj.readlines()
63 self.assertEqual(len(lines_list), 1,
64 "readlines() returned the wrong number of lines")
65 self.assertEqual(lines_list[0], self.text,
66 "readlines() returned improper text")
Skip Montanaro080c9972001-01-28 21:12:22 +000067
Brett Cannon74bfd702003-04-25 09:39:47 +000068 def test_fileno(self):
69 file_num = self.returned_obj.fileno()
Ezio Melottib0f5adc2010-01-24 16:58:36 +000070 self.assertIsInstance(file_num, int, "fileno() did not return an int")
Brett Cannon74bfd702003-04-25 09:39:47 +000071 self.assertEqual(os.read(file_num, len(self.text)), self.text,
72 "Reading on the file descriptor returned by fileno() "
73 "did not return the expected text")
Skip Montanaroe78b92a2001-01-20 20:22:30 +000074
Brett Cannon74bfd702003-04-25 09:39:47 +000075 def test_close(self):
76 # Test close() by calling it hear and then having it be called again
77 # by the tearDown() method for the test
78 self.returned_obj.close()
Skip Montanaro080c9972001-01-28 21:12:22 +000079
Brett Cannon74bfd702003-04-25 09:39:47 +000080 def test_info(self):
Ezio Melottib0f5adc2010-01-24 16:58:36 +000081 self.assertIsInstance(self.returned_obj.info(), mimetools.Message)
Skip Montanaroe78b92a2001-01-20 20:22:30 +000082
Brett Cannon74bfd702003-04-25 09:39:47 +000083 def test_geturl(self):
84 self.assertEqual(self.returned_obj.geturl(), self.pathname)
Skip Montanaro080c9972001-01-28 21:12:22 +000085
Georg Brandl9b0d46d2008-01-20 11:43:03 +000086 def test_getcode(self):
87 self.assertEqual(self.returned_obj.getcode(), None)
88
Brett Cannon74bfd702003-04-25 09:39:47 +000089 def test_iter(self):
90 # Test iterator
91 # Don't need to count number of iterations since test would fail the
92 # instant it returned anything beyond the first line from the
93 # comparison
94 for line in self.returned_obj.__iter__():
95 self.assertEqual(line, self.text)
Skip Montanaro080c9972001-01-28 21:12:22 +000096
Benjamin Peterson2c7470d2008-09-21 21:27:51 +000097class ProxyTests(unittest.TestCase):
98
99 def setUp(self):
Walter Dörwald4b965f62009-04-26 20:51:44 +0000100 # Records changes to env vars
101 self.env = test_support.EnvironmentVarGuard()
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000102 # Delete all proxy related env vars
Senthil Kumaran7a2ee0b2010-01-08 19:20:25 +0000103 for k in os.environ.keys():
Walter Dörwald4b965f62009-04-26 20:51:44 +0000104 if 'proxy' in k.lower():
Senthil Kumarandc61ec32009-10-01 01:50:13 +0000105 self.env.unset(k)
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000106
107 def tearDown(self):
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000108 # Restore all proxy related env vars
Walter Dörwald4b965f62009-04-26 20:51:44 +0000109 self.env.__exit__()
110 del self.env
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000111
112 def test_getproxies_environment_keep_no_proxies(self):
Walter Dörwald4b965f62009-04-26 20:51:44 +0000113 self.env.set('NO_PROXY', 'localhost')
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000114 proxies = urllib.getproxies_environment()
115 # getproxies_environment use lowered case truncated (no '_proxy') keys
Ezio Melotti2623a372010-11-21 13:34:58 +0000116 self.assertEqual('localhost', proxies['no'])
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000117
118
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000119class urlopen_HttpTests(unittest.TestCase):
120 """Test urlopen() opening a fake http connection."""
121
122 def fakehttp(self, fakedata):
123 class FakeSocket(StringIO.StringIO):
124 def sendall(self, str): pass
125 def makefile(self, mode, name): return self
126 def read(self, amt=None):
127 if self.closed: return ''
128 return StringIO.StringIO.read(self, amt)
129 def readline(self, length=None):
130 if self.closed: return ''
131 return StringIO.StringIO.readline(self, length)
132 class FakeHTTPConnection(httplib.HTTPConnection):
133 def connect(self):
134 self.sock = FakeSocket(fakedata)
135 assert httplib.HTTP._connection_class == httplib.HTTPConnection
136 httplib.HTTP._connection_class = FakeHTTPConnection
137
138 def unfakehttp(self):
139 httplib.HTTP._connection_class = httplib.HTTPConnection
140
141 def test_read(self):
142 self.fakehttp('Hello!')
143 try:
144 fp = urllib.urlopen("http://python.org/")
145 self.assertEqual(fp.readline(), 'Hello!')
146 self.assertEqual(fp.readline(), '')
Georg Brandl9b0d46d2008-01-20 11:43:03 +0000147 self.assertEqual(fp.geturl(), 'http://python.org/')
148 self.assertEqual(fp.getcode(), 200)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000149 finally:
150 self.unfakehttp()
151
Senthil Kumaran49c44082011-04-13 07:31:45 +0800152 def test_url_fragment(self):
153 # Issue #11703: geturl() omits fragments in the original URL.
154 url = 'http://docs.python.org/library/urllib.html#OK'
155 self.fakehttp('Hello!')
156 try:
157 fp = urllib.urlopen(url)
158 self.assertEqual(fp.geturl(), url)
159 finally:
160 self.unfakehttp()
161
Kurt B. Kaiser0f7c25d2008-01-02 04:11:28 +0000162 def test_read_bogus(self):
Kurt B. Kaiser0a112322008-01-02 05:23:38 +0000163 # urlopen() should raise IOError for many error codes.
Kurt B. Kaiser0f7c25d2008-01-02 04:11:28 +0000164 self.fakehttp('''HTTP/1.1 401 Authentication Required
165Date: Wed, 02 Jan 2008 03:03:54 GMT
166Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
167Connection: close
168Content-Type: text/html; charset=iso-8859-1
169''')
170 try:
171 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
172 finally:
173 self.unfakehttp()
174
guido@google.comf1509302011-03-28 13:47:01 -0700175 def test_invalid_redirect(self):
176 # urlopen() should raise IOError for many error codes.
177 self.fakehttp("""HTTP/1.1 302 Found
178Date: Wed, 02 Jan 2008 03:03:54 GMT
179Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
180Location: file:README
181Connection: close
182Content-Type: text/html; charset=iso-8859-1
183""")
184 try:
185 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
186 finally:
187 self.unfakehttp()
188
Georg Brandlf66b6032007-03-14 08:27:52 +0000189 def test_empty_socket(self):
Kurt B. Kaiser0a112322008-01-02 05:23:38 +0000190 # urlopen() raises IOError if the underlying socket does not send any
191 # data. (#1680230)
Georg Brandlf66b6032007-03-14 08:27:52 +0000192 self.fakehttp('')
193 try:
194 self.assertRaises(IOError, urllib.urlopen, 'http://something')
195 finally:
196 self.unfakehttp()
197
Brett Cannon19691362003-04-29 05:08:06 +0000198class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000199 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000200
Brett Cannon19691362003-04-29 05:08:06 +0000201 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000202 # Create a list of temporary files. Each item in the list is a file
203 # name (absolute path or relative to the current working directory).
204 # All files in this list will be deleted in the tearDown method. Note,
205 # this only helps to makes sure temporary files get deleted, but it
206 # does nothing about trying to close files that may still be open. It
207 # is the responsibility of the developer to properly close files even
208 # when exceptional conditions occur.
209 self.tempFiles = []
210
Brett Cannon19691362003-04-29 05:08:06 +0000211 # Create a temporary file.
Georg Brandl5a650a22005-08-26 08:51:34 +0000212 self.registerFileForCleanUp(test_support.TESTFN)
Brett Cannon19691362003-04-29 05:08:06 +0000213 self.text = 'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000214 try:
215 FILE = file(test_support.TESTFN, 'wb')
216 FILE.write(self.text)
217 FILE.close()
218 finally:
219 try: FILE.close()
220 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000221
222 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000223 # Delete the temporary files.
224 for each in self.tempFiles:
225 try: os.remove(each)
226 except: pass
227
228 def constructLocalFileUrl(self, filePath):
229 return "file://%s" % urllib.pathname2url(os.path.abspath(filePath))
230
231 def createNewTempFile(self, data=""):
232 """Creates a new temporary file containing the specified data,
233 registers the file for deletion during the test fixture tear down, and
234 returns the absolute path of the file."""
235
236 newFd, newFilePath = tempfile.mkstemp()
237 try:
238 self.registerFileForCleanUp(newFilePath)
239 newFile = os.fdopen(newFd, "wb")
240 newFile.write(data)
241 newFile.close()
242 finally:
243 try: newFile.close()
244 except: pass
245 return newFilePath
246
247 def registerFileForCleanUp(self, fileName):
248 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000249
250 def test_basic(self):
251 # Make sure that a local file just gets its own location returned and
252 # a headers value is returned.
253 result = urllib.urlretrieve("file:%s" % test_support.TESTFN)
254 self.assertEqual(result[0], test_support.TESTFN)
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000255 self.assertIsInstance(result[1], mimetools.Message,
256 "did not get a mimetools.Message instance as "
257 "second returned value")
Brett Cannon19691362003-04-29 05:08:06 +0000258
259 def test_copy(self):
260 # Test that setting the filename argument works.
261 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000262 self.registerFileForCleanUp(second_temp)
263 result = urllib.urlretrieve(self.constructLocalFileUrl(
264 test_support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000265 self.assertEqual(second_temp, result[0])
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000266 self.assertTrue(os.path.exists(second_temp), "copy of the file was not "
Brett Cannon19691362003-04-29 05:08:06 +0000267 "made")
268 FILE = file(second_temp, 'rb')
269 try:
270 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000271 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000272 finally:
273 try: FILE.close()
274 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000275 self.assertEqual(self.text, text)
276
277 def test_reporthook(self):
278 # Make sure that the reporthook works.
279 def hooktester(count, block_size, total_size, count_holder=[0]):
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000280 self.assertIsInstance(count, int)
281 self.assertIsInstance(block_size, int)
282 self.assertIsInstance(total_size, int)
Brett Cannon19691362003-04-29 05:08:06 +0000283 self.assertEqual(count, count_holder[0])
284 count_holder[0] = count_holder[0] + 1
285 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000286 self.registerFileForCleanUp(second_temp)
287 urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN),
288 second_temp, hooktester)
289
290 def test_reporthook_0_bytes(self):
291 # Test on zero length file. Should call reporthook only 1 time.
292 report = []
293 def hooktester(count, block_size, total_size, _report=report):
294 _report.append((count, block_size, total_size))
295 srcFileName = self.createNewTempFile()
296 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
297 test_support.TESTFN, hooktester)
298 self.assertEqual(len(report), 1)
299 self.assertEqual(report[0][2], 0)
300
301 def test_reporthook_5_bytes(self):
302 # Test on 5 byte file. Should call reporthook only 2 times (once when
303 # the "network connection" is established and once when the block is
304 # read). Since the block size is 8192 bytes, only one block read is
305 # required to read the entire file.
306 report = []
307 def hooktester(count, block_size, total_size, _report=report):
308 _report.append((count, block_size, total_size))
309 srcFileName = self.createNewTempFile("x" * 5)
310 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
311 test_support.TESTFN, hooktester)
312 self.assertEqual(len(report), 2)
313 self.assertEqual(report[0][1], 8192)
314 self.assertEqual(report[0][2], 5)
315
316 def test_reporthook_8193_bytes(self):
317 # Test on 8193 byte file. Should call reporthook only 3 times (once
318 # when the "network connection" is established, once for the next 8192
319 # bytes, and once for the last byte).
320 report = []
321 def hooktester(count, block_size, total_size, _report=report):
322 _report.append((count, block_size, total_size))
323 srcFileName = self.createNewTempFile("x" * 8193)
324 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
325 test_support.TESTFN, hooktester)
326 self.assertEqual(len(report), 3)
327 self.assertEqual(report[0][1], 8192)
328 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000329
Brett Cannon74bfd702003-04-25 09:39:47 +0000330class QuotingTests(unittest.TestCase):
331 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000332
Brett Cannon74bfd702003-04-25 09:39:47 +0000333 According to RFC 2396 ("Uniform Resource Identifiers), to escape a
334 character you write it as '%' + <2 character US-ASCII hex value>. The Python
335 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly.
336 Case does not matter on the hex letters.
337
338 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000339
Brett Cannon74bfd702003-04-25 09:39:47 +0000340 Reserved characters : ";/?:@&=+$,"
341 Have special meaning in URIs and must be escaped if not being used for
342 their special meaning
343 Data characters : letters, digits, and "-_.!~*'()"
344 Unreserved and do not need to be escaped; can be, though, if desired
345 Control characters : 0x00 - 0x1F, 0x7F
346 Have no use in URIs so must be escaped
347 space : 0x20
348 Must be escaped
349 Delimiters : '<>#%"'
350 Must be escaped
351 Unwise : "{}|\^[]`"
352 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000353
Brett Cannon74bfd702003-04-25 09:39:47 +0000354 """
355
356 def test_never_quote(self):
357 # Make sure quote() does not quote letters, digits, and "_,.-"
358 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
359 "abcdefghijklmnopqrstuvwxyz",
360 "0123456789",
361 "_.-"])
362 result = urllib.quote(do_not_quote)
363 self.assertEqual(do_not_quote, result,
364 "using quote(): %s != %s" % (do_not_quote, result))
365 result = urllib.quote_plus(do_not_quote)
366 self.assertEqual(do_not_quote, result,
367 "using quote_plus(): %s != %s" % (do_not_quote, result))
368
369 def test_default_safe(self):
370 # Test '/' is default value for 'safe' parameter
371 self.assertEqual(urllib.quote.func_defaults[0], '/')
372
373 def test_safe(self):
374 # Test setting 'safe' parameter does what it should do
375 quote_by_default = "<>"
376 result = urllib.quote(quote_by_default, safe=quote_by_default)
377 self.assertEqual(quote_by_default, result,
378 "using quote(): %s != %s" % (quote_by_default, result))
379 result = urllib.quote_plus(quote_by_default, safe=quote_by_default)
380 self.assertEqual(quote_by_default, result,
381 "using quote_plus(): %s != %s" %
382 (quote_by_default, result))
383
384 def test_default_quoting(self):
385 # Make sure all characters that should be quoted are by default sans
386 # space (separate test for that).
387 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
388 should_quote.append('<>#%"{}|\^[]`')
389 should_quote.append(chr(127)) # For 0x7F
390 should_quote = ''.join(should_quote)
391 for char in should_quote:
392 result = urllib.quote(char)
393 self.assertEqual(hexescape(char), result,
394 "using quote(): %s should be escaped to %s, not %s" %
395 (char, hexescape(char), result))
396 result = urllib.quote_plus(char)
397 self.assertEqual(hexescape(char), result,
398 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000399 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000400 (char, hexescape(char), result))
401 del should_quote
402 partial_quote = "ab[]cd"
403 expected = "ab%5B%5Dcd"
404 result = urllib.quote(partial_quote)
405 self.assertEqual(expected, result,
406 "using quote(): %s != %s" % (expected, result))
407 self.assertEqual(expected, result,
408 "using quote_plus(): %s != %s" % (expected, result))
Senthil Kumaranc7743aa2010-07-19 17:35:50 +0000409 self.assertRaises(TypeError, urllib.quote, None)
Brett Cannon74bfd702003-04-25 09:39:47 +0000410
411 def test_quoting_space(self):
412 # Make sure quote() and quote_plus() handle spaces as specified in
413 # their unique way
414 result = urllib.quote(' ')
415 self.assertEqual(result, hexescape(' '),
416 "using quote(): %s != %s" % (result, hexescape(' ')))
417 result = urllib.quote_plus(' ')
418 self.assertEqual(result, '+',
419 "using quote_plus(): %s != +" % result)
420 given = "a b cd e f"
421 expect = given.replace(' ', hexescape(' '))
422 result = urllib.quote(given)
423 self.assertEqual(expect, result,
424 "using quote(): %s != %s" % (expect, result))
425 expect = given.replace(' ', '+')
426 result = urllib.quote_plus(given)
427 self.assertEqual(expect, result,
428 "using quote_plus(): %s != %s" % (expect, result))
429
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000430 def test_quoting_plus(self):
431 self.assertEqual(urllib.quote_plus('alpha+beta gamma'),
432 'alpha%2Bbeta+gamma')
433 self.assertEqual(urllib.quote_plus('alpha+beta gamma', '+'),
434 'alpha+beta+gamma')
435
Brett Cannon74bfd702003-04-25 09:39:47 +0000436class UnquotingTests(unittest.TestCase):
437 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000438
Brett Cannon74bfd702003-04-25 09:39:47 +0000439 See the doc string for quoting_Tests for details on quoting and such.
440
441 """
442
443 def test_unquoting(self):
444 # Make sure unquoting of all ASCII values works
445 escape_list = []
446 for num in range(128):
447 given = hexescape(chr(num))
448 expect = chr(num)
449 result = urllib.unquote(given)
450 self.assertEqual(expect, result,
451 "using unquote(): %s != %s" % (expect, result))
452 result = urllib.unquote_plus(given)
453 self.assertEqual(expect, result,
454 "using unquote_plus(): %s != %s" %
455 (expect, result))
456 escape_list.append(given)
457 escape_string = ''.join(escape_list)
458 del escape_list
459 result = urllib.unquote(escape_string)
460 self.assertEqual(result.count('%'), 1,
461 "using quote(): not all characters escaped; %s" %
462 result)
463 result = urllib.unquote(escape_string)
464 self.assertEqual(result.count('%'), 1,
465 "using unquote(): not all characters escaped: "
466 "%s" % result)
467
Senthil Kumaranf3e9b2a2010-03-18 12:14:15 +0000468 def test_unquoting_badpercent(self):
469 # Test unquoting on bad percent-escapes
470 given = '%xab'
471 expect = given
472 result = urllib.unquote(given)
473 self.assertEqual(expect, result, "using unquote(): %r != %r"
474 % (expect, result))
475 given = '%x'
476 expect = given
477 result = urllib.unquote(given)
478 self.assertEqual(expect, result, "using unquote(): %r != %r"
479 % (expect, result))
480 given = '%'
481 expect = given
482 result = urllib.unquote(given)
483 self.assertEqual(expect, result, "using unquote(): %r != %r"
484 % (expect, result))
485
486 def test_unquoting_mixed_case(self):
487 # Test unquoting on mixed-case hex digits in the percent-escapes
488 given = '%Ab%eA'
489 expect = '\xab\xea'
490 result = urllib.unquote(given)
491 self.assertEqual(expect, result, "using unquote(): %r != %r"
492 % (expect, result))
493
Brett Cannon74bfd702003-04-25 09:39:47 +0000494 def test_unquoting_parts(self):
495 # Make sure unquoting works when have non-quoted characters
496 # interspersed
497 given = 'ab%sd' % hexescape('c')
498 expect = "abcd"
499 result = urllib.unquote(given)
500 self.assertEqual(expect, result,
501 "using quote(): %s != %s" % (expect, result))
502 result = urllib.unquote_plus(given)
503 self.assertEqual(expect, result,
504 "using unquote_plus(): %s != %s" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000505
Brett Cannon74bfd702003-04-25 09:39:47 +0000506 def test_unquoting_plus(self):
507 # Test difference between unquote() and unquote_plus()
508 given = "are+there+spaces..."
509 expect = given
510 result = urllib.unquote(given)
511 self.assertEqual(expect, result,
512 "using unquote(): %s != %s" % (expect, result))
513 expect = given.replace('+', ' ')
514 result = urllib.unquote_plus(given)
515 self.assertEqual(expect, result,
516 "using unquote_plus(): %s != %s" % (expect, result))
517
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000518 def test_unquote_with_unicode(self):
519 r = urllib.unquote(u'br%C3%BCckner_sapporo_20050930.doc')
520 self.assertEqual(r, u'br\xc3\xbcckner_sapporo_20050930.doc')
521
Brett Cannon74bfd702003-04-25 09:39:47 +0000522class urlencode_Tests(unittest.TestCase):
523 """Tests for urlencode()"""
524
525 def help_inputtype(self, given, test_type):
526 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000527
Brett Cannon74bfd702003-04-25 09:39:47 +0000528 'given' must lead to only the pairs:
529 * 1st, 1
530 * 2nd, 2
531 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000532
Brett Cannon74bfd702003-04-25 09:39:47 +0000533 Test cannot assume anything about order. Docs make no guarantee and
534 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000535
Brett Cannon74bfd702003-04-25 09:39:47 +0000536 """
537 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
538 result = urllib.urlencode(given)
539 for expected in expect_somewhere:
Ezio Melottiaa980582010-01-23 23:04:36 +0000540 self.assertIn(expected, result,
Brett Cannon74bfd702003-04-25 09:39:47 +0000541 "testing %s: %s not found in %s" %
542 (test_type, expected, result))
543 self.assertEqual(result.count('&'), 2,
544 "testing %s: expected 2 '&'s; got %s" %
545 (test_type, result.count('&')))
546 amp_location = result.index('&')
547 on_amp_left = result[amp_location - 1]
548 on_amp_right = result[amp_location + 1]
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000549 self.assertTrue(on_amp_left.isdigit() and on_amp_right.isdigit(),
Brett Cannon74bfd702003-04-25 09:39:47 +0000550 "testing %s: '&' not located in proper place in %s" %
551 (test_type, result))
552 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
553 "testing %s: "
554 "unexpected number of characters: %s != %s" %
555 (test_type, len(result), (5 * 3) + 2))
556
557 def test_using_mapping(self):
558 # Test passing in a mapping object as an argument.
559 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
560 "using dict as input type")
561
562 def test_using_sequence(self):
563 # Test passing in a sequence of two-item sequences as an argument.
564 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
565 "using sequence of two-item tuples as input")
566
567 def test_quoting(self):
568 # Make sure keys and values are quoted using quote_plus()
569 given = {"&":"="}
570 expect = "%s=%s" % (hexescape('&'), hexescape('='))
571 result = urllib.urlencode(given)
572 self.assertEqual(expect, result)
573 given = {"key name":"A bunch of pluses"}
574 expect = "key+name=A+bunch+of+pluses"
575 result = urllib.urlencode(given)
576 self.assertEqual(expect, result)
577
578 def test_doseq(self):
579 # Test that passing True for 'doseq' parameter works correctly
580 given = {'sequence':['1', '2', '3']}
581 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3']))
582 result = urllib.urlencode(given)
583 self.assertEqual(expect, result)
584 result = urllib.urlencode(given, True)
585 for value in given["sequence"]:
586 expect = "sequence=%s" % value
Ezio Melottiaa980582010-01-23 23:04:36 +0000587 self.assertIn(expect, result)
Brett Cannon74bfd702003-04-25 09:39:47 +0000588 self.assertEqual(result.count('&'), 2,
589 "Expected 2 '&'s, got %s" % result.count('&'))
590
591class Pathname_Tests(unittest.TestCase):
592 """Test pathname2url() and url2pathname()"""
593
594 def test_basic(self):
595 # Make sure simple tests pass
596 expected_path = os.path.join("parts", "of", "a", "path")
597 expected_url = "parts/of/a/path"
598 result = urllib.pathname2url(expected_path)
599 self.assertEqual(expected_url, result,
600 "pathname2url() failed; %s != %s" %
601 (result, expected_url))
602 result = urllib.url2pathname(expected_url)
603 self.assertEqual(expected_path, result,
604 "url2pathame() failed; %s != %s" %
605 (result, expected_path))
606
607 def test_quoting(self):
608 # Test automatic quoting and unquoting works for pathnam2url() and
609 # url2pathname() respectively
610 given = os.path.join("needs", "quot=ing", "here")
611 expect = "needs/%s/here" % urllib.quote("quot=ing")
612 result = urllib.pathname2url(given)
613 self.assertEqual(expect, result,
614 "pathname2url() failed; %s != %s" %
615 (expect, result))
616 expect = given
617 result = urllib.url2pathname(result)
618 self.assertEqual(expect, result,
619 "url2pathname() failed; %s != %s" %
620 (expect, result))
621 given = os.path.join("make sure", "using_quote")
622 expect = "%s/using_quote" % urllib.quote("make sure")
623 result = urllib.pathname2url(given)
624 self.assertEqual(expect, result,
625 "pathname2url() failed; %s != %s" %
626 (expect, result))
627 given = "make+sure/using_unquote"
628 expect = os.path.join("make+sure", "using_unquote")
629 result = urllib.url2pathname(given)
630 self.assertEqual(expect, result,
631 "url2pathname() failed; %s != %s" %
632 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000633
Senthil Kumarana99b7612011-04-14 12:54:35 +0800634 @unittest.skipUnless(sys.platform == 'win32',
635 'test specific to the nturl2path library')
636 def test_ntpath(self):
637 given = ('/C:/', '///C:/', '/C|//')
638 expect = 'C:\\'
639 for url in given:
640 result = urllib.url2pathname(url)
641 self.assertEqual(expect, result,
642 'nturl2path.url2pathname() failed; %s != %s' %
643 (expect, result))
644 given = '///C|/path'
645 expect = 'C:\\path'
646 result = urllib.url2pathname(given)
647 self.assertEqual(expect, result,
648 'nturl2path.url2pathname() failed; %s != %s' %
649 (expect, result))
650
Senthil Kumaran5e95e762009-03-30 21:51:50 +0000651class Utility_Tests(unittest.TestCase):
652 """Testcase to test the various utility functions in the urllib."""
653
654 def test_splitpasswd(self):
655 """Some of the password examples are not sensible, but it is added to
656 confirming to RFC2617 and addressing issue4675.
657 """
658 self.assertEqual(('user', 'ab'),urllib.splitpasswd('user:ab'))
659 self.assertEqual(('user', 'a\nb'),urllib.splitpasswd('user:a\nb'))
660 self.assertEqual(('user', 'a\tb'),urllib.splitpasswd('user:a\tb'))
661 self.assertEqual(('user', 'a\rb'),urllib.splitpasswd('user:a\rb'))
662 self.assertEqual(('user', 'a\fb'),urllib.splitpasswd('user:a\fb'))
663 self.assertEqual(('user', 'a\vb'),urllib.splitpasswd('user:a\vb'))
664 self.assertEqual(('user', 'a:b'),urllib.splitpasswd('user:a:b'))
665
666
Senthil Kumaran7c2867f2009-04-21 03:24:19 +0000667class URLopener_Tests(unittest.TestCase):
668 """Testcase to test the open method of URLopener class."""
669
670 def test_quoted_open(self):
671 class DummyURLopener(urllib.URLopener):
672 def open_spam(self, url):
673 return url
674
675 self.assertEqual(DummyURLopener().open(
676 'spam://example/ /'),'//example/%20/')
677
Senthil Kumaran18d5a692010-02-20 22:05:34 +0000678 # test the safe characters are not quoted by urlopen
679 self.assertEqual(DummyURLopener().open(
680 "spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"),
681 "//c:|windows%/:=&?~#+!$,;'@()*[]|/path/")
682
Senthil Kumaran7c2867f2009-04-21 03:24:19 +0000683
Facundo Batistad9880d02007-05-25 04:20:22 +0000684# Just commented them out.
685# Can't really tell why keep failing in windows and sparc.
Ezio Melottic2077b02011-03-16 12:34:31 +0200686# Everywhere else they work ok, but on those machines, sometimes
Facundo Batistad9880d02007-05-25 04:20:22 +0000687# fail in one of the tests, sometimes in other. I have a linux, and
688# the tests go ok.
689# If anybody has one of the problematic enviroments, please help!
690# . Facundo
691#
692# def server(evt):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000693# import socket, time
Facundo Batistad9880d02007-05-25 04:20:22 +0000694# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
695# serv.settimeout(3)
696# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
697# serv.bind(("", 9093))
698# serv.listen(5)
699# try:
700# conn, addr = serv.accept()
701# conn.send("1 Hola mundo\n")
702# cantdata = 0
703# while cantdata < 13:
704# data = conn.recv(13-cantdata)
705# cantdata += len(data)
706# time.sleep(.3)
707# conn.send("2 No more lines\n")
708# conn.close()
709# except socket.timeout:
710# pass
711# finally:
712# serv.close()
713# evt.set()
714#
715# class FTPWrapperTests(unittest.TestCase):
716#
717# def setUp(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000718# import ftplib, time, threading
Facundo Batistad9880d02007-05-25 04:20:22 +0000719# ftplib.FTP.port = 9093
720# self.evt = threading.Event()
721# threading.Thread(target=server, args=(self.evt,)).start()
722# time.sleep(.1)
723#
724# def tearDown(self):
725# self.evt.wait()
726#
727# def testBasic(self):
728# # connects
729# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000730# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000731#
732# def testTimeoutNone(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000733# # global default timeout is ignored
734# import socket
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000735# self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000736# socket.setdefaulttimeout(30)
737# try:
738# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
739# finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000740# socket.setdefaulttimeout(None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000741# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000742# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000743#
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000744# def testTimeoutDefault(self):
745# # global default timeout is used
746# import socket
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000747# self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000748# socket.setdefaulttimeout(30)
749# try:
750# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
751# finally:
752# socket.setdefaulttimeout(None)
753# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
754# ftp.close()
755#
756# def testTimeoutValue(self):
757# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [],
758# timeout=30)
759# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
760# ftp.close()
Facundo Batista711a54e2007-05-24 17:50:54 +0000761
Skip Montanaro080c9972001-01-28 21:12:22 +0000762
763
Brett Cannon74bfd702003-04-25 09:39:47 +0000764def test_main():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000765 import warnings
Brett Cannon672237d2008-09-09 00:49:16 +0000766 with warnings.catch_warnings():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000767 warnings.filterwarnings('ignore', ".*urllib\.urlopen.*Python 3.0",
768 DeprecationWarning)
769 test_support.run_unittest(
770 urlopen_FileTests,
771 urlopen_HttpTests,
772 urlretrieve_FileTests,
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000773 ProxyTests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000774 QuotingTests,
775 UnquotingTests,
776 urlencode_Tests,
777 Pathname_Tests,
Senthil Kumaran5e95e762009-03-30 21:51:50 +0000778 Utility_Tests,
Senthil Kumaran7c2867f2009-04-21 03:24:19 +0000779 URLopener_Tests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000780 #FTPWrapperTests,
781 )
Brett Cannon74bfd702003-04-25 09:39:47 +0000782
783
784
785if __name__ == '__main__':
786 test_main()