blob: 72db1ef29c14b6c7f799b50c9f90ec8a4d3abc0c [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",
46 "close", "info", "geturl", "__iter__"):
47 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
Brett Cannon74bfd702003-04-25 09:39:47 +000086 def test_iter(self):
87 # Test iterator
88 # Don't need to count number of iterations since test would fail the
89 # instant it returned anything beyond the first line from the
90 # comparison
91 for line in self.returned_obj.__iter__():
92 self.assertEqual(line, self.text)
Skip Montanaro080c9972001-01-28 21:12:22 +000093
Hye-Shik Chang39aef792004-06-05 13:30:56 +000094class urlopen_HttpTests(unittest.TestCase):
95 """Test urlopen() opening a fake http connection."""
96
97 def fakehttp(self, fakedata):
98 class FakeSocket(StringIO.StringIO):
99 def sendall(self, str): pass
100 def makefile(self, mode, name): return self
101 def read(self, amt=None):
102 if self.closed: return ''
103 return StringIO.StringIO.read(self, amt)
104 def readline(self, length=None):
105 if self.closed: return ''
106 return StringIO.StringIO.readline(self, length)
107 class FakeHTTPConnection(httplib.HTTPConnection):
108 def connect(self):
109 self.sock = FakeSocket(fakedata)
110 assert httplib.HTTP._connection_class == httplib.HTTPConnection
111 httplib.HTTP._connection_class = FakeHTTPConnection
112
113 def unfakehttp(self):
114 httplib.HTTP._connection_class = httplib.HTTPConnection
115
116 def test_read(self):
117 self.fakehttp('Hello!')
118 try:
119 fp = urllib.urlopen("http://python.org/")
120 self.assertEqual(fp.readline(), 'Hello!')
121 self.assertEqual(fp.readline(), '')
122 finally:
123 self.unfakehttp()
124
guido@google.comf1509302011-03-28 13:47:01 -0700125 def test_invalid_redirect(self):
126 # urlopen() should raise IOError for many error codes.
127 self.fakehttp("""HTTP/1.1 302 Found
128Date: Wed, 02 Jan 2008 03:03:54 GMT
129Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
130Location: file:README
131Connection: close
132Content-Type: text/html; charset=iso-8859-1
133""")
134 try:
135 self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
136 finally:
137 self.unfakehttp()
138
Georg Brandl027ac242007-03-14 08:27:57 +0000139 def test_empty_socket(self):
140 """urlopen() raises IOError if the underlying socket does not send any
141 data. (#1680230) """
142 self.fakehttp('')
143 try:
144 self.assertRaises(IOError, urllib.urlopen, 'http://something')
145 finally:
146 self.unfakehttp()
147
Brett Cannon19691362003-04-29 05:08:06 +0000148class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000149 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000150
Brett Cannon19691362003-04-29 05:08:06 +0000151 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000152 # Create a list of temporary files. Each item in the list is a file
153 # name (absolute path or relative to the current working directory).
154 # All files in this list will be deleted in the tearDown method. Note,
155 # this only helps to makes sure temporary files get deleted, but it
156 # does nothing about trying to close files that may still be open. It
157 # is the responsibility of the developer to properly close files even
158 # when exceptional conditions occur.
159 self.tempFiles = []
160
Brett Cannon19691362003-04-29 05:08:06 +0000161 # Create a temporary file.
Georg Brandl5a650a22005-08-26 08:51:34 +0000162 self.registerFileForCleanUp(test_support.TESTFN)
Brett Cannon19691362003-04-29 05:08:06 +0000163 self.text = 'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000164 try:
165 FILE = file(test_support.TESTFN, 'wb')
166 FILE.write(self.text)
167 FILE.close()
168 finally:
169 try: FILE.close()
170 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000171
172 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000173 # Delete the temporary files.
174 for each in self.tempFiles:
175 try: os.remove(each)
176 except: pass
177
178 def constructLocalFileUrl(self, filePath):
179 return "file://%s" % urllib.pathname2url(os.path.abspath(filePath))
180
181 def createNewTempFile(self, data=""):
182 """Creates a new temporary file containing the specified data,
183 registers the file for deletion during the test fixture tear down, and
184 returns the absolute path of the file."""
185
186 newFd, newFilePath = tempfile.mkstemp()
187 try:
188 self.registerFileForCleanUp(newFilePath)
189 newFile = os.fdopen(newFd, "wb")
190 newFile.write(data)
191 newFile.close()
192 finally:
193 try: newFile.close()
194 except: pass
195 return newFilePath
196
197 def registerFileForCleanUp(self, fileName):
198 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000199
200 def test_basic(self):
201 # Make sure that a local file just gets its own location returned and
202 # a headers value is returned.
203 result = urllib.urlretrieve("file:%s" % test_support.TESTFN)
204 self.assertEqual(result[0], test_support.TESTFN)
205 self.assert_(isinstance(result[1], mimetools.Message),
206 "did not get a mimetools.Message instance as second "
207 "returned value")
208
209 def test_copy(self):
210 # Test that setting the filename argument works.
211 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000212 self.registerFileForCleanUp(second_temp)
213 result = urllib.urlretrieve(self.constructLocalFileUrl(
214 test_support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000215 self.assertEqual(second_temp, result[0])
216 self.assert_(os.path.exists(second_temp), "copy of the file was not "
217 "made")
218 FILE = file(second_temp, 'rb')
219 try:
220 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000221 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000222 finally:
223 try: FILE.close()
224 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000225 self.assertEqual(self.text, text)
226
227 def test_reporthook(self):
228 # Make sure that the reporthook works.
229 def hooktester(count, block_size, total_size, count_holder=[0]):
230 self.assert_(isinstance(count, int))
231 self.assert_(isinstance(block_size, int))
232 self.assert_(isinstance(total_size, int))
233 self.assertEqual(count, count_holder[0])
234 count_holder[0] = count_holder[0] + 1
235 second_temp = "%s.2" % test_support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000236 self.registerFileForCleanUp(second_temp)
237 urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN),
238 second_temp, hooktester)
239
240 def test_reporthook_0_bytes(self):
241 # Test on zero length file. Should call reporthook only 1 time.
242 report = []
243 def hooktester(count, block_size, total_size, _report=report):
244 _report.append((count, block_size, total_size))
245 srcFileName = self.createNewTempFile()
246 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
247 test_support.TESTFN, hooktester)
248 self.assertEqual(len(report), 1)
249 self.assertEqual(report[0][2], 0)
250
251 def test_reporthook_5_bytes(self):
252 # Test on 5 byte file. Should call reporthook only 2 times (once when
253 # the "network connection" is established and once when the block is
254 # read). Since the block size is 8192 bytes, only one block read is
255 # required to read the entire file.
256 report = []
257 def hooktester(count, block_size, total_size, _report=report):
258 _report.append((count, block_size, total_size))
259 srcFileName = self.createNewTempFile("x" * 5)
260 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
261 test_support.TESTFN, hooktester)
262 self.assertEqual(len(report), 2)
263 self.assertEqual(report[0][1], 8192)
264 self.assertEqual(report[0][2], 5)
265
266 def test_reporthook_8193_bytes(self):
267 # Test on 8193 byte file. Should call reporthook only 3 times (once
268 # when the "network connection" is established, once for the next 8192
269 # bytes, and once for the last byte).
270 report = []
271 def hooktester(count, block_size, total_size, _report=report):
272 _report.append((count, block_size, total_size))
273 srcFileName = self.createNewTempFile("x" * 8193)
274 urllib.urlretrieve(self.constructLocalFileUrl(srcFileName),
275 test_support.TESTFN, hooktester)
276 self.assertEqual(len(report), 3)
277 self.assertEqual(report[0][1], 8192)
278 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000279
Brett Cannon74bfd702003-04-25 09:39:47 +0000280class QuotingTests(unittest.TestCase):
281 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000282
Brett Cannon74bfd702003-04-25 09:39:47 +0000283 According to RFC 2396 ("Uniform Resource Identifiers), to escape a
284 character you write it as '%' + <2 character US-ASCII hex value>. The Python
285 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly.
286 Case does not matter on the hex letters.
287
288 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000289
Brett Cannon74bfd702003-04-25 09:39:47 +0000290 Reserved characters : ";/?:@&=+$,"
291 Have special meaning in URIs and must be escaped if not being used for
292 their special meaning
293 Data characters : letters, digits, and "-_.!~*'()"
294 Unreserved and do not need to be escaped; can be, though, if desired
295 Control characters : 0x00 - 0x1F, 0x7F
296 Have no use in URIs so must be escaped
297 space : 0x20
298 Must be escaped
299 Delimiters : '<>#%"'
300 Must be escaped
301 Unwise : "{}|\^[]`"
302 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000303
Brett Cannon74bfd702003-04-25 09:39:47 +0000304 """
305
306 def test_never_quote(self):
307 # Make sure quote() does not quote letters, digits, and "_,.-"
308 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
309 "abcdefghijklmnopqrstuvwxyz",
310 "0123456789",
311 "_.-"])
312 result = urllib.quote(do_not_quote)
313 self.assertEqual(do_not_quote, result,
314 "using quote(): %s != %s" % (do_not_quote, result))
315 result = urllib.quote_plus(do_not_quote)
316 self.assertEqual(do_not_quote, result,
317 "using quote_plus(): %s != %s" % (do_not_quote, result))
318
319 def test_default_safe(self):
320 # Test '/' is default value for 'safe' parameter
321 self.assertEqual(urllib.quote.func_defaults[0], '/')
322
323 def test_safe(self):
324 # Test setting 'safe' parameter does what it should do
325 quote_by_default = "<>"
326 result = urllib.quote(quote_by_default, safe=quote_by_default)
327 self.assertEqual(quote_by_default, result,
328 "using quote(): %s != %s" % (quote_by_default, result))
329 result = urllib.quote_plus(quote_by_default, safe=quote_by_default)
330 self.assertEqual(quote_by_default, result,
331 "using quote_plus(): %s != %s" %
332 (quote_by_default, result))
333
334 def test_default_quoting(self):
335 # Make sure all characters that should be quoted are by default sans
336 # space (separate test for that).
337 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
338 should_quote.append('<>#%"{}|\^[]`')
339 should_quote.append(chr(127)) # For 0x7F
340 should_quote = ''.join(should_quote)
341 for char in should_quote:
342 result = urllib.quote(char)
343 self.assertEqual(hexescape(char), result,
344 "using quote(): %s should be escaped to %s, not %s" %
345 (char, hexescape(char), result))
346 result = urllib.quote_plus(char)
347 self.assertEqual(hexescape(char), result,
348 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000349 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000350 (char, hexescape(char), result))
351 del should_quote
352 partial_quote = "ab[]cd"
353 expected = "ab%5B%5Dcd"
354 result = urllib.quote(partial_quote)
355 self.assertEqual(expected, result,
356 "using quote(): %s != %s" % (expected, result))
357 self.assertEqual(expected, result,
358 "using quote_plus(): %s != %s" % (expected, result))
359
360 def test_quoting_space(self):
361 # Make sure quote() and quote_plus() handle spaces as specified in
362 # their unique way
363 result = urllib.quote(' ')
364 self.assertEqual(result, hexescape(' '),
365 "using quote(): %s != %s" % (result, hexescape(' ')))
366 result = urllib.quote_plus(' ')
367 self.assertEqual(result, '+',
368 "using quote_plus(): %s != +" % result)
369 given = "a b cd e f"
370 expect = given.replace(' ', hexescape(' '))
371 result = urllib.quote(given)
372 self.assertEqual(expect, result,
373 "using quote(): %s != %s" % (expect, result))
374 expect = given.replace(' ', '+')
375 result = urllib.quote_plus(given)
376 self.assertEqual(expect, result,
377 "using quote_plus(): %s != %s" % (expect, result))
378
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000379 def test_quoting_plus(self):
380 self.assertEqual(urllib.quote_plus('alpha+beta gamma'),
381 'alpha%2Bbeta+gamma')
382 self.assertEqual(urllib.quote_plus('alpha+beta gamma', '+'),
383 'alpha+beta+gamma')
384
Brett Cannon74bfd702003-04-25 09:39:47 +0000385class UnquotingTests(unittest.TestCase):
386 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000387
Brett Cannon74bfd702003-04-25 09:39:47 +0000388 See the doc string for quoting_Tests for details on quoting and such.
389
390 """
391
392 def test_unquoting(self):
393 # Make sure unquoting of all ASCII values works
394 escape_list = []
395 for num in range(128):
396 given = hexescape(chr(num))
397 expect = chr(num)
398 result = urllib.unquote(given)
399 self.assertEqual(expect, result,
400 "using unquote(): %s != %s" % (expect, result))
401 result = urllib.unquote_plus(given)
402 self.assertEqual(expect, result,
403 "using unquote_plus(): %s != %s" %
404 (expect, result))
405 escape_list.append(given)
406 escape_string = ''.join(escape_list)
407 del escape_list
408 result = urllib.unquote(escape_string)
409 self.assertEqual(result.count('%'), 1,
410 "using quote(): not all characters escaped; %s" %
411 result)
412 result = urllib.unquote(escape_string)
413 self.assertEqual(result.count('%'), 1,
414 "using unquote(): not all characters escaped: "
415 "%s" % result)
416
417 def test_unquoting_parts(self):
418 # Make sure unquoting works when have non-quoted characters
419 # interspersed
420 given = 'ab%sd' % hexescape('c')
421 expect = "abcd"
422 result = urllib.unquote(given)
423 self.assertEqual(expect, result,
424 "using quote(): %s != %s" % (expect, result))
425 result = urllib.unquote_plus(given)
426 self.assertEqual(expect, result,
427 "using unquote_plus(): %s != %s" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000428
Brett Cannon74bfd702003-04-25 09:39:47 +0000429 def test_unquoting_plus(self):
430 # Test difference between unquote() and unquote_plus()
431 given = "are+there+spaces..."
432 expect = given
433 result = urllib.unquote(given)
434 self.assertEqual(expect, result,
435 "using unquote(): %s != %s" % (expect, result))
436 expect = given.replace('+', ' ')
437 result = urllib.unquote_plus(given)
438 self.assertEqual(expect, result,
439 "using unquote_plus(): %s != %s" % (expect, result))
440
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000441 def test_unquote_with_unicode(self):
442 r = urllib.unquote(u'br%C3%BCckner_sapporo_20050930.doc')
443 self.assertEqual(r, u'br\xc3\xbcckner_sapporo_20050930.doc')
444
Brett Cannon74bfd702003-04-25 09:39:47 +0000445class urlencode_Tests(unittest.TestCase):
446 """Tests for urlencode()"""
447
448 def help_inputtype(self, given, test_type):
449 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000450
Brett Cannon74bfd702003-04-25 09:39:47 +0000451 'given' must lead to only the pairs:
452 * 1st, 1
453 * 2nd, 2
454 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000455
Brett Cannon74bfd702003-04-25 09:39:47 +0000456 Test cannot assume anything about order. Docs make no guarantee and
457 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000458
Brett Cannon74bfd702003-04-25 09:39:47 +0000459 """
460 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
461 result = urllib.urlencode(given)
462 for expected in expect_somewhere:
463 self.assert_(expected in result,
464 "testing %s: %s not found in %s" %
465 (test_type, expected, result))
466 self.assertEqual(result.count('&'), 2,
467 "testing %s: expected 2 '&'s; got %s" %
468 (test_type, result.count('&')))
469 amp_location = result.index('&')
470 on_amp_left = result[amp_location - 1]
471 on_amp_right = result[amp_location + 1]
472 self.assert_(on_amp_left.isdigit() and on_amp_right.isdigit(),
473 "testing %s: '&' not located in proper place in %s" %
474 (test_type, result))
475 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
476 "testing %s: "
477 "unexpected number of characters: %s != %s" %
478 (test_type, len(result), (5 * 3) + 2))
479
480 def test_using_mapping(self):
481 # Test passing in a mapping object as an argument.
482 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
483 "using dict as input type")
484
485 def test_using_sequence(self):
486 # Test passing in a sequence of two-item sequences as an argument.
487 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
488 "using sequence of two-item tuples as input")
489
490 def test_quoting(self):
491 # Make sure keys and values are quoted using quote_plus()
492 given = {"&":"="}
493 expect = "%s=%s" % (hexescape('&'), hexescape('='))
494 result = urllib.urlencode(given)
495 self.assertEqual(expect, result)
496 given = {"key name":"A bunch of pluses"}
497 expect = "key+name=A+bunch+of+pluses"
498 result = urllib.urlencode(given)
499 self.assertEqual(expect, result)
500
501 def test_doseq(self):
502 # Test that passing True for 'doseq' parameter works correctly
503 given = {'sequence':['1', '2', '3']}
504 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3']))
505 result = urllib.urlencode(given)
506 self.assertEqual(expect, result)
507 result = urllib.urlencode(given, True)
508 for value in given["sequence"]:
509 expect = "sequence=%s" % value
510 self.assert_(expect in result,
511 "%s not found in %s" % (expect, result))
512 self.assertEqual(result.count('&'), 2,
513 "Expected 2 '&'s, got %s" % result.count('&'))
514
515class Pathname_Tests(unittest.TestCase):
516 """Test pathname2url() and url2pathname()"""
517
518 def test_basic(self):
519 # Make sure simple tests pass
520 expected_path = os.path.join("parts", "of", "a", "path")
521 expected_url = "parts/of/a/path"
522 result = urllib.pathname2url(expected_path)
523 self.assertEqual(expected_url, result,
524 "pathname2url() failed; %s != %s" %
525 (result, expected_url))
526 result = urllib.url2pathname(expected_url)
527 self.assertEqual(expected_path, result,
528 "url2pathame() failed; %s != %s" %
529 (result, expected_path))
530
531 def test_quoting(self):
532 # Test automatic quoting and unquoting works for pathnam2url() and
533 # url2pathname() respectively
534 given = os.path.join("needs", "quot=ing", "here")
535 expect = "needs/%s/here" % urllib.quote("quot=ing")
536 result = urllib.pathname2url(given)
537 self.assertEqual(expect, result,
538 "pathname2url() failed; %s != %s" %
539 (expect, result))
540 expect = given
541 result = urllib.url2pathname(result)
542 self.assertEqual(expect, result,
543 "url2pathname() failed; %s != %s" %
544 (expect, result))
545 given = os.path.join("make sure", "using_quote")
546 expect = "%s/using_quote" % urllib.quote("make sure")
547 result = urllib.pathname2url(given)
548 self.assertEqual(expect, result,
549 "pathname2url() failed; %s != %s" %
550 (expect, result))
551 given = "make+sure/using_unquote"
552 expect = os.path.join("make+sure", "using_unquote")
553 result = urllib.url2pathname(given)
554 self.assertEqual(expect, result,
555 "url2pathname() failed; %s != %s" %
556 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000557
Skip Montanaro080c9972001-01-28 21:12:22 +0000558
559
Brett Cannon74bfd702003-04-25 09:39:47 +0000560def test_main():
Walter Dörwald21d3a322003-05-01 17:45:56 +0000561 test_support.run_unittest(
562 urlopen_FileTests,
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000563 urlopen_HttpTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000564 urlretrieve_FileTests,
565 QuotingTests,
566 UnquotingTests,
567 urlencode_Tests,
568 Pathname_Tests
569 )
Brett Cannon74bfd702003-04-25 09:39:47 +0000570
571
572
573if __name__ == '__main__':
574 test_main()