blob: c233e3560f616787afeff024bc93aa136984ca2a [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
Jeremy Hylton66dc8c52007-08-04 03:42:26 +00005import io
Brett Cannon74bfd702003-04-25 09:39:47 +00006import unittest
7from test import test_support
8import os
9import mimetools
Georg Brandl5a650a22005-08-26 08:51:34 +000010import tempfile
Guido van Rossume7ba4952007-06-06 23:52:48 +000011import ftplib
12import threading
13import socket
14import time
Jeremy Hylton6102e292000-08-31 15:48:10 +000015
Brett Cannon74bfd702003-04-25 09:39:47 +000016def hexescape(char):
17 """Escape char as RFC 2396 specifies"""
18 hex_repr = hex(ord(char))[2:].upper()
19 if len(hex_repr) == 1:
20 hex_repr = "0%s" % hex_repr
21 return "%" + hex_repr
Jeremy Hylton6102e292000-08-31 15:48:10 +000022
Brett Cannon74bfd702003-04-25 09:39:47 +000023class urlopen_FileTests(unittest.TestCase):
24 """Test urlopen() opening a temporary file.
Jeremy Hylton6102e292000-08-31 15:48:10 +000025
Brett Cannon74bfd702003-04-25 09:39:47 +000026 Try to test as much functionality as possible so as to cut down on reliance
Andrew M. Kuchlingf1a2f9e2004-06-29 13:07:53 +000027 on connecting to the Net for testing.
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000028
Brett Cannon74bfd702003-04-25 09:39:47 +000029 """
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000030
Brett Cannon74bfd702003-04-25 09:39:47 +000031 def setUp(self):
32 """Setup of a temp file to use for testing"""
Guido van Rossum70d0dda2007-08-29 01:53:26 +000033 self.text = bytes("test_urllib: %s\n" % self.__class__.__name__, "ascii")
Alex Martelli01c77c62006-08-24 02:58:11 +000034 FILE = open(test_support.TESTFN, 'wb')
Brett Cannon74bfd702003-04-25 09:39:47 +000035 try:
36 FILE.write(self.text)
37 finally:
38 FILE.close()
39 self.pathname = test_support.TESTFN
40 self.returned_obj = urllib.urlopen("file:%s" % self.pathname)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000041
Brett Cannon74bfd702003-04-25 09:39:47 +000042 def tearDown(self):
43 """Shut down the open object"""
44 self.returned_obj.close()
Brett Cannon19691362003-04-29 05:08:06 +000045 os.remove(test_support.TESTFN)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000046
Brett Cannon74bfd702003-04-25 09:39:47 +000047 def test_interface(self):
48 # Make sure object returned by urlopen() has the specified methods
49 for attr in ("read", "readline", "readlines", "fileno",
Christian Heimes9bd667a2008-01-20 15:14:11 +000050 "close", "info", "geturl", "getcode", "__iter__"):
Brett Cannon74bfd702003-04-25 09:39:47 +000051 self.assert_(hasattr(self.returned_obj, attr),
52 "object returned by urlopen() lacks %s attribute" %
53 attr)
Skip Montanaroe78b92a2001-01-20 20:22:30 +000054
Brett Cannon74bfd702003-04-25 09:39:47 +000055 def test_read(self):
56 self.assertEqual(self.text, self.returned_obj.read())
Skip Montanaro080c9972001-01-28 21:12:22 +000057
Brett Cannon74bfd702003-04-25 09:39:47 +000058 def test_readline(self):
59 self.assertEqual(self.text, self.returned_obj.readline())
Guido van Rossuma0982942007-07-10 08:30:03 +000060 self.assertEqual(b'', self.returned_obj.readline(),
Brett Cannon74bfd702003-04-25 09:39:47 +000061 "calling readline() after exhausting the file did not"
62 " return an empty string")
Skip Montanaro080c9972001-01-28 21:12:22 +000063
Brett Cannon74bfd702003-04-25 09:39:47 +000064 def test_readlines(self):
65 lines_list = self.returned_obj.readlines()
66 self.assertEqual(len(lines_list), 1,
67 "readlines() returned the wrong number of lines")
68 self.assertEqual(lines_list[0], self.text,
69 "readlines() returned improper text")
Skip Montanaro080c9972001-01-28 21:12:22 +000070
Brett Cannon74bfd702003-04-25 09:39:47 +000071 def test_fileno(self):
72 file_num = self.returned_obj.fileno()
73 self.assert_(isinstance(file_num, int),
74 "fileno() did not return an int")
75 self.assertEqual(os.read(file_num, len(self.text)), self.text,
76 "Reading on the file descriptor returned by fileno() "
77 "did not return the expected text")
Skip Montanaroe78b92a2001-01-20 20:22:30 +000078
Brett Cannon74bfd702003-04-25 09:39:47 +000079 def test_close(self):
80 # Test close() by calling it hear and then having it be called again
81 # by the tearDown() method for the test
82 self.returned_obj.close()
Skip Montanaro080c9972001-01-28 21:12:22 +000083
Brett Cannon74bfd702003-04-25 09:39:47 +000084 def test_info(self):
85 self.assert_(isinstance(self.returned_obj.info(), mimetools.Message))
Skip Montanaroe78b92a2001-01-20 20:22:30 +000086
Brett Cannon74bfd702003-04-25 09:39:47 +000087 def test_geturl(self):
88 self.assertEqual(self.returned_obj.geturl(), self.pathname)
Skip Montanaro080c9972001-01-28 21:12:22 +000089
Christian Heimes9bd667a2008-01-20 15:14:11 +000090 def test_getcode(self):
91 self.assertEqual(self.returned_obj.getcode(), None)
92
Brett Cannon74bfd702003-04-25 09:39:47 +000093 def test_iter(self):
94 # Test iterator
95 # Don't need to count number of iterations since test would fail the
96 # instant it returned anything beyond the first line from the
97 # comparison
98 for line in self.returned_obj.__iter__():
99 self.assertEqual(line, self.text)
Skip Montanaro080c9972001-01-28 21:12:22 +0000100
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000101class urlopen_HttpTests(unittest.TestCase):
102 """Test urlopen() opening a fake http connection."""
103
104 def fakehttp(self, fakedata):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000105 class FakeSocket(io.BytesIO):
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000106 def sendall(self, str): pass
107 def makefile(self, mode, name): return self
108 def read(self, amt=None):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000109 if self.closed: return b""
110 return io.BytesIO.read(self, amt)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000111 def readline(self, length=None):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000112 if self.closed: return b""
113 return io.BytesIO.readline(self, length)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000114 class FakeHTTPConnection(httplib.HTTPConnection):
115 def connect(self):
116 self.sock = FakeSocket(fakedata)
Jeremy Hylton77553ab2007-08-04 19:23:09 +0000117 self._connection_class = httplib.HTTPConnection
118 httplib.HTTPConnection = FakeHTTPConnection
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000119
120 def unfakehttp(self):
Jeremy Hylton77553ab2007-08-04 19:23:09 +0000121 httplib.HTTPConnection = self._connection_class
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000122
123 def test_read(self):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000124 self.fakehttp(b"Hello!")
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000125 try:
126 fp = urllib.urlopen("http://python.org/")
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000127 self.assertEqual(fp.readline(), b"Hello!")
128 self.assertEqual(fp.readline(), b"")
Christian Heimes9bd667a2008-01-20 15:14:11 +0000129 self.assertEqual(fp.geturl(), 'http://python.org/')
130 self.assertEqual(fp.getcode(), 200)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000131 finally:
132 self.unfakehttp()
133
Christian Heimes57dddfb2008-01-02 18:30:52 +0000134 def test_read_bogus(self):
135 # urlopen() should raise IOError for many error codes.
136 self.fakehttp(b'''HTTP/1.1 401 Authentication Required
137Date: Wed, 02 Jan 2008 03:03:54 GMT
138Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
139Connection: close
140Content-Type: text/html; charset=iso-8859-1
141''')
142 try:
143 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
144 finally:
145 self.unfakehttp()
146
Guido van Rossumd8faa362007-04-27 19:54:29 +0000147 def test_empty_socket(self):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000148 # urlopen() raises IOError if the underlying socket does not send any
149 # data. (#1680230)
Christian Heimes57dddfb2008-01-02 18:30:52 +0000150 self.fakehttp(b'')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000151 try:
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000152 self.assertRaises(IOError, urllib.urlopen, "http://something")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000153 finally:
154 self.unfakehttp()
155
Brett Cannon19691362003-04-29 05:08:06 +0000156class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000157 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000158
Brett Cannon19691362003-04-29 05:08:06 +0000159 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000160 # Create a list of temporary files. Each item in the list is a file
161 # name (absolute path or relative to the current working directory).
162 # All files in this list will be deleted in the tearDown method. Note,
163 # this only helps to makes sure temporary files get deleted, but it
164 # does nothing about trying to close files that may still be open. It
165 # is the responsibility of the developer to properly close files even
166 # when exceptional conditions occur.
167 self.tempFiles = []
168
Brett Cannon19691362003-04-29 05:08:06 +0000169 # Create a temporary file.
Georg Brandl5a650a22005-08-26 08:51:34 +0000170 self.registerFileForCleanUp(test_support.TESTFN)
Guido van Rossuma0982942007-07-10 08:30:03 +0000171 self.text = b'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000172 try:
Alex Martelli01c77c62006-08-24 02:58:11 +0000173 FILE = open(test_support.TESTFN, 'wb')
Georg Brandl5a650a22005-08-26 08:51:34 +0000174 FILE.write(self.text)
175 FILE.close()
176 finally:
177 try: FILE.close()
178 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000179
180 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000181 # Delete the temporary files.
182 for each in self.tempFiles:
183 try: os.remove(each)
184 except: pass
185
186 def constructLocalFileUrl(self, filePath):
187 return "file://%s" % urllib.pathname2url(os.path.abspath(filePath))
188
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000189 def createNewTempFile(self, data=b""):
Georg Brandl5a650a22005-08-26 08:51:34 +0000190 """Creates a new temporary file containing the specified data,
191 registers the file for deletion during the test fixture tear down, and
192 returns the absolute path of the file."""
193
194 newFd, newFilePath = tempfile.mkstemp()
195 try:
196 self.registerFileForCleanUp(newFilePath)
197 newFile = os.fdopen(newFd, "wb")
198 newFile.write(data)
199 newFile.close()
200 finally:
201 try: newFile.close()
202 except: pass
203 return newFilePath
204
205 def registerFileForCleanUp(self, fileName):
206 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000207
208 def test_basic(self):
209 # Make sure that a local file just gets its own location returned and
210 # a headers value is returned.
211 result = urllib.urlretrieve("file:%s" % test_support.TESTFN)
212 self.assertEqual(result[0], test_support.TESTFN)
213 self.assert_(isinstance(result[1], mimetools.Message),
214 "did not get a mimetools.Message instance as second "
215 "returned value")
216
217 def test_copy(self):
218 # Test that setting the filename argument works.
219 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000220 self.registerFileForCleanUp(second_temp)
221 result = urllib.urlretrieve(self.constructLocalFileUrl(
222 test_support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000223 self.assertEqual(second_temp, result[0])
224 self.assert_(os.path.exists(second_temp), "copy of the file was not "
225 "made")
Alex Martelli01c77c62006-08-24 02:58:11 +0000226 FILE = open(second_temp, 'rb')
Brett Cannon19691362003-04-29 05:08:06 +0000227 try:
228 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000229 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000230 finally:
231 try: FILE.close()
232 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000233 self.assertEqual(self.text, text)
234
235 def test_reporthook(self):
236 # Make sure that the reporthook works.
237 def hooktester(count, block_size, total_size, count_holder=[0]):
238 self.assert_(isinstance(count, int))
239 self.assert_(isinstance(block_size, int))
240 self.assert_(isinstance(total_size, int))
241 self.assertEqual(count, count_holder[0])
242 count_holder[0] = count_holder[0] + 1
243 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000244 self.registerFileForCleanUp(second_temp)
245 urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN),
246 second_temp, hooktester)
247
248 def test_reporthook_0_bytes(self):
249 # Test on zero length file. Should call reporthook only 1 time.
250 report = []
251 def hooktester(count, block_size, total_size, _report=report):
252 _report.append((count, block_size, total_size))
253 srcFileName = self.createNewTempFile()
254 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
255 test_support.TESTFN, hooktester)
256 self.assertEqual(len(report), 1)
257 self.assertEqual(report[0][2], 0)
258
259 def test_reporthook_5_bytes(self):
260 # Test on 5 byte file. Should call reporthook only 2 times (once when
261 # the "network connection" is established and once when the block is
262 # read). Since the block size is 8192 bytes, only one block read is
263 # required to read the entire file.
264 report = []
265 def hooktester(count, block_size, total_size, _report=report):
266 _report.append((count, block_size, total_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000267 srcFileName = self.createNewTempFile(b"x" * 5)
Georg Brandl5a650a22005-08-26 08:51:34 +0000268 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
269 test_support.TESTFN, hooktester)
270 self.assertEqual(len(report), 2)
271 self.assertEqual(report[0][1], 8192)
272 self.assertEqual(report[0][2], 5)
273
274 def test_reporthook_8193_bytes(self):
275 # Test on 8193 byte file. Should call reporthook only 3 times (once
276 # when the "network connection" is established, once for the next 8192
277 # bytes, and once for the last byte).
278 report = []
279 def hooktester(count, block_size, total_size, _report=report):
280 _report.append((count, block_size, total_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000281 srcFileName = self.createNewTempFile(b"x" * 8193)
Georg Brandl5a650a22005-08-26 08:51:34 +0000282 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
283 test_support.TESTFN, hooktester)
284 self.assertEqual(len(report), 3)
285 self.assertEqual(report[0][1], 8192)
286 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000287
Brett Cannon74bfd702003-04-25 09:39:47 +0000288class QuotingTests(unittest.TestCase):
289 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000290
Brett Cannon74bfd702003-04-25 09:39:47 +0000291 According to RFC 2396 ("Uniform Resource Identifiers), to escape a
292 character you write it as '%' + <2 character US-ASCII hex value>. The Python
293 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly.
294 Case does not matter on the hex letters.
295
296 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000297
Brett Cannon74bfd702003-04-25 09:39:47 +0000298 Reserved characters : ";/?:@&=+$,"
299 Have special meaning in URIs and must be escaped if not being used for
300 their special meaning
301 Data characters : letters, digits, and "-_.!~*'()"
302 Unreserved and do not need to be escaped; can be, though, if desired
303 Control characters : 0x00 - 0x1F, 0x7F
304 Have no use in URIs so must be escaped
305 space : 0x20
306 Must be escaped
307 Delimiters : '<>#%"'
308 Must be escaped
309 Unwise : "{}|\^[]`"
310 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000311
Brett Cannon74bfd702003-04-25 09:39:47 +0000312 """
313
314 def test_never_quote(self):
315 # Make sure quote() does not quote letters, digits, and "_,.-"
316 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
317 "abcdefghijklmnopqrstuvwxyz",
318 "0123456789",
319 "_.-"])
320 result = urllib.quote(do_not_quote)
321 self.assertEqual(do_not_quote, result,
322 "using quote(): %s != %s" % (do_not_quote, result))
323 result = urllib.quote_plus(do_not_quote)
324 self.assertEqual(do_not_quote, result,
325 "using quote_plus(): %s != %s" % (do_not_quote, result))
326
327 def test_default_safe(self):
328 # Test '/' is default value for 'safe' parameter
Neal Norwitz221085d2007-02-25 20:55:47 +0000329 self.assertEqual(urllib.quote.__defaults__[0], '/')
Brett Cannon74bfd702003-04-25 09:39:47 +0000330
331 def test_safe(self):
332 # Test setting 'safe' parameter does what it should do
333 quote_by_default = "<>"
334 result = urllib.quote(quote_by_default, safe=quote_by_default)
335 self.assertEqual(quote_by_default, result,
336 "using quote(): %s != %s" % (quote_by_default, result))
337 result = urllib.quote_plus(quote_by_default, safe=quote_by_default)
338 self.assertEqual(quote_by_default, result,
339 "using quote_plus(): %s != %s" %
340 (quote_by_default, result))
341
342 def test_default_quoting(self):
343 # Make sure all characters that should be quoted are by default sans
344 # space (separate test for that).
345 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
346 should_quote.append('<>#%"{}|\^[]`')
347 should_quote.append(chr(127)) # For 0x7F
348 should_quote = ''.join(should_quote)
349 for char in should_quote:
350 result = urllib.quote(char)
351 self.assertEqual(hexescape(char), result,
352 "using quote(): %s should be escaped to %s, not %s" %
353 (char, hexescape(char), result))
354 result = urllib.quote_plus(char)
355 self.assertEqual(hexescape(char), result,
356 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000357 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000358 (char, hexescape(char), result))
359 del should_quote
360 partial_quote = "ab[]cd"
361 expected = "ab%5B%5Dcd"
362 result = urllib.quote(partial_quote)
363 self.assertEqual(expected, result,
364 "using quote(): %s != %s" % (expected, result))
365 self.assertEqual(expected, result,
366 "using quote_plus(): %s != %s" % (expected, result))
367
368 def test_quoting_space(self):
369 # Make sure quote() and quote_plus() handle spaces as specified in
370 # their unique way
371 result = urllib.quote(' ')
372 self.assertEqual(result, hexescape(' '),
373 "using quote(): %s != %s" % (result, hexescape(' ')))
374 result = urllib.quote_plus(' ')
375 self.assertEqual(result, '+',
376 "using quote_plus(): %s != +" % result)
377 given = "a b cd e f"
378 expect = given.replace(' ', hexescape(' '))
379 result = urllib.quote(given)
380 self.assertEqual(expect, result,
381 "using quote(): %s != %s" % (expect, result))
382 expect = given.replace(' ', '+')
383 result = urllib.quote_plus(given)
384 self.assertEqual(expect, result,
385 "using quote_plus(): %s != %s" % (expect, result))
386
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000387 def test_quoting_plus(self):
388 self.assertEqual(urllib.quote_plus('alpha+beta gamma'),
389 'alpha%2Bbeta+gamma')
390 self.assertEqual(urllib.quote_plus('alpha+beta gamma', '+'),
391 'alpha+beta+gamma')
392
Brett Cannon74bfd702003-04-25 09:39:47 +0000393class UnquotingTests(unittest.TestCase):
394 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000395
Brett Cannon74bfd702003-04-25 09:39:47 +0000396 See the doc string for quoting_Tests for details on quoting and such.
397
398 """
399
400 def test_unquoting(self):
401 # Make sure unquoting of all ASCII values works
402 escape_list = []
403 for num in range(128):
404 given = hexescape(chr(num))
405 expect = chr(num)
406 result = urllib.unquote(given)
407 self.assertEqual(expect, result,
408 "using unquote(): %s != %s" % (expect, result))
409 result = urllib.unquote_plus(given)
410 self.assertEqual(expect, result,
411 "using unquote_plus(): %s != %s" %
412 (expect, result))
413 escape_list.append(given)
414 escape_string = ''.join(escape_list)
415 del escape_list
416 result = urllib.unquote(escape_string)
417 self.assertEqual(result.count('%'), 1,
418 "using quote(): not all characters escaped; %s" %
419 result)
420 result = urllib.unquote(escape_string)
421 self.assertEqual(result.count('%'), 1,
422 "using unquote(): not all characters escaped: "
423 "%s" % result)
424
425 def test_unquoting_parts(self):
426 # Make sure unquoting works when have non-quoted characters
427 # interspersed
428 given = 'ab%sd' % hexescape('c')
429 expect = "abcd"
430 result = urllib.unquote(given)
431 self.assertEqual(expect, result,
432 "using quote(): %s != %s" % (expect, result))
433 result = urllib.unquote_plus(given)
434 self.assertEqual(expect, result,
435 "using unquote_plus(): %s != %s" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000436
Brett Cannon74bfd702003-04-25 09:39:47 +0000437 def test_unquoting_plus(self):
438 # Test difference between unquote() and unquote_plus()
439 given = "are+there+spaces..."
440 expect = given
441 result = urllib.unquote(given)
442 self.assertEqual(expect, result,
443 "using unquote(): %s != %s" % (expect, result))
444 expect = given.replace('+', ' ')
445 result = urllib.unquote_plus(given)
446 self.assertEqual(expect, result,
447 "using unquote_plus(): %s != %s" % (expect, result))
448
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000449 def test_unquote_with_unicode(self):
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000450 r = urllib.unquote('br%C3%BCckner_sapporo_20050930.doc')
451 self.assertEqual(r, 'br\xc3\xbcckner_sapporo_20050930.doc')
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000452
Brett Cannon74bfd702003-04-25 09:39:47 +0000453class urlencode_Tests(unittest.TestCase):
454 """Tests for urlencode()"""
455
456 def help_inputtype(self, given, test_type):
457 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000458
Brett Cannon74bfd702003-04-25 09:39:47 +0000459 'given' must lead to only the pairs:
460 * 1st, 1
461 * 2nd, 2
462 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000463
Brett Cannon74bfd702003-04-25 09:39:47 +0000464 Test cannot assume anything about order. Docs make no guarantee and
465 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000466
Brett Cannon74bfd702003-04-25 09:39:47 +0000467 """
468 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
469 result = urllib.urlencode(given)
470 for expected in expect_somewhere:
471 self.assert_(expected in result,
472 "testing %s: %s not found in %s" %
473 (test_type, expected, result))
474 self.assertEqual(result.count('&'), 2,
475 "testing %s: expected 2 '&'s; got %s" %
476 (test_type, result.count('&')))
477 amp_location = result.index('&')
478 on_amp_left = result[amp_location - 1]
479 on_amp_right = result[amp_location + 1]
480 self.assert_(on_amp_left.isdigit() and on_amp_right.isdigit(),
481 "testing %s: '&' not located in proper place in %s" %
482 (test_type, result))
483 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
484 "testing %s: "
485 "unexpected number of characters: %s != %s" %
486 (test_type, len(result), (5 * 3) + 2))
487
488 def test_using_mapping(self):
489 # Test passing in a mapping object as an argument.
490 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
491 "using dict as input type")
492
493 def test_using_sequence(self):
494 # Test passing in a sequence of two-item sequences as an argument.
495 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
496 "using sequence of two-item tuples as input")
497
498 def test_quoting(self):
499 # Make sure keys and values are quoted using quote_plus()
500 given = {"&":"="}
501 expect = "%s=%s" % (hexescape('&'), hexescape('='))
502 result = urllib.urlencode(given)
503 self.assertEqual(expect, result)
504 given = {"key name":"A bunch of pluses"}
505 expect = "key+name=A+bunch+of+pluses"
506 result = urllib.urlencode(given)
507 self.assertEqual(expect, result)
508
509 def test_doseq(self):
510 # Test that passing True for 'doseq' parameter works correctly
511 given = {'sequence':['1', '2', '3']}
512 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3']))
513 result = urllib.urlencode(given)
514 self.assertEqual(expect, result)
515 result = urllib.urlencode(given, True)
516 for value in given["sequence"]:
517 expect = "sequence=%s" % value
518 self.assert_(expect in result,
519 "%s not found in %s" % (expect, result))
520 self.assertEqual(result.count('&'), 2,
521 "Expected 2 '&'s, got %s" % result.count('&'))
522
523class Pathname_Tests(unittest.TestCase):
524 """Test pathname2url() and url2pathname()"""
525
526 def test_basic(self):
527 # Make sure simple tests pass
528 expected_path = os.path.join("parts", "of", "a", "path")
529 expected_url = "parts/of/a/path"
530 result = urllib.pathname2url(expected_path)
531 self.assertEqual(expected_url, result,
532 "pathname2url() failed; %s != %s" %
533 (result, expected_url))
534 result = urllib.url2pathname(expected_url)
535 self.assertEqual(expected_path, result,
536 "url2pathame() failed; %s != %s" %
537 (result, expected_path))
538
539 def test_quoting(self):
540 # Test automatic quoting and unquoting works for pathnam2url() and
541 # url2pathname() respectively
542 given = os.path.join("needs", "quot=ing", "here")
543 expect = "needs/%s/here" % urllib.quote("quot=ing")
544 result = urllib.pathname2url(given)
545 self.assertEqual(expect, result,
546 "pathname2url() failed; %s != %s" %
547 (expect, result))
548 expect = given
549 result = urllib.url2pathname(result)
550 self.assertEqual(expect, result,
551 "url2pathname() failed; %s != %s" %
552 (expect, result))
553 given = os.path.join("make sure", "using_quote")
554 expect = "%s/using_quote" % urllib.quote("make sure")
555 result = urllib.pathname2url(given)
556 self.assertEqual(expect, result,
557 "pathname2url() failed; %s != %s" %
558 (expect, result))
559 given = "make+sure/using_unquote"
560 expect = os.path.join("make+sure", "using_unquote")
561 result = urllib.url2pathname(given)
562 self.assertEqual(expect, result,
563 "url2pathname() failed; %s != %s" %
564 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000565
Guido van Rossume7ba4952007-06-06 23:52:48 +0000566# Just commented them out.
567# Can't really tell why keep failing in windows and sparc.
568# Everywhere else they work ok, but on those machines, someteimes
569# fail in one of the tests, sometimes in other. I have a linux, and
570# the tests go ok.
571# If anybody has one of the problematic enviroments, please help!
572# . Facundo
573#
574# def server(evt):
575# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
576# serv.settimeout(3)
577# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
578# serv.bind(("", 9093))
579# serv.listen(5)
580# try:
581# conn, addr = serv.accept()
582# conn.send("1 Hola mundo\n")
583# cantdata = 0
584# while cantdata < 13:
585# data = conn.recv(13-cantdata)
586# cantdata += len(data)
587# time.sleep(.3)
588# conn.send("2 No more lines\n")
589# conn.close()
590# except socket.timeout:
591# pass
592# finally:
593# serv.close()
594# evt.set()
595#
596# class FTPWrapperTests(unittest.TestCase):
597#
598# def setUp(self):
599# ftplib.FTP.port = 9093
600# self.evt = threading.Event()
601# threading.Thread(target=server, args=(self.evt,)).start()
602# time.sleep(.1)
603#
604# def tearDown(self):
605# self.evt.wait()
606#
607# def testBasic(self):
608# # connects
609# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
610# ftp.ftp.sock.close()
611#
612# def testTimeoutDefault(self):
613# # default
614# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
615# self.assertTrue(ftp.ftp.sock.gettimeout() is None)
616# ftp.ftp.sock.close()
617#
618# def testTimeoutValue(self):
619# # a value
620# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [], timeout=30)
621# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
622# ftp.ftp.sock.close()
623#
624# def testTimeoutNone(self):
625# # None, having other default
626# previous = socket.getdefaulttimeout()
627# socket.setdefaulttimeout(30)
628# try:
629# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
630# finally:
631# socket.setdefaulttimeout(previous)
632# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
633# ftp.ftp.close()
634#
635
Skip Montanaro080c9972001-01-28 21:12:22 +0000636
637
Brett Cannon74bfd702003-04-25 09:39:47 +0000638def test_main():
Walter Dörwald21d3a322003-05-01 17:45:56 +0000639 test_support.run_unittest(
640 urlopen_FileTests,
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000641 urlopen_HttpTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000642 urlretrieve_FileTests,
643 QuotingTests,
644 UnquotingTests,
645 urlencode_Tests,
Guido van Rossume7ba4952007-06-06 23:52:48 +0000646 Pathname_Tests,
647 #FTPWrapperTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000648 )
Brett Cannon74bfd702003-04-25 09:39:47 +0000649
650
651
652if __name__ == '__main__':
653 test_main()