blob: a87ab71ff9c7c5edd766b71f22fa5bda6ff4aaab [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",
50 "close", "info", "geturl", "__iter__"):
51 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
Brett Cannon74bfd702003-04-25 09:39:47 +000090 def test_iter(self):
91 # Test iterator
92 # Don't need to count number of iterations since test would fail the
93 # instant it returned anything beyond the first line from the
94 # comparison
95 for line in self.returned_obj.__iter__():
96 self.assertEqual(line, self.text)
Skip Montanaro080c9972001-01-28 21:12:22 +000097
Hye-Shik Chang39aef792004-06-05 13:30:56 +000098class urlopen_HttpTests(unittest.TestCase):
99 """Test urlopen() opening a fake http connection."""
100
101 def fakehttp(self, fakedata):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000102 class FakeSocket(io.BytesIO):
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000103 def sendall(self, str): pass
104 def makefile(self, mode, name): return self
105 def read(self, amt=None):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000106 if self.closed: return b""
107 return io.BytesIO.read(self, amt)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000108 def readline(self, length=None):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000109 if self.closed: return b""
110 return io.BytesIO.readline(self, length)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000111 class FakeHTTPConnection(httplib.HTTPConnection):
112 def connect(self):
113 self.sock = FakeSocket(fakedata)
Jeremy Hylton77553ab2007-08-04 19:23:09 +0000114 self._connection_class = httplib.HTTPConnection
115 httplib.HTTPConnection = FakeHTTPConnection
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000116
117 def unfakehttp(self):
Jeremy Hylton77553ab2007-08-04 19:23:09 +0000118 httplib.HTTPConnection = self._connection_class
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000119
120 def test_read(self):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000121 self.fakehttp(b"Hello!")
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000122 try:
123 fp = urllib.urlopen("http://python.org/")
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000124 self.assertEqual(fp.readline(), b"Hello!")
125 self.assertEqual(fp.readline(), b"")
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000126 finally:
127 self.unfakehttp()
128
Christian Heimes57dddfb2008-01-02 18:30:52 +0000129 def test_read_bogus(self):
130 # urlopen() should raise IOError for many error codes.
131 self.fakehttp(b'''HTTP/1.1 401 Authentication Required
132Date: Wed, 02 Jan 2008 03:03:54 GMT
133Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
134Connection: close
135Content-Type: text/html; charset=iso-8859-1
136''')
137 try:
138 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
139 finally:
140 self.unfakehttp()
141
Guido van Rossumd8faa362007-04-27 19:54:29 +0000142 def test_empty_socket(self):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000143 # urlopen() raises IOError if the underlying socket does not send any
144 # data. (#1680230)
Christian Heimes57dddfb2008-01-02 18:30:52 +0000145 self.fakehttp(b'')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000146 try:
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000147 self.assertRaises(IOError, urllib.urlopen, "http://something")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000148 finally:
149 self.unfakehttp()
150
Brett Cannon19691362003-04-29 05:08:06 +0000151class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000152 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000153
Brett Cannon19691362003-04-29 05:08:06 +0000154 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000155 # Create a list of temporary files. Each item in the list is a file
156 # name (absolute path or relative to the current working directory).
157 # All files in this list will be deleted in the tearDown method. Note,
158 # this only helps to makes sure temporary files get deleted, but it
159 # does nothing about trying to close files that may still be open. It
160 # is the responsibility of the developer to properly close files even
161 # when exceptional conditions occur.
162 self.tempFiles = []
163
Brett Cannon19691362003-04-29 05:08:06 +0000164 # Create a temporary file.
Georg Brandl5a650a22005-08-26 08:51:34 +0000165 self.registerFileForCleanUp(test_support.TESTFN)
Guido van Rossuma0982942007-07-10 08:30:03 +0000166 self.text = b'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000167 try:
Alex Martelli01c77c62006-08-24 02:58:11 +0000168 FILE = open(test_support.TESTFN, 'wb')
Georg Brandl5a650a22005-08-26 08:51:34 +0000169 FILE.write(self.text)
170 FILE.close()
171 finally:
172 try: FILE.close()
173 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000174
175 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000176 # Delete the temporary files.
177 for each in self.tempFiles:
178 try: os.remove(each)
179 except: pass
180
181 def constructLocalFileUrl(self, filePath):
182 return "file://%s" % urllib.pathname2url(os.path.abspath(filePath))
183
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000184 def createNewTempFile(self, data=b""):
Georg Brandl5a650a22005-08-26 08:51:34 +0000185 """Creates a new temporary file containing the specified data,
186 registers the file for deletion during the test fixture tear down, and
187 returns the absolute path of the file."""
188
189 newFd, newFilePath = tempfile.mkstemp()
190 try:
191 self.registerFileForCleanUp(newFilePath)
192 newFile = os.fdopen(newFd, "wb")
193 newFile.write(data)
194 newFile.close()
195 finally:
196 try: newFile.close()
197 except: pass
198 return newFilePath
199
200 def registerFileForCleanUp(self, fileName):
201 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000202
203 def test_basic(self):
204 # Make sure that a local file just gets its own location returned and
205 # a headers value is returned.
206 result = urllib.urlretrieve("file:%s" % test_support.TESTFN)
207 self.assertEqual(result[0], test_support.TESTFN)
208 self.assert_(isinstance(result[1], mimetools.Message),
209 "did not get a mimetools.Message instance as second "
210 "returned value")
211
212 def test_copy(self):
213 # Test that setting the filename argument works.
214 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000215 self.registerFileForCleanUp(second_temp)
216 result = urllib.urlretrieve(self.constructLocalFileUrl(
217 test_support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000218 self.assertEqual(second_temp, result[0])
219 self.assert_(os.path.exists(second_temp), "copy of the file was not "
220 "made")
Alex Martelli01c77c62006-08-24 02:58:11 +0000221 FILE = open(second_temp, 'rb')
Brett Cannon19691362003-04-29 05:08:06 +0000222 try:
223 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000224 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000225 finally:
226 try: FILE.close()
227 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000228 self.assertEqual(self.text, text)
229
230 def test_reporthook(self):
231 # Make sure that the reporthook works.
232 def hooktester(count, block_size, total_size, count_holder=[0]):
233 self.assert_(isinstance(count, int))
234 self.assert_(isinstance(block_size, int))
235 self.assert_(isinstance(total_size, int))
236 self.assertEqual(count, count_holder[0])
237 count_holder[0] = count_holder[0] + 1
238 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000239 self.registerFileForCleanUp(second_temp)
240 urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN),
241 second_temp, hooktester)
242
243 def test_reporthook_0_bytes(self):
244 # Test on zero length file. Should call reporthook only 1 time.
245 report = []
246 def hooktester(count, block_size, total_size, _report=report):
247 _report.append((count, block_size, total_size))
248 srcFileName = self.createNewTempFile()
249 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
250 test_support.TESTFN, hooktester)
251 self.assertEqual(len(report), 1)
252 self.assertEqual(report[0][2], 0)
253
254 def test_reporthook_5_bytes(self):
255 # Test on 5 byte file. Should call reporthook only 2 times (once when
256 # the "network connection" is established and once when the block is
257 # read). Since the block size is 8192 bytes, only one block read is
258 # required to read the entire file.
259 report = []
260 def hooktester(count, block_size, total_size, _report=report):
261 _report.append((count, block_size, total_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000262 srcFileName = self.createNewTempFile(b"x" * 5)
Georg Brandl5a650a22005-08-26 08:51:34 +0000263 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
264 test_support.TESTFN, hooktester)
265 self.assertEqual(len(report), 2)
266 self.assertEqual(report[0][1], 8192)
267 self.assertEqual(report[0][2], 5)
268
269 def test_reporthook_8193_bytes(self):
270 # Test on 8193 byte file. Should call reporthook only 3 times (once
271 # when the "network connection" is established, once for the next 8192
272 # bytes, and once for the last byte).
273 report = []
274 def hooktester(count, block_size, total_size, _report=report):
275 _report.append((count, block_size, total_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000276 srcFileName = self.createNewTempFile(b"x" * 8193)
Georg Brandl5a650a22005-08-26 08:51:34 +0000277 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
278 test_support.TESTFN, hooktester)
279 self.assertEqual(len(report), 3)
280 self.assertEqual(report[0][1], 8192)
281 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000282
Brett Cannon74bfd702003-04-25 09:39:47 +0000283class QuotingTests(unittest.TestCase):
284 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000285
Brett Cannon74bfd702003-04-25 09:39:47 +0000286 According to RFC 2396 ("Uniform Resource Identifiers), to escape a
287 character you write it as '%' + <2 character US-ASCII hex value>. The Python
288 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly.
289 Case does not matter on the hex letters.
290
291 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000292
Brett Cannon74bfd702003-04-25 09:39:47 +0000293 Reserved characters : ";/?:@&=+$,"
294 Have special meaning in URIs and must be escaped if not being used for
295 their special meaning
296 Data characters : letters, digits, and "-_.!~*'()"
297 Unreserved and do not need to be escaped; can be, though, if desired
298 Control characters : 0x00 - 0x1F, 0x7F
299 Have no use in URIs so must be escaped
300 space : 0x20
301 Must be escaped
302 Delimiters : '<>#%"'
303 Must be escaped
304 Unwise : "{}|\^[]`"
305 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000306
Brett Cannon74bfd702003-04-25 09:39:47 +0000307 """
308
309 def test_never_quote(self):
310 # Make sure quote() does not quote letters, digits, and "_,.-"
311 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
312 "abcdefghijklmnopqrstuvwxyz",
313 "0123456789",
314 "_.-"])
315 result = urllib.quote(do_not_quote)
316 self.assertEqual(do_not_quote, result,
317 "using quote(): %s != %s" % (do_not_quote, result))
318 result = urllib.quote_plus(do_not_quote)
319 self.assertEqual(do_not_quote, result,
320 "using quote_plus(): %s != %s" % (do_not_quote, result))
321
322 def test_default_safe(self):
323 # Test '/' is default value for 'safe' parameter
Neal Norwitz221085d2007-02-25 20:55:47 +0000324 self.assertEqual(urllib.quote.__defaults__[0], '/')
Brett Cannon74bfd702003-04-25 09:39:47 +0000325
326 def test_safe(self):
327 # Test setting 'safe' parameter does what it should do
328 quote_by_default = "<>"
329 result = urllib.quote(quote_by_default, safe=quote_by_default)
330 self.assertEqual(quote_by_default, result,
331 "using quote(): %s != %s" % (quote_by_default, result))
332 result = urllib.quote_plus(quote_by_default, safe=quote_by_default)
333 self.assertEqual(quote_by_default, result,
334 "using quote_plus(): %s != %s" %
335 (quote_by_default, result))
336
337 def test_default_quoting(self):
338 # Make sure all characters that should be quoted are by default sans
339 # space (separate test for that).
340 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
341 should_quote.append('<>#%"{}|\^[]`')
342 should_quote.append(chr(127)) # For 0x7F
343 should_quote = ''.join(should_quote)
344 for char in should_quote:
345 result = urllib.quote(char)
346 self.assertEqual(hexescape(char), result,
347 "using quote(): %s should be escaped to %s, not %s" %
348 (char, hexescape(char), result))
349 result = urllib.quote_plus(char)
350 self.assertEqual(hexescape(char), result,
351 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000352 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000353 (char, hexescape(char), result))
354 del should_quote
355 partial_quote = "ab[]cd"
356 expected = "ab%5B%5Dcd"
357 result = urllib.quote(partial_quote)
358 self.assertEqual(expected, result,
359 "using quote(): %s != %s" % (expected, result))
360 self.assertEqual(expected, result,
361 "using quote_plus(): %s != %s" % (expected, result))
362
363 def test_quoting_space(self):
364 # Make sure quote() and quote_plus() handle spaces as specified in
365 # their unique way
366 result = urllib.quote(' ')
367 self.assertEqual(result, hexescape(' '),
368 "using quote(): %s != %s" % (result, hexescape(' ')))
369 result = urllib.quote_plus(' ')
370 self.assertEqual(result, '+',
371 "using quote_plus(): %s != +" % result)
372 given = "a b cd e f"
373 expect = given.replace(' ', hexescape(' '))
374 result = urllib.quote(given)
375 self.assertEqual(expect, result,
376 "using quote(): %s != %s" % (expect, result))
377 expect = given.replace(' ', '+')
378 result = urllib.quote_plus(given)
379 self.assertEqual(expect, result,
380 "using quote_plus(): %s != %s" % (expect, result))
381
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000382 def test_quoting_plus(self):
383 self.assertEqual(urllib.quote_plus('alpha+beta gamma'),
384 'alpha%2Bbeta+gamma')
385 self.assertEqual(urllib.quote_plus('alpha+beta gamma', '+'),
386 'alpha+beta+gamma')
387
Brett Cannon74bfd702003-04-25 09:39:47 +0000388class UnquotingTests(unittest.TestCase):
389 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000390
Brett Cannon74bfd702003-04-25 09:39:47 +0000391 See the doc string for quoting_Tests for details on quoting and such.
392
393 """
394
395 def test_unquoting(self):
396 # Make sure unquoting of all ASCII values works
397 escape_list = []
398 for num in range(128):
399 given = hexescape(chr(num))
400 expect = chr(num)
401 result = urllib.unquote(given)
402 self.assertEqual(expect, result,
403 "using unquote(): %s != %s" % (expect, result))
404 result = urllib.unquote_plus(given)
405 self.assertEqual(expect, result,
406 "using unquote_plus(): %s != %s" %
407 (expect, result))
408 escape_list.append(given)
409 escape_string = ''.join(escape_list)
410 del escape_list
411 result = urllib.unquote(escape_string)
412 self.assertEqual(result.count('%'), 1,
413 "using quote(): not all characters escaped; %s" %
414 result)
415 result = urllib.unquote(escape_string)
416 self.assertEqual(result.count('%'), 1,
417 "using unquote(): not all characters escaped: "
418 "%s" % result)
419
420 def test_unquoting_parts(self):
421 # Make sure unquoting works when have non-quoted characters
422 # interspersed
423 given = 'ab%sd' % hexescape('c')
424 expect = "abcd"
425 result = urllib.unquote(given)
426 self.assertEqual(expect, result,
427 "using quote(): %s != %s" % (expect, result))
428 result = urllib.unquote_plus(given)
429 self.assertEqual(expect, result,
430 "using unquote_plus(): %s != %s" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000431
Brett Cannon74bfd702003-04-25 09:39:47 +0000432 def test_unquoting_plus(self):
433 # Test difference between unquote() and unquote_plus()
434 given = "are+there+spaces..."
435 expect = given
436 result = urllib.unquote(given)
437 self.assertEqual(expect, result,
438 "using unquote(): %s != %s" % (expect, result))
439 expect = given.replace('+', ' ')
440 result = urllib.unquote_plus(given)
441 self.assertEqual(expect, result,
442 "using unquote_plus(): %s != %s" % (expect, result))
443
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000444 def test_unquote_with_unicode(self):
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000445 r = urllib.unquote('br%C3%BCckner_sapporo_20050930.doc')
446 self.assertEqual(r, 'br\xc3\xbcckner_sapporo_20050930.doc')
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000447
Brett Cannon74bfd702003-04-25 09:39:47 +0000448class urlencode_Tests(unittest.TestCase):
449 """Tests for urlencode()"""
450
451 def help_inputtype(self, given, test_type):
452 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000453
Brett Cannon74bfd702003-04-25 09:39:47 +0000454 'given' must lead to only the pairs:
455 * 1st, 1
456 * 2nd, 2
457 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000458
Brett Cannon74bfd702003-04-25 09:39:47 +0000459 Test cannot assume anything about order. Docs make no guarantee and
460 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000461
Brett Cannon74bfd702003-04-25 09:39:47 +0000462 """
463 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
464 result = urllib.urlencode(given)
465 for expected in expect_somewhere:
466 self.assert_(expected in result,
467 "testing %s: %s not found in %s" %
468 (test_type, expected, result))
469 self.assertEqual(result.count('&'), 2,
470 "testing %s: expected 2 '&'s; got %s" %
471 (test_type, result.count('&')))
472 amp_location = result.index('&')
473 on_amp_left = result[amp_location - 1]
474 on_amp_right = result[amp_location + 1]
475 self.assert_(on_amp_left.isdigit() and on_amp_right.isdigit(),
476 "testing %s: '&' not located in proper place in %s" %
477 (test_type, result))
478 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
479 "testing %s: "
480 "unexpected number of characters: %s != %s" %
481 (test_type, len(result), (5 * 3) + 2))
482
483 def test_using_mapping(self):
484 # Test passing in a mapping object as an argument.
485 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
486 "using dict as input type")
487
488 def test_using_sequence(self):
489 # Test passing in a sequence of two-item sequences as an argument.
490 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
491 "using sequence of two-item tuples as input")
492
493 def test_quoting(self):
494 # Make sure keys and values are quoted using quote_plus()
495 given = {"&":"="}
496 expect = "%s=%s" % (hexescape('&'), hexescape('='))
497 result = urllib.urlencode(given)
498 self.assertEqual(expect, result)
499 given = {"key name":"A bunch of pluses"}
500 expect = "key+name=A+bunch+of+pluses"
501 result = urllib.urlencode(given)
502 self.assertEqual(expect, result)
503
504 def test_doseq(self):
505 # Test that passing True for 'doseq' parameter works correctly
506 given = {'sequence':['1', '2', '3']}
507 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3']))
508 result = urllib.urlencode(given)
509 self.assertEqual(expect, result)
510 result = urllib.urlencode(given, True)
511 for value in given["sequence"]:
512 expect = "sequence=%s" % value
513 self.assert_(expect in result,
514 "%s not found in %s" % (expect, result))
515 self.assertEqual(result.count('&'), 2,
516 "Expected 2 '&'s, got %s" % result.count('&'))
517
518class Pathname_Tests(unittest.TestCase):
519 """Test pathname2url() and url2pathname()"""
520
521 def test_basic(self):
522 # Make sure simple tests pass
523 expected_path = os.path.join("parts", "of", "a", "path")
524 expected_url = "parts/of/a/path"
525 result = urllib.pathname2url(expected_path)
526 self.assertEqual(expected_url, result,
527 "pathname2url() failed; %s != %s" %
528 (result, expected_url))
529 result = urllib.url2pathname(expected_url)
530 self.assertEqual(expected_path, result,
531 "url2pathame() failed; %s != %s" %
532 (result, expected_path))
533
534 def test_quoting(self):
535 # Test automatic quoting and unquoting works for pathnam2url() and
536 # url2pathname() respectively
537 given = os.path.join("needs", "quot=ing", "here")
538 expect = "needs/%s/here" % urllib.quote("quot=ing")
539 result = urllib.pathname2url(given)
540 self.assertEqual(expect, result,
541 "pathname2url() failed; %s != %s" %
542 (expect, result))
543 expect = given
544 result = urllib.url2pathname(result)
545 self.assertEqual(expect, result,
546 "url2pathname() failed; %s != %s" %
547 (expect, result))
548 given = os.path.join("make sure", "using_quote")
549 expect = "%s/using_quote" % urllib.quote("make sure")
550 result = urllib.pathname2url(given)
551 self.assertEqual(expect, result,
552 "pathname2url() failed; %s != %s" %
553 (expect, result))
554 given = "make+sure/using_unquote"
555 expect = os.path.join("make+sure", "using_unquote")
556 result = urllib.url2pathname(given)
557 self.assertEqual(expect, result,
558 "url2pathname() failed; %s != %s" %
559 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000560
Guido van Rossume7ba4952007-06-06 23:52:48 +0000561# Just commented them out.
562# Can't really tell why keep failing in windows and sparc.
563# Everywhere else they work ok, but on those machines, someteimes
564# fail in one of the tests, sometimes in other. I have a linux, and
565# the tests go ok.
566# If anybody has one of the problematic enviroments, please help!
567# . Facundo
568#
569# def server(evt):
570# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
571# serv.settimeout(3)
572# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
573# serv.bind(("", 9093))
574# serv.listen(5)
575# try:
576# conn, addr = serv.accept()
577# conn.send("1 Hola mundo\n")
578# cantdata = 0
579# while cantdata < 13:
580# data = conn.recv(13-cantdata)
581# cantdata += len(data)
582# time.sleep(.3)
583# conn.send("2 No more lines\n")
584# conn.close()
585# except socket.timeout:
586# pass
587# finally:
588# serv.close()
589# evt.set()
590#
591# class FTPWrapperTests(unittest.TestCase):
592#
593# def setUp(self):
594# ftplib.FTP.port = 9093
595# self.evt = threading.Event()
596# threading.Thread(target=server, args=(self.evt,)).start()
597# time.sleep(.1)
598#
599# def tearDown(self):
600# self.evt.wait()
601#
602# def testBasic(self):
603# # connects
604# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
605# ftp.ftp.sock.close()
606#
607# def testTimeoutDefault(self):
608# # default
609# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
610# self.assertTrue(ftp.ftp.sock.gettimeout() is None)
611# ftp.ftp.sock.close()
612#
613# def testTimeoutValue(self):
614# # a value
615# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [], timeout=30)
616# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
617# ftp.ftp.sock.close()
618#
619# def testTimeoutNone(self):
620# # None, having other default
621# previous = socket.getdefaulttimeout()
622# socket.setdefaulttimeout(30)
623# try:
624# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
625# finally:
626# socket.setdefaulttimeout(previous)
627# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
628# ftp.ftp.close()
629#
630
Skip Montanaro080c9972001-01-28 21:12:22 +0000631
632
Brett Cannon74bfd702003-04-25 09:39:47 +0000633def test_main():
Walter Dörwald21d3a322003-05-01 17:45:56 +0000634 test_support.run_unittest(
635 urlopen_FileTests,
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000636 urlopen_HttpTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000637 urlretrieve_FileTests,
638 QuotingTests,
639 UnquotingTests,
640 urlencode_Tests,
Guido van Rossume7ba4952007-06-06 23:52:48 +0000641 Pathname_Tests,
642 #FTPWrapperTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000643 )
Brett Cannon74bfd702003-04-25 09:39:47 +0000644
645
646
647if __name__ == '__main__':
648 test_main()