blob: 84b6f253ab74abaf7004227ace9091bf7ad4b88e [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__"):
Brett Cannon74bfd702003-04-25 09:39:47 +000047 self.assert_(hasattr(self.returned_obj, attr),
48 "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()
69 self.assert_(isinstance(file_num, int),
70 "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):
81 self.assert_(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 +000097class ProxyTests(unittest.TestCase):
98
99 def setUp(self):
Walter Dörwald536120e2009-04-26 21:04:55 +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 Kumarand3ffdb42010-01-08 18:25:42 +0000103 for k in os.environ.keys():
Walter Dörwald536120e2009-04-26 21:04:55 +0000104 if 'proxy' in k.lower():
Senthil Kumaranf1250782009-10-05 04:16:26 +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örwald536120e2009-04-26 21:04:55 +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örwald536120e2009-04-26 21:04:55 +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
116 self.assertEquals('localhost', proxies['no'])
117
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
Kurt B. Kaiser0f7c25d2008-01-02 04:11:28 +0000152 def test_read_bogus(self):
Kurt B. Kaiser0a112322008-01-02 05:23:38 +0000153 # urlopen() should raise IOError for many error codes.
Kurt B. Kaiser0f7c25d2008-01-02 04:11:28 +0000154 self.fakehttp('''HTTP/1.1 401 Authentication Required
155Date: Wed, 02 Jan 2008 03:03:54 GMT
156Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
157Connection: close
158Content-Type: text/html; charset=iso-8859-1
159''')
160 try:
161 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
162 finally:
163 self.unfakehttp()
164
guido@google.comf1509302011-03-28 13:47:01 -0700165 def test_invalid_redirect(self):
166 # urlopen() should raise IOError for many error codes.
167 self.fakehttp("""HTTP/1.1 302 Found
168Date: Wed, 02 Jan 2008 03:03:54 GMT
169Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
170Location: file:README
171Connection: close
172Content-Type: text/html; charset=iso-8859-1
173""")
174 try:
175 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
176 finally:
177 self.unfakehttp()
178
Georg Brandlf66b6032007-03-14 08:27:52 +0000179 def test_empty_socket(self):
Kurt B. Kaiser0a112322008-01-02 05:23:38 +0000180 # urlopen() raises IOError if the underlying socket does not send any
181 # data. (#1680230)
Georg Brandlf66b6032007-03-14 08:27:52 +0000182 self.fakehttp('')
183 try:
184 self.assertRaises(IOError, urllib.urlopen, 'http://something')
185 finally:
186 self.unfakehttp()
187
Brett Cannon19691362003-04-29 05:08:06 +0000188class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000189 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000190
Brett Cannon19691362003-04-29 05:08:06 +0000191 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000192 # Create a list of temporary files. Each item in the list is a file
193 # name (absolute path or relative to the current working directory).
194 # All files in this list will be deleted in the tearDown method. Note,
195 # this only helps to makes sure temporary files get deleted, but it
196 # does nothing about trying to close files that may still be open. It
197 # is the responsibility of the developer to properly close files even
198 # when exceptional conditions occur.
199 self.tempFiles = []
200
Brett Cannon19691362003-04-29 05:08:06 +0000201 # Create a temporary file.
Georg Brandl5a650a22005-08-26 08:51:34 +0000202 self.registerFileForCleanUp(test_support.TESTFN)
Brett Cannon19691362003-04-29 05:08:06 +0000203 self.text = 'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000204 try:
205 FILE = file(test_support.TESTFN, 'wb')
206 FILE.write(self.text)
207 FILE.close()
208 finally:
209 try: FILE.close()
210 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000211
212 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000213 # Delete the temporary files.
214 for each in self.tempFiles:
215 try: os.remove(each)
216 except: pass
217
218 def constructLocalFileUrl(self, filePath):
219 return "file://%s" % urllib.pathname2url(os.path.abspath(filePath))
220
221 def createNewTempFile(self, data=""):
222 """Creates a new temporary file containing the specified data,
223 registers the file for deletion during the test fixture tear down, and
224 returns the absolute path of the file."""
225
226 newFd, newFilePath = tempfile.mkstemp()
227 try:
228 self.registerFileForCleanUp(newFilePath)
229 newFile = os.fdopen(newFd, "wb")
230 newFile.write(data)
231 newFile.close()
232 finally:
233 try: newFile.close()
234 except: pass
235 return newFilePath
236
237 def registerFileForCleanUp(self, fileName):
238 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000239
240 def test_basic(self):
241 # Make sure that a local file just gets its own location returned and
242 # a headers value is returned.
243 result = urllib.urlretrieve("file:%s" % test_support.TESTFN)
244 self.assertEqual(result[0], test_support.TESTFN)
245 self.assert_(isinstance(result[1], mimetools.Message),
246 "did not get a mimetools.Message instance as second "
247 "returned value")
248
249 def test_copy(self):
250 # Test that setting the filename argument works.
251 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000252 self.registerFileForCleanUp(second_temp)
253 result = urllib.urlretrieve(self.constructLocalFileUrl(
254 test_support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000255 self.assertEqual(second_temp, result[0])
256 self.assert_(os.path.exists(second_temp), "copy of the file was not "
257 "made")
258 FILE = file(second_temp, 'rb')
259 try:
260 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000261 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000262 finally:
263 try: FILE.close()
264 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000265 self.assertEqual(self.text, text)
266
267 def test_reporthook(self):
268 # Make sure that the reporthook works.
269 def hooktester(count, block_size, total_size, count_holder=[0]):
270 self.assert_(isinstance(count, int))
271 self.assert_(isinstance(block_size, int))
272 self.assert_(isinstance(total_size, int))
273 self.assertEqual(count, count_holder[0])
274 count_holder[0] = count_holder[0] + 1
275 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000276 self.registerFileForCleanUp(second_temp)
277 urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN),
278 second_temp, hooktester)
279
280 def test_reporthook_0_bytes(self):
281 # Test on zero length file. Should call reporthook only 1 time.
282 report = []
283 def hooktester(count, block_size, total_size, _report=report):
284 _report.append((count, block_size, total_size))
285 srcFileName = self.createNewTempFile()
286 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
287 test_support.TESTFN, hooktester)
288 self.assertEqual(len(report), 1)
289 self.assertEqual(report[0][2], 0)
290
291 def test_reporthook_5_bytes(self):
292 # Test on 5 byte file. Should call reporthook only 2 times (once when
293 # the "network connection" is established and once when the block is
294 # read). Since the block size is 8192 bytes, only one block read is
295 # required to read the entire file.
296 report = []
297 def hooktester(count, block_size, total_size, _report=report):
298 _report.append((count, block_size, total_size))
299 srcFileName = self.createNewTempFile("x" * 5)
300 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
301 test_support.TESTFN, hooktester)
302 self.assertEqual(len(report), 2)
303 self.assertEqual(report[0][1], 8192)
304 self.assertEqual(report[0][2], 5)
305
306 def test_reporthook_8193_bytes(self):
307 # Test on 8193 byte file. Should call reporthook only 3 times (once
308 # when the "network connection" is established, once for the next 8192
309 # bytes, and once for the last byte).
310 report = []
311 def hooktester(count, block_size, total_size, _report=report):
312 _report.append((count, block_size, total_size))
313 srcFileName = self.createNewTempFile("x" * 8193)
314 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
315 test_support.TESTFN, hooktester)
316 self.assertEqual(len(report), 3)
317 self.assertEqual(report[0][1], 8192)
318 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000319
Brett Cannon74bfd702003-04-25 09:39:47 +0000320class QuotingTests(unittest.TestCase):
321 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000322
Brett Cannon74bfd702003-04-25 09:39:47 +0000323 According to RFC 2396 ("Uniform Resource Identifiers), to escape a
324 character you write it as '%' + <2 character US-ASCII hex value>. The Python
325 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly.
326 Case does not matter on the hex letters.
327
328 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000329
Brett Cannon74bfd702003-04-25 09:39:47 +0000330 Reserved characters : ";/?:@&=+$,"
331 Have special meaning in URIs and must be escaped if not being used for
332 their special meaning
333 Data characters : letters, digits, and "-_.!~*'()"
334 Unreserved and do not need to be escaped; can be, though, if desired
335 Control characters : 0x00 - 0x1F, 0x7F
336 Have no use in URIs so must be escaped
337 space : 0x20
338 Must be escaped
339 Delimiters : '<>#%"'
340 Must be escaped
341 Unwise : "{}|\^[]`"
342 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000343
Brett Cannon74bfd702003-04-25 09:39:47 +0000344 """
345
346 def test_never_quote(self):
347 # Make sure quote() does not quote letters, digits, and "_,.-"
348 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
349 "abcdefghijklmnopqrstuvwxyz",
350 "0123456789",
351 "_.-"])
352 result = urllib.quote(do_not_quote)
353 self.assertEqual(do_not_quote, result,
354 "using quote(): %s != %s" % (do_not_quote, result))
355 result = urllib.quote_plus(do_not_quote)
356 self.assertEqual(do_not_quote, result,
357 "using quote_plus(): %s != %s" % (do_not_quote, result))
358
359 def test_default_safe(self):
360 # Test '/' is default value for 'safe' parameter
361 self.assertEqual(urllib.quote.func_defaults[0], '/')
362
363 def test_safe(self):
364 # Test setting 'safe' parameter does what it should do
365 quote_by_default = "<>"
366 result = urllib.quote(quote_by_default, safe=quote_by_default)
367 self.assertEqual(quote_by_default, result,
368 "using quote(): %s != %s" % (quote_by_default, result))
369 result = urllib.quote_plus(quote_by_default, safe=quote_by_default)
370 self.assertEqual(quote_by_default, result,
371 "using quote_plus(): %s != %s" %
372 (quote_by_default, result))
373
374 def test_default_quoting(self):
375 # Make sure all characters that should be quoted are by default sans
376 # space (separate test for that).
377 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
378 should_quote.append('<>#%"{}|\^[]`')
379 should_quote.append(chr(127)) # For 0x7F
380 should_quote = ''.join(should_quote)
381 for char in should_quote:
382 result = urllib.quote(char)
383 self.assertEqual(hexescape(char), result,
384 "using quote(): %s should be escaped to %s, not %s" %
385 (char, hexescape(char), result))
386 result = urllib.quote_plus(char)
387 self.assertEqual(hexescape(char), result,
388 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000389 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000390 (char, hexescape(char), result))
391 del should_quote
392 partial_quote = "ab[]cd"
393 expected = "ab%5B%5Dcd"
394 result = urllib.quote(partial_quote)
395 self.assertEqual(expected, result,
396 "using quote(): %s != %s" % (expected, result))
397 self.assertEqual(expected, result,
398 "using quote_plus(): %s != %s" % (expected, result))
399
400 def test_quoting_space(self):
401 # Make sure quote() and quote_plus() handle spaces as specified in
402 # their unique way
403 result = urllib.quote(' ')
404 self.assertEqual(result, hexescape(' '),
405 "using quote(): %s != %s" % (result, hexescape(' ')))
406 result = urllib.quote_plus(' ')
407 self.assertEqual(result, '+',
408 "using quote_plus(): %s != +" % result)
409 given = "a b cd e f"
410 expect = given.replace(' ', hexescape(' '))
411 result = urllib.quote(given)
412 self.assertEqual(expect, result,
413 "using quote(): %s != %s" % (expect, result))
414 expect = given.replace(' ', '+')
415 result = urllib.quote_plus(given)
416 self.assertEqual(expect, result,
417 "using quote_plus(): %s != %s" % (expect, result))
418
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000419 def test_quoting_plus(self):
420 self.assertEqual(urllib.quote_plus('alpha+beta gamma'),
421 'alpha%2Bbeta+gamma')
422 self.assertEqual(urllib.quote_plus('alpha+beta gamma', '+'),
423 'alpha+beta+gamma')
424
Brett Cannon74bfd702003-04-25 09:39:47 +0000425class UnquotingTests(unittest.TestCase):
426 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000427
Brett Cannon74bfd702003-04-25 09:39:47 +0000428 See the doc string for quoting_Tests for details on quoting and such.
429
430 """
431
432 def test_unquoting(self):
433 # Make sure unquoting of all ASCII values works
434 escape_list = []
435 for num in range(128):
436 given = hexescape(chr(num))
437 expect = chr(num)
438 result = urllib.unquote(given)
439 self.assertEqual(expect, result,
440 "using unquote(): %s != %s" % (expect, result))
441 result = urllib.unquote_plus(given)
442 self.assertEqual(expect, result,
443 "using unquote_plus(): %s != %s" %
444 (expect, result))
445 escape_list.append(given)
446 escape_string = ''.join(escape_list)
447 del escape_list
448 result = urllib.unquote(escape_string)
449 self.assertEqual(result.count('%'), 1,
450 "using quote(): not all characters escaped; %s" %
451 result)
452 result = urllib.unquote(escape_string)
453 self.assertEqual(result.count('%'), 1,
454 "using unquote(): not all characters escaped: "
455 "%s" % result)
456
Senthil Kumaran34f92772010-03-29 19:30:44 +0000457 def test_unquoting_badpercent(self):
458 # Test unquoting on bad percent-escapes
459 given = '%xab'
460 expect = given
461 result = urllib.unquote(given)
462 self.assertEqual(expect, result, "using unquote(): %r != %r"
463 % (expect, result))
464 given = '%x'
465 expect = given
466 result = urllib.unquote(given)
467 self.assertEqual(expect, result, "using unquote(): %r != %r"
468 % (expect, result))
469 given = '%'
470 expect = given
471 result = urllib.unquote(given)
472 self.assertEqual(expect, result, "using unquote(): %r != %r"
473 % (expect, result))
474
475 def test_unquoting_mixed_case(self):
476 # Test unquoting on mixed-case hex digits in the percent-escapes
477 given = '%Ab%eA'
478 expect = '\xab\xea'
479 result = urllib.unquote(given)
480 self.assertEqual(expect, result, "using unquote(): %r != %r"
481 % (expect, result))
482
Brett Cannon74bfd702003-04-25 09:39:47 +0000483 def test_unquoting_parts(self):
484 # Make sure unquoting works when have non-quoted characters
485 # interspersed
486 given = 'ab%sd' % hexescape('c')
487 expect = "abcd"
488 result = urllib.unquote(given)
489 self.assertEqual(expect, result,
490 "using quote(): %s != %s" % (expect, result))
491 result = urllib.unquote_plus(given)
492 self.assertEqual(expect, result,
493 "using unquote_plus(): %s != %s" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000494
Brett Cannon74bfd702003-04-25 09:39:47 +0000495 def test_unquoting_plus(self):
496 # Test difference between unquote() and unquote_plus()
497 given = "are+there+spaces..."
498 expect = given
499 result = urllib.unquote(given)
500 self.assertEqual(expect, result,
501 "using unquote(): %s != %s" % (expect, result))
502 expect = given.replace('+', ' ')
503 result = urllib.unquote_plus(given)
504 self.assertEqual(expect, result,
505 "using unquote_plus(): %s != %s" % (expect, result))
506
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000507 def test_unquote_with_unicode(self):
508 r = urllib.unquote(u'br%C3%BCckner_sapporo_20050930.doc')
509 self.assertEqual(r, u'br\xc3\xbcckner_sapporo_20050930.doc')
510
Brett Cannon74bfd702003-04-25 09:39:47 +0000511class urlencode_Tests(unittest.TestCase):
512 """Tests for urlencode()"""
513
514 def help_inputtype(self, given, test_type):
515 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000516
Brett Cannon74bfd702003-04-25 09:39:47 +0000517 'given' must lead to only the pairs:
518 * 1st, 1
519 * 2nd, 2
520 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000521
Brett Cannon74bfd702003-04-25 09:39:47 +0000522 Test cannot assume anything about order. Docs make no guarantee and
523 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000524
Brett Cannon74bfd702003-04-25 09:39:47 +0000525 """
526 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
527 result = urllib.urlencode(given)
528 for expected in expect_somewhere:
529 self.assert_(expected in result,
530 "testing %s: %s not found in %s" %
531 (test_type, expected, result))
532 self.assertEqual(result.count('&'), 2,
533 "testing %s: expected 2 '&'s; got %s" %
534 (test_type, result.count('&')))
535 amp_location = result.index('&')
536 on_amp_left = result[amp_location - 1]
537 on_amp_right = result[amp_location + 1]
538 self.assert_(on_amp_left.isdigit() and on_amp_right.isdigit(),
539 "testing %s: '&' not located in proper place in %s" %
540 (test_type, result))
541 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
542 "testing %s: "
543 "unexpected number of characters: %s != %s" %
544 (test_type, len(result), (5 * 3) + 2))
545
546 def test_using_mapping(self):
547 # Test passing in a mapping object as an argument.
548 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
549 "using dict as input type")
550
551 def test_using_sequence(self):
552 # Test passing in a sequence of two-item sequences as an argument.
553 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
554 "using sequence of two-item tuples as input")
555
556 def test_quoting(self):
557 # Make sure keys and values are quoted using quote_plus()
558 given = {"&":"="}
559 expect = "%s=%s" % (hexescape('&'), hexescape('='))
560 result = urllib.urlencode(given)
561 self.assertEqual(expect, result)
562 given = {"key name":"A bunch of pluses"}
563 expect = "key+name=A+bunch+of+pluses"
564 result = urllib.urlencode(given)
565 self.assertEqual(expect, result)
566
567 def test_doseq(self):
568 # Test that passing True for 'doseq' parameter works correctly
569 given = {'sequence':['1', '2', '3']}
570 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3']))
571 result = urllib.urlencode(given)
572 self.assertEqual(expect, result)
573 result = urllib.urlencode(given, True)
574 for value in given["sequence"]:
575 expect = "sequence=%s" % value
576 self.assert_(expect in result,
577 "%s not found in %s" % (expect, result))
578 self.assertEqual(result.count('&'), 2,
579 "Expected 2 '&'s, got %s" % result.count('&'))
580
581class Pathname_Tests(unittest.TestCase):
582 """Test pathname2url() and url2pathname()"""
583
584 def test_basic(self):
585 # Make sure simple tests pass
586 expected_path = os.path.join("parts", "of", "a", "path")
587 expected_url = "parts/of/a/path"
588 result = urllib.pathname2url(expected_path)
589 self.assertEqual(expected_url, result,
590 "pathname2url() failed; %s != %s" %
591 (result, expected_url))
592 result = urllib.url2pathname(expected_url)
593 self.assertEqual(expected_path, result,
594 "url2pathame() failed; %s != %s" %
595 (result, expected_path))
596
597 def test_quoting(self):
598 # Test automatic quoting and unquoting works for pathnam2url() and
599 # url2pathname() respectively
600 given = os.path.join("needs", "quot=ing", "here")
601 expect = "needs/%s/here" % urllib.quote("quot=ing")
602 result = urllib.pathname2url(given)
603 self.assertEqual(expect, result,
604 "pathname2url() failed; %s != %s" %
605 (expect, result))
606 expect = given
607 result = urllib.url2pathname(result)
608 self.assertEqual(expect, result,
609 "url2pathname() failed; %s != %s" %
610 (expect, result))
611 given = os.path.join("make sure", "using_quote")
612 expect = "%s/using_quote" % urllib.quote("make sure")
613 result = urllib.pathname2url(given)
614 self.assertEqual(expect, result,
615 "pathname2url() failed; %s != %s" %
616 (expect, result))
617 given = "make+sure/using_unquote"
618 expect = os.path.join("make+sure", "using_unquote")
619 result = urllib.url2pathname(given)
620 self.assertEqual(expect, result,
621 "url2pathname() failed; %s != %s" %
622 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000623
Senthil Kumaranb52c6f82009-08-15 17:49:55 +0000624class URLopener_Tests(unittest.TestCase):
625 """Testcase to test the open method of URLopener class."""
626 def test_quoted_open(self):
627 class DummyURLopener(urllib.URLopener):
628 def open_spam(self, url):
629 return url
630
631 self.assertEqual(DummyURLopener().open(
632 'spam://example/ /'),'//example/%20/')
633
Senthil Kumarana241d0a2010-02-20 22:13:01 +0000634 # test the safe characters are not quoted by urlopen
635 self.assertEqual(DummyURLopener().open(
636 "spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"),
637 "//c:|windows%/:=&?~#+!$,;'@()*[]|/path/")
638
Senthil Kumaranb52c6f82009-08-15 17:49:55 +0000639
Facundo Batistad9880d02007-05-25 04:20:22 +0000640# Just commented them out.
641# Can't really tell why keep failing in windows and sparc.
642# Everywhere else they work ok, but on those machines, someteimes
643# fail in one of the tests, sometimes in other. I have a linux, and
644# the tests go ok.
645# If anybody has one of the problematic enviroments, please help!
646# . Facundo
647#
648# def server(evt):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000649# import socket, time
Facundo Batistad9880d02007-05-25 04:20:22 +0000650# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
651# serv.settimeout(3)
652# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
653# serv.bind(("", 9093))
654# serv.listen(5)
655# try:
656# conn, addr = serv.accept()
657# conn.send("1 Hola mundo\n")
658# cantdata = 0
659# while cantdata < 13:
660# data = conn.recv(13-cantdata)
661# cantdata += len(data)
662# time.sleep(.3)
663# conn.send("2 No more lines\n")
664# conn.close()
665# except socket.timeout:
666# pass
667# finally:
668# serv.close()
669# evt.set()
670#
671# class FTPWrapperTests(unittest.TestCase):
672#
673# def setUp(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000674# import ftplib, time, threading
Facundo Batistad9880d02007-05-25 04:20:22 +0000675# ftplib.FTP.port = 9093
676# self.evt = threading.Event()
677# threading.Thread(target=server, args=(self.evt,)).start()
678# time.sleep(.1)
679#
680# def tearDown(self):
681# self.evt.wait()
682#
683# def testBasic(self):
684# # connects
685# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000686# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000687#
688# def testTimeoutNone(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000689# # global default timeout is ignored
690# import socket
691# self.assert_(socket.getdefaulttimeout() is None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000692# socket.setdefaulttimeout(30)
693# try:
694# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
695# finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000696# socket.setdefaulttimeout(None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000697# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000698# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000699#
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000700# def testTimeoutDefault(self):
701# # global default timeout is used
702# import socket
703# self.assert_(socket.getdefaulttimeout() is None)
704# socket.setdefaulttimeout(30)
705# try:
706# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
707# finally:
708# socket.setdefaulttimeout(None)
709# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
710# ftp.close()
711#
712# def testTimeoutValue(self):
713# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [],
714# timeout=30)
715# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
716# ftp.close()
Facundo Batista711a54e2007-05-24 17:50:54 +0000717
Skip Montanaro080c9972001-01-28 21:12:22 +0000718
719
Brett Cannon74bfd702003-04-25 09:39:47 +0000720def test_main():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000721 import warnings
Brett Cannon672237d2008-09-09 00:49:16 +0000722 with warnings.catch_warnings():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000723 warnings.filterwarnings('ignore', ".*urllib\.urlopen.*Python 3.0",
724 DeprecationWarning)
725 test_support.run_unittest(
726 urlopen_FileTests,
727 urlopen_HttpTests,
728 urlretrieve_FileTests,
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000729 ProxyTests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000730 QuotingTests,
731 UnquotingTests,
732 urlencode_Tests,
733 Pathname_Tests,
Senthil Kumaranb52c6f82009-08-15 17:49:55 +0000734 URLopener_Tests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000735 #FTPWrapperTests,
736 )
Brett Cannon74bfd702003-04-25 09:39:47 +0000737
738
739
740if __name__ == '__main__':
741 test_main()