blob: 1d7fd7324e33a71ecf2f41ded6a0f809461bb88f [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()
Ezio Melottib0f5adc2010-01-24 16:58:36 +000069 self.assertIsInstance(file_num, int, "fileno() did not return an int")
Brett Cannon74bfd702003-04-25 09:39:47 +000070 self.assertEqual(os.read(file_num, len(self.text)), self.text,
71 "Reading on the file descriptor returned by fileno() "
72 "did not return the expected text")
Skip Montanaroe78b92a2001-01-20 20:22:30 +000073
Brett Cannon74bfd702003-04-25 09:39:47 +000074 def test_close(self):
75 # Test close() by calling it hear and then having it be called again
76 # by the tearDown() method for the test
77 self.returned_obj.close()
Skip Montanaro080c9972001-01-28 21:12:22 +000078
Brett Cannon74bfd702003-04-25 09:39:47 +000079 def test_info(self):
Ezio Melottib0f5adc2010-01-24 16:58:36 +000080 self.assertIsInstance(self.returned_obj.info(), mimetools.Message)
Skip Montanaroe78b92a2001-01-20 20:22:30 +000081
Brett Cannon74bfd702003-04-25 09:39:47 +000082 def test_geturl(self):
83 self.assertEqual(self.returned_obj.geturl(), self.pathname)
Skip Montanaro080c9972001-01-28 21:12:22 +000084
Georg Brandl9b0d46d2008-01-20 11:43:03 +000085 def test_getcode(self):
86 self.assertEqual(self.returned_obj.getcode(), None)
87
Brett Cannon74bfd702003-04-25 09:39:47 +000088 def test_iter(self):
89 # Test iterator
90 # Don't need to count number of iterations since test would fail the
91 # instant it returned anything beyond the first line from the
92 # comparison
93 for line in self.returned_obj.__iter__():
94 self.assertEqual(line, self.text)
Skip Montanaro080c9972001-01-28 21:12:22 +000095
Benjamin Peterson2c7470d2008-09-21 21:27:51 +000096
97class ProxyTests(unittest.TestCase):
98
99 def setUp(self):
Walter Dörwald4b965f62009-04-26 20:51:44 +0000100 # Records changes to env vars
101 self.env = test_support.EnvironmentVarGuard()
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000102 # Delete all proxy related env vars
Senthil Kumaran7a2ee0b2010-01-08 19:20:25 +0000103 for k in os.environ.keys():
Walter Dörwald4b965f62009-04-26 20:51:44 +0000104 if 'proxy' in k.lower():
Senthil Kumarandc61ec32009-10-01 01:50:13 +0000105 self.env.unset(k)
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000106
107 def tearDown(self):
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000108 # Restore all proxy related env vars
Walter Dörwald4b965f62009-04-26 20:51:44 +0000109 self.env.__exit__()
110 del self.env
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000111
112 def test_getproxies_environment_keep_no_proxies(self):
Walter Dörwald4b965f62009-04-26 20:51:44 +0000113 self.env.set('NO_PROXY', 'localhost')
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000114 proxies = urllib.getproxies_environment()
115 # getproxies_environment use lowered case truncated (no '_proxy') keys
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
Georg Brandlf66b6032007-03-14 08:27:52 +0000165 def test_empty_socket(self):
Kurt B. Kaiser0a112322008-01-02 05:23:38 +0000166 # urlopen() raises IOError if the underlying socket does not send any
167 # data. (#1680230)
Georg Brandlf66b6032007-03-14 08:27:52 +0000168 self.fakehttp('')
169 try:
170 self.assertRaises(IOError, urllib.urlopen, 'http://something')
171 finally:
172 self.unfakehttp()
173
Brett Cannon19691362003-04-29 05:08:06 +0000174class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000175 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000176
Brett Cannon19691362003-04-29 05:08:06 +0000177 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000178 # Create a list of temporary files. Each item in the list is a file
179 # name (absolute path or relative to the current working directory).
180 # All files in this list will be deleted in the tearDown method. Note,
181 # this only helps to makes sure temporary files get deleted, but it
182 # does nothing about trying to close files that may still be open. It
183 # is the responsibility of the developer to properly close files even
184 # when exceptional conditions occur.
185 self.tempFiles = []
186
Brett Cannon19691362003-04-29 05:08:06 +0000187 # Create a temporary file.
Georg Brandl5a650a22005-08-26 08:51:34 +0000188 self.registerFileForCleanUp(test_support.TESTFN)
Brett Cannon19691362003-04-29 05:08:06 +0000189 self.text = 'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000190 try:
191 FILE = file(test_support.TESTFN, 'wb')
192 FILE.write(self.text)
193 FILE.close()
194 finally:
195 try: FILE.close()
196 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000197
198 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000199 # Delete the temporary files.
200 for each in self.tempFiles:
201 try: os.remove(each)
202 except: pass
203
204 def constructLocalFileUrl(self, filePath):
205 return "file://%s" % urllib.pathname2url(os.path.abspath(filePath))
206
207 def createNewTempFile(self, data=""):
208 """Creates a new temporary file containing the specified data,
209 registers the file for deletion during the test fixture tear down, and
210 returns the absolute path of the file."""
211
212 newFd, newFilePath = tempfile.mkstemp()
213 try:
214 self.registerFileForCleanUp(newFilePath)
215 newFile = os.fdopen(newFd, "wb")
216 newFile.write(data)
217 newFile.close()
218 finally:
219 try: newFile.close()
220 except: pass
221 return newFilePath
222
223 def registerFileForCleanUp(self, fileName):
224 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000225
226 def test_basic(self):
227 # Make sure that a local file just gets its own location returned and
228 # a headers value is returned.
229 result = urllib.urlretrieve("file:%s" % test_support.TESTFN)
230 self.assertEqual(result[0], test_support.TESTFN)
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000231 self.assertIsInstance(result[1], mimetools.Message,
232 "did not get a mimetools.Message instance as "
233 "second returned value")
Brett Cannon19691362003-04-29 05:08:06 +0000234
235 def test_copy(self):
236 # Test that setting the filename argument works.
237 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000238 self.registerFileForCleanUp(second_temp)
239 result = urllib.urlretrieve(self.constructLocalFileUrl(
240 test_support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000241 self.assertEqual(second_temp, result[0])
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000242 self.assertTrue(os.path.exists(second_temp), "copy of the file was not "
Brett Cannon19691362003-04-29 05:08:06 +0000243 "made")
244 FILE = file(second_temp, 'rb')
245 try:
246 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000247 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000248 finally:
249 try: FILE.close()
250 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000251 self.assertEqual(self.text, text)
252
253 def test_reporthook(self):
254 # Make sure that the reporthook works.
255 def hooktester(count, block_size, total_size, count_holder=[0]):
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000256 self.assertIsInstance(count, int)
257 self.assertIsInstance(block_size, int)
258 self.assertIsInstance(total_size, int)
Brett Cannon19691362003-04-29 05:08:06 +0000259 self.assertEqual(count, count_holder[0])
260 count_holder[0] = count_holder[0] + 1
261 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000262 self.registerFileForCleanUp(second_temp)
263 urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN),
264 second_temp, hooktester)
265
266 def test_reporthook_0_bytes(self):
267 # Test on zero length file. Should call reporthook only 1 time.
268 report = []
269 def hooktester(count, block_size, total_size, _report=report):
270 _report.append((count, block_size, total_size))
271 srcFileName = self.createNewTempFile()
272 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
273 test_support.TESTFN, hooktester)
274 self.assertEqual(len(report), 1)
275 self.assertEqual(report[0][2], 0)
276
277 def test_reporthook_5_bytes(self):
278 # Test on 5 byte file. Should call reporthook only 2 times (once when
279 # the "network connection" is established and once when the block is
280 # read). Since the block size is 8192 bytes, only one block read is
281 # required to read the entire file.
282 report = []
283 def hooktester(count, block_size, total_size, _report=report):
284 _report.append((count, block_size, total_size))
285 srcFileName = self.createNewTempFile("x" * 5)
286 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
287 test_support.TESTFN, hooktester)
288 self.assertEqual(len(report), 2)
289 self.assertEqual(report[0][1], 8192)
290 self.assertEqual(report[0][2], 5)
291
292 def test_reporthook_8193_bytes(self):
293 # Test on 8193 byte file. Should call reporthook only 3 times (once
294 # when the "network connection" is established, once for the next 8192
295 # bytes, and once for the last byte).
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" * 8193)
300 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
301 test_support.TESTFN, hooktester)
302 self.assertEqual(len(report), 3)
303 self.assertEqual(report[0][1], 8192)
304 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000305
Brett Cannon74bfd702003-04-25 09:39:47 +0000306class QuotingTests(unittest.TestCase):
307 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000308
Brett Cannon74bfd702003-04-25 09:39:47 +0000309 According to RFC 2396 ("Uniform Resource Identifiers), to escape a
310 character you write it as '%' + <2 character US-ASCII hex value>. The Python
311 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly.
312 Case does not matter on the hex letters.
313
314 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000315
Brett Cannon74bfd702003-04-25 09:39:47 +0000316 Reserved characters : ";/?:@&=+$,"
317 Have special meaning in URIs and must be escaped if not being used for
318 their special meaning
319 Data characters : letters, digits, and "-_.!~*'()"
320 Unreserved and do not need to be escaped; can be, though, if desired
321 Control characters : 0x00 - 0x1F, 0x7F
322 Have no use in URIs so must be escaped
323 space : 0x20
324 Must be escaped
325 Delimiters : '<>#%"'
326 Must be escaped
327 Unwise : "{}|\^[]`"
328 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000329
Brett Cannon74bfd702003-04-25 09:39:47 +0000330 """
331
332 def test_never_quote(self):
333 # Make sure quote() does not quote letters, digits, and "_,.-"
334 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
335 "abcdefghijklmnopqrstuvwxyz",
336 "0123456789",
337 "_.-"])
338 result = urllib.quote(do_not_quote)
339 self.assertEqual(do_not_quote, result,
340 "using quote(): %s != %s" % (do_not_quote, result))
341 result = urllib.quote_plus(do_not_quote)
342 self.assertEqual(do_not_quote, result,
343 "using quote_plus(): %s != %s" % (do_not_quote, result))
344
345 def test_default_safe(self):
346 # Test '/' is default value for 'safe' parameter
347 self.assertEqual(urllib.quote.func_defaults[0], '/')
348
349 def test_safe(self):
350 # Test setting 'safe' parameter does what it should do
351 quote_by_default = "<>"
352 result = urllib.quote(quote_by_default, safe=quote_by_default)
353 self.assertEqual(quote_by_default, result,
354 "using quote(): %s != %s" % (quote_by_default, result))
355 result = urllib.quote_plus(quote_by_default, safe=quote_by_default)
356 self.assertEqual(quote_by_default, result,
357 "using quote_plus(): %s != %s" %
358 (quote_by_default, result))
359
360 def test_default_quoting(self):
361 # Make sure all characters that should be quoted are by default sans
362 # space (separate test for that).
363 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
364 should_quote.append('<>#%"{}|\^[]`')
365 should_quote.append(chr(127)) # For 0x7F
366 should_quote = ''.join(should_quote)
367 for char in should_quote:
368 result = urllib.quote(char)
369 self.assertEqual(hexescape(char), result,
370 "using quote(): %s should be escaped to %s, not %s" %
371 (char, hexescape(char), result))
372 result = urllib.quote_plus(char)
373 self.assertEqual(hexescape(char), result,
374 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000375 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000376 (char, hexescape(char), result))
377 del should_quote
378 partial_quote = "ab[]cd"
379 expected = "ab%5B%5Dcd"
380 result = urllib.quote(partial_quote)
381 self.assertEqual(expected, result,
382 "using quote(): %s != %s" % (expected, result))
383 self.assertEqual(expected, result,
384 "using quote_plus(): %s != %s" % (expected, result))
385
386 def test_quoting_space(self):
387 # Make sure quote() and quote_plus() handle spaces as specified in
388 # their unique way
389 result = urllib.quote(' ')
390 self.assertEqual(result, hexescape(' '),
391 "using quote(): %s != %s" % (result, hexescape(' ')))
392 result = urllib.quote_plus(' ')
393 self.assertEqual(result, '+',
394 "using quote_plus(): %s != +" % result)
395 given = "a b cd e f"
396 expect = given.replace(' ', hexescape(' '))
397 result = urllib.quote(given)
398 self.assertEqual(expect, result,
399 "using quote(): %s != %s" % (expect, result))
400 expect = given.replace(' ', '+')
401 result = urllib.quote_plus(given)
402 self.assertEqual(expect, result,
403 "using quote_plus(): %s != %s" % (expect, result))
404
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000405 def test_quoting_plus(self):
406 self.assertEqual(urllib.quote_plus('alpha+beta gamma'),
407 'alpha%2Bbeta+gamma')
408 self.assertEqual(urllib.quote_plus('alpha+beta gamma', '+'),
409 'alpha+beta+gamma')
410
Brett Cannon74bfd702003-04-25 09:39:47 +0000411class UnquotingTests(unittest.TestCase):
412 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000413
Brett Cannon74bfd702003-04-25 09:39:47 +0000414 See the doc string for quoting_Tests for details on quoting and such.
415
416 """
417
418 def test_unquoting(self):
419 # Make sure unquoting of all ASCII values works
420 escape_list = []
421 for num in range(128):
422 given = hexescape(chr(num))
423 expect = chr(num)
424 result = urllib.unquote(given)
425 self.assertEqual(expect, result,
426 "using unquote(): %s != %s" % (expect, result))
427 result = urllib.unquote_plus(given)
428 self.assertEqual(expect, result,
429 "using unquote_plus(): %s != %s" %
430 (expect, result))
431 escape_list.append(given)
432 escape_string = ''.join(escape_list)
433 del escape_list
434 result = urllib.unquote(escape_string)
435 self.assertEqual(result.count('%'), 1,
436 "using quote(): not all characters escaped; %s" %
437 result)
438 result = urllib.unquote(escape_string)
439 self.assertEqual(result.count('%'), 1,
440 "using unquote(): not all characters escaped: "
441 "%s" % result)
442
443 def test_unquoting_parts(self):
444 # Make sure unquoting works when have non-quoted characters
445 # interspersed
446 given = 'ab%sd' % hexescape('c')
447 expect = "abcd"
448 result = urllib.unquote(given)
449 self.assertEqual(expect, result,
450 "using quote(): %s != %s" % (expect, result))
451 result = urllib.unquote_plus(given)
452 self.assertEqual(expect, result,
453 "using unquote_plus(): %s != %s" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000454
Brett Cannon74bfd702003-04-25 09:39:47 +0000455 def test_unquoting_plus(self):
456 # Test difference between unquote() and unquote_plus()
457 given = "are+there+spaces..."
458 expect = given
459 result = urllib.unquote(given)
460 self.assertEqual(expect, result,
461 "using unquote(): %s != %s" % (expect, result))
462 expect = given.replace('+', ' ')
463 result = urllib.unquote_plus(given)
464 self.assertEqual(expect, result,
465 "using unquote_plus(): %s != %s" % (expect, result))
466
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000467 def test_unquote_with_unicode(self):
468 r = urllib.unquote(u'br%C3%BCckner_sapporo_20050930.doc')
469 self.assertEqual(r, u'br\xc3\xbcckner_sapporo_20050930.doc')
470
Brett Cannon74bfd702003-04-25 09:39:47 +0000471class urlencode_Tests(unittest.TestCase):
472 """Tests for urlencode()"""
473
474 def help_inputtype(self, given, test_type):
475 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000476
Brett Cannon74bfd702003-04-25 09:39:47 +0000477 'given' must lead to only the pairs:
478 * 1st, 1
479 * 2nd, 2
480 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000481
Brett Cannon74bfd702003-04-25 09:39:47 +0000482 Test cannot assume anything about order. Docs make no guarantee and
483 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000484
Brett Cannon74bfd702003-04-25 09:39:47 +0000485 """
486 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
487 result = urllib.urlencode(given)
488 for expected in expect_somewhere:
Ezio Melottiaa980582010-01-23 23:04:36 +0000489 self.assertIn(expected, result,
Brett Cannon74bfd702003-04-25 09:39:47 +0000490 "testing %s: %s not found in %s" %
491 (test_type, expected, result))
492 self.assertEqual(result.count('&'), 2,
493 "testing %s: expected 2 '&'s; got %s" %
494 (test_type, result.count('&')))
495 amp_location = result.index('&')
496 on_amp_left = result[amp_location - 1]
497 on_amp_right = result[amp_location + 1]
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000498 self.assertTrue(on_amp_left.isdigit() and on_amp_right.isdigit(),
Brett Cannon74bfd702003-04-25 09:39:47 +0000499 "testing %s: '&' not located in proper place in %s" %
500 (test_type, result))
501 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
502 "testing %s: "
503 "unexpected number of characters: %s != %s" %
504 (test_type, len(result), (5 * 3) + 2))
505
506 def test_using_mapping(self):
507 # Test passing in a mapping object as an argument.
508 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
509 "using dict as input type")
510
511 def test_using_sequence(self):
512 # Test passing in a sequence of two-item sequences as an argument.
513 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
514 "using sequence of two-item tuples as input")
515
516 def test_quoting(self):
517 # Make sure keys and values are quoted using quote_plus()
518 given = {"&":"="}
519 expect = "%s=%s" % (hexescape('&'), hexescape('='))
520 result = urllib.urlencode(given)
521 self.assertEqual(expect, result)
522 given = {"key name":"A bunch of pluses"}
523 expect = "key+name=A+bunch+of+pluses"
524 result = urllib.urlencode(given)
525 self.assertEqual(expect, result)
526
527 def test_doseq(self):
528 # Test that passing True for 'doseq' parameter works correctly
529 given = {'sequence':['1', '2', '3']}
530 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3']))
531 result = urllib.urlencode(given)
532 self.assertEqual(expect, result)
533 result = urllib.urlencode(given, True)
534 for value in given["sequence"]:
535 expect = "sequence=%s" % value
Ezio Melottiaa980582010-01-23 23:04:36 +0000536 self.assertIn(expect, result)
Brett Cannon74bfd702003-04-25 09:39:47 +0000537 self.assertEqual(result.count('&'), 2,
538 "Expected 2 '&'s, got %s" % result.count('&'))
539
540class Pathname_Tests(unittest.TestCase):
541 """Test pathname2url() and url2pathname()"""
542
543 def test_basic(self):
544 # Make sure simple tests pass
545 expected_path = os.path.join("parts", "of", "a", "path")
546 expected_url = "parts/of/a/path"
547 result = urllib.pathname2url(expected_path)
548 self.assertEqual(expected_url, result,
549 "pathname2url() failed; %s != %s" %
550 (result, expected_url))
551 result = urllib.url2pathname(expected_url)
552 self.assertEqual(expected_path, result,
553 "url2pathame() failed; %s != %s" %
554 (result, expected_path))
555
556 def test_quoting(self):
557 # Test automatic quoting and unquoting works for pathnam2url() and
558 # url2pathname() respectively
559 given = os.path.join("needs", "quot=ing", "here")
560 expect = "needs/%s/here" % urllib.quote("quot=ing")
561 result = urllib.pathname2url(given)
562 self.assertEqual(expect, result,
563 "pathname2url() failed; %s != %s" %
564 (expect, result))
565 expect = given
566 result = urllib.url2pathname(result)
567 self.assertEqual(expect, result,
568 "url2pathname() failed; %s != %s" %
569 (expect, result))
570 given = os.path.join("make sure", "using_quote")
571 expect = "%s/using_quote" % urllib.quote("make sure")
572 result = urllib.pathname2url(given)
573 self.assertEqual(expect, result,
574 "pathname2url() failed; %s != %s" %
575 (expect, result))
576 given = "make+sure/using_unquote"
577 expect = os.path.join("make+sure", "using_unquote")
578 result = urllib.url2pathname(given)
579 self.assertEqual(expect, result,
580 "url2pathname() failed; %s != %s" %
581 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000582
Senthil Kumaran5e95e762009-03-30 21:51:50 +0000583class Utility_Tests(unittest.TestCase):
584 """Testcase to test the various utility functions in the urllib."""
585
586 def test_splitpasswd(self):
587 """Some of the password examples are not sensible, but it is added to
588 confirming to RFC2617 and addressing issue4675.
589 """
590 self.assertEqual(('user', 'ab'),urllib.splitpasswd('user:ab'))
591 self.assertEqual(('user', 'a\nb'),urllib.splitpasswd('user:a\nb'))
592 self.assertEqual(('user', 'a\tb'),urllib.splitpasswd('user:a\tb'))
593 self.assertEqual(('user', 'a\rb'),urllib.splitpasswd('user:a\rb'))
594 self.assertEqual(('user', 'a\fb'),urllib.splitpasswd('user:a\fb'))
595 self.assertEqual(('user', 'a\vb'),urllib.splitpasswd('user:a\vb'))
596 self.assertEqual(('user', 'a:b'),urllib.splitpasswd('user:a:b'))
597
598
Senthil Kumaran7c2867f2009-04-21 03:24:19 +0000599class URLopener_Tests(unittest.TestCase):
600 """Testcase to test the open method of URLopener class."""
601
602 def test_quoted_open(self):
603 class DummyURLopener(urllib.URLopener):
604 def open_spam(self, url):
605 return url
606
607 self.assertEqual(DummyURLopener().open(
608 'spam://example/ /'),'//example/%20/')
609
610
Facundo Batistad9880d02007-05-25 04:20:22 +0000611# Just commented them out.
612# Can't really tell why keep failing in windows and sparc.
613# Everywhere else they work ok, but on those machines, someteimes
614# fail in one of the tests, sometimes in other. I have a linux, and
615# the tests go ok.
616# If anybody has one of the problematic enviroments, please help!
617# . Facundo
618#
619# def server(evt):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000620# import socket, time
Facundo Batistad9880d02007-05-25 04:20:22 +0000621# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
622# serv.settimeout(3)
623# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
624# serv.bind(("", 9093))
625# serv.listen(5)
626# try:
627# conn, addr = serv.accept()
628# conn.send("1 Hola mundo\n")
629# cantdata = 0
630# while cantdata < 13:
631# data = conn.recv(13-cantdata)
632# cantdata += len(data)
633# time.sleep(.3)
634# conn.send("2 No more lines\n")
635# conn.close()
636# except socket.timeout:
637# pass
638# finally:
639# serv.close()
640# evt.set()
641#
642# class FTPWrapperTests(unittest.TestCase):
643#
644# def setUp(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000645# import ftplib, time, threading
Facundo Batistad9880d02007-05-25 04:20:22 +0000646# ftplib.FTP.port = 9093
647# self.evt = threading.Event()
648# threading.Thread(target=server, args=(self.evt,)).start()
649# time.sleep(.1)
650#
651# def tearDown(self):
652# self.evt.wait()
653#
654# def testBasic(self):
655# # connects
656# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000657# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000658#
659# def testTimeoutNone(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000660# # global default timeout is ignored
661# import socket
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000662# self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000663# socket.setdefaulttimeout(30)
664# try:
665# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
666# finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000667# socket.setdefaulttimeout(None)
Facundo Batistad9880d02007-05-25 04:20:22 +0000668# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000669# ftp.close()
Facundo Batistad9880d02007-05-25 04:20:22 +0000670#
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000671# def testTimeoutDefault(self):
672# # global default timeout is used
673# import socket
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000674# self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000675# socket.setdefaulttimeout(30)
676# try:
677# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
678# finally:
679# socket.setdefaulttimeout(None)
680# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
681# ftp.close()
682#
683# def testTimeoutValue(self):
684# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [],
685# timeout=30)
686# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
687# ftp.close()
Facundo Batista711a54e2007-05-24 17:50:54 +0000688
Skip Montanaro080c9972001-01-28 21:12:22 +0000689
690
Brett Cannon74bfd702003-04-25 09:39:47 +0000691def test_main():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000692 import warnings
Brett Cannon672237d2008-09-09 00:49:16 +0000693 with warnings.catch_warnings():
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000694 warnings.filterwarnings('ignore', ".*urllib\.urlopen.*Python 3.0",
695 DeprecationWarning)
696 test_support.run_unittest(
697 urlopen_FileTests,
698 urlopen_HttpTests,
699 urlretrieve_FileTests,
Benjamin Peterson2c7470d2008-09-21 21:27:51 +0000700 ProxyTests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000701 QuotingTests,
702 UnquotingTests,
703 urlencode_Tests,
704 Pathname_Tests,
Senthil Kumaran5e95e762009-03-30 21:51:50 +0000705 Utility_Tests,
Senthil Kumaran7c2867f2009-04-21 03:24:19 +0000706 URLopener_Tests,
Brett Cannon8bb8fa52008-07-02 01:57:08 +0000707 #FTPWrapperTests,
708 )
Brett Cannon74bfd702003-04-25 09:39:47 +0000709
710
711
712if __name__ == '__main__':
713 test_main()