blob: 8d41bf089dc72b4453a15a4b052373007a0150b2 [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
8import mimetools
Georg Brandl5a650a22005-08-26 08:51:34 +00009import tempfile
Hye-Shik Chang39aef792004-06-05 13:30:56 +000010import StringIO
Jeremy Hylton6102e292000-08-31 15:48:10 +000011
Brett Cannon74bfd702003-04-25 09:39:47 +000012def hexescape(char):
13 """Escape char as RFC 2396 specifies"""
14 hex_repr = hex(ord(char))[2:].upper()
15 if len(hex_repr) == 1:
16 hex_repr = "0%s" % hex_repr
17 return "%" + hex_repr
Jeremy Hylton6102e292000-08-31 15:48:10 +000018
Brett Cannon74bfd702003-04-25 09:39:47 +000019class urlopen_FileTests(unittest.TestCase):
20 """Test urlopen() opening a temporary file.
Jeremy Hylton6102e292000-08-31 15:48:10 +000021
Brett Cannon74bfd702003-04-25 09:39:47 +000022 Try to test as much functionality as possible so as to cut down on reliance
Andrew M. Kuchlingf1a2f9e2004-06-29 13:07:53 +000023 on connecting to the Net for testing.
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000024
Brett Cannon74bfd702003-04-25 09:39:47 +000025 """
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000026
Brett Cannon74bfd702003-04-25 09:39:47 +000027 def setUp(self):
28 """Setup of a temp file to use for testing"""
29 self.text = "test_urllib: %s\n" % self.__class__.__name__
Guido van Rossum51735b02003-04-25 15:01:05 +000030 FILE = file(test_support.TESTFN, 'wb')
Brett Cannon74bfd702003-04-25 09:39:47 +000031 try:
32 FILE.write(self.text)
33 finally:
34 FILE.close()
35 self.pathname = test_support.TESTFN
36 self.returned_obj = urllib.urlopen("file:%s" % self.pathname)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000037
Brett Cannon74bfd702003-04-25 09:39:47 +000038 def tearDown(self):
39 """Shut down the open object"""
40 self.returned_obj.close()
Brett Cannon19691362003-04-29 05:08:06 +000041 os.remove(test_support.TESTFN)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000042
Brett Cannon74bfd702003-04-25 09:39:47 +000043 def test_interface(self):
44 # Make sure object returned by urlopen() has the specified methods
45 for attr in ("read", "readline", "readlines", "fileno",
Georg Brandl9b0d46d2008-01-20 11:43:03 +000046 "close", "info", "geturl", "getcode", "__iter__"):
Benjamin Peterson5c8da862009-06-30 22:57:08 +000047 self.assertTrue(hasattr(self.returned_obj, attr),
Brett Cannon74bfd702003-04-25 09:39:47 +000048 "object returned by urlopen() lacks %s attribute" %
49 attr)
Skip Montanaroe78b92a2001-01-20 20:22:30 +000050
Brett Cannon74bfd702003-04-25 09:39:47 +000051 def test_read(self):
52 self.assertEqual(self.text, self.returned_obj.read())
Skip Montanaro080c9972001-01-28 21:12:22 +000053
Brett Cannon74bfd702003-04-25 09:39:47 +000054 def test_readline(self):
55 self.assertEqual(self.text, self.returned_obj.readline())
56 self.assertEqual('', self.returned_obj.readline(),
57 "calling readline() after exhausting the file did not"
58 " return an empty string")
Skip Montanaro080c9972001-01-28 21:12:22 +000059
Brett Cannon74bfd702003-04-25 09:39:47 +000060 def test_readlines(self):
61 lines_list = self.returned_obj.readlines()
62 self.assertEqual(len(lines_list), 1,
63 "readlines() returned the wrong number of lines")
64 self.assertEqual(lines_list[0], self.text,
65 "readlines() returned improper text")
Skip Montanaro080c9972001-01-28 21:12:22 +000066
Brett Cannon74bfd702003-04-25 09:39:47 +000067 def test_fileno(self):
68 file_num = self.returned_obj.fileno()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000069 self.assertTrue(isinstance(file_num, int),
Brett Cannon74bfd702003-04-25 09:39:47 +000070 "fileno() did not return an int")
71 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):
Benjamin Peterson5c8da862009-06-30 22:57:08 +000081 self.assertTrue(isinstance(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 +000097
98class ProxyTests(unittest.TestCase):
99
100 def setUp(self):
Walter Dörwald4b965f62009-04-26 20:51:44 +0000101 # Records changes to env vars
102 self.env = test_support.EnvironmentVarGuard()
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000103 # Delete all proxy related env vars
Senthil Kumaran7a2ee0b2010-01-08 19:20:25 +0000104 for k in os.environ.keys():
Walter Dörwald4b965f62009-04-26 20:51:44 +0000105 if 'proxy' in k.lower():
Senthil Kumarandc61ec32009-10-01 01:50:13 +0000106 self.env.unset(k)
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000107
108 def tearDown(self):
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000109 # Restore all proxy related env vars
Walter Dörwald4b965f62009-04-26 20:51:44 +0000110 self.env.__exit__()
111 del self.env
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000112
113 def test_getproxies_environment_keep_no_proxies(self):
Walter Dörwald4b965f62009-04-26 20:51:44 +0000114 self.env.set('NO_PROXY', 'localhost')
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000115 proxies = urllib.getproxies_environment()
116 # getproxies_environment use lowered case truncated (no '_proxy') keys
117 self.assertEquals('localhost', proxies['no'])
118
119
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000120class urlopen_HttpTests(unittest.TestCase):
121 """Test urlopen() opening a fake http connection."""
122
123 def fakehttp(self, fakedata):
124 class FakeSocket(StringIO.StringIO):
125 def sendall(self, str): pass
126 def makefile(self, mode, name): return self
127 def read(self, amt=None):
128 if self.closed: return ''
129 return StringIO.StringIO.read(self, amt)
130 def readline(self, length=None):
131 if self.closed: return ''
132 return StringIO.StringIO.readline(self, length)
133 class FakeHTTPConnection(httplib.HTTPConnection):
134 def connect(self):
135 self.sock = FakeSocket(fakedata)
136 assert httplib.HTTP._connection_class == httplib.HTTPConnection
137 httplib.HTTP._connection_class = FakeHTTPConnection
138
139 def unfakehttp(self):
140 httplib.HTTP._connection_class = httplib.HTTPConnection
141
142 def test_read(self):
143 self.fakehttp('Hello!')
144 try:
145 fp = urllib.urlopen("http://python.org/")
146 self.assertEqual(fp.readline(), 'Hello!')
147 self.assertEqual(fp.readline(), '')
Georg Brandl9b0d46d2008-01-20 11:43:03 +0000148 self.assertEqual(fp.geturl(), 'http://python.org/')
149 self.assertEqual(fp.getcode(), 200)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000150 finally:
151 self.unfakehttp()
152
Kurt B. Kaiser0f7c25d2008-01-02 04:11:28 +0000153 def test_read_bogus(self):
Kurt B. Kaiser0a112322008-01-02 05:23:38 +0000154 # urlopen() should raise IOError for many error codes.
Kurt B. Kaiser0f7c25d2008-01-02 04:11:28 +0000155 self.fakehttp('''HTTP/1.1 401 Authentication Required
156Date: Wed, 02 Jan 2008 03:03:54 GMT
157Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
158Connection: close
159Content-Type: text/html; charset=iso-8859-1
160''')
161 try:
162 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
163 finally:
164 self.unfakehttp()
165
Georg Brandlf66b6032007-03-14 08:27:52 +0000166 def test_empty_socket(self):
Kurt B. Kaiser0a112322008-01-02 05:23:38 +0000167 # urlopen() raises IOError if the underlying socket does not send any
168 # data. (#1680230)
Georg Brandlf66b6032007-03-14 08:27:52 +0000169 self.fakehttp('')
170 try:
171 self.assertRaises(IOError, urllib.urlopen, 'http://something')
172 finally:
173 self.unfakehttp()
174
Brett Cannon19691362003-04-29 05:08:06 +0000175class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000176 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000177
Brett Cannon19691362003-04-29 05:08:06 +0000178 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000179 # Create a list of temporary files. Each item in the list is a file
180 # name (absolute path or relative to the current working directory).
181 # All files in this list will be deleted in the tearDown method. Note,
182 # this only helps to makes sure temporary files get deleted, but it
183 # does nothing about trying to close files that may still be open. It
184 # is the responsibility of the developer to properly close files even
185 # when exceptional conditions occur.
186 self.tempFiles = []
187
Brett Cannon19691362003-04-29 05:08:06 +0000188 # Create a temporary file.
Georg Brandl5a650a22005-08-26 08:51:34 +0000189 self.registerFileForCleanUp(test_support.TESTFN)
Brett Cannon19691362003-04-29 05:08:06 +0000190 self.text = 'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000191 try:
192 FILE = file(test_support.TESTFN, 'wb')
193 FILE.write(self.text)
194 FILE.close()
195 finally:
196 try: FILE.close()
197 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000198
199 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000200 # Delete the temporary files.
201 for each in self.tempFiles:
202 try: os.remove(each)
203 except: pass
204
205 def constructLocalFileUrl(self, filePath):
206 return "file://%s" % urllib.pathname2url(os.path.abspath(filePath))
207
208 def createNewTempFile(self, data=""):
209 """Creates a new temporary file containing the specified data,
210 registers the file for deletion during the test fixture tear down, and
211 returns the absolute path of the file."""
212
213 newFd, newFilePath = tempfile.mkstemp()
214 try:
215 self.registerFileForCleanUp(newFilePath)
216 newFile = os.fdopen(newFd, "wb")
217 newFile.write(data)
218 newFile.close()
219 finally:
220 try: newFile.close()
221 except: pass
222 return newFilePath
223
224 def registerFileForCleanUp(self, fileName):
225 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000226
227 def test_basic(self):
228 # Make sure that a local file just gets its own location returned and
229 # a headers value is returned.
230 result = urllib.urlretrieve("file:%s" % test_support.TESTFN)
231 self.assertEqual(result[0], test_support.TESTFN)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000232 self.assertTrue(isinstance(result[1], mimetools.Message),
Brett Cannon19691362003-04-29 05:08:06 +0000233 "did not get a mimetools.Message instance as second "
234 "returned value")
235
236 def test_copy(self):
237 # Test that setting the filename argument works.
238 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000239 self.registerFileForCleanUp(second_temp)
240 result = urllib.urlretrieve(self.constructLocalFileUrl(
241 test_support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000242 self.assertEqual(second_temp, result[0])
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000243 self.assertTrue(os.path.exists(second_temp), "copy of the file was not "
Brett Cannon19691362003-04-29 05:08:06 +0000244 "made")
245 FILE = file(second_temp, 'rb')
246 try:
247 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000248 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000249 finally:
250 try: FILE.close()
251 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000252 self.assertEqual(self.text, text)
253
254 def test_reporthook(self):
255 # Make sure that the reporthook works.
256 def hooktester(count, block_size, total_size, count_holder=[0]):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000257 self.assertTrue(isinstance(count, int))
258 self.assertTrue(isinstance(block_size, int))
259 self.assertTrue(isinstance(total_size, int))
Brett Cannon19691362003-04-29 05:08:06 +0000260 self.assertEqual(count, count_holder[0])
261 count_holder[0] = count_holder[0] + 1
262 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000263 self.registerFileForCleanUp(second_temp)
264 urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN),
265 second_temp, hooktester)
266
267 def test_reporthook_0_bytes(self):
268 # Test on zero length file. Should call reporthook only 1 time.
269 report = []
270 def hooktester(count, block_size, total_size, _report=report):
271 _report.append((count, block_size, total_size))
272 srcFileName = self.createNewTempFile()
273 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
274 test_support.TESTFN, hooktester)
275 self.assertEqual(len(report), 1)
276 self.assertEqual(report[0][2], 0)
277
278 def test_reporthook_5_bytes(self):
279 # Test on 5 byte file. Should call reporthook only 2 times (once when
280 # the "network connection" is established and once when the block is
281 # read). Since the block size is 8192 bytes, only one block read is
282 # required to read the entire file.
283 report = []
284 def hooktester(count, block_size, total_size, _report=report):
285 _report.append((count, block_size, total_size))
286 srcFileName = self.createNewTempFile("x" * 5)
287 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
288 test_support.TESTFN, hooktester)
289 self.assertEqual(len(report), 2)
290 self.assertEqual(report[0][1], 8192)
291 self.assertEqual(report[0][2], 5)
292
293 def test_reporthook_8193_bytes(self):
294 # Test on 8193 byte file. Should call reporthook only 3 times (once
295 # when the "network connection" is established, once for the next 8192
296 # bytes, and once for the last byte).
297 report = []
298 def hooktester(count, block_size, total_size, _report=report):
299 _report.append((count, block_size, total_size))
300 srcFileName = self.createNewTempFile("x" * 8193)
301 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
302 test_support.TESTFN, hooktester)
303 self.assertEqual(len(report), 3)
304 self.assertEqual(report[0][1], 8192)
305 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000306
Brett Cannon74bfd702003-04-25 09:39:47 +0000307class QuotingTests(unittest.TestCase):
308 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000309
Brett Cannon74bfd702003-04-25 09:39:47 +0000310 According to RFC 2396 ("Uniform Resource Identifiers), to escape a
311 character you write it as '%' + <2 character US-ASCII hex value>. The Python
312 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly.
313 Case does not matter on the hex letters.
314
315 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000316
Brett Cannon74bfd702003-04-25 09:39:47 +0000317 Reserved characters : ";/?:@&=+$,"
318 Have special meaning in URIs and must be escaped if not being used for
319 their special meaning
320 Data characters : letters, digits, and "-_.!~*'()"
321 Unreserved and do not need to be escaped; can be, though, if desired
322 Control characters : 0x00 - 0x1F, 0x7F
323 Have no use in URIs so must be escaped
324 space : 0x20
325 Must be escaped
326 Delimiters : '<>#%"'
327 Must be escaped
328 Unwise : "{}|\^[]`"
329 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000330
Brett Cannon74bfd702003-04-25 09:39:47 +0000331 """
332
333 def test_never_quote(self):
334 # Make sure quote() does not quote letters, digits, and "_,.-"
335 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
336 "abcdefghijklmnopqrstuvwxyz",
337 "0123456789",
338 "_.-"])
339 result = urllib.quote(do_not_quote)
340 self.assertEqual(do_not_quote, result,
341 "using quote(): %s != %s" % (do_not_quote, result))
342 result = urllib.quote_plus(do_not_quote)
343 self.assertEqual(do_not_quote, result,
344 "using quote_plus(): %s != %s" % (do_not_quote, result))
345
346 def test_default_safe(self):
347 # Test '/' is default value for 'safe' parameter
348 self.assertEqual(urllib.quote.func_defaults[0], '/')
349
350 def test_safe(self):
351 # Test setting 'safe' parameter does what it should do
352 quote_by_default = "<>"
353 result = urllib.quote(quote_by_default, safe=quote_by_default)
354 self.assertEqual(quote_by_default, result,
355 "using quote(): %s != %s" % (quote_by_default, result))
356 result = urllib.quote_plus(quote_by_default, safe=quote_by_default)
357 self.assertEqual(quote_by_default, result,
358 "using quote_plus(): %s != %s" %
359 (quote_by_default, result))
360
361 def test_default_quoting(self):
362 # Make sure all characters that should be quoted are by default sans
363 # space (separate test for that).
364 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
365 should_quote.append('<>#%"{}|\^[]`')
366 should_quote.append(chr(127)) # For 0x7F
367 should_quote = ''.join(should_quote)
368 for char in should_quote:
369 result = urllib.quote(char)
370 self.assertEqual(hexescape(char), result,
371 "using quote(): %s should be escaped to %s, not %s" %
372 (char, hexescape(char), result))
373 result = urllib.quote_plus(char)
374 self.assertEqual(hexescape(char), result,
375 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000376 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000377 (char, hexescape(char), result))
378 del should_quote
379 partial_quote = "ab[]cd"
380 expected = "ab%5B%5Dcd"
381 result = urllib.quote(partial_quote)
382 self.assertEqual(expected, result,
383 "using quote(): %s != %s" % (expected, result))
384 self.assertEqual(expected, result,
385 "using quote_plus(): %s != %s" % (expected, result))
386
387 def test_quoting_space(self):
388 # Make sure quote() and quote_plus() handle spaces as specified in
389 # their unique way
390 result = urllib.quote(' ')
391 self.assertEqual(result, hexescape(' '),
392 "using quote(): %s != %s" % (result, hexescape(' ')))
393 result = urllib.quote_plus(' ')
394 self.assertEqual(result, '+',
395 "using quote_plus(): %s != +" % result)
396 given = "a b cd e f"
397 expect = given.replace(' ', hexescape(' '))
398 result = urllib.quote(given)
399 self.assertEqual(expect, result,
400 "using quote(): %s != %s" % (expect, result))
401 expect = given.replace(' ', '+')
402 result = urllib.quote_plus(given)
403 self.assertEqual(expect, result,
404 "using quote_plus(): %s != %s" % (expect, result))
405
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000406 def test_quoting_plus(self):
407 self.assertEqual(urllib.quote_plus('alpha+beta gamma'),
408 'alpha%2Bbeta+gamma')
409 self.assertEqual(urllib.quote_plus('alpha+beta gamma', '+'),
410 'alpha+beta+gamma')
411
Brett Cannon74bfd702003-04-25 09:39:47 +0000412class UnquotingTests(unittest.TestCase):
413 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000414
Brett Cannon74bfd702003-04-25 09:39:47 +0000415 See the doc string for quoting_Tests for details on quoting and such.
416
417 """
418
419 def test_unquoting(self):
420 # Make sure unquoting of all ASCII values works
421 escape_list = []
422 for num in range(128):
423 given = hexescape(chr(num))
424 expect = chr(num)
425 result = urllib.unquote(given)
426 self.assertEqual(expect, result,
427 "using unquote(): %s != %s" % (expect, result))
428 result = urllib.unquote_plus(given)
429 self.assertEqual(expect, result,
430 "using unquote_plus(): %s != %s" %
431 (expect, result))
432 escape_list.append(given)
433 escape_string = ''.join(escape_list)
434 del escape_list
435 result = urllib.unquote(escape_string)
436 self.assertEqual(result.count('%'), 1,
437 "using quote(): not all characters escaped; %s" %
438 result)
439 result = urllib.unquote(escape_string)
440 self.assertEqual(result.count('%'), 1,
441 "using unquote(): not all characters escaped: "
442 "%s" % result)
443
444 def test_unquoting_parts(self):
445 # Make sure unquoting works when have non-quoted characters
446 # interspersed
447 given = 'ab%sd' % hexescape('c')
448 expect = "abcd"
449 result = urllib.unquote(given)
450 self.assertEqual(expect, result,
451 "using quote(): %s != %s" % (expect, result))
452 result = urllib.unquote_plus(given)
453 self.assertEqual(expect, result,
454 "using unquote_plus(): %s != %s" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000455
Brett Cannon74bfd702003-04-25 09:39:47 +0000456 def test_unquoting_plus(self):
457 # Test difference between unquote() and unquote_plus()
458 given = "are+there+spaces..."
459 expect = given
460 result = urllib.unquote(given)
461 self.assertEqual(expect, result,
462 "using unquote(): %s != %s" % (expect, result))
463 expect = given.replace('+', ' ')
464 result = urllib.unquote_plus(given)
465 self.assertEqual(expect, result,
466 "using unquote_plus(): %s != %s" % (expect, result))
467
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000468 def test_unquote_with_unicode(self):
469 r = urllib.unquote(u'br%C3%BCckner_sapporo_20050930.doc')
470 self.assertEqual(r, u'br\xc3\xbcckner_sapporo_20050930.doc')
471
Brett Cannon74bfd702003-04-25 09:39:47 +0000472class urlencode_Tests(unittest.TestCase):
473 """Tests for urlencode()"""
474
475 def help_inputtype(self, given, test_type):
476 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000477
Brett Cannon74bfd702003-04-25 09:39:47 +0000478 'given' must lead to only the pairs:
479 * 1st, 1
480 * 2nd, 2
481 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000482
Brett Cannon74bfd702003-04-25 09:39:47 +0000483 Test cannot assume anything about order. Docs make no guarantee and
484 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000485
Brett Cannon74bfd702003-04-25 09:39:47 +0000486 """
487 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
488 result = urllib.urlencode(given)
489 for expected in expect_somewhere:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000490 self.assertTrue(expected in result,
Brett Cannon74bfd702003-04-25 09:39:47 +0000491 "testing %s: %s not found in %s" %
492 (test_type, expected, result))
493 self.assertEqual(result.count('&'), 2,
494 "testing %s: expected 2 '&'s; got %s" %
495 (test_type, result.count('&')))
496 amp_location = result.index('&')
497 on_amp_left = result[amp_location - 1]
498 on_amp_right = result[amp_location + 1]
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000499 self.assertTrue(on_amp_left.isdigit() and on_amp_right.isdigit(),
Brett Cannon74bfd702003-04-25 09:39:47 +0000500 "testing %s: '&' not located in proper place in %s" %
501 (test_type, result))
502 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
503 "testing %s: "
504 "unexpected number of characters: %s != %s" %
505 (test_type, len(result), (5 * 3) + 2))
506
507 def test_using_mapping(self):
508 # Test passing in a mapping object as an argument.
509 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
510 "using dict as input type")
511
512 def test_using_sequence(self):
513 # Test passing in a sequence of two-item sequences as an argument.
514 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
515 "using sequence of two-item tuples as input")
516
517 def test_quoting(self):
518 # Make sure keys and values are quoted using quote_plus()
519 given = {"&":"="}
520 expect = "%s=%s" % (hexescape('&'), hexescape('='))
521 result = urllib.urlencode(given)
522 self.assertEqual(expect, result)
523 given = {"key name":"A bunch of pluses"}
524 expect = "key+name=A+bunch+of+pluses"
525 result = urllib.urlencode(given)
526 self.assertEqual(expect, result)
527
528 def test_doseq(self):
529 # Test that passing True for 'doseq' parameter works correctly
530 given = {'sequence':['1', '2', '3']}
531 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3']))
532 result = urllib.urlencode(given)
533 self.assertEqual(expect, result)
534 result = urllib.urlencode(given, True)
535 for value in given["sequence"]:
536 expect = "sequence=%s" % value
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000537 self.assertTrue(expect in result,
Brett Cannon74bfd702003-04-25 09:39:47 +0000538 "%s not found in %s" % (expect, result))
539 self.assertEqual(result.count('&'), 2,
540 "Expected 2 '&'s, got %s" % result.count('&'))
541
542class Pathname_Tests(unittest.TestCase):
543 """Test pathname2url() and url2pathname()"""
544
545 def test_basic(self):
546 # Make sure simple tests pass
547 expected_path = os.path.join("parts", "of", "a", "path")
548 expected_url = "parts/of/a/path"
549 result = urllib.pathname2url(expected_path)
550 self.assertEqual(expected_url, result,
551 "pathname2url() failed; %s != %s" %
552 (result, expected_url))
553 result = urllib.url2pathname(expected_url)
554 self.assertEqual(expected_path, result,
555 "url2pathame() failed; %s != %s" %
556 (result, expected_path))
557
558 def test_quoting(self):
559 # Test automatic quoting and unquoting works for pathnam2url() and
560 # url2pathname() respectively
561 given = os.path.join("needs", "quot=ing", "here")
562 expect = "needs/%s/here" % urllib.quote("quot=ing")
563 result = urllib.pathname2url(given)
564 self.assertEqual(expect, result,
565 "pathname2url() failed; %s != %s" %
566 (expect, result))
567 expect = given
568 result = urllib.url2pathname(result)
569 self.assertEqual(expect, result,
570 "url2pathname() failed; %s != %s" %
571 (expect, result))
572 given = os.path.join("make sure", "using_quote")
573 expect = "%s/using_quote" % urllib.quote("make sure")
574 result = urllib.pathname2url(given)
575 self.assertEqual(expect, result,
576 "pathname2url() failed; %s != %s" %
577 (expect, result))
578 given = "make+sure/using_unquote"
579 expect = os.path.join("make+sure", "using_unquote")
580 result = urllib.url2pathname(given)
581 self.assertEqual(expect, result,
582 "url2pathname() failed; %s != %s" %
583 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000584
Senthil Kumaran5e95e762009-03-30 21:51:50 +0000585class Utility_Tests(unittest.TestCase):
586 """Testcase to test the various utility functions in the urllib."""
587
588 def test_splitpasswd(self):
589 """Some of the password examples are not sensible, but it is added to
590 confirming to RFC2617 and addressing issue4675.
591 """
592 self.assertEqual(('user', 'ab'),urllib.splitpasswd('user:ab'))
593 self.assertEqual(('user', 'a\nb'),urllib.splitpasswd('user:a\nb'))
594 self.assertEqual(('user', 'a\tb'),urllib.splitpasswd('user:a\tb'))
595 self.assertEqual(('user', 'a\rb'),urllib.splitpasswd('user:a\rb'))
596 self.assertEqual(('user', 'a\fb'),urllib.splitpasswd('user:a\fb'))
597 self.assertEqual(('user', 'a\vb'),urllib.splitpasswd('user:a\vb'))
598 self.assertEqual(('user', 'a:b'),urllib.splitpasswd('user:a:b'))
599
600
Senthil Kumaran7c2867f2009-04-21 03:24:19 +0000601class URLopener_Tests(unittest.TestCase):
602 """Testcase to test the open method of URLopener class."""
603
604 def test_quoted_open(self):
605 class DummyURLopener(urllib.URLopener):
606 def open_spam(self, url):
607 return url
608
609 self.assertEqual(DummyURLopener().open(
610 'spam://example/ /'),'//example/%20/')
611
612
Facundo Batistad9880d02007-05-25 04:20:22 +0000613# Just commented them out.
614# Can't really tell why keep failing in windows and sparc.
615# Everywhere else they work ok, but on those machines, someteimes
616# fail in one of the tests, sometimes in other. I have a linux, and
617# the tests go ok.
618# If anybody has one of the problematic enviroments, please help!
619# . Facundo
620#
621# def server(evt):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000622# import socket, time
Facundo Batistad9880d02007-05-25 04:20:22 +0000623# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
624# serv.settimeout(3)
625# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
626# serv.bind(("", 9093))
627# serv.listen(5)
628# try:
629# conn, addr = serv.accept()
630# conn.send("1 Hola mundo\n")
631# cantdata = 0
632# while cantdata < 13:
633# data = conn.recv(13-cantdata)
634# cantdata += len(data)
635# time.sleep(.3)
636# conn.send("2 No more lines\n")
637# conn.close()
638# except socket.timeout:
639# pass
640# finally:
641# serv.close()
642# evt.set()
643#
644# class FTPWrapperTests(unittest.TestCase):
645#
646# def setUp(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000647# import ftplib, time, threading
Facundo Batistad9880d02007-05-25 04:20:22 +0000648# ftplib.FTP.port = 9093
649# self.evt = threading.Event()
650# threading.Thread(target=server, args=(self.evt,)).start()
651# time.sleep(.1)
652#
653# def tearDown(self):
654# self.evt.wait()
655#
656# def testBasic(self):
657# # connects
658# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000659# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000660#
661# def testTimeoutNone(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000662# # global default timeout is ignored
663# import socket
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000664# self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000665# socket.setdefaulttimeout(30)
666# try:
667# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
668# finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000669# socket.setdefaulttimeout(None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000670# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000671# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000672#
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000673# def testTimeoutDefault(self):
674# # global default timeout is used
675# import socket
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000676# self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000677# socket.setdefaulttimeout(30)
678# try:
679# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
680# finally:
681# socket.setdefaulttimeout(None)
682# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
683# ftp.close()
684#
685# def testTimeoutValue(self):
686# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [],
687# timeout=30)
688# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
689# ftp.close()
Facundo Batista711a54e2007-05-24 17:50:54 +0000690
Skip Montanaro080c9972001-01-28 21:12:22 +0000691
692
Brett Cannon74bfd702003-04-25 09:39:47 +0000693def test_main():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000694 import warnings
Brett Cannon672237d2008-09-09 00:49:16 +0000695 with warnings.catch_warnings():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000696 warnings.filterwarnings('ignore', ".*urllib\.urlopen.*Python 3.0",
697 DeprecationWarning)
698 test_support.run_unittest(
699 urlopen_FileTests,
700 urlopen_HttpTests,
701 urlretrieve_FileTests,
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000702 ProxyTests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000703 QuotingTests,
704 UnquotingTests,
705 urlencode_Tests,
706 Pathname_Tests,
Senthil Kumaran5e95e762009-03-30 21:51:50 +0000707 Utility_Tests,
Senthil Kumaran7c2867f2009-04-21 03:24:19 +0000708 URLopener_Tests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000709 #FTPWrapperTests,
710 )
Brett Cannon74bfd702003-04-25 09:39:47 +0000711
712
713
714if __name__ == '__main__':
715 test_main()